Obsah
Novinky
Zverejnili sme seriál článkov Auto Tools, ktorý vychádzal na stránkach PC Revue v číslach 01/2002 - 04/2003.
Auto Tools
Seriál článkov o sade nástrojov pre vývojárov na platforme Unix (Linux) je uvoľnený pod Open Source licenciou. Ak začínate s vývojom aplikácií na spomínaných platformách, iste sa vám tieto články zídu.
3. časť: Zastupujúce znaky, automatické premenné, vzory
V tejto časti si povieme niečo o zastupujúcich znakoch (wildcard characters) a o automatických premenných. Obidve témy patria k sebe, jedno bez druhého nemá priveľký význam (hlavne automatické premenné bez zastupujúcich znakov sú na nič). Tieto témy sú pre dokonalé zvládnutie písania súborov Makefile nevyhnutné, preto ak by vám po prečítaní nasledujúceho textu nebolo niečo jasné, skúste si to prečítať ešte raz, ak sa to ani potom nezlepší, skúste nahliadnuť do manuálu k programu. Výbornou pomôckou môžu byť aj súbory z existujúcich projektov - skúste si preštudovať (na začiatok jednoduchší) súbor Makefile, snažte sa mu porozumieť, prípadne i poučiť sa a zapamätať si nejaké tie triky, ako sa dá daný problém vyriešiť.
Zastupujúce znaky
Istotne poznáte znak * (hviezdička, angl. asterisk), ktorý môžete použiť tak vo Windows, ako aj vo všetkých možných shelloch v Unixe. Niečo podobné sa nachádza aj v regulárnych výrazoch (regular expressions) a v mnohých iných oblastiach programovania, ale aj bežného počítačového života. Ak by vám predsa len nebolo jasné, na čo taká hviezdička môže slúžiť, tu je krátke vysvetlenie: znak * zastupuje ľubovoľnú množinu znakov. Ak by ste zadali príkaz:
rm *.cpp
v Unixe alebo
del *.cpp
v DOSe, zmažú sa všetky súbory, ktoré sa začínajú nejakými znakmi a končia sa koncovkou ".cpp". Make pozná tieto zastupujúce znaky (sú prebrané zo shellu):
- * ľubovoľná množina znakov
- [abc] vymenovaná množina znakov
- ? jeden ľubovoľný znak
a všetky ostatné, ktoré pozná každý bežný shell. Substitúcia zástupných znakov - nahradenie skutočnou hodnotou - sa však nedeje automaticky pri priradení hodnoty do premennej. Ak by sme potrebovali do premennej SRC uložiť mená všetkých zdrojových súborov s príponou .cpp a následne by sme ich chceli vypísať, priradenie
SRC = *.cpp
a príkaz:
echo $(SRC)by asi nesplnili naše očakávania - premenná SRC totiž obsahuje hodnotu *.cpp a nie mená všetkých súborov s uvedenou príponou. Ak by sme však takúto premennú použili v pravidle - napríklad vo vymenovaní zdrojov alebo cieľov, použila by sa síce hodnota *.cpp, tá by sa však neskôr nahradila menami konkrétnych súborov - teraz by nám teda mohlo byť jedno, kedy sa substitúcia vykoná. Ak by sme potrebovali, aby sa zastupujúce znaky nahradili hodnotou už pri priradení, mohli by sme to spraviť takto:
SRC = $(wildcard *.cpp)
wildcard je funkcia, o tých sa budeme rozprávať neskôr. Zatiaľ si len všimnite, ako sa volajú. Make však pozná aj iné zastupujúce znaky. Používajú sa vo všeobecných pravidlách, teda v pravidlách, ktoré nemusia vytvoriť iba jeden súbor, ale množstvo podobných súborov. Ako príklad môžeme uviesť pravidlo, ktorého zdrojom sú súbory s príponou .cpp a cieľom sú súbory s príponou .o - je dosť pravdepodobné, že všetky zdrojové súbory C++ sa budú kompilovať rovnako. Pomocou takýchto pravidiel si môžeme tvorbu súborov Makefile podstatne zjednodušiť (hlavne pri programoch s väčším počtom súborov). V súvislosti zo všeobecnými pravidlami sa môžeme sa stretnúť aj s pojmom automatické premenné - sú to premenné, ktorým hodnotu priraďuje make sám. Teraz nasleduje príklad všeobecného pravidla s automatickými premennými, ktoré sa neviaže na žiadne konkrétne zdrojové súbory:
%.o: %.cpp
g++ -c $< -o $@
Toto pravidlo sa použije na vytvorenie všetkých súborov s príponou .o (zo súboru file.cpp vytvorí file.o); automatická premenná $@ sa nahradí cieľom pravidla (teda textom pred dvojbodkou), premenná $< sa nahradí prvým zdrojom pravidla (textom za dvojbodkou). Teraz nasleduje trochu väčší a užitočnejší príklad. Zdrojové súbory sú rovnaké, ako boli v minulej časti (main.cpp vkladá hlavičkový súbor ahoj1.h, zdrojový súbor ahoj1.cpp zase vkladá ahoj2.h).
OBJECTS = ahoj1.o ahoj2.o main.o
TARGET = ahoj
CC = g++
all: $(TARGET)
$(CC) -o $(TARGET) $(OBJECTS)
%.o: %.cpp
$(CC) -o $@ -c $<
ahoj1.cpp: ahoj2.h
touch $@
main.cpp: ahoj1.h
touch $@
Teraz si vysvetlíme jednotlivé riadky. Prvých päť riadkov by malo byť (po prečítaní predchádzajúcich častí) každému zrejmé. Pravidlo
%.o: %.cpp
vyhovuje každému súboru s príponou .o, teda po prvom spustení programu make sa jeho príkazy vykonajú trikrát (pričom premenné $@ a $< sa budú pre každý jeden súbor meniť. Nasledujúce štyri riadky by takisto mali byť zrejmé (zabezpečia, aby sa pri zmene hlavičkového súboru skompiloval zdrojový súbor, ktorý ho používa). Celý príklad však môžeme ešte viac skrátit, pričom bude fungovať rovnako a navyše bude aj trochu prehľadnejší:
OBJECTS = ahoj1.o ahoj2.o main.o
TARGET = ahoj
CC = g++
all: $(TARGET)
$(CC) -o $(TARGET) $(OBJECTS)
%.o: %.cpp
$(CC) -o $@ -c $<
ahoj1.o: ahoj2.h
main.o: ahoj1.h
Jediný rozdiel medzi príkladmi je v zapísaní "závislostí". Napríklad súbory .cpp sú závislé na .h a podobne. Teraz stačí za dvojbodku pridať toľko hlavičkových súborov, koľko sa nám zapáči. Odporúčam však pridávať iba tie hlavičkové súbory, ktoré sú naozaj potrebné, inak sa budú zdrojové súbory prekladať stále dookola bez toho, aby to bolo potrebné. Ak by viac zdrojových súborov vkladalo tie isté hlavičkové súbory, môžeme pridať do jedného riadku viac cieľov (pred dvojbodku), napríklad:
file1.o file2.o: header1.h header2.h header3.h
Automatické premenné
$@
Obsahuje cieľ pravidla. Ak jedno pravidlo má viacero cieľov, táto premenná bude obsahovať meno toho cieľa, kôli ktorému sa dané pravidlo zavolalo. Ak je toto pravidlo "všeobecné" (ako v príklade vyššie), premenná $@ bude takisto obsahovať meno cieľa, kôli ktorému sa pravidlo zavolalo. Ak je cieľ členom archívu (preberieme niekedy inokedy), táto premenná bude obsahovať názov archívu.
$%
Ak je cieľ členom nejakého archívu, obsahuje meno člena. Napríklad:
archiv.a(objekt.o)
V tomto prípade bude premenná $@ = archív.a, $% = objekt.o. Ak cieľ nie je členom žiadneho archívu, táto premenná bude prázdna (zatiaľ teda pre nás nemá význam).
$<
Meno prvého zdroja (ak je zdroj uvedený podobne, ako v našom príklade - teda zo znakom %, táto premenná bude obsahovať aj príponu zdroja).
$?
Obsahuje názvy všetkých zdrojov, ktoré sú novšie ako cieľ (sú oddelené medzerou). Ak sú niektoré zdroje členmi archívov, uvedie sa iba ich názov.
$^
Obsahuje názvy všetkých zdrojov daného pravidla. Pre členov archívov platí to, čo som uviedol pri predchádzjúcej premennej. Ak je niektorý zdroj uvedený viackrát, v tejto premennej bude iba raz.
$+
Táto premenná je podobná predchádzajúcej s jediným rozdielom: ak je jeden zdroj uvedený viackrát, aj v tejto premennej sa bude nachádzať viackrát - a v rovnakom poradí.
$*
Obsahuje koreň vzoru. Ak máme vzor %.cpp a súbor ahoj.cpp, ktorý tomuto vzoru vyhovuje, premenná $* bude obsahovať text ahoj.
Vzory
Na koncii tretej časti si ešte povieme niečo o vzoroch (angl. pattern). Vzor je vlastne textový reťazec, ktorý sa používa v cieli a zdroji všeobecných pravidiel. Má takýto formát:
prefix%suffix
Prefix a/alebo suffix môžeme vynechať. Ak vynecháme obidve časti, dostaneme vzor, ktorému vyhovuje každý cieľ.
Text medzi prefixom a suffixom sa nazýva koreň (angl. stem). Ak máme vzor %.o a súbor file.o, koreň bude file. Ak by sme v pravidle použili vzor aj namiesto zdroja, znak % v zdrojovom vzore sa nahradí koreňom zo vzoru cieľa. Ak by sme použili súbor file.o a pravidlo:
%.o: %.c
echo $<
echo $*
dostali by sme takýto výpis:
file.c
file
Ak cieľ obsahuje znak / (ide teda o súbor v nejakom podadresári), make sa správa mierne odlišne. Najprv sa časť pred lomkou (vrátane lomky) oddelí, porovná sa zvyšok názvu so vzorom a potom sa na začiatok koreňa pripojí názov adresára. Ak by sme mali vzor a.%.c a cieľ dir/a.b.c, koreň by bol dir/b.
Vzory, zastupujúce znaky a automatické premenné sú veľmi použiteľnou (a zároveň veľmi používanou) časťou súborov Makefile, a preto je nutné, aby ste im rozumeli a zvládli ich.
Oto Komiňák
Článok bol uverejnený v magazíne PC Revue 03/2002.
