GNU Build System

V této kapitole vám představím všechny důležité části GNU Build System (autotools). Programy, skritpy a konfigurační soubory, které se spolupodílejí na vytvoření skriptu configure, hlavičkového souboru config.h a Makefile souborů. Toto je stěžejní kapitola celého seriálu o autotools.

O GNU Build Systému

Autotools je sada programů, která nějaké soubory čte a nějaké vytváří. V této části vám popíši, jaké programy jsou součástí autotools a s jakými konfiguračními soubory pracuje.

Soubor configure.ac, program autoconf, skripty configure a config.status a soubor config.log

Tím nejdůležitějším vstupním souborem je configure.ac (dříve pojmenovaný configure.in. Do tohoto souboru se zapisují makra jazyka m4. Program m4 je preprocessor, podobně jako CPP. Tj. nahrazuje nějaké kusy textu za jiné kusy textu. Oproti CPP je o něco složitejší, tj. umí toho mnohem více. Například v něm můžete napsat něco jako funkci, používat switche, atd. Kapitola o m4 se věnuje základům tohoto jazyka.

Nejjednodušší configure.ac může vypadat takto:

# 02GNUBuildSystem/example1/configure.ac
AC_INIT([psani-profi], [3.5.00], [sallyx@example.org],
        [], [http://www.sallyx.org/sally/psani-vsemi-deseti/])

AC_OUTPUT

Toto jsou jediná dvě povinná makra v configure.ac. První makro, AC_INIT, má 5 argumentů (z toho jen první dva jsou povinné). Hranaté závorky se používají jako uvozovky textu/kusu kódu. m4 totiž umožňuje uvozovky vnořovat, proto musí být počáteční „uvozovka“ jiná, než ukončovací. (Nepleťte si to tedy s definicí pole z jazyka C.)
Druhé makro, AC_OUTPUT, se postará o zapsaní všech předchozích maker do skriptu configure. Cokoliv zapíšete za makro AC_OUTPUT bude ignorováno.

Mezi názvem makra a závorkou ( nesmí být mezera!

Nejvíce práce při učení se autotools spočívá v poznávání podobných maker. Budete se učit, jaká makra existují, k čemu jsou, jaké požadují argumenty atp. Není nic složitého. Všechna jsou dobře zadokumentována. Ale je jich takové množství, že se v tom začátečník snadno utopí. Proto čtěte dále, vybral jsem pro vás ty nejdůležitější :-).

Program autoconf přečte soubor configure.ac (z aktuálního adresáře) a vytvoří skript configure. Kromě toho se ještě vytvoří adresář autom4te.cache, kam si automake ukládá výsledky nějakých svých operací pro rychlejší znovuspuštění. (Tento adresář můžete klidně kdykoliv smazat.)

Můžete si to zkusit s předchozím configure.ac:

$ cat configure.ac
AC_INIT([psani-profi], [3.5.00], [sallyx@example.org],
	[], [http://www.sallyx.org/sally/psani-vsemi-deseti/])

AC_OUTPUT
$ autoconf
$ ./configure -h
`configure' configures psani-profi 3.5.00 to adapt to many kinds of systems.

Usage: ./configure [OPTION]... [VAR=VALUE]...
...
Report bugs to <sallyx@example.org>.
psani-profi home page: <http://www.sallyx.org/sally/psani-vsemi-deseti/>.
$ ./configure
configure: loading site script /usr/share/site/x86_64-unknown-linux-gnu
configure: creating ./config.status

Zatím toho moc configure neumí, ale nápovědu má velkou :-). Něco však přeci jen dělá. Vytváří soubor config.status. To je také bash skript, který dělá spoustu práce za configure. Především vytváří soubory na základě template souborů (config.h na základě config.h.in atp., viz dále).

Můžete se podívat na jeho nápovědu (./config.status -h). Protože ale zatím v configure.ac není o vytváření žádných souborů požádáno, tak config.status zatím také nic nedělá. Kdyby něco dělal, vytvořil by adresář config.cache, ve kterém si ukládá výsledky některých testů, aby jeho opětovné spuštění mohlo být rychlejší. Tento adresář můžete kdykoliv bez obav smazat.

Skript config.status je obvykle spouštěn skriptem configure, takže se o něj ani moc zajímat nemusíte. (Občas může být rychlejší spouštět přímo config.status, když víte co děláte …).

Tip: Když spustíte config.status s volbou --recheck, tak spustí skript configure se stejnými volbami, se kterými byl configure původně spuštěn.

Po spuštění configure se ještě vytvoří soubor config.log. V něm najdete podrobně popsáno, co configure dělá. Pokud vám z nějakého důvodu configure selže, tak na konci tohoto logu najdete to, co dělal naposledy. Moc užitečné pro ladění.

Soubor aclocal.m4 a adresář m4/

Makra používaná v configure.ac musí být někde definována. Mnoho jich přináší balíček ze kterého autotools instalujete. Jsou nainstalována do nějakých souborů, které si autoconf najde. Pokud potřebujete, můžete si napsat vlastní makra (v jazku m4). Pak musí být definována před makrem AC_INIT, nebo v souboru aclocal.m4. (Nic jiného než definice maker (a komentáře) by před AC_INIT nemělo být!)

Další možností je zavolat makro AC_CONFIG_MACRO_DIR([m4]) (až za AC_INIT). Pak se budou načítat makra ze souborů v adresáři m4. Jméno tohoto adresáře může být jakékoliv, ale zvykem je používat m4.

Kromě standardních maker instalovaných s autotools existuje autoconf archive, který obsahuje celou řadu dalších užitečných maker napsaných uživateli autotools. (Takže potřeba psát vlastní makra je velice vzácná.) Pokud nějaké z nich potřebujete použít, uložte jej do adresáře m4 (nezapomeňte zapsat AC_CONFIG_MACRO_DIR([m4]) do configure.h).

Například ax_lib_postgresql.m4 definuje makro AX_LIB_POSTGRESQL, které vám zjistí, zda je nainstalovaná postgres knihovna a jaké jsou potřeba přepínače pro překladač a preprocessor. Jak se používá vysvětlím na příkladu v některé z dalších kapitol.

Všechny makra z archivu můžete stáhnout pomocí gitu: git clone git://git.sv.gnu.org/autoconf-archive.git. V OpenSuSE distribuci existuje balíček autoconf-archive. Raději ale vždy stahuji aktuální verzi maker, (jen ta, která potřebuji), z webu do svého projektu (adresáře m4).

Program autoheader, skript configure.scan a soubor config.h.in

Program autoheader si přečte obsah souboru configure.ac a na jeho základě vytvoří soubor config.h.in.

Přesněji řečeno, vytvoří vstupní soubor pro první hlavičkový soubor, který určíte makrem AC_CONFIG_HEADERS. Tomuto makru se předává jako argument název souborů, které chcete nechat vygenerovat skriptem configure (který k tomu použije skript config.status). Názvy souborů jsou odděleny mezerou. Je zvykem první hlavičkový soubor nazývat config.h. (Ale můžete jej pojmenovat libovolně, třeba i včteně adresáre: src/config.h).

# 02GNUBuildSystem/example2/configure.ac
AC_INIT([psani-profi], [3.5.00], [sallyx@example.org],
        [], [http://www.sallyx.org/sally/psani-vsemi-deseti/])

AC_CONFIG_HEADERS([config.h test.h])

AC_OUTPUT

S takovýmto configure.ac souborem vám autoheader vytvoří následující config.h.in:

/* config.h.in.  Generated from configure.ac by autoheader.  */

/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT

/* Define to the full name of this package. */
#undef PACKAGE_NAME

/* Define to the full name and version of this package. */
#undef PACKAGE_STRING

/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME

/* Define to the home page for this package. */
#undef PACKAGE_URL

/* Define to the version of this package. */
#undef PACKAGE_VERSION

Program autoheader přečte makra použitá v configure.ac a zjistí, jaké proměnné tyto makra definují. Pro ty pak vytvoří #undef řádky v config.h.in. Zatím je v configure.ac jen jedno makro definující nějaké proměnné, a to AC_INIT (proměnné jsou definované v těle makra AC_INIT, v jazyce m4.)

$ autoconf
$ autoheader
$ ls
autom4te.cache  config.h.in configure  configure.ac
$ ./configure
configure: creating ./config.status
config.status: creating config.h
config.status: error: cannot find input file: `test.h.in'
Pokud chcete generovat test.h, vytvořte si test.h.in a napište si do něj, co chcete …

Formát pro *.h.in soubory se může zdát na první pohled zvláštní. Kromě komentářů tam jsou jen řádky s #undef. O tom, jestli bude dané makro definováno, rozhodne až test na cílovém systému. Skript configure může ke svému běhu využívat jen standardní unixové nástroje. K vytvoření config.h z config.h.in používá config.status program sed, kterým nahrazuje existující řádky za něco jiného (dle výsledků testu se buď řádek s #undef zakomentuje, nebo se nahradí řádkem #define s hodnotou, kterou během testování zjistil). Proto takový divný formát.

Vygenerovaný config.h (skriptem config.status) vypadá takto:

/* config.h.  Generated from config.h.in by configure.  */
/* config.h.in.  Generated from configure.ac by autoheader.  */

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "sallyx@example.org"

/* Define to the full name of this package. */
#define PACKAGE_NAME "psani-profi"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "psani-profi 3.5.00"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "psani-profi"

/* Define to the home page for this package. */
#define PACKAGE_URL "http://www.sallyx.org/sally/psani-vsemi-deseti/"

/* Define to the version of this package. */
#define PACKAGE_VERSION "3.5.00"

Jiný .in.h soubor než config.h obvykle potřebovat nebudete, takže pro další příklad test.h z configure.ac smažu. Ukáži vám ale ještě jedno nové m4 makro, které se používá pro definování proměnných, které se používají při generování hlavičkových souborů.

Tím makrem je AC_DEFINE. Má tři (povinné) argumenty. Prvním je jméno proměnné (používají se velká písmena), druhým je hodnota proměnné a posledním je libovolný popis.

# 02GNUBuildSystem/example3/configure.ac

AC_INIT([psani-profi], [3.5.00], [sallyx@example.org],
        [], [http://www.sallyx.org/sally/psani-vsemi-deseti/])

AC_DEFINE([HELLO_WORLD], ["Ahoj svete!"], [Definice pozdravu])

AC_CONFIG_HEADERS([config.h])

AC_OUTPUT

Všiměte si, že preprocessor m4 používá jako uvozovky hranaté závorky, ale pro cpp ve vygenerovaném config.h je potřeba použít dvojité uvozovky. Proto je druhý argument jak v hranatých závorkách, tak s uvozovkami. Pravda ale je, že AC_DEFINE je dost chytré, takže i když dvojité uvozovky nepoužijete, v config.h budou stejně.

$ autoheader
$ autoconf
$ ./configure
configure: creating ./config.status
config.status: creating config.h

Výsledný config.h vypadá takto:

/* config.h.  Generated from config.h.in by configure.  */
/* config.h.in.  Generated from configure.ac by autoheader.  */

/* Definice pozdravu */
#define HELLO_WORLD "Ahoj svete!"

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "sallyx@example.org"

/* Define to the full name of this package. */
#define PACKAGE_NAME "psani-profi"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "psani-profi 3.5.00"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "psani-profi"

/* Define to the home page for this package. */
#define PACKAGE_URL "http://www.sallyx.org/sally/psani-vsemi-deseti/"

/* Define to the version of this package. */
#define PACKAGE_VERSION "3.5.00"

Makro AC_INIT interně používá právě makro AC_DEFINE k tomu, aby definovalo PACKAGE_* proměnné. Jiná makra definují proměnné na základě výsledků testů systému, takže jejich výsledná hodnota nebude vždy jasně daná, jako v tomto příkladu.

Program autoscan a soubor configure.scan

Program autoscan projde rekurzivně celý adresář, prohledá všechny zdrojové kódy (.c,.cpp,.h,…) a vytvoří šablonu pro configure.ac se jménem configure.scan.

Soubor configure.scan obsahuje vše, co si autoscan myslí, že by měl obsahovat configure.ac. To zní na první pohled super, bohužel možnosti autoscan programu jsou omezené a tak je vždy potřeba configure.scan ještě trochu doplnit a poopravit.

Program autoscan vytváří soubor se jménem configure.scan a ne configure.ac proto, aby nepřepsal vaše úpravy v configure.ac (pokud už by existoval).

Pro následující ukázku jsem vytvořil tento jednoduchý zdrojový kód:

/*------------------------------------------------*/
/* 02GNUBuildSystem/example4/src/hello.c          */

#include <stdio.h>
#include "../config.h"

int main(void)
{
    printf("%s z %s verze %s\n", HELLO_WORLD, PACKAGE_NAME, PACKAGE_VERSION);
    return 0;
}
/*------------------------------------------------*/

Pro samotné autotools je potřeba hodně souborů a adresářů, proto se obvykle zdrojové kódy ukládjí do podadrsáře src. Název src/ sice není povinný, ale je to „nepsaný standard“.

$ autoscan
$ tree
.
├── autoscan.log
├── configure.scan
└── src
    └── hello.c

1 directory, 3 files

Výsledkem je configure.scan s tímto obsahem:

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([src/hello.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT

Makro AC_PREG určuje minimálni požadovanou verzi autoconf, která by měla vygenerované konfiguraci rozumět. Je možné, že budete mít novější verzi než je 2.69 a tak tam budete mít jiné číslo.

AC_INIT už znáte. Program autoscan nemůže znát název vašeho programu, ani jeho verzi nebo vaší emailovou adresu, takže do AC_INIT dosadil nějaké zástupné hodnoty, které byste měli přepsat.

Jedna z voleb programu configure umožňuje tento skript spustit nad adresářem, který určíte. Makro AC_CONFIG_SRCDIR je tu jen jako pojistka, která se ujistí, že vybraný adresář obsahuje soubor, který má jako argument. Argument by tedy měl být co nejunikátnější název zdrojového souboru, aby byl uživatel varován, pokud omylem určí špatný adresář. Program autoscan si dosadí náhodně vybraný soubor, vy si jej přepište dle libosti.

Poslední nové makro je AC_PROG_CC. To je první reálný test systému. Toto makro se snaží najít nějaký překladač jazyka C. Pokud je váš program psaný v C++, použijte makro AC_PROG_CXX.

Makro AC_PROG_CC hledá překladač v proměnné prostředí, pak se dívá po gcc, cc a dalších. Viz Volby pro configure.

V configure.scan najdete ještě několik komentářů oddělující sekce, kde by měly být další testy. Popořadě by se nejdříve měla kontrolovat existence programů, které jsou potřeba pro překlad či běh vašeho programu, dále existence knihoven, hlavičkových souborů, různých standardních struktur a typů a nakonec existence funkcí z knihoven.

Makra jsou na sobě obvykle nezávislá a nezáleží tak na jejich pořadí (čest vyjímkám, jako je AC_INIT a AC_OUTPUT). Přesto je asi logičtější nejdříve hledat existenci knihovny, než to, jestli daná knihovna obsahuje konkrétní funkci …

Program autoscan nenašel v našem malém zdrojáku nic, co by bylo potřeba kontrolovat. Obvykle je úspěšnější, ale čas od času je potřeba mu pomoci a dopsat další testy, které neodhalil. O makrech, které by se k tomu měli používat bude některá z dalších kapitol.

Dalším krokem je přejmenovat configure.scan na configure.ac a upravit jej podle potřeby:

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([hello-world], [0.4], [hello-world@example.org])
AC_CONFIG_SRCDIR([src/hello.c])
AC_CONFIG_HEADERS([config.h])

AC_DEFINE([HELLO_WORLD], ["Ahoj svete!"], [Definice pozdravu])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT

Všiměte si, že jsem doplnil AC_DEFINE. Berte to jen jako učebnicový příklad, v praxi je samozřejmě lepší vytvořit si nějaký .h soubor a definice napsat přímo do něj. Do configure.ac má smysl dávat jen definice, které se obvykle mění např. se změnou verze programu, nebo je možné je změnit pomocí nějaké konfigurační volby skriptu configure. Jak se to dělá, tak o tom zase někdy jindy.

Další postup už znáte:

$ mv configure.scan configure.ac # upravit configure.ac
$ autoconf
$ autoheader
$ ./configure
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
configure: creating ./config.status
config.status: creating config.h

Hurá! Konfigurační skrypt už konečně něco checkuje! Schválně, co se stane, když se pokusím podstrčit neexistující překladač:

$ CC=xaxa ./configure
checking for gcc... xaxa
checking whether the C compiler works... no
configure: error: in
`.../02GNUBuildSystem/example4':
configure: error: C compiler cannot create executables
See `config.log' for more details

Je skvélé, že už máme skript, který kontroluje existenci překladače, teď ještě tak mít Makefile, který tento překladač použije.

Soubory Makefile.in

Pro vytvoření Makefile souborů musíte vytvořit předlohy v podobě souborů Makefile.in. K předchozímu příkladu přidám Makefile.in do rootu projektu, který pouze předá cíle druhému Makefile.in v adresáři src/. (Jejich obsah vizte dále.)

Takto vypadá počáteční souborová struktura (example5):

$ tree
.
├── Makefile.in
└── src
    ├── hello.c
    └── Makefile.in

1 directory, 3 files

Po spuštění autoscan přibylo do configure.scan nové makro:

...
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
...
AC_CONFIG_FILES([Makefile
                 src/Makefile])

AC_OUTPUT

Toto makro určuje, jaké soubory se mají vygenerovat dle jejich *.in předloh. Toto makro tedy přidám do configure.ac.

Podívejte se nejdříve na obsah Makefile.in. Vygenerovaný Makefile má za úkol pouze předat cíle all a clean do adresáře src/:

# @configure_input@

all clean:
        $(MAKE) -C @builddir@/src $@

To, co je mezi dvěmi zavynáči (@) se nahradí proměnnou, definovanou makrem AC_SUBST. Existuje několik předdefinovaných proměnných, mezi něž patří @configure_input@ i @builddir@. Další proměnné mohou být definovány makry, jako je např. AC_INIT. V dokumentaci k tomuto makru se dočtete, že definuje následujicí output variables: PACKAGE_NAME, PACKAGE_TARNAME, PACKAGE_VERSION, PACKAGE_STRING, PACKAGE_BUGREPORT, PACKAGE_URL.

@configure_input@ se nahradí textem Makefile. Generated from Makefile.in by configure.

@builddir@ se nahradí adresářem, kam se budou generovat výstupní soubory (Makefile, *.o soubory a výsledný program) – tedy tečkou reprezentující aktuální adresář. Vzpomeňte, že configure se může spouštět z jiného adresáře, než kde jsou uloženy zdrojové kódy (ty mohou být na read-only médiu). Opomenutí použití @builddir@ a podobných proměnných je jeden z častých důvodů, proč neprojde make distcheck.

Soubor src/Makefile.in je o malinko zajímavější, ale také využívá jen output variables předdefinované, nebo definované makrem AC_INIT:

# @configure_input@

all:
        $(CC) @CPPFLAGS@ @CFLAGS@ @DEFS@ -o @top_builddir@@PACKAGE_NAME@ @top_srcdir@/hello.c @LDFLAGS@ @LIBS@

        clean:
                $(RM) @PACKAGE_NAME@

Krátce se zmíním o @DEFS@. Pokud byste nepoužili makro AC_CONFIG_HEADERS, pak by proměnná @DEFS@ obsahovala spousty -D přepínačů s makry, které jsou jinak definavené v config.h.
Při použití AC_CONFIG_HEADERS obsahuje @DEFS@ jen -DHAVE_CONFIG_H.

Další proměnné jsou definovány autotools, nebo je najdete ve vašem vygenerovaném config.h souboru (například @PACKAGE_NAME@).

Proměnná @top_builddir@ obsahuje kořen adresáře, kde dochází k překladu. Výsledný program bude tedy uložen na stejné úrovni, jako je adresář, ze kterého se spouští configure. Proměnná @top_srcdir@ obsahuje absolutní cestu k adresáři, kde je příslušný Makefile.in.

Můžete si to jednoduše vyzkoušet. Spusťte configure například z /tmp adresáře:

$ cd  /tmp/
$ /home/p.../02GNUBuildSystem/example5/configure
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
configure: creating ./config.status
config.status: creating Makefile
vconfig.status: creating src/Makefile
config.status: creating config.h
config.status: config.h is unchanged
$ cat src/Makefile
# src/Makefile.  Generated from Makefile.in by configure.

all:
	$(CC)  -g -O2 -DHAVE_CONFIG_H -o ../hello-world /home/p.../02GNUBuildSystem/example5/src/hello.c  

clean:
	$(RM) hello-world
$ make
make -C ./src all
make[1]: Vstupuje se do adresáře „/tmp/src“
cc  -g -O2 -DHAVE_CONFIG_H -o ../hello-world /home/p.../02GNUBuildSystem/example5/src/hello.c  
make[1]: Opouští se adresář „/tmp/src“

O naplnění ostatních proměnných se postarají makra, která v configure.ac použijete. (Respektive vygenerovaný configure.scan skript.) Některé hodnoty jsou „jen“ defaultní. Např. $(CC) můžete nadále změnit až při spuštění programu make…

Programy automake, aclocal, soubory aclocal.m4, Makefile.am a adresář build-aux

Sliboval jsem vám, že vám autotools pomohou vytvořit Makefile se standardními cíli. K tomu slouží program automake, jenž vygeneruje Makefile.in na základě Makefile.am šablony (jo jo, šablona pro vygenerování šablony :-).

Automake se přidal k autotools o něco později, takže autoconf na automake nezávisí, ale automake na autotools ano.

Program automake také čte confiugre.ac, aby zjistil, jaké soubory má generovat. Nehledá Makefile.am v souborovém systému, ale hledá makro AC_CONFIG_FILES. Krom toho musíte do configure.ac přidat nějaká další makra, která ovlivňují chování automake.

Tyto makra nejsou součástí autoconfigu, ale automake naštěstí přichází s pomocným programem aclocal, který vytvoří soubor aclocal.m4 s potřebnými makry. Ale pozor! Obsah aclocal.m4 je závislý na tom, jaká automake makra použijete v configure.ac. Tudíž je potřeba čas od času zavolat program aclocal znovu.

Automake vytvoří Makefile.in na základě Makefile.am. Z takto vyenerovaného Makefile.in pak skript configure vytvoří Makefile, který bude umět všechny standardní cíle GNU, který je přenositelný na všechny podporované systémy.

automake(<-Makefile.am) => Makefile.in
autoconf(<-configure.ac) => configure
./configure(<-Makefile.in config.h.in) => Makefile config.h

To má ale jeden drobný háček. Třeba co se týče instaslace, tak ta se provádní na různých systémech různě. Během instalace je potřeba přesunout soubory na správná místa, nastavit správně přístupová práva, občas zavolat nějaký configurační program. A protože se tyto věci systém od systému liší, automake přichází s několika podpůrnými skripty. Protože váš výsledný configure skript i Makefile soubory mají fungovat i na systémech bez nainstalovaných autotools, je nutné tyto skripty přibalit k vašemu balíčku. Makro AC_CONFIG_AUX_DIR určuje adresář, kam se tyto pomocné skripty nahrají.

Tolik k teorii a teď zpět k praxi. Soubor configure.ac z předchozího příkladu doplním takto:

  1. #                                               -*- Autoconf -*-
  2. # Process this file with autoconf to produce a configure script.
  3.  
  4. AC_PREREQ([2.69])
  5. AC_INIT([hello-world], [0.6], [hello-world@example.org])
  6. AC_CONFIG_SRCDIR([src/hello.c])
  7. AC_CONFIG_HEADERS([config.h])
  8.  
  9. AC_DEFINE([HELLO_WORLD], ["Ahoj svete!"], [Definice pozdravu])
  10.  
  11. AC_CONFIG_AUX_DIR([build-aux])
  12.  
  13. AM_INIT_AUTOMAKE([gnu -Wall -Werror])
  14.  
  15. # Checks for programs.
  16. AC_PROG_CC
  17.  
  18. # Checks for libraries.
  19.  
  20. # Checks for header files.
  21.  
  22. # Checks for typedefs, structures, and compiler characteristics.
  23.  
  24. # Checks for library functions.
  25.  
  26. AC_CONFIG_FILES([Makefile src/Makefile])
  27.  
  28. AC_OUTPUT

Makro AM_INIT_AUTOMAKE inicializuje automake. Prvním argumentem tohoto makra jsou nějaké volby, které ovlivňují chování automake. Co se první volby týče, máte 3 možnosti: gnits, gnu a foreign. Volba gnu je defaultní. S touto volbou vyžaduje automake existenci souborů NEWS, README, AUTHORS, ChangeLog, případně ještě INSTALL a COPYING (soubory mohou být prázdné). Co má být obsahem těchto souborů a jaký má být jejich formát se dočtete v GNU Coding standardu. Pokud soubor COPYING nevytvoříte, automake ho vytvoří a zapíše do něj GNU licenci. Podobně to platí pro INSTALL, do kterého zapíše postup instalace.

Pokud tyto soubory vytvářet nechcete, použijte místo gnu volbu foreign. Ta nic nevyžaduje. Volba gnit je nějaký nový, ještě nedokončený standard, takže si jí zatím nemusíte všímat.

Další volba pro automake, -Wall říká, že se mají vyhazovat všechny varování. Pozor, jedná se o varování programu automake, nemá to nic společného s -Wall pro překladač gcc!

Volba -Werror způsobí, že se varování změní na chyby, které ukončí běh automake. To je super pro vývoj, protože tak žádné varování nepřehlédnete. Ale je to smrtící pro distribuci, protože některá varování se týkají použití zastaralých maker. Takže pokud by váš balíček někdo použil s novější verzí automake, ve které by některé vaše makro bylo deprecated, varování by (zbytečně) znemožnilo automake úspěšně dokončit tvorbu Makefile.in. Proto nikdy nenechávejte volbu -Werror v balíčku, který chcete vypusti do světa!

Automake vyžaduje AC_CONFIG_FILES, aby poznalo, jaké Makefile.in má generovat. Bez toho se tedy také neobejdete.

Teď už je téměř vše přichystáno. Ještě je potřeba vytvořit soubory Makefile.am a src/Makefile.am. Prozatím mohou zůstat prázdné.

$ tree
.
├── configure.ac
└── src
    └── hello.c

1 directory, 2 files
$ mkdir build-aux
$ touch NEWS README AUTHORS ChangeLog Makefile.am src/Makefile.am
$ autoheader
$ aclocal
$ automake
configure.ac:16: error: required file 'build-aux/compile' not found
configure.ac:16:   'automake --add-missing' can install 'compile'
configure.ac:13: error: required file 'build-aux/install-sh' not found
configure.ac:13:   'automake --add-missing' can install 'install-sh'
configure.ac:13: error: required file 'build-aux/missing' not found
configure.ac:13:   'automake --add-missing' can install 'missing'
Makefile.am: error: required file './INSTALL' not found
Makefile.am:   'automake --add-missing' can install 'INSTALL'
Makefile.am: error: required file './COPYING' not found
Makefile.am:   'automake --add-missing' can install 'COPYING'

Jak vidíte, automake si stěžuje, že neexistují soubory INSTALL, COPYING a další pomocné soubory, které bude výsledný Makefile potřebovat. Zároveň také nabízí řešení: zavolat automake --add-missing.

$ automake --add-missing
configure.ac:16: installing 'build-aux/compile'
configure.ac:13: installing 'build-aux/install-sh'
configure.ac:13: installing 'build-aux/missing'
Makefile.am: installing './INSTALL'
Makefile.am: installing './COPYING' using GNU General Public License v3 file
Makefile.am:     Consider adding the COPYING file to the version control system
Makefile.am:     for your code, to avoid questions about which license your project uses
$ autoconf
$ tree
.
├── aclocal.m4
├── AUTHORS
├── autom4te.cache
│   ...
├── build-aux
│   ├── compile -> /usr/share/automake-1.15/compile
│   ├── install-sh -> /usr/share/automake-1.15/install-sh
│   └── missing -> /usr/share/automake-1.15/missing
├── config.h.in
├── configure
├── configure.ac
├── COPYING -> /usr/share/automake-1.15/COPYING
├── ChangeLog
├── INSTALL -> /usr/share/automake-1.15/INSTALL
├── Makefile.am
├── Makefile.in
├── NEWS
├── README
└── src
    ├── hello.c
    ├── Makefile.am
    └── Makefile.in

3 directories, 25 files

Projekt se trošičku rozrostl, na to, že se stará jen o hello.c zdroják, že? :-)

Soubory vytvořené příkazem automake --add-missing jsou symbolické linky. Takto to samozřejmně nelze uživatelům distribuovat, ale příkaz make dist naštěstí nahradí symlinky za obyčejné soubory. (Výhoda symlinků je, že při aktualizaci autotools bude ve vašem projektu dostupná aktuální verze těchto souborů).

Kdyby vás to z nějakého důvodu jó hodně štvalo, můžete použít přepínač -c, se kterým automake místo symlinků vytvoří obyčejné soubory: automake -a -c.

V tuto chvíli už můžete spustit ./configure a nechat si vygenerovat Makefile soubory. Takové Makefile už dokonce budou mít své cíle, jako je make all, make distcheck atp.

Aby ale něco skutečně dělaly, musí se něco zapsat do Makefile.am souborů. Formátu těchto souborů věnuji celou kapitolu, protože je to, bohužel, rozsáhlá látka. To, co vám teď ukáži, je jen nezbytné minimum.

První soubor Makefile má za úkol jen spustit cíle v adresáři src/, takže obsah Makefile.am je jednoduchý:

# 02GNUBuildSystem/example6/Makefile.am
SUBDIRS = src

V souboru src/Makefile.am se určí jen název výsledného binárního programu a seznam zdrojových kódu, které jsou pro sestavení programu potřeba:

# 02GNUBuildSystem/example6/src/Makefile.am
bin_PROGRAMS=hello

hello_SOURCES = hello.c

Teď je potřeba znovu spustit automake, který z Makefile.am vytvoří Makefile.in. Automake si všimne, že chcete sestavovat binární soubor, tak začne vyžadovat další pomocný skript …

$ automake
src/Makefile.am: error: required file 'build-aux/depcomp' not found
src/Makefile.am:   'automake --add-missing' can install 'depcomp'
$ automake -a
src/Makefile.am: installing 'build-aux/depcomp'
$ autoconf

Tím je dílo ukončeno. Nyní můžete spustit ./configure; make distcheck, což vám vytvoří balíček hello-world-0.6.tar.gz, který můžete poslat do světa.

$ ./configure -q
$ make --no-print-directory V=0
make  all-recursive
Making all in src
CC       hello.o
CCLD     hello
$ ./src/hello
Ahoj svete! z hello-world verze 0.6
$ make distcheck
...
=================================================
hello-world-0.6 archives ready for distribution: 
hello-world-0.6.tar.gz
=================================================

No není to fantastické? V podstatě vám stačí jen dvě řádky v Makefile.am a váš Makefile soubor je schopen překladu, instalace, vytvoření distribučního balčíku a to na všech možných, autotoolem podporovaných, systémech!

Program autoreconf

Teď už máte k dispozici celou řádku programů, které je potřeba spustit. Proto autotools přišel s ještě jedním navíc: autoreconf. Ten spustí všechny potřebné programy, spustí je ve správném pořadí a spustí je jen tehdy, když je to potřeba (když se změnil nějaký soubor, na kterém jsou dané programy závislé).

Místo autoheader;aclocal;automake;autoconf stačí spustit autoreconf. A on spustí jen to, co je potřeba.

Od teď používejte jen autoreconf ;-).

Program autoreconf má, mimo jiné, jednu zajímavou volbu: -i. S touto volbou autoreconf zavolá automake --add-missing, pokud je to potřeba.

Závěr

Toto byly všechny důležité programy a konfigurační subory z autotools. Vím, že jich je hodně, ale z programů potřebujete znát je autoreconf a když se znovu podíváte na poslední configure.ac soubor, jsem si jistý, že makra v něm zapsaná vám jsou již jasná. Není na nich nic složitého. Až uděláte s autotools dva, nebo tři projekty, zjistíte, že jen přidáváte makra do configure.ac (s čímž vám hodně pomůže autoscan) a tvoříte Makefile.am soubory.

V následujících kapitolách se budu věnovat především dalším důležitým autotools makrům a konfiguraci automake. To první je v zásadě jednoduché, to druhé až zas tak moc ne.

Komentář Hlášení chyby
Vytvořeno: 24.12.2018
Naposledy upraveno: 24.12.2018
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..