PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : GNU Autoconf, Automake und Libtool



RapidMax
29-11-2003, 18:25
Ich möchte hier ein paar Grundlagen zu den Tools vermitteln.

Offizielle Dokumentation über den GNU Dokumentations-Index:
http://www.gnu.org/manual/

Autoconf: http://www.gnu.org/software/autoconf/manual/autoconf-2.57/autoconf.html
Automake: http://www.gnu.org/software/automake/manual/automake.html
Libtool: http://www.gnu.org/software/libtool/manual.html

Autoconf Makros im GNU Macro Archive
http://www.gnu.org/software/ac-archive/

Literatur in Buch-Form (Am besten über den Amazon-Banner hier):
GNU Autoconf, Automake and Libtool / Gary V.Vaughan, ben Elliston, Tom Tromey, and Lance Taylor / New Riders / ISBN 1-57870-190-2 / Online Version (http://sources.redhat.com/autobook/autobook/autobook_toc.html#SEC_Contents)

Gruss, Andy

RapidMax
29-11-2003, 18:27
Für ein kleines Projekt ist ein Buildsystem mit wenig Aufwand möglich.

Grundlage ist ein configure.in und ein oder mehrere Makefile.am. Ich handhabe es so, dass ein Modul in einem Unterverzeichnis landet und ein eigenes Makefile.am bekommt. Die restlichen Dateien werden alle aus diesen Dateien generiert. Darum müssen sie nicht unbedingt im CVS landen. Wenn ein Entwickler keine oder alter Versionen von autoconf und automake hat oder Anwender auf das CVS zugreifen, dann sollten die Dateien trotzden dort aufgenommen werden. Zum kompilieren sind dann autoconf und automake nicht mehr notwendig.

Source
Nehmen wir an unser Projekt enthält folgende Dateien:


talk.h:
extern void sayHello();

talk.c:
#include <stdio.h>
#include "talk.h"
void sayHello() { printf("Hello"); }

main.c:
#include <stdio.h>
#include "talk.h"
int main() { sayHello(); printf(" World\n"); return 0; }

Das Buildsystem liegt im Projekt-root-Verzeichnis und der Source im Unterverzeichnis "src".

automake
Für automake sind später noch ein paar Einträge in der configure.in zu erledigen, vorerst kümmern wir uns um die Makefile.am.
Wir haben zwei Source-Files und einen Header. Daraus werden zwei Objekt-Files die zusammengelinkt das Program "helloworld" ergeben sollen. Das dazugehörige Makefile.am im Verzeichnis "src" sieht dann so aus:


## Process this file with automake to produce Makefile.in
# Program binary name
bin_PROGRAMS = helloworld
# sources
helloworld_SOURCES = main.c talk.c
# mark headers to include also in package
EXTRA_DIST = talk.h

Für das Projekt-root-Verzeichnis brauchen wir ebenfalls ein Makefile.am, das nichts anderes macht, als das Makefile im Verzeichnis src aufzurufen und Automake mitteilt, dass keine GNU-Dateien (README, COPYING etc.) vorhanden sein müssen.


## Process this file with automake to produce Makefile.in
SUBDIRS = src
AUTOMAKE_OPTIONS = foreign


autoconf
In diesem einfachen Fall ist die configure.in sehr einfach zu erstellen:


$ autoscan
$ mv configure.scan configure.in

Autoscan erstellt die Grundstruktur und durchsucht die Sourcen nach problematischen Stellen und fügt dafür Makros ein. Das ist natürlich nicht vollständig, aber für uns reicht das.
Die configure.in, die wir so erhalten haben muss noch editiert werden. Einerseits um Angaben zum Projekt-Namen zu machen und andererseits um Automake zu integieren. Die Test in der Mitte können so stehen gelassen werden. Der Header wird jedoch umgestellt und es wird der Pfad zu den Makefiles angegeben. Schlussendlich sieht configure.in so aus:


# Process this file with autoconf to produce a configure script.
AC_INIT([hworld], [0.1.0], [user@host.de])
AC_CONFIG_SRCDIR([config.h.in])
AM_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE

# 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_CONFIG_FILES([Makefile
src/Makefile])
AC_OUTPUT

Man beachte AM_CONFIG_HEADER statt AC_CONFIG_HEADER und die Angabe der resultierenden Makefiles.

Buildsystem bauen lassen
Im Folgenden werden ein paar Tools aufgerufen, welche Dateien in das Projekt-Verzeichnis kopieren und neue Dateien generieren. Das ist immer Dann notwendig, wenn sich was am Buildsystem ändert, z.B. wenn neue Dateien in den Makefile.am hinzugefügt werden oder configure.in editiert wurde. Um diesen Vorgang zu automatisieren gibt es zwar autogen, ich persönlich bevorzuge ein kleines Shellscript Namens bootstrap das die Aufrufe enthält.
Folgende Schritte sind notwendig:


# aclocal.m4 erstellen:
aclocal
# config.h.in aus configure.in erstellen
autoheader
# aus Makefiles.am Makefile.in generieren und einige
# zusätzliche Tools in das Verzeichnis kopieren
# ("--add-missing --copy" bewirkt letzeres)
automake --add-missing --copy
# schlussendlich aus configure.in das configure-Script erstellen
autoconf

Damit sind wir schon soweit, dass jeder jetzt die folgenden Schritte bereits kennt. Kompilieren wir die Sourcen:


$ ./configure && make
$ ./src/helloworld
Hello World
$ make dist
$ ls
Makefile aclocal.m4 config.h.in configure hworld-0.1.0.tar.gz mkinstalldirs
Makefile.am autom4te.cache config.log configure.in install-sh src
Makefile.in config.h config.status depcomp missing stamp-h1
$ tar tzf hworld-0.1.0.tar.gz

Wie man sieht, sind weitere nützliche Targets vorhanden, wie "make dist" das ein Tarball erstellt, der den Benutzern verteilt werden kann.

RapidMax
29-11-2003, 18:55
Mich stört es, wenn die Dateien des Build-System das Projekt-root-Verzeichnis zumüllen. Im Folgenden geht es darum, das Ganze ein bisschen besser zu struktuerieren. Ich baue auf dem Beispiel oben auf.

Ich möchte möglichst viele Dateien des Buildsystem im Unterordner ./config verstauen:


$ ls
Makefile.am bootstrap configure.in

src:
Makefile.am main.c talk.c talk.h
$ mkdir config
$ mv boostrap config/bootstrap
$ touch config/acinclude.m4

In die config/acinclude.m4 kommen später eigene und zusätzliche Makros. Zwar haben wir noch keine, aber irgendwann werden die sowieso benötigt, so dass jetzt ein guter Zeitpunkt ist, zu zeigen, wo diese zu verstauen sind.

Mit der Änderung sind nun ein paar Arbeiten notwendig, um die Umstellung fertig zu stellen. Zuerst sollte "bootstrap" angepasst werden, dass es so aussieht:


#!/bin/sh
aclocal -I config
autoheader
automake --add-missing --copy
autoconf

Und in der configure.in wird gleich nach AC_INIT folgende Zeile hinzugefügt:


AC_CONFIG_AUX_DIR(config)


Damit kann das Build-System wieder erstellt werden:


$ ./config/bootstrap
$ ./configure && make
$ ./src/helloworld
Hello World

RapidMax
30-11-2003, 00:05
Nun soll das Programm eine weitere Funktion erhalten. Da es sich um Code handelt, der wiederverwertbar ist, soll ein eigens Modul entstehen, mit einem eigenen Verzeichnis und eingenem Makefile.am. Das Ganze soll dann zu einer statischen Bibliothek gelinkt werden und so vom Programm verwendet werden. Wieder baue ich auf dem Beispiel oben auf.

Neuer Quelltext
Wir fügen dem Projekt nun folgende Dateien hinzu:


$ mkdir src/str
$ touch src/str/Makefile.am src/str/str.h src/str/str.c

Der zugehörige Quelltext sieht wie folgt aus:


str/str.h:
#ifndef STR_H
#define STR_H
extern char* bigLetter(const char *str);
#endif

str/str.c:
#include <string.h>
#include <ctype.h>
#include "str.h"
char* bigLetter(const char *str) {
int i;
size_t len = strlen(str);
char *res = strdup(str);
for (i = 1; i < len; i++)
if (res[i-1] == ' ') res[ i ] = toupper(res[ i ]);
return res;
}

main.c (geändert):
#include <stdio.h>
#include <stdlib.h>
#include "talk.h"
#include "str/str.h"
int main() {
char *msg = "Another sensless sentence";
char *str;
sayHello();
printf(" World\n");
str = bigLetter(msg);
printf("Message: %s\n", str);
free(str);
return 0;
}


Makefiles
Um die Bibliothek zu bauen muss die src/str/Makefile.am wie folgt gefüllt werden:


## Process this file with automake to produce Makefile.in
# name of the library
noinst_LIBRARIES = libstr.a
INCLUDES = $(all_includes)
libstr_a_METASOURCES = AUTO
# source files
libstr_a_SOURCES = str.c
# headers to include in distribution
EXTRA_DIST = str.h

Hier sieht man gleich sehr schön, wie die Namensgebung läuft: Alle Sonderzeichen im Dateinamen (alles ausser Buchstaben und Ziffern) wird durch einen Underscore "_" ersetzt. Aus dem Punkt "." wird so ein "_".
Mit diesen Deklarationen wird eine Bibliothek erstellt, die nicht installiert wird. Für installierbare Libraries sollte auf Libtool zurückgegriffen werden.

Damit das Makefile aufgerufen wird und die Bibliothek mit gelinkt wird, muss das src/Makefile.am um die Zeilen ergänzt werden:


SUBDIRS = str
...
# add libraries
helloworld_LDADD = ./str/libstr.a


configure.in
Ebenso muss die configure.in angepasst werden. Hier sind noch weitere Anpassungen notwendig. Man beachte die neu hinzugefügten Header und Funktionen. Diese sind nicht 100% portierbar. Wenn wir jetzt nochmals autoscan über die Quellen laufen lassen, stellen wir fest, dass es diverse neue Tests hinzufügt. Wenn wir diese in die unsere configure.in übernehmen und bootstrap laufen lassen, meldet automake, dass der Test für ranlib fehlt. Ranlib ist für das Erstellen von Bibliotheks-Indizes zuständig (aber unter Linux nicht notwendig). Wenn wir auch noch diesen Test hinzufügen und das neue Makefile nicht vergessen, dann sieht unsere configure.in wie folgt aus:


# Process this file with autoconf to produce a configure script.
AC_INIT([hworld], [0.1.0], [user@host.de])
AC_CONFIG_AUX_DIR(config)
AC_CONFIG_SRCDIR([config.h.in])
AM_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE

# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_RANLIB
AC_PROG_AWK

# Checks for libraries.

# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h string.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T

# Checks for library functions.
AC_CHECK_FUNCS([strdup])

AC_CONFIG_FILES([Makefile
src/Makefile
src/str/Makefile])
AC_OUTPUT

Jetzt nicht vergessen ./config/bootstrap aufzurufen und ./configure neu durchlaufen zu lassen:


$ ./config/boostrap
$ ./configure && make
$ ./src/helloworld
Hello World
Message: Another Sensless Sentence

tuxipuxi
30-11-2003, 10:28
das buch, dass du genannt hast, ist auch frei im internet erhaeltlich unter:
http://sources.redhat.com/autobook/autobook/autobook_toc.html#SEC_Contents

gruss,
tuxipuxi.

alex
28-02-2004, 12:48
Und wie läuft das ganze dann bei einer shared library ab? Ich mein - da gibt es ja keine Bausführbare Datei, ist da BIN_NAME einfach der so-name?

[_El_ReSeT_]
28-05-2004, 20:35
Und wenn man doxygen als Dokumentations-Tool verwendet, kann man im Unterverzeichnis ../doc
folgendes als Makefile.am reinstellen: (Erstellung nur für HTML Files)

<code>
# Datei, die von Doxygen bearbeitet werden soll
EXTRA_DIST = tvDemo.dox
# Die zu reinigenden files
CLEANFILES = *.html *.gif *.css *.png
# zu erstellende Datei
noinst_PROGRAMS = index.html
# Sourcefile
index_html_SOURCES = tvDemo.dox
# ausfueren von Doxygen mit dem sourcefile
index.html: tvDemo.dox
doxygen $(srcdir)/tvDemo.dox
</code>

Damit jedoch, die Dateien nicht immer wieder neu generiert werden und auch löschbar sind muss man in seinem Doxygen File folgende Zeile folgendermaßen ändern:

HTML_OUTPUT = .