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.
15. časť: Definovanie C/C++ makier
V tejto poslednej časti si ukážeme ďalší dôležitý prvok, ktorý sa vám určite zíde - automatické definovanie pomocou céčkovského makra preprocesora - #define.
AC_DEFINE
Toto je jedno z veľmi dôležitých makier, ktoré môžete používať v súbore configure.in (alebo inom, ktorý obsahuje M4 makrá). Najprv si ukážeme použitie v praxi. Predstavte si dosť bežnú situáciu - váš program/knižnica používa nejakú funkciu s určitej knižnice. Časy sa však menia a knižnica, ktorú používate, sa vyvíja. No a naraz príde okamih, keď sa zmenia nielen "vnútornosti" funkcie, ktorú potrebujete, ale napríklad aj parametre, s ktorými ju môžete volať. Vy ako vývojár môžete jednoducho prejsť na novú knižnicu, ale ako prinútiť užívateľov, aby spravili to isté? Ak máte štastie, a zmeny v novom interface neboli príliš zásadné, dokážete tento zmenený interface nejako nahradiť - napríklad zavoláte zmenenú funkciu s ďalšími potrebnými parametrami, prípadne pred volaním funkcie jej pripravíte vhodné podmienky. Takáto situácia nemusí nastať iba v prípade jednej vyvíjajúcej sa knižnice, niečo podobné sa stáva pri portovaní programov v rámci unixových operačných systémov: niektoré funkcie sa nazývajú odlišne, prípadne majú iný počet parametrov či návratovú hodnotu iného typu. Ďalší možný prípad je, že máte k dispozícii na výber viac knižníc s rovnakou alebo podobnou funkciou, a vy si musíte jednu vybrať. Možností uplatnenia je teda neúrekom.
Teraz si podrobnejšie rozoberieme, ako makro sa AC_DEFINE používa. Predpokladajme, že s pomocou dosiaľ nadobudnutých vedomostí ste schopní zistiť, aké knižnice sú na cieľovom systéme prítomné, vrátane verzie. Teraz ide o to, ako môžete tieto informácie sprostredkovať zdrojovým súborom. Asi už tušíte, že to bude prostredníctvom direktívy #define. Nemá veľký zmysel teoretizovať nad možnými spôsobmi, ukážeme si, ako použiť naše nové makro na príklade.
Hello, ver. 2.7182
Nasleduje zoznam všetkých súborov, ktoré budeme musieť napísať sami. Niektoré sú podobné súborom z niektorých predchádzajúcich častí, niektoré budete musieť upraviť alebo vytvoriť.
bootstrap
configure.in
main.c
Makefile.am
hello.c
hello.h
Ako vidíte, nie je toho až tak veľa. Najprv si ukážeme najjednoduchší súbor, boostrap:
aclocal && \
autoheader && \
automake --foreign --add-missing --copy && \
autoconf
Veľmi dôležitý je druhý riadok, potrebný vždy, keď chceme používať automaticky vygenerovaný hlavičkový súbor config.h. Načo ho potrebujeme? To uvidíte neskôr, keď sa dostaneme k hlavnému zdrojovému súboru main.c. Súbor configure.in zatiaľ preskočíme a ukážeme si zdrojové súbory.
hello.c:
#include "hello.h"
void hello(char* name)
{
printf("hello, %s!\n", name);
}
hello.h:
#include <stdio.h>
void hello(char* name);
Tieto súbory budú predstavovať akúsi knižnicu (nazvime ju libhello). Môžete z nej vytvoriť libhello.so - shared library (zdieľaná knižnica), to by ste už takisto mali zvládnuť. Umiestnite ju napríklad do /usr/lib, a súbor hello.h do /usr/include. Tieto súbory teda nepatria do nášho projektu.
Teraz nasleduje posledný zdrojový súbor - main.c. Prepokladajme, že HELLO je definované, pokiaľ máme k dipozícii našu novú knižnicu libhello.so a hello.h, teda aj funkciu hello() a. HAVE_CONFIG_H je nadefinované vždy, ak je vygenerovaný súbor config.h.
main.c:
#include <stdio.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HELLO
#include <hello.h>
#else
void hi(void)
{
printf("hi!\n");
}
#endif /* HELLO */
int main(int argc, char* argv[])
{
#ifdef HELLO
if (argc < 2) {
printf(PACKAGE " " VERSION "\n");
printf("Usage: %s \"text\"\n", argv[0]);
return 1;
}
hello(argv[1]);
#else
hi();
#endif
return 0;
}
Ak máme "poruke" našu knižnicu, použijeme ju. Inak si urobíme vlastnú jednoduchšiu funkciu, ktorá nás pekne pozdraví. Zatiaľ je to jednoduché, ale ako definovať HELLO?
Skôr, ako sa k tomu dostaneme, ukážme si ešte Makefile.am, ten je takisto jednoduchý:
bin_PROGRAMS=hello
hello_SOURCES=main.c
AUTOMAKE_OPTIONS=foreign
EXTRA_DIST=bootstrap
Teraz sa konečne dostávame k poslednému súboru - configure.in, ktorý by mal všetko vysvetliť najlepšie. Najprv základ, ktorý nie je ničím zvláštny:
AC_INIT(main.c)
AM_INIT_AUTOMAKE(hello, 3.14)
AM_CONFIG_HEADER(config.h)
AC_PROG_CC
AC_OUTPUT(Makefile)
Teraz potrebujeme spomínané definovanie HELLO, ale iba vtedy, ak existujú potrebné súbory:
if [ test -f /usr/lib/libhello.so ] && [ test -f /usr/include/hello.h]; then
AC_DEFINE(HELLO, 1, [Have libhello])
fi
Tento kúsok kódu vložíme za AC_PROG_CC. Samozrejme, je to len veľmi jednoduchý test, ale na náš učel postačuje. Nič vám nebráni zdokonaliť ho, dokonca by som vám to odporúčal - v reálnom projekte minimálne otestovať ešte /usr/local/, prípadne urobiť aj test kompilácie, teda vytvoríte jednoduchý súbor, ktorý obsahuje napríklad iba jedno volanie niektorej funkcie z potrebnej knižnice a potom sa ho pokúste skompilovať s parametrami, aké ste práve zistili. To môže konfiguráciu dosť zbrzdiť, preto to používajte opatrne a rozumne.
Z predchádzajúceho príkladu ste asi zistili parametre, ktoré môžete makru AC_DEFINE dať. Syntax je:
AC_DEFINE(premenná, hodnota, popis)
Popis sa objaví v súboroch config.h.in a config.h. Skúste si oba tieto súbory prezrieť. Ak by ste potrebovali popis dlhší, ako jedno slovo, uzavrite ho ako v našom príklade do hranatých zátvoriek.
Často sa môže stať, že vám nestačí iba možnosť niečo definovať alebo nedefinovať, niekedy môže byť dôležitá práve hodnota definície, ktorá sa môže meniť v závislosti od niektorých okolností, ktoré zistí configure počas svojho behu. Ak by ste chceli použiť niečo také:
$foo_var=moo
AC_DEFINE(FOO, $foo_var, [Foo...])
po otvorení config.h by ste uvideli takýto riadok:
#define FOO $foo_var
a nie
#define FOO "moo"
ako by ste očakávali. Ak chcete dosiahnuť iné správanie sa configure, musíte použiť namiesto makra AC_DEFINE makro AC_DEFINE_UNQUOTED, ktoré sa bude správať presne podľa očakávania.
Záver
A je tu koniec nášho seriálu. Za niečo vyše roka, čo sme sa spolu stretávali, ste mali možnosť nadobudnúť vedomosti, ktoré vám môžu uľahčiť život unixového programátora a takisto pomôžu sprostredkovať vaše diela čo najväčšiemu možnému počtu užívateľov na najrôznejších konfiguráciách počítačov.
Ak by vám poskutnuté informácie nepostačovali a chceli by ste získať ďalšie informácie z tejto oblasti, môžem vás odkázať na viacero zdrojov. V prvom rade je to dokumentácia k jednotlivým programom, hlavne info automake, info autoconf a info make. Existuje viacero zdrojov, ktoré mi kedysi pomohli - skúste na internete pohľadať tutoriály na danú tému. No a na záver rozsiahlejšia kniha v elektronickej podobe - David MacKenzie: Autoconf, Automake and Libtool, ktorá mi takisto veľmi pomohla aj pri tvorbe tohto seriálu.
Na záver by som sa chcel poďakovať všektým čitateľom za ich poznámky i trpezlivosť, rovnako aj redakcii PC Revue za poskytnutý priestor.
Oto Komiňák
Článok bol uverejnený v magazíne PC Revue 04/2003.
