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.
12. časť: Makrá M4
Kedysi som robil istý program v C++, ktorý spolupracoval s MySQL databázou. Keďže štandardné MySQL API nebolo na dostatočne vysokej úrovni (neobjektové...), rozhodol som sa použiť objektovo orientovanú knižnicu SQL++. Keďže projekt mal trochu viac súborov, potreboval som použiť Auto Tools.
Možno ste si všimli, že niektoré programy pri spustení configure vypisujú niečo ako:
checking for foo... yes
Prípadne ešte vypíšu nájdenú verziu programu (alebo knižnice), ktorú pre svoju inštaláciu alebo beh potrebujú. A tu u mňa nastal problém - pre ostatné knižnice, ktoré môj projekt používal, som si makrá buď našiel (a požičal) z iných programov, ktoré danú knižnicu takisto používali, alebo ich podpora už bola zahrnutá v inštalácii, resp. stačilo použiť podobné makro:
AC_CHECK_LIB(kniznica, funkcia)
Pre knižnicu SQL++ som však nič nenašiel. Možno stačilo lepšie hľadať, no namiesto toho som si vytvoril vlastné makro. Teraz si ukážeme, ako také niečo urobiť.
Všetko sa to bude točiť okolo makrojazyka M4, ktorý sa používa aj v súboroch configure.in, a my sme sa s ním teda už stretli, hoci sme o tom nevedeli. Doteraz sme sa však obmedzili iba na používanie makier, dnes si ich budeme aj definovať.
Pri definovaní makier máme na výber dve možnosti: ak sú to jednoduché a krátke makrá, môžete ich napísať priamo do súboru configure.in. Druhá možnosť je uložiť ich do špeciálneho súboru acinclude.m4, o ktorý sa postará program aclocal. Ten prescanuje configure.in a acinclude.m4 a makrá uloží do súboru aclocal.m4. Zo začiatku môžeme bez výčitiek použiť prvú možnosť.
Definovanie makra
M4 je makrojazyk. Platí: (skoro) všetko je makro. Chceme definovať nové makro? Použijeme na to iné makro. V nových makrách môžeme s výhodou použiť shell príkazy. Teraz si ukážeme, ako si môžeme vytvoriť nové vlastné makro. Definícia vyzerá nasledovne:
AC_DEFUN(nazov_makra, telo)
Predpokladajme, že telo bude obsahovať viacero príkazov, preto ich všetky uzavrieme do bloku pomocou hranatých zátvoriek (podobne ako v jazyku C/C++ na takýto účel slúžia krútené zátvorky). Teraz si skúsime vytvoriť naše prvé makro. Otvoríme súbor configure.in a niekde na začiatok vložíme nasledujúce riadky:
AC_DEFUN(MY_MACRO, [
echo "Hello, M4!"
echo "Hello, Autotools!"
])
Samozrejme, povolené sú prakticky všetky príkazy shellu, nie len echo. Keď sme si už definovali makro MY_MACRO, je na čase použiť ho. Do nášho otvoreného súboru zapíšeme názov makra, a ostatné sa už spraví za nás. Dôležité je, aby bolo makro definované pred jeho "volaním" (nie, makra sa nevolajú, ale substituujú, ale o tom snáď inokedy; prípadne si prečítajte manuál k M4). Teda niekde za definíciu makra napíšeme:
MY_MACRO
Teraz spustíme náš známy súbor bootstrap, ktorý môže obsahovať napríklad takéto riadky:
aclocal && \
autoheader && \
automake && \
autoconf
Teraz spustíme ./configure a medzi nám už známe riadky sa dostanú aj tieto nové:
Hello, M4!
Hello, Autotools!
Miesto výpisu závisí od toho, kde sme umiestnili "volanie" nového makra MY_MACRO.
Parametre makier
Makrá môžu mať aj parametre, podobne ako napríklad funkcie jazyka C. Teraz si vytvoríme makro, ktoré sa nám neskôr zíde, a na ktorom si zároveň ukážeme, ako používať parametre makier. Makro bude vyhľadávať súbory v zadaných adresároch. Má tri parametre. Prvý obsahuje zoznam hľadaných súborov oddelených medzerami. Druhý obsahuje zoznam adresárov, v ktorých má prebehnúť vyhľadávanie. Tretí parameter je názov premennej, do ktorej sa uloží adresár, v ktorom sa po prvýkrát našiel hľadaný súbor. Definícia je relatívne jednoduchá:
AC_DEFUN(FIND_FILE, [
for i in $2; do
for j in $1; do
if test -r "$i/$j"; then
$3=$i
break 2
fi
done
done
])
Teraz si ukážeme, ako toto makro môžeme použiť v praxi. Nie je to veľmi užitočný príklad, ale ukážeme si na ňom, ako môžeme volať makrá s parametrami.
FIND_FILE(stdio.h, /usr/local/include /usr/include, where_is_stdio)
echo $where_is_stdio
Tieto riadky môžeme, samozrejme, vložiť hocikde za definíciou makra FIND_FILE. Po prvom riadku už budeme mať k dispozícii premennú where_is_stdio, ktorá obsahuje pravdepodobne /usr/include.
Je zrejmé, že aj v makrách môžeme volať iné makrá. To sa dosť hojne využíva. Teraz si opíšeme niekoľko najčastejšie používaných makier, ktoré máme k dispozícii.
Výstup
Najprv si ukážeme, ako môžeme vypisovať užitočné informácie aj inou cestou ako pomocou príkazu echo. Prvé z makier je AC_MSG_CHECKING. Jediný parameter je text, ktorý sa vypíše za checking for. Toto makro teda použijeme na začiatku nášho komplexnejšieho makra, ktoré môže napríklad kontrolovať prítomnosť nejakej potrebnej knižnice.
Ďalšie makro je AC_MSG_RESULT. Ako už názov napovedá, makro oznamuje výsledok - teda niečo ako yes, no, prípadne môže vypísať verziu nájdenej knižnice. Všimnite si, čo vypisujú rôzne programy, ktoré kompilujete a ktoré majú aj súbor configure.
Makro AC_MSG_WARN už nemá len informačný charakter, ide o varovanie, že nastali nie celkom bežné podmienky, avšak program sa môže skompilovať (teda nie je to nič fatálne).
Posledné z makier, ktoré slúžia na výpis informácií užívateľovi, je AC_MSG_ERROR. Názov napovedá, že ide o chybové hlásenie. Mali by sme ho používať iba vo vážnych prípadoch, napríklad keď program bez chýbajúcej knižnice nie je schopný pracovať. Toto makro totiž ukončí beh configure a hlásenie sa vypíše na štandardný chybový výstup, a nie na stdout.
Vstup
Pod vstupom rozumieme zadanie parametrov na príkazový riadok pri spúštaní configure. Napríklad:
./configure --with-some-feature --with-my-lib=/usr/local/lib/... \
--without-x --enable-foo
Pomocou shell príkazov dokážeme zabezpečiť aj interaktívny vstup, no nie je to celkom bežné. Stretol som sa s istým programom, ktorý pri spustení ./configure zrazu zastal a pýtal si heslo, ktoré sa potom zakompilovalo do binárky (zrejme nie práve najlepší nápad). Myslím, že by to pre skúsenejších užívateľov shellu nemal byť problém niečo podobné naprogramovať.
Zoznam povolených argumentov dostaneme klasicky zadaním ./configure --help. Všimnime si, že niektoré programy majú vo svojom configure niekde ku koncu výpisu riadok
--enable and --with options recognized:
Za týmto riadkom nasleduje viacero povolených --with a --enable argumentov. Teraz si ukážeme, ako také niečo môžeme do tohto zoznamu pridať aj my.
Ako prvé si ukážeme makro AC_ARG_ENABLE, ktoré umožní zvoliť --enable parameter na príkazovom riadku. Prvým parametrom je názov pridaného parametra, ktorý bude za --enable- (resp. --disable-, viď ./configure --help). Druhým parametrom je text, ktorý sa zobrazí ako help. Tu je niekedy na mieste trošku sa "pohrať" s medzerami a vymerať text tak, aby sedel s ostatnými riadkami. Ako úvodzovky môžete použiť opäť hranaté zátvorky (to aby vám M4 neignoroval nadbytočné medzery). Ďalšie dva parametre obsahujú príkazy, ktoré sa vykonajú pri použítí enable, resp. disable. Ak na príkazovom riadku nezvolíme ani jednu z týchto možností, štandardná hodnota je disable (teda vykonajú sa príkazy nie z tretieho, ale zo štvrtého parametra). Teraz si to celé predvedieme:
AC_ARG_ENABLE(my-feature,
[ --enable-my-feature enables my feature...],
[
echo "My feature enabled!"
], [
echo "My feature disabled!"
])
Niekedy nestačí dať konfiguračnému programu len informáciu o požadovaných funkciách kompilovaného programu, často potrebujeme predať aj nejaké konkrétne hodnoty. To urobíme jednoducho: --enable-my-feature=123. Túto hodnotu potom dostaneme v premennej $enableval. Tu je teda vylepšená verzia predchádzajúceho príkladu:
AC_ARG_ENABLE(my-feature,
[ --enable-my-feature enables my feature...],
[
echo "My feature enabled!"
echo $enableval
], [
echo "My feature disabled!"
])
Program by na ďalšom riadku vypísal hodnotu 123. Ak nezadáme žiadnu hodnotu, premenná bude obsahovať yes, resp. no v závislosti od spôsobu volania.
Oto Komiňák
Článok bol uverejnený v magazíne PC Revue 01/2003.
