Identifikační údaje školy
Číslo projektu Název projektu Číslo a název šablony Autor Tematická oblast Číslo a název materiálu
Anotace Vytvořeno Určeno pro Přílohy
Vyšší odborná škola a Střední škola, Varnsdorf, příspěvková organizace Bratislavská 2166, 407 47 Varnsdorf, IČO: 18383874 www.vosassvdf.cz, tel. +420412372632 CZ.1.07/1.5.00/34.1076 Pro vzdělanější Šluknovsko 32 - Inovace a zkvalitnění výuky prostřednictvím ICT 0202 Ing. Vladimír Ďurči LINUX VY_32_INOVACE_0202_0303 Jak vytvořit program v Linuxu? Makefile [3/3] JAZYK „C“ - OS LINUX
25. 8. 2013 Operační systémy 4. ročník, maturitní obor Přiložené textové soubory, a zpracované programy
IMPLEMENTACE OPERAČNÍHO SYSTÉMU LINUX DO VÝUKY INFORMAČNÍCH TECHNOLOGIÍ
JAZYK C
Lekce 3
Jak vytvořit program v Linuxu? Makefile
Obsah lekce:
Cíle ...................................................................................................................................... 1 Makefile.............................................................................................................................. 2 Příklad + Zabalení ............................................................................................................ 3 Shrnutí 1. a 3. lekce .......................................................................................................... 4 Lab…………………………………………………………………………………………5
Cíle Tato lekce je velmi stručným úvodem do vytváření souboru.
Makefile Pro jednoduché programy (jako je příklad v předchozí kapitole) stačí na kompilaci a slinkování jeden řádek v shellu. Ale pro rozsáhlejší projekty, kdy je zdrojový kód ve více souborech, by bylo psaní příkazu pro každý soubor velmi neefektivní a zdlouhavé. Samozřejmě to za nás může udělat skript, ale brzy zjistíme, že to stále není ono (už jen proto, že takhle to nikdo nedělá :-)). Pro kompilaci a linkování malých i velkých (př. jádro) programů nebo knihoven se prostě používá pouze a jedině Makefile. Makefile je obyčejný textový soubor, ve kterém jsou popsány závislosti mezi soubory a způsob kompilace a linkování. Tento soubor používá program make, který jej po spuštění hledá jako soubor Makefile, makefile nebo GNUmakefile.
Příklad + Zabalení Příklad Soubor "Makefile": # Program "priklad", 2000 # CFLAGS = -Wall priklad: priklad.c libtext.h libtext.so $(CC) $(CFLAGS) -o $@ $< -L. -ltext libtext.so: libtext.c libtext.h $(CC) $(CFLAGS) -shared -o $@ $< clean: rm -f libtext.so priklad
První dva řádky jsou komentáře. Nejdříve se nastaví proměnná CFLAGS. Proměnné se definují jako jmeno = hodnota a volají se jako $(jmeno) (bez závorek, pokud je jméno jednopísmenné). Pak se určí první závislost - na čem je závislý samotný program: na zdrojových souborech priklad.c, libtext.h a knihovně libtext.so, která se musí teprve vytvořit. Závislosti se píší ve tvaru cile: soubory_na_kterych_jsou_cile_zavisle, kde cile jsou jsou soubory, které se mají vytvořit, oddělené mezerou, a za dvojtečkou jsou soubory, které jsou k tomu potřeba. Další řádek je příkaz, kterým se vytvoří program "priklad" a vykoná se jen, pokud bude některý ze souborů priklad.c, libtext.h nebo libtext.so novější než soubor priklad. POZOR: Příkaz v Makefile 3
musí začínat tabulátorem (mezery make nezbaští)!!! make každý příkaz vypisuje. Pokud nechcete, aby se příkaz nepsal na výstup, napište před něj zavináč @. Další řádky určují závislost a způsob vytvoření knihovny libtext.so. Pokud potřebujete něco, co má být na jednom řádku, rozdělit do více řádků, musí být na konci všech řádků (kromě posledního) zpětné lomítko \. V praxi (a v tomto příkladě také) se často používají již předdefinované proměnné, např.: CC -- kompilátor, defaultně cc MAKE -- program make; tato proměnná se používá k rekurzivnímu volání make $ -- znak $ @ -- cíle v určení závislosti, tj. všechno před dvojtečkou < -- první soubor za dvojtečkou ^ -- všechny soubory za dvojtečkou (oddělené mezerou, každý jedenkrát) a dále se obvykle nastavují např. tyto (defaultně jsou nastavené na ""): CFLAGS -- volby kompilátoru LDFLAGS -- volby linkeru TARGETS -- konečné cíle, většinou jméno programu Nyní můžete spustit program make. Ten najde soubor Makefile a vezme si první cíl (priklad). Soubor libtext.so neexistuje, takže make přejde na určení jeho závislosti, vytvoří jej a nakonec už může provést cíl priklad. Pokud spustíte make s parametrem priklad, stane se totéž. Pokud jej však spustíte s parametrem libtext.so, vytvoří se jen knihovna. Při spuštění bez parametru si make totiž vezme ten první cíl, parametrem můžeme určit, jaký cíl má provést. Pokud za dvojtečkou není uveden žádný soubor, přikaz se provede vždy. Klasickým příkladem je "čistka" (vymazání souborů vzniklých kompilací a linkováním): clean: rm -f priklad.o libtext.so priklad
Program make má samozřejmě také nějaké parametry, zde jen ty nejdůležitější: -C dir -- ještě před čtením Makefile se přepne se do adresáře dir; používá se při rekurzivním volání make -f file -- místo Makefile zpracovává soubor file -j jobs -- počet úloh (příkazů) prováděných paralelně; pokud jobs není uvedeno, počet není omezen -n -- jen vypisuje příkazy, které by vykonal, ale nevykonává je -s -- nevypisuje příkazy
Zabalení Teď, kdy už všechno máme hotové, můžeme zdrojové texty a Makefile (a vše ostatní, př. datové soubory, dokumentaci, ...) zabalit do balíčku pro uživatele. Standardně jsou to archivy tar.gz (tgz). Balíček vytvoříme takto: tar cfz balicek.tar.gz adresar_s_programem
4
Tento balíček můžeme dát např. na internet. (Více se o balení pod Linuxem dozvíte v článku Balení a rozbalování pod Linuxem.)
Příklad Vytvoření balíčku: tar cfz priklad.tar.gz priklad
Uživatelská část V této části se podíváme na uživatelovo počínání s naším programem. Ten si např. stáhne náš program (balíček) z internetu a zkopíruje do adresáře, kde jej chce mít. Teď musí balíček rozbalit: tar xfz balicek.tar.gz
Pak přejde do adresáře s programem a zkompiluje ho: make
Nakonec je někdy potřeba udělat ještě nějaké další věci, které jak který program potřebuje (př. pro náš příklad - nastavit proměnnou prostředí LD_LIBRARY_PATH). Jak je vidět, uživatel má nesrovnatelně jednodušší práci než my - vývojáři (nebo chcete-li programátoři).
Shrnutí 1. a 2. lekce Překlad s gcc Z minulé lekce známe základy práce s gcc. Jednoduché projekty z několika zdrojových souborů lze obvykle přeložit prostým příkazem gcc soubor1.c soubor2.c souborN.c -o program
V případě větších projektů je tento postup nevýhodný. Překlad může obsahovat sestavování jednotlivých logických celků, vytváření a linkování knihoven, navíc výsledkem může být hned několik programů, které mají část kódu společnou. Překlad C nebo C++ kódu je hlavně díky preprocesoru a optimalizacím časově náročný a zejména při vývoji by bylo neúnosné překládat po jediné změně libovolného zdrojového souboru celý projekt od začátku. Hodně času ušetří oddělení fáze preprocesingu a vlastního překladu od linkování, neboť pak můžeme využít mezivýsledky minulého překladu. gcc gcc gcc gcc
soubor1.c soubor2.c souborN.c soubor1.o
-c -c -c soubor2.o souborN.o -o program
Prvními třemi příkazy provedeme odděleně vlastní překlad jednotlivých zdrojových souborů, objektový kód se uloží do soubor1.o, soubor2.o a souborN.o. Posledním příkazem pak objektové 5
soubory slinkujeme do výsledného programu. Pokud potom při ladění změníme například první *.c soubor, stačí zavolat gcc soubor1.c -c gcc soubor1.o soubor2.o souborN.o -o program
Při modifikaci hlavičkového souboru sice musíme překompilovat všechny *.c soubory, které jej přímo nebo zprostředkovaně inkludují, ale přesto nám oddělení vlastního překladu od linkování při vývoji skutečných praktických projektů ušetří spoustu času, který bychom jinak strávili čekáním na překladač. Bohužel vyznat se v časech modifikací a závislostech zdrojového kódu na hlavičkových souborech je nad síly běžného programátora. Proto vznikl make.
Makefile Příkaz make provádí akce závislé na jiných akcích a může přitom mimo jiné testovat existenci a porovnávat datum poslední modifikace souboru. Seznam akcí a závislostí je popsán v souboru, který se obvykle jmenuje Makefile. Samotný make není přímo svázaný s překladem C, lze a má rozumný smysl jej použít v podstatě na libovolnou složitější sadu akcí s vysokým stupněm závislosti, kde neexistuje lepší řešení, klidně třeba vytvoření balíčku s dokumentací v pdf z textovských zdrojáků. Je ovšem pravda, že překlad C/C++ je určitě nejčastějším příkladem použití make a platí to i naopak, standardním způsobem organizace překladu na Unixu je Makefile. Jednoduchý projekt ze tří souborů v Makefile by mohl vypadat asi takhle: priklad: funkce.o main.o gcc funkce.o main.o -o priklad funkce.o: funkce.c gcc funkce.c -c main.o: main.c funkce.h gcc main.c -c
Umístíme jej do adresáře se zdrojovým kódem a projekt přeložíme prostým příkazem make
Pokud si to budete chtít vyzkoušet a budete kopírovat Makefile z webového prohlížeče přes schránku, dejte si pozor na odsazení příkazů. Odsazení jednotlivých příkazů musí být provedeno pomocí tabelátoru. To je určitě nejhloupější vlastnost make. Stáhněte si proto raděj celý příklad zabalený jako c17beta.tar.gz. Jak to celé funguje? V souboru Makefile je sada pravidel typu cíl: závislost1 závislost2 ... [tabelátor]akce
Cíl uvedený jako první je implicitní cíl příkazu make. Můžeme jej také určit explicitně jako první parametr, takže například make main.o
provede pouze vlastní překlad souboru main.c podle třetího pravidla. Při volání make bez parametrů je cílem přeložený program - soubor priklad. Make nejprve projde závislosti, zde funkce.o a main.o. Nejdřív ověří funkce.o a zjistí, že soubor neexistuje, ale může jej vytvořit pomocí druhého pravidla. 6
V pravidle pro funkce.o je závislost na funkce.c, ta je splněna, neboť soubor funkce.c existuje a není pro něj žádné pravidlo. Dojde tedy na akci pravidla pro funkce.o, make zavolá gcc funkce.c -c
a vrátí se k testování závislostí prvního pravidla. Přečte si, že priklad závisí ještě na main.o, a tak jej pomocí třetího pravidla (zcela analogicky jako v případě funkce.o) vytvoří. Nyní již jsou splněny všechny závislosti a make se dostane k vykonání akce hlavního prvního pravidla. gcc funkce.o main.o -o priklad
Trochu složitější to je, pokud jsme už celý projekt přeložili, ale dodatečně ještě změnili main.c (stačí zavolat touch main.c) a zavolali make. Při testu závislostí prvního pravidla sice oba objektové soubory existují a budou i o nějakou tu desetinu vteřiny starší než soubor priklad, ale v Makefile jsou i pro ně napsaná pravidla, a make tedy musí nejprve ověřit rekurzivně i jejich závislosti. V případě funkce.o je závislost splněna, neboť funkce.c je starší než funkce.o a pro funkce.c neexistuje žádné pravidlo. V případě main.o je tomu jinak, neboť main.c je mladší než main.o. Dojde tedy na akci gcc main.c -c
a tím se vytvoří nový main.o s aktuálním časem modifikace. To znamená, že main.o bude mladší než priklad a make musí po návratu do zpracování prvního pravidla zavolat na závěr i jeho akci. gcc funkce.o main.o -o priklad
Syntaxe Makefile umožňuje také vkládat komentáře a definovat proměnné. # Tohle je naše první proměnná OBJ=main.o funkce.o # Použitím proměnné OBJ si ušetříme trochu psaní priklad: ${OBJ} gcc ${OBJ} -o priklad
Jako typické použití proměnných bych uvedl nepovinné parametry překladače. Pomocí přepínačů O0 až -O3 můžeme určit míru optimalizace gcc, pomocí -g zase přidáme do kódu ladící informace, které pak můžeme využít například nástroji typu gdb nebo valgrind. Nastavením jediné proměnné v Makefilu tak můžeme ovlivnit způsob překladu všech souborů, nejspíš se bude lišit překlad distribuční verze projektu od překladu během vývoje. Často se v Makefile vyskytují vedlejší cíle. Už víme, že implicitně make zpracovává první cíl uvedený v Makefile, ale nic nám nebrání definovat další, obvyklé jsou například clean (smazání souborů vygenerovaných při překladu), install (instalace přeloženého projektu), uninstall a distrib (vytvoření distribuce zdrojového kódu projektu v jediném balíčku), běžně se lze také setkat s generováním dokumentace nebo přeložených balíčků pro systémy správy nainstalovaného software jako je například RPM. V souvislosti s cíli, jimž neodpovídá žádný soubor se používá speciální cíl .PHONY. S jeho pomocí můžeme sdělit make, že cíl není vázaný na soubor stejného jména. Příkaz make clean
7
pak bude fungovat i v případě, že v adresáři projektu shodou okolností existuje soubor jménem clean.
8
Otázky k opakování _____________________________________
1.
Kterou funkci obsahují v jazyce C? Proč je vhodné rozdělit velký program do několika funkcí?
2. Jakým příkazem se přeloží soubory prog.c a func.c do spustitelného programu?
9
Lab _________
.
10