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.
8. časť: Šablóny, úvod do Auto Tools
Šablóny
Niekedy sa stane, že vo viacerých súboroch Makefile používame rovnaké pravidlá, premenné a podobne. Riešenie je triviálne - stačí použiť príkaz include. Čo však v prípade, že v jednom súbore budeme musieť okrem týchto "štandardných" pravidiel použiť aj pravidlo vlastné s rovnakým cieľom ako niektoré z už definovaných pravidiel? Ako už asi viete, make neschvaľuje viacero pravidiel s rovnakým cieľom. Je tu však jeden trik, ako to celé obísť.
V súbore inc budú pravidlá a premenné, ktoré chceme vkladať do všetkých ostatných Makefile súborov. Súbor sa bude nachádzať v hlavnom adresári daného softvérového projektu. Okrem toho budú v adresároch 1 a 2 súbory Makefile, ktoré budú obsahovať riadok:
include ../inc
Okrem toho môžu, samozrejme, obsahovať aj iné príkazy a pravidlá. Súbor inc bude obsahovať aj pravidlo na vytvorenie súboru foo. My však z nejakého dôvodu potrebujeme v Makefile v hlavnom adresári projektu zmeniť toto východzie pravidlo na nejaké iné, avšak potrebujeme ostatné veci zo súboru inc a preto ho musíme vložiť. Tento Makefile by sme mohli spraviť takto:
foo: 1.o 2.o main.o
$(CC) -o $@ $<
%: force
$(MAKE) -f inc $@
force: ;
Ak si spomínate, s pravidlom force sme sa už stretli - ako už z názvu vyplýva, má niekoho (niečo) prinútiť k niečomu. Celý predchádzajúci príklad funguje takto: ak potrebujeme vytvoriť súbor/program foo, použije sa prvé pravidlo, inak sa použije pravidlo, ktoré vyhovuje všetkému - teda ak spustíme:
make program
spustí sa:
make -f inc program
Súbor inc by mal obsahovať pravidlo na vytvorenie daného programu. Pravidlo force sme použili preto, aby sa toto pravidlo vykonalo vždy, aj keby takýto program existoval. Koniec koncov, v súbore inc sa budú prípadné závislosti či existencia niektorých súborov kontrolovať, takže to nie je problém.
Hello, AutoTools!
Tak, konečne ste sa dočkali! Po nutnej (nudnej) prvej polovici seriálu venovanej súborom Makefile sa konečne môžeme vrhnúť na programy automake, autoconf, configure a spol. Začneme, ako inak, na programe Hello, World. V tejto časti nebudem všetko do detailov vysvetľovať, na to treba viac miesta a času - takže si to preberieme postupne.
Najprv si vytvoríme nový adresár hello. Potom si vytvoríme zdrojové súbory:
hello.h:
#include <stdio.h>
void hello(char* name);
hello.c:
#include "hello.h"
void hello(char* name)
{
printf("hello, %s\n", name);
}
main.c:
#include "hello.h"
int main(int argc, char* argv[])
{
if (argc < 2) {
printf(PACKAGE " " VERSION "\n");
printf("Usage: %s \"text\"\n", argv[0]);
return 1;
}
hello(argv[1]);
return 0;
}
Program nerobí dohromady nič užitočné, iba pozdraví toho, koho zadáme ako prvý parameter programu. Ak parameter nezadáme, program vypíše informáciu o tom, ako sa má správne používať a zároveň vypíše svoju verziu. PACKAGE a VERSION sú definované pri kompilácii (parameter -D programu gcc).
Teraz pridáme nové súbory, ktoré "spojazdnia" autotools. Najprv si vytvoríme súbor Makefile.am, z ktorého vytvorí automake súbor Makefile.in, z ktorého nakoniec vytvorí program configure obyčajný Makefile, ktorý môžeme použiť spustením známeho programu make. A aby to nebolo až také jednoduché, program configure bude takisto automaticky vygenerovaný, a to zo súboru configure.in.
Makefile.am:
## Process this file with automake to produce Makefile.in
bin_PROGRAMS= hello
hello_SOURCES= hello.c main.c
noinst_HEADERS= hello.h
AUTOMAKE_OPTIONS=foreign
Prvý riadok je komentár. Prečo sa začína dvoma mriežkami? Komentár s takýmito dvoma mriežkami odstráni automake, naproti tomu ten s jednou mriežkou ostáva a môžete ho uvidieť vo vygenerovanom Makefile.in. (Keď už budú vygenerované všetky tri Makefile (.am, .in aj ten bez prípony), všimnite si, že najkratší je .am. Medzi .in a tým bez prípony je menej rozdielov, akurát configure doplní do .in niektoré premenné, ktoré sa mu podarí zistiť (napríklad prítomnosť rôznych knižníc).
Teraz si vysvetlíme význam jednotlivých premenných:
bin_PROGRAMS - názvy všetkých programov, ktoré sú v tomto adresári (niekedy nabudúce si ukážeme, ako urobiť viac adresárov v jednom projekte).
hello_SOURCES - zdrojové súbory, ktoré patria programu hello. Ak by predchádzajúca premenná obsahovala viacero mien (teda kompilovalo by sa viac programov), stačí pridať ďalšie premenné *_SOURCES so správnymi názvami súborov. Ak by názov niektorého programu malobsahovať znaky ako napríklad +, v názve tejto premennej ho budete musieť nahradiť podškrtovníkom _, teda napríklad program g++ bude mať premennú g___SOURCES (tri znaky _).
noinst_HEADERS - názvy všetkých hlavičkových súborov, ktoré majú byť v distribúcii programu, ale nebudú sa nikam inštalovať (napríklad do adresára /usr/include). Budem trošku predbiehať, ak poviem, že noinst môžeme použiť aj pre PROGRAMS - tieto programy sa nebudú inštalovať do žiadneho adresára pri zadaní príkazu make install.
AUTOMAKE_OPTIONS - programu automake povieme, že náš projekt nie je celkom GNU kompatibilný, totiž neobsahuje súbory AUTHORS, ChangeLog, COPYING, NEWS, README a INSTALL. Bez tohto nastavenia by nám sústavne hlásil chybu. Po tom, čo tieto súbory doplníme, môžeme tento riadok pokojne zmazať.
Teraz si napíšeme súbor configure.in. Tento súbor je v každom projekte iba jeden, na rozdiel od Makefile.am, ktorý môže byť v každom podadresári.
configure.in:
dnl Process this file with autoconf to produce a configure script.
AC_INIT(main.c)
AM_INIT_AUTOMAKE(hello, 1.0)
AC_PROG_CC
AC_OUTPUT(Makefile)
Tento súbor používa makrojazyk M4 a všekty príkazy sú vlastne makrá (vzdialene podobné makrám preprocesora jazykov C a C++). Prvý riadok je komentár (dnl ...). Druhý riadok inicializuje autoconf, parameter tohto makra je ľubovoľný existujúci súbor v projekte, za ktorý sa môžeme zaručiť, že bude existovať naveky. Ďalším riadkom inicializujeme automake a nastavujeme názov a verziu programu. Práve obsah týchto dvoch parametrov sa prenesie do makier PACKAGE a VERSION. Štvrtým riadkom oznamujeme, že sa chystáme používať jazyk C. Posledným riadkom vygenerujeme Makefile. Jednoduché, nie?
Teraz to celé spustíme. Najprv použijeme aclocal. Tento program prejde celým súborom configure.in a použité makrá nahrá do súboru aclocal.m4. Teraz príde na rad automake, ktorý má za úlohu prejsť všetky Makefile.am a vytvoriť zodpovedajúce Makefile.in. Spustíme ho príkazom
automake --foreign --add-missing --copy
Prvý parameter má rovnakú funkciu ako pri AUTOMAKE_OPTIONS a ak doplníme chýbajúce súbory, pokojne ho môžeme vynechať.Keďže sme vytvorili nový projekt a nenahrali sme všetky potrebné pomocné súbory, použijeme ďalšie dva parametre. Nahrajú sa súbory install-sh, missing a mkinstalldirs (prvýkrát môže vypísať nejaké varovania). Nakoniec pustíme autoconf, ktorý z configure.in vytvorí configure. Na celú akciu si môžeme spraviť súbor (shell skript) s názvom napríklad bootstrap, ktorý dané tri príkazy vykoná.
bootstrap:
aclocal && \
automake --foreign --add-missing --copy && \
autoconf
Teraz už máme všetko, čo potrebujeme. Stačí spustiť známu kombináciu:
configure && make && make install
a máme náš príklad hotový (ten posledný príkaz - make install - môžete vynechať). configure skontroluje, či na cieľovom systéme máme nainštalované všetky potrebné programy a knižnice a podľa prípadných odlišností prispôsobí Makefile tak, aby všetko fungovalo, ako má (súbory Makefile vytvorí z Makefile.in). Skúste si pozorne pozrieť, čo configure vypíše na terminál:
creating cache ./config.cache
checking for a BSD compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking whether make sets ${MAKE}... yes
checking for working aclocal... found
checking for working autoconf... found
checking for working automake... found
checking for working autoheader... found
checking for working makeinfo... found
checking for gcc... gcc
checking whether the C compiler (gcc ) works... yes
checking whether the C compiler (gcc ) is a cross-compiler... no
checking whether we are using GNU C... yes
checking whether gcc accepts -g... yes
updating cache ./config.cache
creating ./config.status
creating Makefile
Prvý riadok nás informuje o tom, že sa vytvára cache súbor, do ktorého sa zapíšu vlastnosti vášho systému, ktoré by sa tak často nemali meniť a preto by bolo zbytočné a časovo náročnejšie stále ich dookola zisťovať. Má to zmysel hlavne vtedy, ak budete zisťovať prítomnosť rôznych knižníc a programov ako QT, kdelib, mysql, atď. Pri ich zisťovaní sa typicky prehľadávajú viaceré adresáre, čo môže zaťažiť a zdržať systém, pričom je málo pravdepodobné, že medzi kompiláciami vášho programu by sa malo niečo meniť (samozrejme, cache sa dá vypnúť alebo zmazať, vtedy sa všetko zisťuje nanovo). K tomuto prvému riadku patrí aj tretí od konca - vtedy sa cache opraví na novo zistené skutočnosti. Skúsme teda spustiť konfiguráciu ešte raz:
loading cache ./config.cache
checking for a BSD compatible install... (cached) /usr/bin/install -c
checking whether build environment is sane... yes
checking whether make sets ${MAKE}... (cached) yes
checking for working aclocal... found
checking for working autoconf... found
checking for working automake... found
checking for working autoheader... found
checking for working makeinfo... found
checking for gcc... (cached) gcc
checking whether the C compiler (gcc ) works... yes
checking whether the C compiler (gcc ) is a cross-compiler... no
checking whether we are using GNU C... (cached) yes
checking whether gcc accepts -g... (cached) yes
creating ./config.status
creating Makefile
Znova si všimnite prvý riadok. Tentoraz je cache súbor config.cache iba načítaný - už sa nevytvára, ani sa na konci neupravuje. Takisto pri niektorých riadkoch si všimnite text (cached), ktorý znamená, že daná vlastnosť sa už nezisťovala, iba bola vytiahnutá z cache. Niektoré parametre si program do cache neukladá (typicky veci, ktoré sa týkajú jeho príbuzných z rodiny autotools a niektoré ďalšie dôležité nastavenia).
Ostatné riadky nás veľmi zaujímať nemusia - zisťuje sa prítomnosť rôznych dôležitých programov, prekladačov a ich parametrov. Zároveň sa nastavujú premenné Makefile ako $(CC) a spol. Všimnite si predposledný riadok - vytvorí sa súbor config.status, pomocou ktorého môžete dostať konfiguráciu vášho projektu do takého stavu, aký bol pri vytváraní tohto súboru. Okrem tohto súboru sa vytvorí aj config.log, v ktorom je zaznamenaný priebeh configure. Nakoniec si všimnite posledný riadok, ktorý nás informuje, že sa práve vytvára konkrétny súbor Makefile zo súboru Makefile.in v tom istom adresári (ak by sme potrebovali vytvoriť viacero týchto súborov, upravili by sme posledný riadok v súbore configure.in a v každom podadresári by sme vytvorili Makefile.in, ale o tom až neskôr).
Teraz si ešte povieme o tom, ktorý súbor sa bude distribuovať (bude v balíčku so zdrojákmi - tar.gz/bz2) a ktorý sa vytvorí až na cieľovom stroji. Najprv listing súborov, ktoré vytvárame "ručne":
bootstrap
configure.in
Makefile.am
hello.c
hello.h
main.c
Prvý súbor by sme mohli a nemuseli dávať ďalej. Osobne som sa s ním veľmi často v balíčkoch netretol. Má totiž zmysel iba vtedy, ak zmeníme súbor configure.in a to nebýva až tak často (všimnite si, že pri zmene Makefile.am sa automake spustí automaticky). Ja by som ho však odporúčal pribaliť. Ako ho teda pridať do distribúcie? Jednoducho - na koniec súboru Makefile.am pridáme riadok:
EXTRA_DIST=bootstrap
Takto môžeme pridať ľubovoľný súbor, ktorý sa štandardne nedistribuuje. Súbory uvedené v *_SOURCES a *_HEADERS, samozrejme, nemusíme uvádzať, tie sa pribalia automaticky. Takisto súbory README, ChangeLog, COPYING, atď. (kompletný zoznam dostaneme spustením automake --help). Je jasné, že ani configure.in a Makefile.am nemusíme uvádzať. Takže z uvedených šiestich súborov distribujeme minimálne päť. Teraz pridáme súbory, ktoré pribudnú po spustení bootstrap:
Makefile.in
aclocal.m4
configure
install-sh
missing
mkinstalldirs
Aj tieto súbory budeme distribuovať. Prvý sa vytvorí spustením automake zo súboru Makefile.am, druhý spustením programu aclocal, ktorý prehľadá configure.in. Bez tohto súboru configure nevytvoríte. Aj tretí súbor pribalíme; vytvorí sa zo súboru configure.in programom autoconf. Ďalšie tri súbory (shell skripty) do adresára pridal (resp. prekopíroval zo svojho systémového adresára) program automake. Tak a to je všetko, čo potrebujeme, aby sme vytvorili balíček so zdrojovými kódmi. Teda súbory
Makefile
config.cache
config.log
config.status
nebudeme pribaľovať. Všetky štyri sa vytvoria pri konfigurácii. Takisto nemá zmysel pri zdrojákoch ditribuovať aj *.o, výslednú binárku a pod. Už sme si toho o balíčkoch povedali dosť, ešte som však nepovedal, ako ho vytvoriť. Ak máme Makefile vytvorený, stačí spustiť make dist a o chvíľku sa nám objaví súbor hello-1.0.tar.gz. Ak by sme chceli všetko ešte raz prekontrolovať, skúsme príkaz make distcheck. Ten vytvorí balíček, rozbalí ho, spustí
configure && makea vyhlási, že balíček je pripravený pre distribúciu (ak nenastali chyby). To je dosť zjednodušený pohľad na vec, podrobnejšie niekedy nabudúce.
Oto Komiňák
Článok bol uverejnený v magazíne PC Revue 09/2002.
