Programujeme v C++ (2) - make, cmake

Programujeme v C++ (2) - make, cmake
01.07.2008 09:15 | Články | Miroslav Bendík
V tejto časti seriálu si predstavíme make. Na niekoľkých ukážkach si predvedieme ako funguju závislosti v Makefile. Na konci článku nás čaká ľahký úvod do cmake.

Mnohí z vás určite poznajú trojicu príkazov configure, make a make install. V tejto časti sa pokúsim vysvetliť čo sa za týmito príkazmi skrýva a ako to využiť pri vlastných projektoch.

Make

Make je nástroj, ktorý dokáže automaticky zistiť poradie v ktorom majú byť časti programu skompilované. Na to aby vedel určiť v akom poradí sa majú súbory kompilovať musíme vytvoriť súbor Makefile ktorý obsahuje závislosti a príkazy. Veľmi dôležitou vlastnosťou make je rekompilácia iba tých častí, ktoré sa musia znovu skompilovať. Tieto vlastnosti robia z GNU Make veľmi silný nástroj.

Závislosti

Pri kompilácii programu musíme zaistiť aby jednotlivé časti kompilácie prebehli v správnom poradí. Ak chceme napríklad vytvoriť súbor objekt.o budeme na kompiláciu potrebovať súbory objekt.h a objekt.cpp (za predpokladu, že tieto súbory nepotrebujú žiadne ďalšie závislosti). Akonáhle máme všetky objektové súbory (súbory s príponou *.o) skompilované môžeme celý program zlinkovať. Toto správanie sa dá veľmi ľahko popísať grafom závislostí.

Graf závislostí

Graf závislostí

Tento graf znázorňuje program "Ahoj svet" z minulej časti. Na začiatku máme súbory hello_lib.cpp, hello_lib.h a hello_main.cpp. Potrebujeme skompilovať výsledný program (hello). Na úspešné zlinkovanie tohto programu potrebujeme hello_lib.o a hello_main.o. Preto musíme najskôr skompilovať tieto 2 objektové kódy a až potom môžeme pokračovať linkovaním.

Teraz si predstavme situáciu, že všetko je správne skompilované a pri testovaní programu sme našli chybu. Táto chyba sa nachádza v jedinom súbore - hello_lib.cpp. Jednou z výhod oddelenej kompilácie je to, že nemusíme po nájdení chyby prekompilovať celý program, ale iba časť v ktorej sa chyba nachádza a všetky ďalšie časti ktoré zmena ovplyvní.

Graf závislostí po editácii

V tomto prípade treba znovu skompilovať hello_lib.o. Tým sa nam ale zmenila jedna zo závislostí programu hello preto musí byť hello znovu zlinkovaný. Všetko za nás našťastie rieši make, stačí len správne napísať súbor Makefile.

Tvorba makefile

Graf závislostí po editácii

Graf závislostí je teraz potrebné prepísať do súboru Makefile, ktorý má nasledujúcu syntax:

cieľ: závislosti
	príkazy

Každý príkaz sa musí začínať tabulátorom. Ak chceme do súboru pridať komentár stačí pred začiatok komentára vložiť znak #. Cieľ je súbor ktorý bude vytvorený alebo aktualizovaný ak sa zmení akýkoľvek súbor uvedený v závislostiach. Prepis grafu závislostí do Makefile by mohol vyzerať takto:

hello: hello_lib.o hello_main.o
	g++ hello_lib.o hello_main.o -o hello

hello_lib.o: hello_lib.cpp hello_lib.h
	g++ -c hello_lib.cpp

hello_main.o: hello_main.cpp hello_lib.h
	g++ -c hello_main.cpp

Pozor pri prepise treba dávať hlavne na hlavičkové súbory. Ak by sme zabudli na uvedenie hlavičkových súborov mohlo by sa nám stať, že by sa po ich úprave program nekorektne skompiloval.

Kompilácia pomocou make

Najskôr si vytvoríme nový adresár. Všetky zdrojové kódy nášho projektu skopírujeme do nového adresára a vytvoríme tam súbor Makefile. Po úspešnom vytvorení súboru Makefile môžeme v adresári s projektom spustiť príkaz make hello. V prípade, že sa náš Makefile súbor volá ináč než Makefile musíme príkazu make špecifikovať ktorý súbor chceme použiť - make -f NášMakefile hello. Ak nešpecifikujeme cieľ ktorý chceme skompilovať make automaticky skompiluje prvý cieľ ktorý v súbore nájde. V našom prípade je prvý cieľ hello preto namiesto make hello môžeme napísať make a kompilácia prebehne úplne rovnako.

Premenné

Ak by sme teraz chceli vymeniť kompilátor g++ za icc museli by sme nahradiť vo všetkých riadkoch kde kompilujeme príkaz g++ za icc. Pri väčších projektoch by sa toto mohlo stať nočnou morou programátora. Preto je lepšie príkazy vložiť do premenných.

Syntax vytvorenia premennej vyzerá takto:

názov_premennej = hodnota

Viacriadkové premenné môžeme zapísať pomocou znaku \ (spätné lomítko).

názov premennej = 1. riadok \
2. riadok

Takto vytvorené premenné je možné použiť v príkazoch. Prístup k premennej je možný cez $(názov_premennej).

Náš Makefile s použitím premenných bude vyzerať takto:

CXX        = g++
LINK       = g++
CXX_FLAGS  = -Wall

hello: hello_lib.o hello_main.o
	$(LINK) hello_lib.o hello_main.o -o hello

hello_lib.o: hello_lib.cpp hello_lib.h
	$(CXX) $(CXX_FLAGS) -c hello_lib.cpp

hello_main.o: hello_main.cpp hello_lib.h
	$(CXX) $(CXX_FLAGS) -c hello_main.cpp

Automatické premenné

Automatické premenné sú vytvárané samostatne pre každý cieľ.

Zoznam niektorých automatických premenných

$@ Táto premenná obsahuje názov cieľa. Ak je cieľov viacero príkaz v ktorom sa nachádza $@ sa vykoná pre každý cieľ samostatne.
$< Názov prvého súboru zo závislostí.
$? Medzerou oddelené názvy všetkých závislostí ktoré sú potrebné na vytvorenie cieľa.

Kompletný zoznam automatických premenných obsahuje manuál ku GNU `make'.

S využitím automatických premenných bude náš Makefile vyzerať nasledovne:

CXX        = g++
LINK       = g++
CXX_FLAGS  = -Wall

hello: hello_lib.o hello_main.o
	$(LINK) $? -o $@

hello_lib.o: hello_lib.cpp hello_lib.h
	$(CXX) $(CXX_FLAGS) -c $< -o $@

hello_main.o: hello_main.cpp hello_lib.h
	$(CXX) $(CXX_FLAGS) -c $< -o $@

Posledné 2 pravidlá sú takmer identické. V takýchto prípadoch môžeme použiť implicitné pravidlá. Tieto 2 pravidlá môžeme zapísať pomocou implicitných pravidiel takto:

%.o: %.cpp hello_lib.h
	$(CXX) $(CXX_FLAGS) -c $< -o $@

Znak % môže reprezentovať akýkoľvek reťazec. V tomto prípade make vyhľadá všetky súbory *.cpp a skompiluje ich.

Úvod do problematiky automatickej kompilácie by sme mali za sebou. Pre tých, ktorí by sa chceli viac dozvedieť o GNU Make a Auto Tools som pripravil pár odkazov.

Odkazy

Stručný popis makefile (anglicky)
Manuál k make (anglicky)
Make tutoriál (anglicky)
Seriál o Auto Tools (slovensky)

CMake

CMake alebo Cross Platform Make je určený na vytvorenie natívnych Makefile súborov. Okrem unixových Makefile vie generovať napríklad Windows MSVC projekty, "Borland Makefiles" a ďalšie. Okrem multiplatformovosti sa CMake vyznačuje aj jednoduchou syntaxou a vhodnosťou pre veľké projekty (CMake využíva napr. KDE4).

Syntax CMake je veľmi jednoduchá. Celý súbor sa skladá z CMake príkazov a parametrov. Príkazy a parametre sa zapisujú Príkaz(parametre). Príkazy nie sú citlivé na veľkosť znakov. Komentáre podobne ako v Makefile začíname znakom #.

Ako príklad použijem znova program "Ahoj svet". Adresár s projektom vytvoríme podobne ako pri GNU Make. Namiesto Makefile si vytvoríme súbor CMakeLists.txt s nasledujúcim obsahom:

PROJECT(hello)
INCLUDE_DIRECTORIES ("${PROJECT_BINARY_DIR}")
ADD_EXECUTABLE(hello hello_lib.cpp hello_main.cpp)

V prvom riadku nastavíme názov projektu. Príkazom INCLUDE_DIRECTORIES pridáme adresáre v ktorých bude CMake hľadať hlavičkové súbory. Ak by sme neuviedli tento príkaz nemali by sme v závislostiach hlavičkové súbory. Posledným príkazom ADD_EXECUTABLE špecifikujeme zdrojové súbory potrebné na vytvorenie spustiteľného súboru.

Kompilácia

Pred kompiláciou najskôr vygenerujeme Makefile príkazom:

cmake cesta k adresáru s projektom

Aj keď cmake spúšťame v adresári s projektom musíme zadať cestu k adresáru. Ako cestu zadáme aktuálny adresár (cmake .). CMake automaticky zistí prítomnosť kompilátora a vytvorí Makefile. Na kompiláciu projektu stačí už len spustiť make.

V budúcej časti sa budeme zaoberať ďalšími funkciami CMake. Ukážeme si ako pomocou CMake vytvoriť config.h a povieme si niečo o preprocesore a direktívach pre preprocesor kompilátora.

    • jednoduchsie 01.07.2008 | 16:00
      Avatar Tommy Angelo   Používateľ
      najprv som bol skepticky voci manualnemu kompilovaniu, preferoval som nieco ako kdevelop, eclipse, code:block, ale casom som zistil, ze ani jeden nekompiluje spravne...po odporucani pouzivat cmake som si toto [dle mna jednoduchsie riesenie] natolko oblubil, ze pre kodenie v C++ pouzivam uz len kate + cmake.
      • Re: jednoduchsie 07.07.2008 | 02:18
        Avatar nardew debian  Používateľ
        nekompiluje spravne? to mi teda budes musiet vysvetlit
    • super 05.07.2008 | 19:44
      Avatar m4jkl   Používateľ
      kvalitny clanok

      dik :)