- předchozí článek - následující článek - obsah - úvodní stránka -

Linuxové noviny 03-04/99

Rychlo-školička pro Makefile

Marek Sezemský, 27. března 1999

Když jsem v Linuxu začínal psát vlastní programy v céčku, pro kompilaci stačil jeden řádek v shellu. Jak jsem začal zpřehledňovat (a komplikovat) do více souborů, bohatě stačil script, který natvrdo vše zkompiloval a slinkoval. Bohužel je to funkční, ale pomalé a nepřehledné řešení. Pro kompilace malých i obrovských (jádro, apache, sendmail) programů/knihoven se prostě používá pouze a jedině Makefile.

Jak to pracuje?

Makefile je sám o sobě textový soubor, ve kterém jsou popsány závislosti různých souborů na jiných souborech. Program, který s ním umí zacházet se jmenuje "make". Ten při svém spuštění hledá v aktuálním adresáři soubor Makefile, makefile a nebo GNUmakefile. Pokud jej nalezne, zkontroluje data souborů a podle závislostí v něm definovaných provede akci, která přísluší té které závislosti. Čtěte dál, pochopíte.

Formát souboru Makefile

Uvedu příklad pro vysvětlenou: píšete program který pracuje s Internetem. Krom programu samotného potřebujete knihovnu pro sítě a uživatelské rozhraní. Program je v main.c, sítě v net.c a komunikaci s uživatelem obstará gui.c. Existují také halvičkové soubory net.h a gui.h. Program používá funkce z net.c a gui.c, takže si inkluduje i hlavičky. Makefile pro tento projekt vypadá asi takto:

# Program (C) Sezi, 1999
# 

program: main.o net.o gui.o
        $(CC) -o $@ main.o net.o gui.o

main.o: main.c net.h gui.h
net.o: net.c net.h
gui.o: gui.c gui.h

Vytvořte si tento Makefile a výše zmíněné soubory. Mohou být prázdné, ale main.c musí obsahovat f-ci main() (klidně i prázdnou).

Ale teď již na Makefile: první dva řádky jsou komentáře (hojně používejte). Třetí řádek popisuje to hlavní: na čem je závislý 'program': soubory main.o net.o gui.o. Následující řádek je příkaz, který se provede pokud bude některý soubor novějšího data než 'program'. $(CC) znamená 'makro s jménem CC' a $@ se rozvine jako text před dvojtečkou (takže 'program'). Tyto (a další) makra si rozebereme později, prozatím stačí vědět, že $(CC) je jméno kompilátoru. POZOR: Příkaz v Makefile musí začínat tabulátorem! Pokud použijete mezery, make to nezbaští a pošle vás někam. Další řádky definují závislosti jednotlivých .o souborů. Takže pokud máte vytvořeny soubory včetně Makefile, zkuste spustit "make". Pravděpodobně uvidíte tyto řádky:

$ make
cc    -c main.c -o main.o
cc    -c net.c -o net.o
cc    -c gui.c -o gui.o
cc    -o program main.o net.o gui.o
$

Jelikož make nenalezl žádný z souborů .o, prostě postupoval po závislostech a zkompiloval soubory uvedené na posledních 3 řádkách. Poté vykonal řádku 'program'. Pokud zkusíte změnit datum u gui.c ("touch gui.c") a opět spustíte make, zkompiluje se pouze gui a program se celý slinkuje.

$ touch gui.c
$ make
cc    -o gui.o gui.c
cc -o program main.o net.o gui.o
$

Nyní si zkuste touch na nějaký hlavičkový soubor (např. net.h) a poté opět make. Nyní se již přeloží net.c i main.c, neboť ten je na net.h závislý též. Nyní ručně vymažte "program" plus všechny .o soubory a zkuste "make net.o". Přeloží se pouze net.o a vše ostatní se nechá na pokoji. Make si totiž při spuštění bez parametrů vezme první závislost a tu zpracovává. Parametrem lze ale zadat, kterou část Makefile bude zpracovávat (net.o). Ale v Makefile nemusí být uvedeny pouze soubory: zkuste si na konec našeho Makefile připsat následující řádky (nezapomeňte na tabulátor),

clean:
Tab	rm -f *.o program

a spustit "make clean". Vymažou se soubory vzniklé kompilací. Takže už víme, že pokud za dvojtečkou není uveden žádný soubor, příkaz se provede vždy.

Nyní zpět k makrům. Makra se definují jako jméno = hodnota a odkazy na ně jsou jako $(jméno). Takové základní a univerzální jsou CC (kompilátor) a CFLAGS (volby ke kompilátoru). Pokud si např. na začátku Makefile nastavíte CC na gcc, tak se místo kompilátoru CC použije GCC. Stejně tak CFLAGS. To samozřejmě i pro řádky, kde toto makro není uvedeno. Ale pokud se rozhodnete a tato makra předefinujete, tak se v našem příkladu v sekci "program" nebude brát v potaz makro CFLAGS, protože není uvedeno v příkazu.

Dále fungují i příkazy include (vložení jiného souboru), ifdef ... else ... endif a ifeq ... else ... endif. První je na test definice makra, druhý porovnává výrazy. Koho to zajímá, nechť pohlédne do Makefile u jádra, kde jsou obě podmínky a spousta dalšího názorně používány. Nevysvětluji to proto, jelikož málokdo něco z toho používá (kromě Linuse). Ale jejich použití je skutečně jednoduché.

Parametry programu make

Ačkoliv se to nezdá, program make má mnoho parametrů. Jejich použití je vysvětleno v manuálu (pod make(1)). Píše se tam sice něco o rozsáhlejší dokumentaci, ale popis parametrů v man-u stačí bohatě. Abych nezdržoval, popíšu jen ty důležitější.

-C <dir>:
před načítáním Makefile se přepne do adresáře <dir>. Pokud je zadáno více parametrů (např: "-C / -C etc" je to totéž jako "-C /etc". Používá se při rekursivním volání make.

-f <file>:
použije soubor <file> místo vyhledávaného Makefile.

-j <num>:
počet souběžných procesů - (nejen) pro SMP.

-n:
nevykonává příkazy, pouze je vypisuje.

-s:
tiché (silent) vykonávání (nevypisuje příkazy).

Makefile se samozdřejmě nemusí používat pouze pro programy v C/C++, stejně dobře zvládá i ostatní programovací jazyky a další funkce, ve kterých se kontroluje závislost souborů na časech modifikace, je to opravdu skvělá pomůcka.

Doufám, že vám tento článek pomohl při pronikání do programátorských zákoutí Linuxu. Pokud máte zájem, po vstřebání těchto informací si přečtěte další článek, tentokrát o automatizaci tvorby Makefile (v Linových novinách ze srpna a září). *


- předchozí článek - následující článek - obsah - úvodní stránka -