Ausgetrickst

Gnu-Tools wie automake erleichtern Entwicklern die Arbeit erheblich. Auf der Anwenderseite verursachen sie jedoch gelegentlich Schwierigkeiten – die man mit ein paar Tricks umgehen kann.

vorlesen Druckansicht
Lesezeit: 4 Min.
Von
  • Michael Riepe

Trotz zahlreicher Alternativen verwenden viele Entwickler von Open-Source-Software immer noch make, um ihre Programme zu übersetzen. Allerdings schreiben sie die Makefiles immer seltener selbst. Stattdessen setzen sie meist die Gnu-Tools automake und autoconf ein.

Während automake dem Entwickler die Arbeit enorm erleichtert, hält es für den Anwender einige Tücken bereit. So enthält ein von automake generiertes Makefile nicht nur die Übersetzungsregeln, sondern auch Anweisungen, wie das Makefile selbst neu zu generieren ist. Die schlagen immer dann zu, wenn die Zeitstempel der betroffenen Dateien durcheinander geraten – etwa beim Kopieren der Dateien oder beim Einspielen von Patches. Aber auch, wenn das Arbeitsverzeichnis per NFS gemountet ist und die Uhren von Client und Server nicht synchron laufen.

Hat man die passenden Werkzeuge installiert, generiert make in so einem Fall zuerst die gesamte Übersetzungs-Infrastruktur neu: Aus jedem Makefile.am entsteht ein Makefile.in, aus configure.in oder configure.ac sowie dem ebenfalls automatisch erzeugten aclocal.m4 baut autoconf ein neues configure zusammen. Das startet anschließend erneut, um aus jedem modifizierten Makefile.in ein neues, aktuelles Makefile zu erzeugen.

Dabei kann allerhand schiefgehen – vor allem, wenn der Nutzer andere Versionen von automake und autoconf installiert hat als der Entwickler. Oft sind die generierten Makefiles unbrauchbar. Auch beschwert sich autoconf häufig über undefinierte Makros, weil der Erneuerungsprozess ein unvollständiges aclocal.m4 erzeugt hat. In dem Fall schlägt generell auch der erneute configure-Lauf fehl – die Software lässt sich nicht mehr übersetzen.

Zwar kann man falsche Zeitstempel oft mit dem Befehl make –t korrigieren: Statt die gewünschten Dateien neu zu übersetzen, setzt das Kommando einfach ihre mtime auf die aktuelle Uhrzeit. Das funktioniert jedoch nicht beim Makefile selbst oder bei den Dateien, aus denen es entsteht, weil make darauf besteht, sie zu aktualisieren, bevor es mit der eigentlichen Arbeit beginnt.

Will der Nutzer automake ein Schnippchen schlagen, muss er daher selbst Hand anlegen – etwa indem er die Zeitstempel der „veralteten“ Dateien mit dem Programm touch neu setzt. Allerdings muss er dabei Vorsicht walten lassen: touch legt normalerweise Dateien an, falls sie noch nicht existieren. Bei der Gnu-Version kann man dem mit der Option –c entgegenwirken.

Eine Liste der zu „berührenden“ Dateien kann man mit find zusammenstellen. Es empfiehlt sich jedoch, nicht nach den Zieldateien – etwa Makefile.in – zu suchen, sondern nach den Ursprungsdateien, aus denen sie entstehen. Anschließend kann man mit sed die Namen ändern (siehe Listing 1).

Neben Makefiles kann configure auch Header-Dateien mit Definitionen erzeugen, die sich direkt in C/C++-Code einbinden lassen. Gewöhnlich hören sie auf den Namen config.h. Das Programm autoheader erzeugt dazu ein passendes Template, in der Regel config.h.in. Der Entwickler kann jedoch in configure.in beziehungsweise configure.ac beliebige Namen vorgeben. Die Zeile AC_CONFIG_HEADER(defs.h) etwa veranlasst autoheader, eine Datei defs.h.in zu erstellen, aus der später defs.h entsteht. Soll die Template-Datei zum Beispiel defs.in heißen, kann man ihren Namen mit einem Doppelpunkt getrennt anhängen: defs.h:defs.in.

Da configure.in und configure.ac für den Unix-Makroprozessor m4 geschrieben sind, bietet es sich an, auch die Namen der Templates mit einem m4-Skript zu extrahieren (siehe Listing 2). Der Befehl sinclude bindet eine andere Datei ein, sofern sie existiert. Mit divert lässt sich die Ausgabe dirigieren: divert(0) schickt den folgenden Text zur Standardausgabe, divert(-1) ins digitale Nirvana. dnl leitet einen einzeiligen Kommentar ein. In der Ausgabe des Skripts erscheinen daher nur die Argumente der vorher definierten Makros.

Die for-Schleife in der Shell-Funktion findfiles bereitet die gelieferten Namen auf. Damit der Aufruf von m4 funktioniert, müssen die Skripte im selben Verzeichnis liegen und – bis auf die zusätzliche Endung .m4 – denselben Namen besitzen. Beim Autor leisten die beiden als autofool und autofool.m4 seit Jahren gute Dienste.

Mehr Infos

Listing 1

Ein einfaches Shell-Skript setzt die Zeitstempel der gewünschten Dateien neu.

findfiles() {
find . -name aclocal.m4 -print
find . -name configure.in -print | sed 's,\.in$,,'
find . -name configure.ac -print | sed 's,\.ac$,,'
find . -name Makefile.am -print | sed 's,\.am$,.in,'
for f in $(m4 $0.m4); do
case $f in
(*:*) echo ${f#*:};;
(*) echo $f.in;;
esac
done
}
touch -c $(findfiles)
Mehr Infos

Listing 2

Die zusätzlich benötigten Dateinamen lassen sich mit wenigen Zeilen m4-Code extrahieren.

divert(-1)
define(`AC_CONFIG_HEADERS', `divert(0)'$1
`divert(-1)')dnl
define(`AC_CONFIG_HEADER', `divert(0)'$1
`divert(-1)')dnl
define(`AM_CONFIG_HEADER', `divert(0)'$1
`divert(-1)')dnl
changequote([, ])
sinclude(configure.in)
sinclude(configure.ac)
divert(0)dnl

(mr)