ADE: GNU Make 3.75Jan Skýpala
Utilita make je základní vývojový nástroj programátora na Unixu a mnohých
dalších platformách. Ač se začátečníkovi líbí různé project managery jak chtějí,
časem stejně přijde na něco, co neumí. Make umí všechno. A GNU Make ještě víc... Tato definice je poměrně výstižná. Ale hodilo by se asi dodat „ale mocnější
než všechny pohodlné.“ Pokud jste nikdy neprogramovali, tak vám musím stručně
vysvětlit, co to ta správa programu je.
Čím je program delší, tím je nepraktičtější držet celý zdroják v jednom souboru.
Jednak se v něm špatně hledá a ještě navíc se dlouho překládá. Takže větší
programy mají většinou více zdrojových souborů a po nějaké změně (přidání nové
funkce, odstranění staré chyby apod.) se překládá pouze to, co je zapotřebí.
No a to byla asi základní myšlenka při vzniku utility make (té obecné Unixové
verze). Takže bylo třeba zajistit, aby prográmek make uměl poznat to, co je
třeba udělat (např. právě které soubory překompilovat).
Make předpokládá, že (většinou) nějaká akce končí vytvořením nějakého souboru, a
to na základě souborů jiných. Například u programu soubor xxx vznikne ze souboru
xxx.o po linkování a xxx.o vznikne z xxx.c po přeložení překladačem céčka.
Soubor xxx.c navíc includuje soubor xxx.h. Pokud tomu tak je, měl by být čas a
datum u souboru xxx pozdější než u xxx.o a ten pozdější než u xxx.c a xxx.h. A
to je přesně princip, podle kterého utilita make rozhoduje, co je třeba udělat.
Když make spustíte, tak načte soubor Makefile a tam předpokládá uložení
závislostí (tedy který soubor je závislý na kterém) a co má provádět.
Následující příklad řekne více:
xxx.o: xxx.c xxx.h
gcc -c xxx.c -o xxx.o
První řádek znamená, že soubor xxx.o má mít pozdější čas uložení než soubory
xxx.c a xxx.h. Druhý řádek obsahuje, co se má udělat, když tomu tak není - zde
spuštění GNU C překladače.
Řádků s příkazy může být za sebou pochopitelně více, celá sekvence bude ukončena
buď prázdným řádkem nebo dalším řádkem se závislostmi. Co je ovšem u unixových
make utilit a GNU make podmínkou, že řádek s příkazem začíná tabulátorem; pozor
- mezera (32 ASCII) není tabulátor (9 ASCII). smake (z SAS/C) vystačí se dvěmi
mezerami, dmake (DiceC) nepotřebuje ani jednu.
Čistě teoreticky vám výše uvedené stačí k rozumnému používání prográmku make.
Pokud ale např. chcete dát někomu archiv se zdrojákem svého programu, může se
stát, že bude mít úplně jiný překladač céčka, než vy, a bude ho muset úplně
všude v souboru Makefile přepsat (třeba všude změnit gcc na lcc). Aby to nebylo
tak obtížné, lze v Makefile zavést proměnné.
Takže změňme náš malý příkládek na:
CC = gcc xxx.o: xxx.c
xxx.h $(CC) -c xxx.c
-o xxx.o
První řádek nám zavede proměnnou CC, do které uložíme jméno překladače. A na
třetím řádku ji před vyvoláním příkazu make vyhodnotí, takže volaný řádek bude
vypadat úplně stejně, jako předtím. Takže až bude váš kamarád chtít
překompilovat vaše programy svým (jiným) překladačem, změní jediný řádek, a to
ten, kde definujete proměnnou CC.
Proměnné se samozřejmě používají na všechno možné, např. i pro zadání parametrů
pro překladač. Tato proměnná má doporučené jméno CPPFLAGS a v ní by měla být
např. uvedená optimalizace nebo cílový procesor. Takže řádek vyvolávající
překlad by měl být:
$(CC) $(CPPFLAGS) –c
xxx.c -o xxx.o
GNU make nemusí mít tyto proměnné definovány v souboru Makefile. Pokud tam
nejsou, převezme je ze shellu. Takže doporučuji přidat si do user-startup řádek
„Set CC gcc“ a podobně.
Tímto místem končí kompatibilita s dmake (DiceC). Některé následující věci dmake
ještě umí, ale má jinou syntaxi.
Náš řádek zajišťující překlad lze ještě zkrátit. Make umí proměnné, které jsou
při spouštění příkazu nahrazovány údaji z definice závislosti. Konkrétně tedy
proměnná $@ bude rozvinuta na jméno cílového souboru (xxx.o). Proměnná $? bude
rozvinuta do všech zdrojových souborů (xxx.c xxx.h). A proměnná $< bude
rozvinuta do prvního zdrojového souboru (xxx.c).
Takže náš řádek pěkně zkrátíme na
$(CC) $(CPPFLAGS) -C
$< -o $@.
Jak je vidět, v tomto řádku není jediné konkrétní jméno, a tak je zřejmé, že ho
lze nakopírovat za každou závislost pro překlad céčkovského zdrojáku na objekt.
Jen je nutné dát si pozor, aby vždy jako první zdrojový soubor byl uveden
skutečný zdroják pro daný objekt (omylem by se vám tam mohl připlést třeba
nějaký *.h).
Některé make utility umí i takzvaná implicitní pravidla. Ta jsou použita, pokud
v Makefile neuvedete, co má make dělat. GNU make jich umí spousty a smake
přinejmenším jedno: jak vytvořit *.o soubor z *.c souboru. O odstavec výše
zmíněné zkrácení řádku je přesně tím příkazem, který volá GNU make, SAS/C má
volání $(CC) $<. Závislost je pochopitelně *.o: *.c, GNU make nám ale navíc
umožňuje definovat ještě další závislosti (někde jinde v Makefile souboru). To
znamená, že pro GNU make stačí správně nastavit hodnoty $(CC) a $(CPPFLAGS) a
uvést řádek „xxx.o: xxx.c xxx.h“ a bude to fungovat přesně tak, jak si přejeme.
Tak a zde končíme i s kompatibilitou s smake (SAS/C). Následující vlastnosti
smake neumí (nebo jsem přinejmenším nepřišel na to jak). dmake první z nich umí,
ale zápis je jiný. Ovšem co nám brání používat všemocný GNU make i s DiceC nebo
SAS/C?
Jak je výše uvedeno, mohli jsme v smake vypustit pravidlo pro céčkovský překlad,
pokud byl objekt závislý pouze na svém zdrojáku, a v GNU make jsme mohli
takovéto pravidlo vypustit úplně. Ne pro všechny typy závislostí zná make
pravidla a proto lze v GNU make udělat pravidlo obecné pro daný typ podle masek
zdrojového a cílového souboru. Znaky % musí odpovídat v obou částech. Tak tedy
např. GNU make pochopitelně nic netuší o programovacím jazyce AmigaE, ale
pravidlo
%: %.e EC:ec $< OPTIMIZE
způsobí, že bude-li muset vytvořit nějaký soubor, k němuž na disku existuje
soubor s příponou .e, bude automaticky vědět jak na to.
Ještě ale musím zmínit jeden rozdíl mezi smake + dmake a unixovskými make
(včetně GNU make). smake a dmake, pokud je spustíte jen tak, bez parametru,
budou za hlavní cíl považovat to, co je výsledný soubor u první závislosti v
Makefile. Unixové make utility naopak budou dělat to, co je uvedené u závislosti
„all:“ To, že se při kompilaci žádný soubor se jménem all nevytvoří, vůbec
nevadí.
Závislosti, které nemají žádné zdrojové soubory, by se normálně nevykonávaly.
Prostě vytvářený soubor (i třeba neexistující) bude vlastně vždy novější. Proto
na začátek Makefile uveďte řádky, kde bude pro každou závislost, která nemá
žádné zdrojové soubory, uvedeno: „.PHONY : target“ (přičemž target je ona
závislost). V Makefile souborech se většinou vyskytuje takovýchto závislostí
více a když spustíte make se jménem závislosti, bude provádět ji, a ne tu se
jménem all. Závislost nazvaná clean většinou smaže všechny soubory vytvořené
kompilací, závislost install nainstaluje program tam, kam má a podobně.
Nyní by se hodilo nějak vymyslet generování závislostí, aby to člověk nemusel
psát do Makefile souboru ručně. To není zase až tak složité. Céčkovské
preprocesory na unixu (včetně preprocesoru u GNU C) při direktivě -M místo
normální činnosti vypíšou závislosti. GNU C preprocesor navíc s direktivou MM
vypíše pouze závislosti na nesystémových header souborech.
Dobrá, teď umíme závislosti vygenerovat, ale jak je přidat do Makefile souboru?
Dříve se to řešilo tak, že v Makefile byla položka depend, která způsobila
vygenerování závislostí do souboru, a pak tento soubor připojila ke starému
Makefile a mohlo se provést normální make. To je samozřejmě nepříjemné, musíte
make volat dvakrát. V GNU make to lze vyřešit takto: Nejdříve si zaveďme
pravidlo, které nám pro každý céčkovský zdroják vygeneruje soubor s příponou .d
(místo .c) se závislostí:
%.d: %.c /bin/sh –ec
„$(CC) -MM $(CPPFLAGS)
$< > $@“
Mějme v proměnné SOURCES zadefinované všechny céčkovské zdrojáky, pak
interpretace $(SOURCES:.c=.d) nám udělá všechny soubory s příponou .d a
direktivou include tyto soubory do Makefile přidáme:
include $(SOURCES:.c=.d)
Nazvěme nějak výsledný spustitelný soubor (já preferuji main, ale vy můžete mít
lepší název). Dejme ho do proměnné BUILD a nastavme pro all: závislost právě na
$(BUILD). Do proměnné OBJECTS dejme všechny objekty (soubory zkompilované z
céčkovských zdrojáků). Do proměnné LOADLIBES dejme jména všech linkovaných
knihoven (pokud budete linkovat pomocí gcc nebo ld a používáte přitom nějaké
vymoženosti C++, přilinkujte knihovnu stdc++). Do proměnné LDOPTS dejme
parametry pro linkování (třeba -s) a přidejme pravidlo:
$(BUILD): $(OBJECTS)
$(CC) $(LDOPTS) $? -o
$@ $(LOADLIBES)
Nyní máme Makefile který nám pro sadu uvedených objektů, k nimž existují
zdrojáky, bude pracovat až k vytvoření spustitelného souboru. A blížíme se do
finiše. Poslední co nám zbývá, je zajistit, aby si make našel všechny céčkovské
zdrojáky na disku sám. Tím vytvoříme potencionálně nezávislý Makefile použitelný
pro jakýkoliv jednodušší program v céčku.
Bylo by chyba dát OBJECTS = *.o - v momentu, kdy bude program rozdělaný a bude
se znovu a znovu kompilovat, je vše v pořádku. Ale po smazání všech souborů s
příponou .o by make přestal pracovat, protože proměnná OBJECTS by byla prázdná.
Takže můžeme dát SOURCES = *.c a na další řádek OBJECTS = $(SOURCES:.c=.o), ale
ještě lepší bude použít přímo funkce GNU make a vytvořit si proměnnou OBJECTS
takto:
OBJECTS = $(pathsubst %.c, %.o,$(wildcard *.c))
funkce wildcard nám najde všechny soubory podle dané masky a funkce pathsubst
potom v nich provede změnu z .c na .o.
Tak teď už skutečně máme dosti dobrý Makefile, který vám bude, doufám, dlouho
sloužit. Celý je vylistovaný vedle článku, takže vám stačí si ho jen opsat a
můžete programovat a téměř se nestarat o správu programu.
Doufám, že každý pochopil, v čem je síla make. To co jsem tady vysvětloval, může
vypadat jako přesně to, co umí i ty různé project managery u takzvaných
integrovaných prostředí, ale make je obecný. Nemusíte spouštět jenom překladač
céčka, ale cokoliv. Do Makefile si můžete dát třeba i generování dokumentace
(často se používá formát TeXinfo, z něhož se pak generuje jak manuál, tak online
he/p). Pokud pracujete s gramatikami, make může automaticky spouštět lex nebo
yacc. A tak podobně.
GNU make toho samozřejmě umí mnohem více, např. podmíněné části souboru
Makefile. Takže si například můžete přímo do Makefile zahrnout jaké pravidlo má
použít při daném překladači apod. Velice oblíbené a mocné je také volat make
rekurzivně, tzn. spustit z Makefile znovu make např. na některý podadresář.
Ještě pár poznámek na závěr. Pokud používáte nějaké specifické funkce nějaké
make utility, místo Makefile použijte specifické jméno, které daná verze zná a
preferuje, zatímco ostatní make utility ji vůbec nepoužijí. U GNU make je to
GNUmakefile (pozor, záleží na velkých a malých písmenech), u smake smakefile, u
dmake dmakefile. GNU make najdete na jakémkoliv serveru s ADE archivem, např.
ftp.grolierfr/pub/amiga/ade/current/amiga-bin/make-3.75bin.lha
A jako vždycky si dobře pročtěte dokumentaci. Guide k GNU make má skoro 400kB a
najdete v něm úplně všechno. Univerzální GNU makefile pro jednodušší céčkovské programy
(poznámka: pro zdrojáky v C++ doporučuji používat příponu .cc, GNU make pak sám
zná implicitní pravidlo):
# Universal GNUmakefile by Jan Skypala .PHONY: clean
# what to do: BUILD = main
# System configuration SHELL = /bin/sh
# System environment CC = gcc CXX = g++
CPPFLAGS = LDFLAGS = -s LOADLIBES = -lstdc++
OBJ = $(patsubst %.cc, %.o,$(wildcard *.cc))
$(patsubst %.c, %.o,$(wildcard *.c))
all: $(BUILD)
clean: rm -f $(BUILD) $(BUILD:%=%.o)
$(BUILD:%=%.d)
%.d: %.c $(SHELL) -ec „$(CC) -MM $(CPPFLAGS) $< | sed s!$*.o: *!$*.o $@: !g >
$@“
%.d: %.cc $(SHELL) -ec „$(CXX) -MM $(CXXFLAGS) $(CPPFLAGS) $< | sed s!$*.o:
*!$*.o $@: !g > $@“
include $(BUILD:%=%.d) #END OF FILE#
GNU Make |
Hodnocení: 9,5 z 10 |
Autor: FSF |
Typ: freeware |
+ |
plně kompatibilní s UNIXovým
maker mnohem více funkcí; zadarmo |
- |
není pro začínající
programátory |
Vytlačiť článok
Pozn.: články boli naskenované ako text a preto obsahujú aj zopár chýb. Taktiež neručíme za zdrojové kódy (Asm, C, Arexx, AmigaGuide, Html) a odkazy na web. Dúfame, že napriek tomu vám táto databáza dobre poslúži.
Žiadna časť nesmie byť reprodukovaná alebo inak šírená bez písomného povolenia vydavatela © ATLANTIDA Publishing
none
|