Die GNU autotools sind eine Sammlung von tools, die das Erstellen von angepassten Makefiles erleichtert.
Hier gibt es ein Mini-Howto zum Umgang mit diesen tools.
Für den Anfang starten wir mit dem einfachsten source code. Ein Programm, welches nur eine Zeile Text ausgibt und nur aus einer c Datei besteht:
#include <stdlib.h> #include <stdio.h> int main (void) { printf("hello.. :-)\n"); return 0; }Natürlich lässt sich so ein einfaches Beispiel direkt übersetzen, auch ohne Makefile:
gcc -o hello main.c
Wenn allerdings viele .c Dateien ins Spiel kommen oder Bibliotheken verlinkt werden müssen, dann wird es schon schwieriger.
Dann gilt es herauszufinden, wo die header Dateien der Bibliotheken liegen, wo die Bibliotheken selbst liegen,
welche Optionen der Linker dafür benötigt.
Noch schwieriger würde es mit den verschiedenen compilern, Varianten der Betriebssystem und Auswahl des Installationsortes.
Hier kommen dann Systeme wie die autotools oder cmake zur Anwendung.
Wenn wir ein configure script erstellen wollen, dann benötigen wir dafür eine Datei namens configure.in
aus der das configure script erstellt wird.
Dabei hilft autoscan, welches uns ein Template namens configure.scan aus unserem source code erstellt:
autoscan
Die erstellte Datei configure.scan sieht nun so aus:
# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) AC_CONFIG_SRCDIR([main.c]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. AC_CHECK_HEADERS([stdlib.h]) # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT
Diese Datei benennen wir nach configure.in um:
-bash-3.00# mv configure.scan configure.in -bash-3.00# ls -al insgesamt 12 drwxr-xr-x 2 root root 57 2. Apr 13:15 . drwxr-xr-x 5 root root 4096 2. Apr 13:05 .. -rw-r--r-- 1 root root 0 2. Apr 13:09 autoscan.log -rw-r--r-- 1 root root 495 2. Apr 13:09 configure.in -rw-r--r-- 1 root root 101 2. Apr 11:42 main.c
Jetzt wird configure.in editiert, indem
# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) # our program is called 'hello', its version is 0.0.1; # the address for bug reports is 'deine.emailadresse@deinedomain.de' AC_INIT([hello], [0.0.1], [deine.emailadresse@deinedomain.de]) # prepare for automake AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([main.c]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) # Checks for programs. # we're using the C compiler AC_PROG_CC # AC_PROG_CXX # AC_PROG_OBJC, # AM_PROG_AS # AM_PROG_GCJ # AM_PROG_UPC # Checks for libraries. # Checks for header files. AC_CHECK_HEADERS([stdlib.h]) # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_OUTPUT
Jetzt benutzen wir aclocal, um aclocal.m4 zu erstellen.
aclocal scannt configure.in (wir hätten diese Datei auch configure.ac nennen können)
und schreibt die dort von uns verwendeten macros in die Datei aclocal.m4.
Jedesmal wenn configure.in erweitert wurde, muss also aclocal ausgeführt werden.
-bash-3.00# aclocal -bash-3.00# ls -al insgesamt 48 drwxr-xr-x 3 root root 95 2. Apr 13:37 . drwxr-xr-x 5 root root 4096 2. Apr 13:05 .. -rw-r--r-- 1 root root 33817 2. Apr 13:37 aclocal.m4 drwxr-xr-x 2 root root 51 2. Apr 13:37 autom4te.cache -rw-r--r-- 1 root root 0 2. Apr 13:09 autoscan.log -rw-r--r-- 1 root root 789 2. Apr 13:22 configure.in -rw-r--r-- 1 root root 101 2. Apr 11:42 main.c
Als nächstes wird autoconf benutzt, um das configure script zu erstellen:
-bash-3.00# autoconf -bash-3.00# ls -al insgesamt 208 drwxr-xr-x 3 root root 111 2. Apr 13:39 . drwxr-xr-x 5 root root 4096 2. Apr 13:05 .. -rw-r--r-- 1 root root 33817 2. Apr 13:37 aclocal.m4 drwxr-xr-x 2 root root 81 2. Apr 13:39 autom4te.cache -rw-r--r-- 1 root root 0 2. Apr 13:09 autoscan.log -rwxr-xr-x 1 root root 163596 2. Apr 13:39 configure -rw-r--r-- 1 root root 789 2. Apr 13:22 configure.in -rw-r--r-- 1 root root 101 2. Apr 11:42 main.c
Viele Programme nutzen eine Datei config.h, in der definiert ist, welche header Dateien und Libraries auf dem Zielsystem vorhanden sind.
Das configure script script prüft die Datei config.h.in und ersetzt darin die gefundenen
#undef HAVE_<ID>mit
#define HAVE<ID>falls vorhanden. Ein Template erstellt uns autoheader aus unserer configure.in:
-bash-3.00# autoheader -bash-3.00# ls -al insgesamt 212 drwxr-xr-x 3 root root 129 2. Apr 13:59 . drwxr-xr-x 5 root root 4096 2. Apr 13:05 .. -rw-r--r-- 1 root root 33817 2. Apr 13:37 aclocal.m4 drwxr-xr-x 2 root root 81 2. Apr 13:39 autom4te.cache -rw-r--r-- 1 root root 0 2. Apr 13:09 autoscan.log -rw-r--r-- 1 root root 1369 2. Apr 13:44 config.h.in -rwxr-xr-x 1 root root 163596 2. Apr 13:39 configure -rw-r--r-- 1 root root 789 2. Apr 13:22 configure.in -rw-r--r-- 1 root root 101 2. Apr 11:42 main.c
Die erzeugte config.h.in sieht nun so aus:
/* config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if you have theheader file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Name of package */ #undef PACKAGE /* 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 version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION
Nachdem soweit nun fast alles automatisch erzeugt werden konnte, wird es jetzt Zeit etwas selbst zu tun.
Die Datei Makefile.am muss erstellt werden. Der wichtigste Inhalt der Datei ist, welche source code Dateien zu welchem Programm gehören.
Zeilen mit einer Raute '#' sind Kommentare.
# Makefile.am example AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip bin_PROGRAMS = hello hello_SOURCES = main.c
Anschließend führen wir automake aus,
um aus Makefile.am das Template für das Makefile Makefile.in zu erzeugen:
-bash-3.00# touch {NEWS,README,AUTHORS,ChangeLog} -bash-3.00# automake --add-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. -bash-3.00# ls -al insgesamt 240 drwxr-xr-x 3 root root 4096 2. Apr 14:16 . drwxr-xr-x 5 root root 4096 2. Apr 13:05 .. -rw-r--r-- 1 root root 33817 2. Apr 13:37 aclocal.m4 -rw-r--r-- 1 root root 0 2. Apr 14:15 AUTHORS drwxr-xr-x 2 root root 81 2. Apr 13:39 autom4te.cache -rw-r--r-- 1 root root 0 2. Apr 13:09 autoscan.log -rw-r--r-- 1 root root 0 2. Apr 14:15 ChangeLog -rw-r--r-- 1 root root 1369 2. Apr 13:44 config.h.in -rwxr-xr-x 1 root root 163596 2. Apr 13:39 configure -rw-r--r-- 1 root root 789 2. Apr 13:22 configure.in lrwxrwxrwx 1 root root 33 2. Apr 14:16 COPYING -> /usr/share/automake-1.10b/COPYING lrwxrwxrwx 1 root root 33 2. Apr 14:16 INSTALL -> /usr/share/automake-1.10b/INSTALL -rw-r--r-- 1 root root 101 2. Apr 11:42 main.c -rwxr--r-- 1 root root 109 2. Apr 14:09 Makefile.am -rw-r--r-- 1 root root 19400 2. Apr 14:16 Makefile.in -rw-r--r-- 1 root root 0 2. Apr 14:15 NEWS -rw-r--r-- 1 root root 0 2. Apr 14:15 README
Das Paket ist nun fertig vorbereitet, Zeit für einen Test.
-bash-3.00# ./configure --prefix=/usr checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... 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 checking for style of include used by make... GNU checking dependency style of gcc... gcc3 checking how to run the C preprocessor... gcc -E checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for ANSI C header files... yes checking for sys/types.h... yes checking for sys/stat.h... yes checking for stdlib.h... yes checking for string.h... yes checking for memory.h... yes checking for strings.h... yes checking for inttypes.h... yes checking for stdint.h... yes checking for unistd.h... yes checking for stdlib.h... (cached) yes configure: creating ./config.status config.status: creating Makefile config.status: creating config.h config.status: executing depfiles commands -bash-3.00# make make all-am make[1]: Entering directory `/usr/src/autotools_howto' gcc -DHAVE_CONFIG_H -I. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c mv -f .deps/main.Tpo .deps/main.Po gcc -g -O2 -o hello main.o make[1]: Leaving directory `/usr/src/autotools_howto'
Perfekt. Unser source code compiliert ohne Probleme und die Datei config.h wird ebenso erstellt.
Aber wie macht man daraus nun ein Paket, welches man zum Download anbieten kann? Dafür gibt es das make Target 'make dist'.
-bash-3.00# make dist { test ! -d "hello-0.0.1" || { find "hello-0.0.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-0.0.1"; }; } test -d "hello-0.0.1" || mkdir "hello-0.0.1" find "hello-0.0.1" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/sh /usr/src/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "hello-0.0.1" tardir=hello-0.0.1 && /bin/sh /usr/src/missing --run tar chof - "$tardir" | bzip2 -9 -c >hello-0.0.1.tar.bz2 { test ! -d "hello-0.0.1" || { find "hello-0.0.1" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-0.0.1"; }; }
Nach dem 'make dist' findet sich ein Paket hello-0.0.1.tar.bz2 im Ordner. Hier endet das erste Beispiel.
Das tool 'scan' aus dem linuxtv-dvb-apps Paket hat kein configure script und ist deswegen ideal als zweites Beispiel.
Das original Makefile wird nicht benötigt und wird deswegen gelöscht.
wget http://linuxtv.org/hg/dvb-apps/archive/tip.tar.bz2 tar xfj tip.tar.bz2 cd dvb-apps-<VERSION>/util/scan rm Makefile
Als erstes wird autoscan aufgerufen und configure.in erzeugt.
-bash-3.00# autoscan -I atsc -bash-3.00# mv configure.scan configure.in
Nach dem Editieren sieht configure.in so aus:
# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([scan], [cvs-7de0663facd9], [http://www.linuxtv.org]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([scan.c]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/ioctl.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_ERROR_AT_LINE AC_FUNC_MALLOC AC_CHECK_FUNCS([memset strcasecmp strdup strtoul]) AC_OUTPUT
Wie im ersten Beispiel werden aclocal, autoheader und autoconf ausgeführt.
-bash-3.00# aclocal -bash-3.00# autoheader -bash-3.00# autoconf
Wir benötigen die Dateien COPYING, README, INSTALL,..
COPYING wird zur originalen Datei verlinkt. INSTALL wird neu erzeugt,
da die Installation mit configure script etwas anders verläuft als mit dem originalen Makefile.
-bash-3.00# ln -s ../../COPYING . -bash-3.00# touch {NEWS,README,AUTHORS,ChangeLog}
Natürlich wird auch wieder ein Makefile.am benötigt:
-bash-3.00# export PACKAGE="scan" -bash-3.00# export PACKAGE_OWNER="http://www.linuxtv.org" -bash-3.00# SRCFILES=$(ls *.{c,h}) -bash-3.00# echo "# Makefile.am for $PACKAGE" >> Makefile.am -bash-3.00# echo "# please send bug reports to $PACKAGE_OWNER" >> Makefile.am -bash-3.00# echo "#" >> Makefile.am -bash-3.00# echo "#" >> Makefile.am -bash-3.00# echo "AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip" >> Makefile.am -bash-3.00# echo "bin_PROGRAMS = $PACKAGE" >> Makefile.am -bash-3.00# echo -n $PACKAGE"_SOURCES =" >> Makefile.am -bash-3.00# for source in $SRCFILES; do -bash-3.00# echo -n " $source" >> Makefile.am -bash-3.00# done -bash-3.00# echo "" >> Makefile.am
Unser fertiges Makefile.am wird noch um atsc_psip_section.(c/h) erweitert, die erst vom Makefile erstellt werden.
-bash-3.00# more Makefile.am # Makefile.am for scan # please send bug reports to http://www.linuxtv.org # # AUTOMAKE_OPTIONS= dist-bzip2 no-dist-gzip bin_PROGRAMS= atsc_psip_section.h scan scan_SOURCES= diseqc.c diseqc.h dump-vdr.c dump-vdr.h dump-zap.c dump-zap.h list.h lnb.c lnb.h scan.c scan.h section.c section.h scan_SOURCES+=atsc_psip_section.c atsc_psip_section.h: perl section_generate.pl atsc_psip_section.pl make CLEANFILES = atsc_psip_section.c atsc_psip_section.h
HINWEIS: Es gibt diesmal zwei Makefile Targets, atsc_psip_section.h und scan.
Zuerst wird perl section_generate.pl atsc_psip_section.pl
aufgerufen, um atsc_psip_section.(c,h) zu generieren.
Danach ruft das Makefile sich selbst auf, beim zweiten Aufruf wird jedoch das erste Target atsc_psip_section.h ausgelassen,
weil diese Datei bereits vorhanden und aktuell ist.
Nachdem die Vorarbeiten fertig sind, kann mit automake Makefile.in erzeugt werden.
Die Option --add-missing kopiert bzw. verlinkt fehlende Dateien wie INSTALL und COPYING (default: GPL).
-bash-3.00# automake --add-missing configure.in:6: installing `./install-sh' configure.in:6: installing `./missing' Makefile.am: installing `./INSTALL' Makefile.am: installing `./depcomp'
Als letztes nun noch Test und Erzeugung des Pakets.
-bash-3.00# ./configure -bash-3.00# make make all-am make[1]: Entering directory `/usr/src/autotools_test/test/dvb-apps-7de0663facd9/util/scan' perl section_generate.pl atsc_psip_section.pl make make[2]: Entering directory `/usr/src/autotools_test/test/dvb-apps-7de0663facd9/util/scan' make all-am make[3]: Entering directory `/usr/src/autotools_test/test/dvb-apps-7de0663facd9/util/scan' gcc -DHAVE_CONFIG_H -I. -g -O2 -MT diseqc.o -MD -MP -MF .deps/diseqc.Tpo -c -o diseqc.o diseqc.c mv -f .deps/diseqc.Tpo .deps/diseqc.Po gcc -DHAVE_CONFIG_H -I. -g -O2 -MT dump-vdr.o -MD -MP -MF .deps/dump-vdr.Tpo -c -o dump-vdr.o dump-vdr.c mv -f .deps/dump-vdr.Tpo .deps/dump-vdr.Po gcc -DHAVE_CONFIG_H -I. -g -O2 -MT dump-zap.o -MD -MP -MF .deps/dump-zap.Tpo -c -o dump-zap.o dump-zap.c mv -f .deps/dump-zap.Tpo .deps/dump-zap.Po gcc -DHAVE_CONFIG_H -I. -g -O2 -MT lnb.o -MD -MP -MF .deps/lnb.Tpo -c -o lnb.o lnb.c mv -f .deps/lnb.Tpo .deps/lnb.Po gcc -DHAVE_CONFIG_H -I. -g -O2 -MT scan.o -MD -MP -MF .deps/scan.Tpo -c -o scan.o scan.c mv -f .deps/scan.Tpo .deps/scan.Po gcc -DHAVE_CONFIG_H -I. -g -O2 -MT section.o -MD -MP -MF .deps/section.Tpo -c -o section.o section.c mv -f .deps/section.Tpo .deps/section.Po gcc -DHAVE_CONFIG_H -I. -g -O2 -MT atsc_psip_section.o -MD -MP -MF .deps/atsc_psip_section.Tpo -c -o atsc_psip_section.o atsc_psip_section.c mv -f .deps/atsc_psip_section.Tpo .deps/atsc_psip_section.Po gcc -g -O2 -o scan diseqc.o dump-vdr.o dump-zap.o lnb.o scan.o section.o atsc_psip_section.o make[3]: Leaving directory `/usr/src/autotools_test/test/dvb-apps-7de0663facd9/util/scan' make[2]: Leaving directory `/usr/src/autotools_test/test/dvb-apps-7de0663facd9/util/scan' make[1]: Leaving directory `/usr/src/autotools_test/test/dvb-apps-7de0663facd9/util/scan' -bash-3.00# make dist { test ! -d "scan-cvs-7de0663facd9" || { find "scan-cvs-7de0663facd9" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "scan-cvs-7de0663facd9"; }; } test -d "scan-cvs-7de0663facd9" || mkdir "scan-cvs-7de0663facd9" find "scan-cvs-7de0663facd9" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec /bin/sh /usr/src/autotools_test/test/dvb-apps-7de0663facd9/util/scan/install-sh -c -m a+r {} {} \; \ || chmod -R a+r "scan-cvs-7de0663facd9" tardir=scan-cvs-7de0663facd9 && /bin/sh /usr/src/autotools_test/test/dvb-apps-7de0663facd9/util/scan/missing --run tar chof - "$tardir" | bzip2 -9 -c >scan-cvs-7de0663facd9.tar.bz2 { test ! -d "scan-cvs-7de0663facd9" || { find "scan-cvs-7de0663facd9" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "scan-cvs-7de0663facd9"; }; }