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.
13. časť: Makrá M4 po druhé
Minule sme si ukázali makro AC_DEFUN, pomocou ktorého definujeme vlastné makrá. Ďalej to boli makrá na výstup textu (AC_MSG_CHECKING, AC_MSG_RESULT, AC_MSG_WARN a AC_MSG_ERROR) a makro, ktoré rozšíri akceptovateľné parametre programu configure (AC_ARG_ENABLE). Toto posledne menované makro pridá spomenutému programu configure parameter --enable-..., ktorý potom môžete smelo používať ako ktorýkoľvek iný parameter tohto programu. Dnes si povieme o podobnom makre, ktoré ale pridá parameter --with-..., ďalej si ukážeme aj nejaké praktické príklady použitia všetkých týchto makier.
AC_ARG_WITH
Toto makro pridá parameter --with-. Používa sa podobne, ako AC_ARG_ENABLE:
AC_ARG_WITH(lib, help, [ak áno], [ak nie])
Prvý parameter je názov, ktorý sa použije za --with-, v tomto prípade to teda bude --with-lib. help je text, ktorý sa zobrazí pri tomto parametri pri spustení ./configure --help. Tretí parameter obsahuje príkazy, ktoré sa vykonajú, ak náš --with parameter pri konfigurovaní použijeme, no a posledný sa analogicky použije pri nepoužití nášho parametra. Napríklad:
AC_ARG_WITH(mylib,
[ --with-mylib=DIR use mylib installed in DIR],
[
echo "Using mylib installed in $withval"
], [
echo "Configuring without mylib!"
])
Z príkladu vidíte, že v premennej $withval sa bude nachádzať text za --with-mylib=. V prípade, že uvediete iba --with-mylib, premenná bude obsahovať yes. Ak uvediete --without-mylib, premenná bude obsahovať text no - vždy sa však vykoná tretí parameter makra AC_ARG_WITH. V poslednom prípade (teda neuvediete vôbec nič), vykoná sa štvrtý parameter tohto makra - vypíše sa text Configuring without mylib!. Toto si treba dobre uvedomiť, pretože je rozdiel, keď neuvediete nič alebo uvediete --without-mylib! Teraz si ukážeme jednoduchý príklad, pomocou ktorého môžete špecifikovať adresár, v ktorom sa nachádzajú MySQL knižnice a hlavičkové súbory.
AC_ARG_WITH(mysql,
[ --with-mysql=DIR use mysql installed in DIR],
[
if test -n $withval && test $withval != "no" && \
test $withval != "yes"; then
echo "Using MySQL installed in $withval"
elif test $withval = "no"; then
AC_MSG_ERROR([This program needs MySQL to work!])
else
echo "Using standard MySQL installation dir /usr/local/"
fi
], [
echo "Using standard MySQL installation dir /usr/local/"
])
Toto makro bude fungovať nasledovne: ak nepoužijeme parameter --with-mysql vôbec, vypíše sa informácia o použití štandardného adresára s nainštalovanou MySQL databázou (vykoná sa teda predposledný riadok v našom výpise). Ak použijeme iba parameter --with-mysql bez určenia adresára (teda nepripíšeme =...), vypíše sa rovnaká informácia, tentokrát je to však riadok za else (vyššie). Ak použijeme kompletný parameter (a teda premenná $withval neobsahuje ani no, ani yes, ani nie je prázdna - to všetko kontroluje ten dlhý riadok s if), vypíše sa informácia o použitom adresári. Ak by sme nechceli použiť MySQL vôbec (teda sme použili --without-mysql), configure nás na to upozorní chybovým hlásením a nepustí nás ďalej (použili sme nám už známe makro AC_MSG_ERROR, s ktorým sme sa zoznámili v minulej časti).
Naše makro síce funguje, ale nemá žiaden praktický význam, pretože zistený adresár s inštaláciou MySQL nijako neposunieme ďalej, len ho vypíšeme na terminál. Najlepšie by bolo, ak by sme zistené informácie vedeli predať tomu správnemu Makefile súboru. Potom by sme mohli upraviť premennú CFLAGS, ktorá obsahuje parametre prekladača. Takto by sme mu napríklad mohli dať vedieť, kde má hľadať hlavičkové súbory. Spôsobov je viacero, my si ukážeme jeden veľmi jednoduchý a pritom veľmi účinný - je ním makro AC_SUBST. Má iba jediný parameter - názov premennej. Pamätáte sa, keď sme sa kedysi dávno zaoberali makrom AC_OUTPUT? Parametrami tohto makra boli názvy Makefile súborov, ktoré sa mali vygenerovať v záverečnej fáze behu programu configure. Áno, práve toto makro spôsobilo výpis creating Makefile. A v tejto fáze prebieha (okrem iných) aj tento proces: máme premenné, ktoré sme si "označkovali" makrom AC_SUBST napríklad niekde v súbore configure.in (teda napríklad aj tam, kde sme zapísali naše vlastné makrá). V súboroch Makefile.am použijeme takéto značky - @premenna@. A v spomenutej záverečnej fáze sa všetky tieto značky nahradia aktuálnym obsahom $premennej. Aktuálnym preto, že obsah "označkovanej" premennej sa môže po "označkovaní" zmeniť, použije sa až jej posledná hodnota. Teraz si ukážeme vylepšené makro, tentoraz pre známu grafickú knižnicu QT:
AC_MSG_CHECKING([for Qt])
qt_default=$QTDIR
AC_ARG_WITH(qt,
[ --with-qt=DIR where the root of Qt is installed],
[
if test -n "$withval" && test "$withval' != "no" && \
test "$withval" != "yes"; then
qt_dir=$withval
elif test $withval = "no"; then
AC_MSG_ERROR([You must have Qt enabled!)
else
qt_dir=$qt_default
fi
], [
qt_dir=$qt_default
])
qt_lib=$qt_dir/lib
qt_inc=$qt_dir/include
AC_MSG_RESULT([libs: $qt_lib, headers: $qt_inc])
AC_SUBST(qt_lib)
AC_SUBST(qt_inc)
Zmysel celého kódu by vám mal byť zrejmý. Premenná $QTDIR je systémová a obsahuje inštalačný adresár knižnice Qt. Ak na svojom počítači túto knižnicu nemáte, pokojne si ju môžete nahradiť napríklad za /usr/local/qt, na funkčnosti príkladu to vôbec nič nezmení. Teraz si konečne môžeme zaeditovať niektorý z našich Makefile.am súborov. Napríklad ak máme v hlavnom adresári projektu podadresár so zdrojovými súbormi src, otvorme src/Makefile.am. Môže vyerať napríklad takto:
## Process this file with automake to produce Makefile.in
bin_PROGRAMS =foo
foo_SOURCES = main.cpp foo1.cpp foo2.cpp
foo_LDADD = -lqt
foo_LDFLAGS = -L@qt_lib@
INCLUDES = -I@qt_inc@
Všimnite si hlavne posledné dva riadky. Potom spustite automake a poprezerajte si vytvorený súbor Makefile.in. Nájdete tam takisto @qt_lib@ a @qt_inc@. Po spustení ./configure si pozrite to isté miesto v súbore Makefile - a tieto texty tam už nenájdete, nahradia sa konkrétnymi hodnotami.
Teraz si naše makro ešte trošku vylepšíme: pridáme si "autodetekciu" adresára s nainštalovanou knižnicou a overenie, či zadaný adresár naozaj obsahuje potrebné knižnice. To prvé by sme mohli vyriešiť napríklad takto: v minulej časti sme si ukázali makro,ktoré vyhľadáva v daných adresároch istý súbor a názov prvého adresára, ktorý ho obsahuje, uloží do premennej. Tu ho máme:
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
])
Opísali sme si ho už v minulej časti, a tak sa s ním teraz nemusíme zdržiavať. Toto makro nám však samo o sebe nepostačí. Nadefinujeme si druhé makro, ktoré potom v súbore ./configure.in môžeme jednoducho použiť (samozrejme, všetko môžeme písať do jedného súboru, ale pri takýchto a rozsiahlejších makrách si pomôžeme ináč - tieto dve makrá napíšeme do súboru acinclude.m4). Úlohou druhého makra bude:
- pridať --with parametre;
- skontrolovať obsah premenných - ak nie sú prázdne, overiť, či sa v daných adresároch naozaj nachádzajú správne súbory;
- ak sú premenné prázdne, alebo neukazujú na správne adresáre, vyskúšať štandardné inštalačné adresáre, do ktorých sa knižnice zvyknú inštalovať (môže ich byť aj viac)
- zadefinovať premenné pre použitie v Makefile.am súboroch.
Teraz si postupne rozoberieme všetky body. Po prvé, musíme si uvedomiť, ktoré parametre chceme vlastne pridať. V našom prípade máme tri možnosti. Buď to bude iba jedna voľba - zadať adresár s nainštalovanou knižnicou Qt, a adresáre s hlavičkovými súbormi a knižnicami sa automaticky vytvorí pridaním /include, resp. /lib. Druhou možnosťou je pridať dve voľby - prvá pre knižnicu, druhá pre hlavičkové súbory. Tretia možnosť vznikne spojením dvoch predošlých - pridáme tri parametre. Prvým môžeme určiť spoločný základ oboch podadresárov. Druhými dvoma parametrami ho môžeme prepísať. Je to najzložitejšia možnosť, ale pre užívateľa asi najpríjemnejšia. Pri troche znalostí shell skriptovania by vám však nemalo robiť problémy implementovať hocktorú z týchto troch možností. My sa rozhodneme pre poslednú možnosť.
V druhom bode si pomôžeme makrom FIND_FILE, ktoré sme si definovali vyššie.
Tretí bod je podobný, avšak namiesto adresárov, ktoré nám oznámil užívateľ prostredníctvom príkazového riadku, použijeme zoznam typických adresárov, v ktorých by sa knižnica a hlavičkové súbory mohli nachádzať.
Štvrtý bod je najjednoduchší, podobný tomu v predchádzajúcom príklade.
Teraz sa môžeme pustiť do tvorby nášho makra. Nazvime si ho napríklad QT. Rovnako, ako aj makro FIND_FILE, uložíme ho do súboru acinclude.m4. Začínať sa môže napríklad takto:
AC_DEFUN(QT, [
AC_MSG_CHECKING([for Qt])
AC_ARG_WITH(qt,
[ --with-qt=DIR where the root of Qt is installed],
[
ac_qt_lib=$withval/lib
ac_qt_inc=$withval/include
])
AC_ARG_WITH(qt-lib,
[ --with-qt-lib=DIR where the Qt libraries are installed],
[
ac_qt_lib=$withval
])
AC_ARG_WITH(qt-includes,
[ --with-qt-includes=DIR where the Qt headers are installed],
[
ac_qt_inc=$withval
])
])
Pridali sme si tri parametre --with- a informovali sme užívateľa, že configure sa práve zaoberá zisťovaním prítomnosti knižnice Qt. Cestu ku knižnici ukladáme do premennej $ac_qt_lib, cestu k hlavičkovým súborom máme zase v premennej $ac_qt_inc. Toto sú len pomocné premenné, v súboroch Makefile.am ich nebudeme používať. Teraz si overíme, či tieto premenné vôbec niečo obsahujú, a ak áno, tak či ukazujú na správne adresáre. Pred posledný riadok doplníme tieto riadky:
if test -n $ac_qt_lib && test -e $ac_qt_lib/libqt.so; then
qt_lib=ac_qt_lib
else
FIND_FILE(libqt.so,
[$QTDIR/lib /usr/local/qt/lib /usr/lib /usr/local/lib],
qt_lib)
fi
if test -z $qt_lib; then
AC_MSG_RESULT(no)
AC_MSG_ERROR([The Qt libraries were not found!])
fi
Najprv overíme obsah premennej $ac_qt_lib. Ak je jej obsah správny, priradíme ho do premennej qt_lib. Inak sa pokúsime správny adresár "uhádnuť" - druhý parameter makra FIND_FILE je zoznam adresárov, ktoré potenciálne môžu obsahovať súbor libqt.so, teda knižnicu Qt. Ak niektorý z daných adresárov tento súbor skutočne obsahuje, jeho meno priradí do premennej qt_lib. Ak je táto premenná aj po tomto kroku prázdna, znamená to, že sa nám knižnicu nepodarilo nájsť.Preto to oznámime nasledujúcimi riadkami užívateľovi. Podobne to urobíme aj s hlavičkovými súbormi:
if test -n $ac_qt_inc && test -e $ac_qt_inc/qt.h; then
qt_inc=ac_qt_inc
else
FIND_FILE(qt.h,
[$QTDIR/include /usr/local/qt/include /usr/include /usr/local/include],
qt_inc)
fi
if test -z $qt_inc; then
AC_MSG_RESULT(no)
AC_MSG_ERROR([The Qt headers were not found!])
fi
Ak všetko prebehne bezchybne - či už užívateľ zadal správne adresáre, alebo sme ich "uhádli" my - mali by sme to užívateľovi oznámiť. My ho navyše informujeme o tom, ktoré adresáre sme použili. Nakoniec ešte použijeme nám už známe makro AC_SUBST:
AC_MSG_RESULT([libs: $qt_lib, headers: $qt_inc])
AC_SUBST(qt_lib)
AC_SUBST(qt_inc)
Teraz už môžeme spustíť bootstrap alebo:
aclocal && autoheader && automake && autoconf
Potom nasleduje ./configure, buď s parametrami alebo bez (v závislosti od toho, či sme náš adresár s Qt zahrnuli medzi štandardné adresáre). No a nakoniec vytúžený príkaz make, ktorý zabezpečí kompiláciu.
Oto Komiňák
Článok bol uverejnený v magazíne PC Revue 02/2003.
