Hlavní navigace

GNU - pomoc při tvorbě programů: Autoconf

26. 2. 2001
Doba čtení: 12 minut

Sdílet

V tomto pokračování se dozvíte něco o prvním z programů, o kterých byla řeč minule, tedy o Autoconfu. Jak již bylo řečeno, usnadňuje přenos projektu mezi různými softwarovými i hardwarovými konfiguracemi. Ovšem každá sranda něco stojí. Co, a jestli se to vyplatí, se můžete podívat právě teď.

Úplně na úvod bych rád alespoň se zpožděním reagoval na diskuzi k předcházejícímu článku. Byl jsem po jeho vydání lehce off-line, tak alespoň takto dodatečně. Tedy velmi stručně:

  • Gettext – dle mého názoru je „standardní“ cesta. Minimálně pro GNU/Linux a případně ostatní Unixy. Na druhou stranu mohu potvrdit, že přenositelnost není úplně dotažená do konce a problémy s detekcí v libc, použitím v non-unix systémech a překódování znakových sad jsou skutečné.
  • GNU GPL/LGPL – opět můj soukromý názor je, že tyto licence přinesly něco, co dlouho chybělo. Nejen svým obsahem, ale i (a možná hlavně) hnutím kolem GNU. Řekl bych, že lidem kolem GNU, a taky samozřejmě linuxového jádra, vděčíme za stav jaký je dnes. To znamená, že se o komunitě opensource/freesoft mluví a ví. Pro různé účely a/nebo skupiny nemusí být tyto licence a myšlenky, na kterých jsou postavené vhodné a/nebo přijatelné. To je důvod, proč se také s licencemi poslední dobou roztrhl pytel (viz. např. Mozilla). Jsme ve svobodném světe a můžete si vybrat, jakou licenci chcete. BSD licence jsou opravdu volnější a asi i (z jistého pohledu) více free, ale není to prostě jediná varianta. Myslím, že diskuzí na tohle téma je všude plno, takže stačí.
  • BSD systémy – Nemohu si pomoci, ale pokaždé, když se setkám s někým, kdo mluví o BSD, je to tímto tónem a způsobem. Nepochybuji o tom, že jde o systémy kvalitní, ale proč to každý takový člověk vidí tak jednostranně? Na jedné straně bezchybná zbožňovaná xxxBSD a na druhé hnusný nefunkční zkažený Linux. Zdá se mi, že existují snad pouze dvě vysvětlení:
    • Buď je to pravda a BSD je/jsou opravdu o tolik lepší než Linux a potom nechápu, proč to dotyční nejsou schopni dát najevo s jiným tónem a posoudit to více objektivně, případně poradit co udělat lépe.
    • Nebo to pravda není, a potom si nemůžu pomoct, ale připadá mi to jako slepá závist nebo truchlení nad něčím, co je dávno pryč.

Pokud by chtěl někdo pokračovat v některé z těchto flamewar-like diskuzí, obraťte se prosím přímo na mne (tomas.kasparek@seznam.cz). Myslím, že to většina čtenářů ROOTa ocení.

Omlouvám se za malé zdržení, ale nedalo mi to nereagovat. Tak teď již k věci. Jen ještě malá poznámka: Pro další text je použit Autoconf 2.13 z distribuce RedHat.

Ve své podstatě je to jednoduché. Autoconf je nástroj, který vytvoří skript (pro shell), který se potom při kompilaci použije k vygenerování souboru(ů) Makefile, přesněji k nastavení některých voleb a hodnot v nich. Důležitou vlastností je, že generovaný skript pro svůj běh nepotřebuje žádné podpůrné prostředky (shell má snad každý, ne?) a tedy ani Autoconf jako takový.
V následujícím textu budu používat označení programátor pro toho, kdo vytváří projekt a hlavně podklady pro Autoconf a uživatel pro člověka, který potřebuje projekt pouze přeložit a zprovoznit.

Uživatel

Cíl celého našeho snažení. Vytvořit jednoduchou a pokud možno standardní cestu, jak provádět překlad a instalaci našeho projektu. Dnes je již poměrně častá posloupnost configure → make → make install. Co se pod ní skrývá? Pro nás je teď zajímavá především první část (configure). Ta je produktem Autoconfu a generuje Makefile. Většinou stačí zadat příkaz bez voleb a provede se předvolené nastavení nebo automatická detekce. Chování a vlastnosti výsledku překladu je možno ovlivňovat dvojím způsobem.

  • Proměnné prostředí

    Uvažují se proměnné prostředí jako CC, CPP, CFLAGS, CPPFLAGS, CXXFLAGS, LDFLAGS, MAKE a další. Pokud jsou nastaveny, použijí se jejich hodnoty jako výchozí. Mohou být potom doplněny nebo samozřejmě také ignorovány, pokud to výslovně uvedeme.
  • Parametry skriptu configure

    Tato varianta modifikace chování skriptu je, řekl bych, častější. Lze zadat jednak standardní parametry, a potom ty, které jsme sami doplnili. Z těch nejpoužívanějších a nejdůležitějších:
Tabulka č. 99
 –help vypíše způsob použití, všechny možné volby a jejich implicitní hodnoty
 –quiet, –silent nevypisuje hlášky o jednotlivých testech
 –version verze Autoconfu, která vytvořila tento skript configure
 –prefix=DIR adresář, pod nějž se budou instalovat části programu [/usr/local]
 –??dir=DIR umožňuje instalovat části programu do konkrétních adresářů. Příkladem je –bindir, –datadir, –libdir a další.
 –host=HOST určuje cílový počítač, normálně se detekuje automaticky ale někdy je třeba zadat ručně. Příkladem budiž „i686-pc-linux-gnu“.
 –x-includes=DIR explicitní zadání umístění hlavičkových souborů pro X Window
 –x-libraries=DIR explicitní určení umístění knihoven X Windows
 –with-gtk-prefix=DIR explicitní určení umístění knihoven Gtk+
 –disable-gtktext neprovádí test správnosti instalace Gtk – překlad jednoduchého programu
 –disable-nls zakáže použití NLS – Native Language support
 –with-included-gettext použije knihovnu gettext obsaženou v projektu

Volby se samozřejmě mohou nepatrně lišit. Pokud nepoužíváte Gettext neobjeví se poslední dvě možnosti. Podobné je to s Gtk+. Jindy mohou být v závislosti na obsahu configure přítomny další volby. Ve výpisu pro –help je obsažen krátký komentář ke každé volbě, takže si lze udělat docela jasnou představu, jaký má vliv na překládaný projekt.

To je z uživatelova pohledu vše. Prostě jen spustit configure a poté, co si člověk případně doplní chybějící knihovny a vše ostatní, co balík vyžaduje, je možno přistoupit k vlastnímu překladu. Takto to vypadá, pokud vše funguje tak, jak má. Pokud tomu tak není, je možné nastavit některé věci explicitně pomocí parametrů (nebo proměnných prostředí). Pokud ani to nepomůže, nezbývá než přesně zjistit co je špatně. Nyní se projeví velká výhoda toho, že celý systém je sada shellovských skriptů. Jejich modifikací a využitím možností pro ladění skriptů se totiž téměř vždy dá problém přesně odhalit, lokalizovat a následně řešit.

Programátor

Autor projektu to má přece jen těžší. Jeho úkolem je vytvořit skript configure a také říci jak mají vypadat soubory Makefile. Obě akce se provedou napsáním šablon, ze kterých potom Autoconf generuje výsledky. Šablony mají příponu „.in“. Konkrétně to vypadá následovně:

Autoconf(confi­gure.in) → configure
configure(xxx.in) → xxx + pomocné skripty a soubory

Jak je vidět, nemusí se generovat vždy jen a pouze Makefile. Lze vytvářet libovolné soubory, které se použijí jako šablona. Začněme ale od začátku. Vše, co Autoconf (resp. configure) dělá je, že nahrazuje určité texty za jiné. Jednoduchý soubor configure.in tedy může být:

1  dnl Process this file with autoconf to produce a configure script.
2  AC_INIT(configure.in)

3  dnl *** check for programs ***************************************
4  # check for c compiler
5  AC_PROG_CC

6  dnl *** check for libraries **************************************
7  # search for Gtk+
8  AM_PATH_GTK(1.2.0, , AC_MSG_ERROR(Cannot find GTK: Is
gtk-config in path?))

9  dnl *** compiler characteristic **********************************
10 # Use -Wall
11 CFLAGS="$CFLAGS -Wall"

12 dnl *** package settings *****************************************
13 # Set PACKAGE_LOCALE_DIR in config.h.
14 if test "x${prefix}" = "xNONE"; then
15   AC_DEFINE_UNQUOTED(PACKAGE_LOCALE_DIR,
"${ac_default_prefix}/${DATADIRNAME}/locale")
16 else
17   AC_DEFINE_UNQUOTED(PACKAGE_LOCALE_DIR, "${prefix}/$
{DATADIRNAME}/locale")
18 fi

19 dnl *** Autoconf output - Makefiles  *****************************
20 AC_OUTPUT([
21 Makefile
22 src/Makefile
23 ])

Číslování řádků do souboru samozřejmě nepatří. Asi to není příklad, který byste viděli v praxi, ale pro naše účely stačí. V našem případě jsou použity pouze standardní testy. Mimo to lze samozřejmě vytvářet testy vlastní a vůbec celý systém doplňovat a přizpůsobovat. Začneme od začátku.

1. Je vhodné umístit na první řádek (mezi první řádky) tento komentář pro nezasvěcené. Je zde rovněž vidět, jak se píše komentář. Jsou dvě možnosti. ‚dnl‘ a text do konce řádku je komentář, který vyeliminuje autoconf a neobjeví se v configure. Dále generovaný configure je skript pro shell a je tudíž možno použít komentář ‚#‘ (viz ř.4).

2. Před jakoukoliv další činností je třeba zavolat inicializační rutiny autoconfu. Ty zahrnují především zpracování parametrů na příkazové řádce a nastavení některých základních proměnných. Jako parametr se zadává jedinečné jméno v hlavním adresáři s projektem. Dle něj se provede test a nastaví proměnná pro vrchol adresářové struktury projektu $top_srcdir.

5. Asi nejpoužívanější test – překladač jazyka C. Ten nastaví (pokud není) proměnnou $CC. Dále pro gcc nastaví proměnnou GCC=„yes“. Pokud není nastaví také $CFLAGS většinou na „-O2 -g“. Obdobně lze testovat další běžné programy jako c++, lex, yacc, cpp, f77, install, ln. Vždy se také nastaví příslušné proměnné.

8. Zde je malý háček. Prozatím všechny testy začínaly předponou AC_. Jde o makra (testy) nebo proměnné Autoconfu. Spolu s ním se často používá další systém Automake, který jak vidno doplňuje kromě jiného také další testy. Ty fungují obdobně jako testy Autoconfu. Tento test zkontroluje přítomnost knihoven Gtk+ včetně požadavku na minimální verzi. Pokud neuspěje, skript configure skončí a vypíše chybovou hlášku. Ověřování detekovaných vlastností lze v tomto případě vypnout volbou –disable-gtktext. Generují se proměnné $GTK_CFLAGS a $GTK_LIBS. Pro detekci využívá gtk-config. O systému Automake však až někdy příště.

11. Můžeme také měnit obsah libovolných proměnných. Zde se přidává přepínač pro $CFLAGS. Zápisem CFLAGS=„-Wall“ bychom obsah proměnné nahradili. Případné zrušení vlivu některé proměnné je tedy možné buď nastavením na prázdný řetězec nebo pomocí unset.

14. Zde je vidět, jak používat hodnot získaných během testu prostředí. Kontrolujeme, zda uživatel použil volbu měnící prefix a podle situace generujeme symbol pro preprocesor C.

15. Makro definuje symbol stejně jako zápis #define PACKAGE_LOCALE_DIR hodnota. Kromě toho existuje ještě AC_DEFINE. Provádí to samé až na „hodnota“ místo hodnota.

20. Makro AC_OUTPUT zajistí vlastní generování daných souborů. Druhá forma zápisu je OUTPUT(Makefile, src/Makefile), ale tohle je asi přehlednější.

Jestliže v adresáři se souborem configure.in spustíme autoconf, provede vygenerování skriptu configure. Po spuštění configure by se v našem případě provedla transformace Makefile.in → Makefile a src/Makefile.in → src/Makefile.

Zbývá nám tedy vytvořit soubory Makefile.in. Opět jako ukázku uveďme část souboru z našeho pomyslného projektu:

.....
# check for c compiler
CC = @CC@
....
# search for Gtk+
GTK_CFLAGS = @GTK_CFLAGS@
GTK_CONFIG = @GTK_CONFIG@
GTK_LIBS = @GTK_LIBS@
.....

A tady je vidět možný výsledek. Fragment souboru Makefile pro konkrétní podmínky:

.....
# check for c compiler
CC = gcc
....
# search for Gtk+
GTK_CFLAGS = -I/usr/lib/glib/include -I/usr/X11R6/include
GTK_CONFIG = /usr/bin/gtk-config
GTK_LIBS = -L/usr/lib -L/usr/X11R6/lib -lgtk -lgdk -rdynamic -lgmodule -lglib -ldl -lXext -lX11 -lm
.....

Asi by jste neřekli, že je to Makefile, uznávám, že je to hodně „krouhlý“, ale je doufám jednoznačně vidět, co se stalo. Všechny výskyty @NECO@ jsou nahrazeny skutečnými hodnotami získanými při detekci v úvodní fázi. Hezké, že? Dané proměnné se potom použijí v akcích pro řešení závislostí a je to.

Takže si to shrňme. Vytváříme navíc soubor configure.in, kde definujeme, jaké testy se mají dělat a případné reakce na ně. Je zde také řečeno, na které soubory se aplikuje pozdější transformace. Místo souborů Makefile vytváříme Makefile.in, které se liší pouze v tom, že neobsahují konkrétní údaje (hodnoty proměnných), ale odkazy ve stylu autoconfu. Při spuštění skriptu configure se provede vygenerování požadovaných souborů z jejich šablon a doplnění konkrétních údajů. A to je opravdu všechno.

Existující testy

root_podpora

Programy
Existují testy na konkrétní programy. Sem patří AC_PROG_AWK, AC_PROG_CC, AC_PROG_CPP, AC_PROG_CXX, AC_PROG_CXXCPP, AC_PROG_F77, AC_PROG_INSTALL, AC_PROG_LEX, AC_PROG_YACC. Kontrolují (po řadě) přítomnost programů awk, překladače C, preprocesoru C, překladače C++, preprocesoru C++, překladače Fortranu 77, program install, lex, yacc. Nastavují odpovídající proměnné pro odkaz na daný program a případně další proměnné pro bližší charakteristiku.

Dále jsou tu obecné testy pro libovolné programy: AC_CHECK_FILE, AC_CHECK_PROG, AC_PATH_PROG. Hledají obecný soubor (program) a nastavují (xxx_PROG) proměnnou dle výsledku testu. Verze _PATH_ vloží do proměnné celou cestu k souboru/programu.
Knihovny
Zde jsou hlavní funkce AC_CHECK_LIB pro zjištění přítomnosti funkce v dané knihovně a makro AC_HAVE_LIBRARY pro zjištění pouze přítomnosti knihovny.
Funkce
Opět jsou zde testy na konkrétní funkce včetně: AC_FUNC_ALLOCA, AC_FUNC_GETLOADAVG, AC_FUNC_MEMCMP, AC_FUNC_MMAP, AC_FUNC_WAIT3, AC_FUNC_VFORK. Všechny testují přítomnost a korektní chování příslušných funkcí a definují HAVE_xxx pro podmíněný překlad. Také zde jsou obecné testy a to hlavně AC_CHECK_FUNC[S], které testují přítomnost dané funkce a definují příslušný symbol.
Hlavičkové soubory
Testy AC_HEADER_DIRENT pro dirent.h, AC_HEADER_STDC pro ANSI C hlav. soubory (stdlib.h, stdarg.h, string.h, float.h). AC_HEADER_SYS_WAIT pro sys/wait.h. Převážně se ale používají obecné testy a to AC_CHECK_HEADER[S].
Datové typy
Z hotových testů zmíním jen AC_TYPE_SIZE_T pro kontrolu přítomnosti typu ‚size_t‘. Pokud chybí, je definován jako ‚unsigned‘. Obecným testem je AC_CHECK_TYPE. Ten umožňuje testovat daný typ a pokud není definován (v stddef.h, sys/types.h, stdlib.h) definuje se jako dodaný primitivní typ jazyka.
Vlastnosti překladače
Tady jen letem světem: AC_C_BIGENDIAN, AC_C_CONST, AC_C_INLINE, AC_C_CHAR_UNSIGNED, AC_C_LONG_DOUBLE, AC_CHECK_SIZEOF.
Vlastnosti systému
Typické přípony programů resp. objektových souborů definuje AC_EXEEXT resp. AC_OBJEXT. AC_CYGWIN testuje přítomnost prostředí Cygwin. AC_PATH_X zjistí umístění X Window systému. AC_SYS_LONG_FI­LE_NAMES pro test podpory dlouhých názvů jmen souborů. AC_ISC_POSIX testuje, zda prostředí vyhovuje normě POSIX.
Další užitečná makra
  • AC_SUBST(PROM) – zpřístupní nově definovanou proměnnou. Pokud použijete vlastní proměnnou v configure a chcete ji použít i v Makefile.in, je třeba ji zveřejnit, aby ji autoconf vzal na vědomí.
  • AC_CONFIG_SUB­DIRS(DIR …) – pro rozsáhlý projekt, který má více skriptů configure. Určuje, ve kterých podadresářích se mají spustit další vnitřní configure skripty.
  • AC_TRY_LINK, AC_TRY_COMPILE, AC_TRY_RUN – pokud potřebujete vyzkoušet něco složitějšího, tahle makra se vám budou hodit. Prostě napíšete kus kódu a necháte ho zkompilovat, slinkovat nebo i spustit.
  • Již jsem se zmínil, že skriptu ‚configure‘ můžete zadat vlastní parametry. Provede se to pomocí dvou maker: AC_ARG_WITH, AC_ARG_ENABLE. Zadáte název, popis a příslušné akce pro ANO a NE. Podle nich se pak můžete rozhodovat dál.
  • Pokud chcete během provádění testů uživateli něco sdělit, tak od toho jsou tu makra AC_MSG_CHECKING, AC_MSG_RESULT, AC_MSG_ERROR, AC_MSG_WARN. Těm jednoduše předáte vlastní text a ony jej vytisknou v požadovaném formátování.

Na závěr ještě přece jen alespoň malou informaci o hlavičkovém souboru config.h, o kterém jsem se zmínil minule. Pomocí autoheader nebo ručně vytvoříme šablonu config.h.in. Ta má tvar:

/* Define if you have the <sys/utsname.h> header file.  */
#undef HAVE_SYS_UTSNAME_H
/* Define if you have the <unistd.h> header file.  */
#undef HAVE_UNISTD_H
/* Define if you have the i library (-li).  */
#undef HAVE_LIBI

Název souboru (config.h) potom v configure.in použijeme v makru AC_CONFIG_HEA­DER(config.h). Dále v testech se objeví například AC_CHECK_HEADER­S(unistd.h). Pokud je hlavičkový soubor detekován, změní se ve výsledném config.h příslušný řádek na #define HAVE_UNISTD_H 1. Hlavičkový soubor config.h vložíme pomocí #include do našich zdrojáků a je to. Dalšími testy autoconfu jsou ještě AC_CHECK_FUNCS, AC_CHECK_LIB, AC_CHECK_SIZEOF.

Byl pro vás článek přínosný?