Kompilacja i budowanie programów¶
Etapy kompilacji¶
gcc uruchamia kolejno cztery programy. Każdy etap można wykonać osobno:
| Etap | Polecenie | Wynik |
|---|---|---|
| preprocessing | gcc -E prog.c -o prog.i |
kod C z wklejonymi #include i rozwiniętymi #define |
| compilation | gcc -S prog.c |
prog.s: kod w asemblerze |
| assembly | gcc -c prog.c |
prog.o: plik obiektowy |
| linking | gcc prog.o -o prog |
program |
- Kompilator przetwarza jeden plik
.cnaraz. - Plik obiektowy zawiera kod i listę symboli:
nm prog.opokazuje zdefiniowane (T) i brakujące (U). - Linker łączy pliki obiektowe i biblioteki, uzupełniając brakujące symbole.
Program z wielu plików:
gcc -c main.c -o main.o
gcc -c util.c -o util.o
gcc main.o util.o -o prog
Rodzaje błędów¶
main.c:6:10: fatal error: util.h: No such file or directory preprocessor
main.c:12:5: error: implicit declaration of function 'foo' compiler
undefined reference to `foo' linker
multiple definition of `foo' linker
- Błąd z numerem linii: kompilacja pojedynczego pliku.
undefined reference: brak definicji, np. brak pliku.olub biblioteki w poleceniu, albo nazwa w nagłówku różni się od nazwy w bibliotece.multiple definition: ta sama funkcja zdefiniowana w dwóch plikach.
Nagłówki i biblioteki¶
Nagłówek (.h) zawiera deklaracje, biblioteka zawiera kod.
| Opcja | Znaczenie |
|---|---|
-Iinclude |
katalog z nagłówkami |
-Llib |
katalog z bibliotekami |
-lfoo |
dołącz libfoo.so lub libfoo.a |
-lm |
biblioteka matematyczna |
Biblioteki podajemy po plikach obiektowych: linker czyta argumenty od lewej.
gcc main.o util.o -Llib -lfoo -lm -o prog # dobrze
gcc -lm -lfoo main.o util.o -o prog # undefined reference
nm -D libfoo.so wypisuje funkcje udostępniane przez bibliotekę.
Biblioteki statyczne i dzielone¶
| Statyczna | Dzielona | |
|---|---|---|
| plik | libfoo.a |
libfoo.so (Windows .dll, macOS .dylib) |
| tworzenie | ar rcs libfoo.a a.o b.o |
gcc -shared -fPIC foo.c -o libfoo.so |
| kod | kopiowany do programu | wczytywany przy uruchomieniu przez loader |
Loader szuka bibliotek w katalogach systemowych:
$ ./prog
./prog: error while loading shared libraries: libfoo.so: cannot open shared object file
$ ldd ./prog
libfoo.so => not found
LD_LIBRARY_PATH=lib ./prog: dodatkowy katalog na jedno uruchomienie.gcc ... -Wl,-rpath,'$ORIGIN/lib': ścieżka zapisana w programie;$ORIGINto katalog programu. Sprawdzenie:readelf -d prog. W macOS:@loader_path.
Przydatne opcje¶
| Opcja | Działanie |
|---|---|
-Wall -Wextra |
ostrzeżenia |
-Werror |
ostrzeżenia jako błędy |
-g |
informacje dla debuggera |
-O0, -O2 |
bez optymalizacji / z optymalizacjami |
-std=c17 |
wersja języka |
-fsanitize=address,undefined |
wykrywanie błędów pamięci i niezdefiniowanych zachowań w czasie działania |
Sanitizer zgłasza błąd, gdy program wykona błędną linię; z -g podaje jej numer:
palette.c:20:19: runtime error: index 256 out of bounds for type 'rgb [256]'
make¶
Makefile składa się z reguł: cel, zależności, polecenie (wcięte tabulatorem).
prog: main.o util.o
gcc main.o util.o -o prog
main.o: main.c util.h
gcc -c main.c -o main.o
util.o: util.c util.h
gcc -c util.c -o util.o
Cel jest budowany, gdy nie istnieje lub któraś zależność jest od niego nowsza.
make buduje pierwszy cel w pliku, make util.o wskazany.
Ze zmiennymi i regułą wzorcową:
CC = gcc
CFLAGS = -Wall -Wextra -g -Iinclude
LDFLAGS = -Llib
LDLIBS = -lm
OBJS = src/main.o src/util.o
prog: $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@
src/%.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $@
src/main.o: include/util.h
src/util.o: include/util.h
clean:
rm -f prog $(OBJS)
.PHONY: clean
$@cel,$<pierwsza zależność,$^wszystkie zależności..PHONY: cele, które nie są plikami.make -nwypisuje polecenia bez wykonania,make -Bbuduje wszystko od nowa.-MMD -MPwCFLAGSi-include $(OBJS:.o=.d)na końcu: zależności od nagłówków generuje kompilator.
Większe projekty używają generatorów, np. CMake,
które tworzą Makefile z opisu projektu.