| name | ||
.c
|
C source code | |
.h
|
C header file | |
.s
|
(or .asm)
|
assembly file |
.o
|
(or .obj)
|
object file (binary of assembly) |
| (none) |
(or .exe)
|
executable file |
| .a |
(or .lib)
|
statically linked library |
| [collection of .o files] | ||
| .so |
(or .dll or .dylib)
|
dynamically linked library |
| [‘shared object’] |
Unix-like
internally: archive of .o files with index
create: ar rcs libfoo.a file1.o file2.o …
ar and not normal C compileruse:
-l and library namecc could be clang, gcc, clang++, g++, etc.-L/path/to/lib not needed if in standard locationLinux
create:
-fPIC (position independent code)cc -shared … -o libfoo.souse:
cc = C compiler (clang, gcc, etc.)-L… sets path
runtime path set separately
$ ls
libexample.so main.c
$ clang -o main main.c -lexample
/usr/bin/ld: cannot find -lexample
clang: error: linker command failed with exit code 1 (use -v to see invocation)
$ clang -o main main.c -L. -lexample
$ ./main
./main: error while loading shared libraries:
libexample.so: cannot open shared object file: No such
file or directory
$ LD_LIBRARY_PATH=. ./main
$ export LD_LIBRARY_PATH=.
$ ./main
$ clang -o main main.c -L. -lexample -Wl,-rpath .
$ ./main
/path/to/lib only used to create programlibfoo.so Linux default: libfoo.so expected to be in /usr/lib, /lib, and other ‘standard’ locations
possible overrides:
-Wl,-rpath=/path/to/lib when creating executablea.c:
void foo() { puts("A"); }
b.c:
void foo() { puts("B"); }
main.c:
int main() {foo();}
$ clang -c main.c -o main.o
$ clang -c a.c -o a.o
$ ar rcs libfoo.a a.o
$ clang main.o -L. -lfoo -o program
$ ./program
A
$ rm libfoo.a
$ clang -c b.c -o b.o
$ ar rcs libfoo.a b.o
$ ./program
exercise: output?
a.c:
void foo() { puts("A"); }
b.c:
void foo() { puts("B"); }
main.c:
int main() {foo();}
$ clang -c main.c -o main.o
$ clang -fPIC -c a.c -o a.o
$ clang -shared -o libfoo.so a.o
$ clang main.o -Wl,-rpath . -L. -lfoo -o program
$ ./program
A
$ rm libfoo.so
$ clang -fPIC -c b.c -o b.o
$ clang -shared -o libfoo.so b.o
$ ./program
exercise: output?
when linking against libraries use:
clang -o executable foo.o bar.o -lName
rather than
clang -o executable -lName foo.o bar.o
by default, linker processes files in order
might only grab things that previous files needed from library
clang -c main.c # command 1
clang -c extra.c # command 2
clang -o program main.o extra.o # command 3
What commands need to be rerun if…
make — Unix program for ‘‘making’’ things…
… by running commands based on what’s changed
what commands? based on
makefile or Makefile (no extension))main.o: main.c main.h extra.h
▶ clang -Wall -c main.c
before colon: target(s) (file(s) generated/updated)
after colon: prerequisite(s) (also known as dependencies)
following lines prefixed by a tab character: command(s) to run
make runs commands if any prereq modified date after target
… after making sure prerequisites up to date
program: main.o extra.o
▶ clang -Wall -o program main.o extra.o
extra.o: extra.c extra.h
▶ clang -Wall -c extra.c
main.o: main.c main.h extra.h
▶ clang -Wall -c main.c
program, first…‘‘make ’’
Makefile in current directory for rulestarget is up-to-date‘‘make ’’
‘‘make’’
firstTarget ’’ is the first rule in Makefile,make firstTarget ’’| A. none |
B. buildY only
|
C. buildW then buildY
|
D. buildY then buildW
|
||
F. buildX then buildW
|
G. something else |
first: to make W, need X, Y up to date
then build W if less recent than X (yes, now) or Y (yes) \(\checkmark{}\)
all: program1 program2 libfoo.a
make all’’ effectively shorthand for ‘‘make program1 program2 libfoo.a’’make clean’’ to remove generated filesclean:
▶ rm –force main.o extra.o
clean:
▶ rm –force main.o extra.o
all: program1 program2 libfoo.a
clean:
▶ rm –force main.o extra.o
all: program1 program2 libfoo.a
special .PHONY rule says ‘‘ ‘all’ and ‘clean’ not real files’’
(not required by POSIX, but in every make version I know)
| target name | purpose |
(default), all
|
build everything |
install
|
install to standard location |
test
|
run tests |
clean
|
remove generated files |
program: main.o extra.o
▶ clang -Wall -o program main.o extra.o
extra.o: extra.c extra.h
▶ clang -Wall -o extra.o -c extra.c
main.o: main.c main.h extra.h
▶ clang -o main.o -c main.c
clang with -fsanitize=address instead of -Wall?clangto gcc?CC = gcc
CFLAGS = -Wall -pedantic -std=c11 -fsanitize=address
LDFLAGS = -Wall -pedantic -fsanitize=address
LDLIBS = -lm
program: main.o extra.o
▶ $(CC) $(LDFLAGS) -o program main.o extra.o $(LDLIBS)
extra.o: extra.c extra.h
▶ $(CC) $(CFLAGS) -o extra.o -c extra.c
main.o: main.c main.h extra.h
▶ $(CC) $(CFLAGS) -o main.o -c main.c
CC, CFLAGS, LDFLAGS, etc.
CC
|
C compiler |
CFLAGS
|
C compiler options |
LDFLAGS
|
linking options |
LIBS or LDLIBS
|
libraries |
CC = gcc
CFLAGS = -Wall
LDFLAGS = -Wall
LDLIBS = -lm
program: main.o extra.o
▶ $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
extra.o: extra.c extra.h
▶ $(CC) $(CFLAGS) -o $@ -c $<
main.o: main.c main.h extra.h
▶ $(CC) $(CFLAGS) -o $@ -c $<
aside: $^ works on GNU make (usual on Linux), but not portable.
multiple implementations of make
for stuff we’ve talked about so far, no differences
most common on Linux: GNU make
will talk about ‘pattern rules’, which aren’t supported by some other make versions
CC = gcc
CFLAGS = -Wall
LDFLAGS = -Wall
LDLIBS = -lm
program: main.o extra.o
▶ $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
%.o: %.c
▶ $(CC) $(CFLAGS) -o $@ -c $<
extra.o: extra.c extra.h
main.o: main.c main.h extra.h
aside: these rules work on GNU make (usual on Linux), but less portable than suffix rules.
CC = gcc
CFLAGS = -Wall
LDFLAGS = -Wall
LDLIBS = -lm
program: main.o extra.o
▶ $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
extra.o: extra.c extra.h
main.o: main.c main.h extra.h
error-prone to write all .h dependencies
-MM (and related) options to gcc or clang
Makefile generators
alternatives to writing Makefiles:
other make-ish build systems
tools that generate inputs for make-ish build systems