Search
Příma kompilace programu prostřednictvím kompilátoru a příkazové je vhodnou pro prvotní seznámení se základními přepínači kompilátoru a linkeru. Pro komplexníší programy, ale také pro často opakované akce je mnohem výhodnější použít vhodný nástroj pro řízení překladu. Mezi ty základní patří zcela jistě make nebo případě Linuxu tzv. GNU Make. Není to jediný způsobem mezi další používáné nástroje patří např. cmakecmake nebo třeba Ninja. Pro celou řadu případů a řešení úloh v PRP nám plně postačí make, který lze nalézt snad na všech distribucích Linuxu jako příkaz make, případně jako gmake v BSD* systémech.
make
gmake
Předpis jak program sestavit se zapisuje do tzv. Makefile, a při volání make program hledá v aktuálním pracovním adresáři právě soubor s názvem Makefile. Základní syntax není složitá, ale pokročilé Makefile, které zjednodušují zápis mohou být na první pohled relativně komplexní, neboť se používají zavedená jména proměnných. Nicméně vždy se jedná o deklarativní zápis pravidel jak vytvořit soubor (cíl) z jiných souborů (závislostí).
Makefile
“gnu make tutorial”
“gnu make manual”
Základní zápis pravidla má tvar
cíl: závislosti akce
Make obsahuje jak impliciní pravidla, tak umožňuje zápis explicitních pravidla, na kterých si nejdříve ukážeme základní použití. Následně si zápis Makefile souborů zjednodušíme využitím tzv. “pattern rules” nebo implicitních pravidel.
pattern rules
Mějme program se zdrojovým souborem program.c, který můžeme zkompilovat do binárního spustitelného soubor a.out prostým voláním. clang program.c. Raději však explicitně určíme výstupní soubor program voláním:
program.c
a.out
clang program.c
program
% clang program.c -o program
% clang -c program.c -o program.o % clang program.o -o program
program: program.c clang program.c -o program
% make make: 'program' is up to date
To se hodí zejména v projektech s mnoha soubory, kde je pak výhodné kompilovat jednotlivé soubory zvláště do příslušných .o souborů a následně samostatně linkovat. Mimo jiné pak lze využít i paraleního překladu na strojích s více výpočetními jádry nebo procesory. Předpis pro překlad souboru a následné linkování může například vypadat následovně
program.o: program.c clang -c program.c -o program.o program: program.o clang program.o -o program
program.o
% make program clang -c program.c -o program.o clang program.o -o program
Abychom nemuseli explicitně uvádět cíl při každém volání make můžeme jako první dát implicitní cíl. V našem případě to uděláme vytvořením cíle bin, který má jako závislost 'program'.
bin
bin: program
clean
bin: program program.o: program.c clang -c program.c -o program.o program: program.o clang program.o -o program clean: rm -rf program program.o
Výše uvedené příklady Makefile souborů lze jistě použít, ale vyžadují poměrné rozsáhlou editaci a uvedení jmen souborů na vícero místech. Mnohem praktičtější je využití vzorů pro překlad soubor, např. jak vytvořit soubory .o ze souborů .c
%.o: %.c clang -c $< -o $@
Dále není nutné uvádět explicitně kompilátor, ale je možné využít základních proměnných CC a také parametrů pro preprocessor (CPPFLAGS) a kompilátor CFLAGS.
CC
CPPFLAGS
CFLAGS
%.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
-O2
$ CFLAGS=-O2 gmake clang -O2 -c program.c -o program.o clang program.o -o program
gcc
% CC=gcc make gcc -O2 -pipe -c program.c -o program.o clang program.o -o program
Komplexnější Makefile, ve kterém je nutné pouze specifikovat jméno programu, který se má sestavit ze zdrojových souborů .c (resp. .o) pak může vypadat například
TARGET = program OBJS = $(patsubst %.c,%.o,$(wildcard *.c)) CFLAGS +=-std=c99 -pedantic -Wall CFLAGS += -O2 bin: $(TARGET) $(OBJS): %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ $(TARGET): $(OBJS) $(CC) $(OBJS) $(LDFLAGS) -o $@ clean: rm -rf $(OBJS) $(TARGET)
Jméno programu nastavuje na první řádku hodnotou proměnné TARGET. Na druhém řádku jsou jména všech souborů v pracovním adresáři končící na .c uložena do proměnné OBJS, ale nejdříve je nahrazen výskyt .c za .o, čímž získáme seznam všech object souborů, ze kterých sestavíme program. Následně specifikujeme nastavení kompilátoru a jeho verzi a to tak, aniž bychom přepsali nějaký původní obsah proměnné CFLAGS, například specifikovaný proměnnou prostředí. Podobně přidáme mezi parametry kompilátoru optimizalizaci -O2. Proměnnou TARGET použijeme jako závislost prvního cíle bin, ale také jako cíl závislý na přeložených souborech $(OBJS), které jsou přeloženy specifikovaných pravidlem se dvěma :, které specifikuje jak individuálně vytvořit soubory uvedené v OBJS ze souborů .c.
TARGET
.c
OBJS
.o
:
*.c
make clean