Jan Vlášek: MAKE
Predchozi (Obsah) Dalsi

4. Popis

Příkaz make má několik platných verzí a je především určen k zjednodušení udržování jiných programů. Verze příkazu make je SYSTEM V (1) dodávaným s Berkeley (2) .

Program make provádí příkazy v makefile, aby došlo ke změně jednoho nebo více cílů uvedených v parametru jméno. Argument (parametr) je typicky program. Jestliže není uveden příznak -f, hledají se postupně následující soubory:

  • makefile
  • Makefile
  • s.makefile
  • s.Makefile

Tyto soubory obsahují popisy závislostí a jejich hledání se provádí ve výše uvedeném pořadí.

Jestliže makefile je zastoupen znakem -, popisy závislostí jsou očekávány na standardním vstupu. Je také možné specifikovat více než jen jeden argument -f makefile.

Program make aktualizuje jediný cíl, jestliže je na cílu závislý. Všechny předpokládané soubory z cíle jsou rekurzivně přidávány do seznamu cílů. Chybějícím souborem míníme změněný (neaktuální) soubor.

Argument makefile obsahuje sekvence specifických závislostí vstupů. První řádka vstupu je prázdná, samostatná. Dále je uveden nenulový (neprázdný) seznam cílů následovaný dvojtečkou a pak seznam předem daných souborů nebo závislostí, který již může být prázdný. Za textem následuje středník a všechny další řádky začínající tabulátorem <TAB> jsou příkazy shellu, jež jsou vykonány pro aktualizaci cílu!

Pozor:
První řádka nezačíná ani tabulátorem (<TAB>), ani znakem čísla (#). Začíná tak nová závislost či definice makra. Znak čísla uvozuje komentář. Nikdy nenahrazujte tabulátor mezerami!

Struktura argumentu makefile je následující:

cíl: závislost1 závislost2 ...;
příkaz shellu 1;
.
.
příkaz shellu n;

Poznámka:
V případě že za textem uvádíte středníky, může vám make během své činnosti vypsat hlášku (null command). Pokud středníky neuvádíte, make proběhne naprosto bezproblémově.

Za zpětným lomítkem(\ ) a sekvencí nové řádky (RET) mohou pokračovat příkazy shellu. Shell je příkazový interpret v systému Unix. Všechno tisknutelné v make (vyloučeny pouze počáteční tabulátory) shellu přímo vyhovuje. Jednoduchý příklad ilustruje použití zpětného lomítka:

echo a\
b

Tyto vstupy produkují za sebou jdoucí ab. A tento výstup je přesně to samé, jako by to bylo produkováno shellem. Znak čísla (#) a nová řádka oblopuje komentáře. Tedy jednoduše. Vše co následuje za # je komentář. Následující makefile "říká", že pgm závisí na dvou souborech a.o, b.o, a že tyto jednotlivě závisejí na jejich příslušných (korespondujících) zdrojových souborech a příkazovém (hlavičkovém) souboru incl.h:

pgm: a.o b.o
cc a.o b.o -o pgm
a.o: incl.h a.c
cc -c a.c
b.o: incl.h b.c
cc -c b.c

Příkazové řádky jsou vykonány najednou, každá s vlastním shellem. První jeden, nebo dva znaky v příkazu mohou být následující:

  • -
  • @
  • -@ nebo @-

Jestliže je prezentováno @, je potlačen tisk příkazu (3) . Je-li uvedeno -, make ignoruje chyby. Řádka je po vykonání vytištěna. V případě, že je prezentován příznak -s nebo vstup .SILENT: anebo počáteční sekvence obsahuje @, řádka vytištěna není. Příznak -n specifikuje tisk bez spuštění (vykonání) příkazů (4) . Pokud ale příkazová řádka obsahuje řetězec $(MAKE), je vždy vykonána (viz dále makro MAKEFLAG v oddíle 4.1.). Příznak -t aktualizuje soubor s pozměněnými daty bez vykonání příkazů. To může být vhodné třeba v případě, že ve zdrojovém souboru jste pozměnili nebo přidali nějaký komentář a tudíž je zcela zbytečné provádět celý překlad a aktualizovat na něm závislé soubory.

Při normálním ukončení make je návratová (vracená) hodnota příkazů nenulová. Je-li na příkazové řádce uveden příznak -i nebo v makefile cíl .IGNORE, či počáteční znaková sekvence obsahuje -, pak jsou případné chyby ignorovány. Pokud je uveden příznak -k, v případě chyby zastaví práci na právě prováděném vstupu (větvi). Pokračuje ale v provádění dalších vstupů (závislostí), u kterých nedošlo k chybě a jsou nezávislé na neúspěšném vstupu. Příznak -b umožňuje spustit staré "make soubory" (psané pro starší verze make) bez chyb. Rozdíl mezi starou a současnou verzí je ten, že současná verze vyžaduje, aby všechny závislé řádky měly (možná nulový nebo implicitní) příkaz jím asociovaný. Předchozí verze make udávala, že jestliže příkaz nebyl specifikován explicitně, pak byl příkaz nulový. Přerušení nebo ukončení způsobí vymazání cíle, jestliže cíl není závislý na speciálním jméně .PRECIOUS.

4.1. Prostředí

Prostředí je vždy čteno při spuštění make. Všechny proměnné jsou přijímány do definic makra a jako takové zpracovány. Příznak -e způsobí přehlédnutí prostředí ukládané do makra v makefile.

Příkaz make pracuje ve třech kompatibilních módech. O typu módu je rozhodnuto z hodnot z prostředí proměnných PROG_ENV a z cesty, kterou je make vykonán. Proměnná PROG_ENV má dvě platné hodnoty:

  • BSD
  • POSIX

V BSD módu je vyvolán make kompatibilní Berkeley (5) . Tento prostředek /bin/sh je vždy použit jako příkazový interpret, který nebere ohled na hodnoty shellu, a příkazy jsou vypisovány (echovány) na standardní výstup s prefixem <tab>.

V módu POSIX je vyvolán make kompatibilní POSIX (6) takový, že proměnná prostředí SHELL je vždy ignorována. SHELL je vždy nahrazen (přepsán) proměnnou MAKESHELL, kde shell je pokaždé použit k vykonání příkazů a příkazy jsou vypisovány na standardní výstup s prefixem <tab>.

Proměnná prostředí MAKEFLAGS je vždy zavedena při spuštění make pro všechny legální vstupní příznaky (kromě -p, -f a -d) definované pro příkazový řádek. Dále, při vyvolání procedury, make vytvoří proměnnou jestliže není v prostředí, vloží do ní aktuální příznak a rozšíří ji do vyvolaných příkazů. MAKEFLAGS tedy vždy obsahuje aktuální vstupní příznak. To se jeví jako velmi výhodné pro super-makes. Totiž, tak jako výše uvedeno, když je uveden příznak -n, příkaz $(MAKE) je přesto spuštěn. Proto se jednou může provést make -n rekurzivně v celém softwarovém systému, abychom viděli, jak má být spuštěn. To protože -n je dán v MAKEFLAGS a zabraňuje další vyvolání z $(MAKE). Toto je jedna cesta překládání všeho z makefile souborů pro softwarový projekt bez veškeré aktualizace.

4.2. Makra

Makra mohou být definována čtyřmi rozdílnými způsoby. Samotná makra mohou být definována implicitně uvnitř make. Do definic makra jsou přijímány všechny proměnné prostředí. Makra mohou být definována také v makefile, právě tak jako při make na příkazové řádce. Implicitně jsou vnitřní makra přepisována proměnnými prostředí, makra definovaná v makefile nedbají na proměnné prostředí (přehlíží je) a makra definovaná na příkazové řádce nedbají na makra definované v makefile. Implicitně je tedy dána priorita definic maker. Následující výčet těchto definic je uveden pro přehlednost a uspořádán od nejnižší priority:

  1. vnitřní makra
  2. proměnné prostředí
  3. makra v makefile
  4. makra na příkazové řádce

Příznak -e změní implicitní priority tak, aby proměnné prostředí nedbaly maker definovaných v makefile. Vstupy formy string1=string2 jsou definicí makra. String2 je definován jako komentář se všemi velkými znaky, nebo nevyvázaná nová řádka.

Další výskyty $(string1[:subst1=[subst2]]) jsou nahrazeny obsahem string2. Závorky (kulaté) jsou nepovinné, jestliže je užit samotný znak jména makra a který není substituční sekvencí. Substituční sekvence subst1=subst2 je nepovinná. Jestliže je ale specifikována, všechny nepřekrývající se výskyty subst1 v uvedeném makru jsou nahrazeny proměnnou subst2. Výskyt subst1 musí být uveden před koncem slova string1. Řetězce, nyní míněné substitučního typu, jsou uvedeny znaky prázdnými, tabulátory, či znaky nové řádky, a začínajícími řádky. Příklad užití substituční sekvence je patrný v sekci knihovny - odstavec 4.7..

Poznámka:
Maker se hojně využívá. Makro je možné v příkazu vyvolat jako ${jméno_makra} , např.:

  • Definujeme makro KONST jako symbolickou konstantu a vyvoláme jej. KONST=prvni
    .
    .
    ${KONST}.o: ${KONST}.c defin.h

Makro MACHINE je definováno při make, abychom mohli vzít v úvahu stroj nezávislých souborů makefile. Implicitní řetězec pro MACHINE je "vax", "mips" nebo "alpha". To podle toho, z jakého stroje je aplikace spuštěna. Makro MACHINE je možné předefinovat jedním z daných řetězců pro vývojové práce pro jiné platformy.

4.3. Vnitřní makra

Vnitřně udržovaných maker (vnitřních maker) je celkem pět. Jsou vhodná k zapisování pravidel pro sestavování cílů.

$*
- makro $* obsahuje část jména souboru z běžné závislosti s vymazanou příponou. Toho je využito pouze v odvozovacích pravidlech.
$@
- makro $@ obsahuje plné jméno cíle z běžného cíle. To je oceněno pouze pro jasně jmenované závislosti.
$<
- makro $< je výhodné používat pouze v odvozovacích pravidlech nebo v .DEFAULT pravidle. To je modul, který je zastaralý (není aktuální) vzhledem k cíli (tj. vyrobí se závislost jména souboru). Tedy například v pravidle .c.o ohodnotí $< makro .c soubor. Dále následují dva příklady pro vytvoření optimalizovaných (objektových) .o souborů z .c souborů: .c.o:
cc -c -O $*.c
.c.o:
cc -c -O $<
$?
- makro $? využijete tehdy, když jsou explicitní pravidla ohodnocena ze souborů makefile. To je seznam předpokladů, které jsou zastaralé (neaktuální) vzhledem k cíli.
$%
- makro $% je oceněno pouze, když cíl je položka archivu knihovny formy lib(file.o). V tomto případě $@ ohodnotí lib a $% ohodnotí položku file.o.

Čtyři z pěti maker mohou mít alternativní formy. Když je doplněna volba velkého D nebo F do každého ze čtyř maker, znamená to změnu části adresáře pro D, nebo části souboru pro F. Tedy makro $(@D) se vztahuje k části adresáře z řetězce $@. Jestliže zde není adresářová část, je generována sekvence znaků ./. Pouze makro $? je vyloučené z těchto alternativních forem. Důvody pro to jsou diskutabilní.

4.4. Speciální jména

.DEFAULT
Jestliže soubor musí být vytvořen, ale nejsou definovány žádné explicitní příkazy a nebo nejsou s ním provázány vestavěná pravidla, pak příkazy svázané se jménem .DEFAULT jsou užity, jestliže však existuje.
.PRECIOUS
Je-li voláno přerušení, pak závislosti z tohoto cíle nejsou odstraněny.
.SILENT
Tentýž efekt jako příznak -s.
.IGNORE
Tentýž efekt jako příznak -i.
.SUFFIXES
Závislosti ze .SUFFIXES speciálního cíle jsou vloženy do tabulky známých přípon.

Poznámka:
Pokud chceme v makefile použít určitá speciální jména, je třeba je uvádět jako cíl - tedy s dvojtečkou na konci a pokud možno samostatně na novém řádku.

4.5. Přípony

Určitá jména (pro instanci, která končí příponou .o) mají předběžné požadavky na soubory .c, .s, které mohou být odvozeny. Jestliže se nezměněné příkazy pro takový soubor objeví v makefile a jestliže odvozené předpoklady existují, pak předpoklad je přeložen (kompilován) do make cíle. V takovém případě má make odvozená pravidla, která dovolí (umožní) sestavovat soubory z jiných souborů pomocí vyšetřování přípon a rozhodování o použití nějakého vhodného odvozovacího pravidla. Běžná implicitní odvozovací pravidla jsou následující:

.c.c  .sh.sh  .c.o .c .o .c .c .s.o
.s .o .y.o .y .o .l.o .l .o .y.c
.y .c .l.c .c.a .c .a .s .a .h .h

Vnitřní pravidla pro program make jsou obsažena ve zdrojovém souboru rules.c. Tato pravidla mohou být lokálně modifikována. K vytištění (vypsání) výstupních pravidel přeložených uvnitř make ve formě vhodné k rekompilaci (přestavení) je použit následující příkaz (7) z /bin/sh:

make -fp - 2>/dev/null </dev/null

Pouhá zvláštnost v tomto výstupu je (nulový) řetězec, který tiskne printf(3), když je předán nulový řetězec. Tilda (~) ve výše uvedených pravidlech odkazuje na SCCS soubor. Tedy pravidlo .c .o bude transformovat SCCS C zdrojový soubor na objektový soubor (.o). Protože s. z SCCS souborů je předpona (prefix), je to neslučitelné s make příponou 'point-to-view'. Proto tilda je cesta změn všech odkazů souboru na odkazy SCCS soubory.

Pravidlo pouze s jednou příponou (to je .c:) je definice, která říká, jak sestavit x z x.c. Druhá přípona je opravdu nulová. To je užitečné při sestavování cílů pouze z jednoho zdrojového souboru (např. shell procedury, samotné C programy).

Dodatečné přípony jsou dány jako seznam závislostí pro cíl jménem .SUFFIXES. Řazení je významné. První možné jméno, pro které jak soubor tak i závislost existuje, je odvozeno jako předpoklad. Implicitně je dán seznam následovně:

.SUFFIXES: .o .c .y .l .s

Zde znovu výše uvedený příkaz pro tisk vnitřních pravidel zobrazí seznam přípon implementovaných na běžném stroji. Akumuluje mnohonásobné seznamy přípon; .SUFFIXES: bez závislostí čistí seznam přípon.

4.6. Vnitřní pravidla

Stručný a jednoduchý příklad:

pgm: a.o b.o
cc a.o b.o -o pgm
a.o b.o: incl.h

Výše uvedený příklad může být takto jednoduše zapsán, protože make má množinu vnitřních pravidel pro sestavení souborů. Uživatel smí přidat pravidla do tohoto seznamu, samotným vložením do souboru makefile.

Určitá makra jsou použita implicitními pravidly, aby umožnila začlenění volitelných přepínačů ve výsledných příkazech. Například CFLAGS, LFLAGS a YFLAGS jsou užity jako příznaky překladače k cc, lex a yacc samostatně. A znovu doporučena předchozí metoda pro prohlížení běžných pravidel.

Odvozování z předpokladů může být kontrolováno. Například pravidlo k vytvoření souboru s příponou .o ze souboru .c je specifikováno jako vstup s .c.o: jako cíl a ne závislosti. Příkazy shellu asociované cílem definujícím pravidlo pro vytvoření .o souboru z .c souboru. Každý cíl, který v něm nemá přepínače a začíná tečkou, je identifikován jako pravidlo a není pravým cílem.

4.7. Knihovny

Jestliže cíl nebo jméno závislosti obsahuje závorky, je přejímán do archivu knihovny. Řetězec v závorkách odkazuje na položku v knihovně. Tedy lib(file.o) i $(LIB)(file.o) ukazují do archivu, který obsahuje file.o. (Toto přijímá LIB makro, které musí být nejdříve definováno.) Výraz typu $(LIB)(file1.o file2.o) je nepřípustný.

Pravidla náleží do archivu knihoven a mají formu .XX .a, kde .XX je přípona, ze které je vyrobena položka archivu. Bohužel vedlejší produkt z běžné implementace žádá rozdílný XX z přípon archivu položek. Tedy lib(file.o) nesmí být explicitně závislý na file.o. V příkladě je to přijímáno, když zdrojové soubory jsou všechny zdroje typu C:

lib: lib(file1.o) lib(file2.o) lib(file3.o)
@echo lib is now up-to-date
.c.a:
$(CC) -c $(CFLAGS1) $<
ar rv $@ $*.o
rm -f $*.o

Ve skutečnosti je pravidlo .c.a - zapsané výše - sestaveno v make a není tedy v tomto příkladě nutné. Více zajímavý, ale více omezený příklad z udržování archivu knihovny má následující konstrukci:

lib: lib(file1.o) lib(file2.o) lib(file3.o)
$(CC) -c $(CFLAGS) $(?:.o=.c)
ar rv lib $?
rm $?
@echo lib is now up-to-date
.c.a:;

V tomto příkladě je užit substituční mód z expanze makra. $? seznam je definován do množiny jmen objektového souboru (uvnitř lib), jehož C zdrojové soubory jsou zastaralé. Substituční mód převádí .o do .c. (Bohužel, jeden nesmí transformovat na .c .) Deaktivuje (znepřístupní) tedy .c.a: pravidlo, které by mělo vytvořit každý objektový soubor, jeden po druhém. Uvedený typ konstrukce začíná velmi nešikovně, pokud archiv knihovny obsahuje směs programů v jazyce C a programů assembleru.



Predchozi
Converted by Selathco 0.85 on 15.06.1999 11:08
Dalsi