You are on page 1of 40

Autoconf/Automake Basics

Speaker: Mark K. Kim Linux Users' Group of Davis March 2, 2004


Slide modified slightly after the talk to fix some errors and add some minor information

The portability problem

Hardware differences

Endian-ness Word size Executable file names Device file names File name conventions Compiler name & arguments Header file names & definitions Keywords

OS differences

Compiler differences

Why use Autoconf/Automake?

Portability Code reuse Professional look

What does it look like?


$./configure checkingforaBSDcompatibleinstall.../usr/bin/installc checkingwhetherbuildenvironmentissane...yes checkingforgawk...gawk checkingwhethermakesets${MAKE}...yes checkingforgcc...gcc ... $make makeallrecursive make[1]:Enteringdirectory`/home/vindaci/orgs/lugod/20040302autotools_talk/con trib/hello2.1.1' Makingallincontrib ... $su Password: #makeinstall setfnord$MAKEFLAGS;amf=$2;\ dot_seen=no;\ target=`echoinstallrecursive|seds/recursive//`;\ list='contribdocintlposrcmanm4tests';forsubdirin$list;do\ ... #

Writing a C program the code


/*hello.c:Astandard"Hello,world!"program*/ #include<stdio.h> intmain(intargc,char*argv[]) { printf("Hello,world!\n"); return0; }
#Makefile:AstandardMakefileforhello.c all:hello clean: rmfhello

Writing a C program the execution


$ls Makefilehello.c $make cchello.cohello $ls Makefilehello*hello.c $./hello Hello,world! $

Creating `configure` - The steps

`configure` is created from configure.ac (using `autoconf`) configure.ac can be created automatically (using `autoscan`)

Creating `configure` - The first try (1/2)


$ls hello.cMakefile $autoscan $ls autoscan.logconfigure.scanhello.cMakefile $mvconfigure.scanconfigure.ac $autoconf $ls autom4te.cache/configure*hello.c autoscan.logconfigure.acMakefile $

Creating `configure` - The first try (2/2)


$./configure checkingforgcc...gcc checkingforCcompilerdefaultoutputfilename...a.out checkingwhethertheCcompilerworks...yes checkingwhetherwearecrosscompiling...no checkingforsuffixofexecutables... checkingforsuffixofobjectfiles...o checkingwhetherweareusingtheGNUCcompiler...yes checkingwhethergccacceptsg...yes checkingforgccoptiontoacceptANSIC...noneneeded configure:creating./config.status config.status:error:cannotfindinputfile:Makefile.in $

Creating `configure` - The first try (2/2)


$./configure checkingforgcc...gcc checkingforCcompilerdefaultoutputfilename...a.out checkingwhethertheCcompilerworks...yes checkingwhetherwearecrosscompiling...no checkingforsuffixofexecutables... checkingforsuffixofobjectfiles...o checkingwhetherweareusingtheGNUCcompiler...yes checkingwhethergccacceptsg...yes checkingforgccoptiontoacceptANSIC...noneneeded configure:creating./config.status config.status:error:cannotfindinputfile:Makefile.in $mvMakefileMakefile.in $

Creating `configure` - The second try (1/2)


$mvMakefileMakefile.in $./configure checkingforgcc...gcc checkingforCcompilerdefaultoutputfilename...a.out checkingwhethertheCcompilerworks...yes checkingwhetherwearecrosscompiling...no checkingforsuffixofexecutables... checkingforsuffixofobjectfiles...o checkingwhetherweareusingtheGNUCcompiler...yes checkingwhethergccacceptsg...yes checkingforgccoptiontoacceptANSIC...noneneeded configure:creating./config.status config.status:creatingMakefile config.status:creatingconfig.h config.status:error:cannotfindinputfile:config.h.in $

Creating `configure` - The second try (2/2)


$ls autom4te.cache/config.status*hello.c autoscan.logconfigure*Makefile config.logconfigure.acMakefile.in $make ccsO2Wallhello.cohello $./hello Hello,world! $

Recap Creating `configure`

Creating `configure`:
1) Prepare sources and the Makefile.in 2) Run `autoscan` 3) Rename configure.scan to configure.ac 4) Run `autoconf` 5) ./configure 6) make

Still to consider:
1) Creating Makefile.in using Automake 2) Creating config.h.in 3) Using config.h to make our program portable

What is configure.ac?
#*Autoconf* #Processthisfilewithautoconftoproduceaconfigurescript. AC_PREREQ(2.59) AC_INIT(FULLPACKAGENAME,VERSION,BUGREPORTADDRESS) AC_CONFIG_SRCDIR([hello.c]) AC_CONFIG_HEADER([config.h]) #Checksforprograms. AC_PROG_CC #Checksforlibraries. #Checksforheaderfiles. #Checksfortypedefs,structures,andcompilercharacteristics. #Checksforlibraryfunctions. AC_CONFIG_FILES([Makefile]) AC_OUTPUT

What is configure?
#!/bin/sh #GuessvaluesforsystemdependentvariablesandcreateMakefiles. #GeneratedbyGNUAutoconf2.59forFULLPACKAGENAMEVERSION. # #Reportbugsto<BUGREPORTADDRESS>. # #Copyright(C)2003FreeSoftwareFoundation,Inc. #Thisconfigurescriptisfreesoftware;theFreeSoftwareFoundation #givesunlimitedpermissiontocopy,distributeandmodifyit. #### ##M4shInitialization.## #### #BeBournecompatible iftestn"${ZSH_VERSION+set}"&&(emulatesh)>/dev/null2>&1;then emulatesh NULLCMD=: #Zsh3.xand4.xperformswordsplittingon${1+"$@"},which #iscontrarytoourusage.Disablethisfeature. aliasg'${1+"$@"}'='"$@"' eliftestn"${BASH_VERSION+set}"&&(setoposix)>/dev/null2>&1;then setoposix fi DUALCASE=1;exportDUALCASE#forMKSsh

An example program the code


/*epoch.c:AprogramtoshowthetimesincetheEpoch*/ #include<stdio.h> #include<sys/time.h> intmain(intargc,char*argv[]) { doublesec; structtimevaltv; gettimeofday(&tv,NULL); sec=tv.tv_sec; sec+=tv.tv_usec/1000000.0; printf("%f\n",sec); return0; }

Example program the execution


#Makefile:AstandardMakefileforepoch.c all:epoch clean: rmfepoch

$ls epoch.cMakefile $make ccsO2Wallepoch.coepoch $./epoch 1077857890.903839 $

Portability problem!
gettimeofday() is not available on all systems!
GETTIMEOFDAY(2)LinuxProgrammersManualGETTIMEOFDAY(2) NAME gettimeofday,settimeofdayget/settime SYNOPSIS .............................................................................. CONFORMINGTO SVr4,BSD4.3.POSIX1003.12001describesgettimeofday()butnotset timeofday(). SEEALSO

Potential solution: Use time()


TIME(2)LinuxProgrammersManualTIME(2) NAME timegettimeinseconds SYNOPSIS #include<time.h> time_ttime(time_t*t); DESCRIPTION timereturnsthetimesincetheEpoch(00:00:00UTC,January1,1970), measuredinseconds. .............................................................................. CONFORMINGTO SVr4,SVID,POSIX,X/OPEN,BSD4.3 UnderBSD4.3,thiscallisobsoletedbygettimeofday(2).POSIXdoes notspecifyanyerrorconditions. SEEALSO

Better Solution

Use gettimeofday() if available. Fall back on time() if gettimeofday() is not available.

Better epoch.c The code


/*epoch.c:AprogramtoshowthetimesincetheEpoch*/ #include<stdio.h> #include<sys/time.h> #include<time.h> #include"config.h" intmain(intargc,char*argv[]) { printf("%f\n",get_epoch()); return0; } doubleget_epoch() { doublesec; #ifdefHAVE_GETTIMEOFDAY structtimevaltv; gettimeofday(&tv,NULL); sec=tv.tv_sec; sec+=tv.tv_usec/1000000.0; #else sec=time(NULL); #endif returnsec; }

Generating config.h

config.h is created by `configure` from config.h.in config.h.in is created by `autoheader` from the C sources and headers.

Sample session
$ls epoch.cMakefile $autoscan $ls autoscan.logconfigure.scanepoch.cMakefile $mvconfigure.scanconfigure.ac $ls autoscan.logconfigure.acepoch.cMakefile $autoheader $ls autom4te.cache/config.h.inepoch.c autoscan.logconfigure.acMakefile $mvMakefileMakefile.in $autoconf $ls autom4te.cache/config.h.inconfigure.acMakefile.in autoscan.log configure*epoch.c $./configure checkingforgcc...gcc checkingforCcompilerdefaultoutputfilename..a.out checkingwhethertheCcompilerworks...yes checkingwhetherwearecrosscompiling...no checkingforsuffixofexecutables... checkingforsuffixofobjectfiles...o checkingwhetherweareusingtheGNUCcompiler...yes checkingwhethergccacceptsg...yes checkingforgccoptiontoacceptANSIC...noneneeded checkinghowtoruntheCpreprocessor...gccE checkingforegrep...grepE checkingforANSICheaderfiles...yes checkingforsys/types.h...yes checkingforsys/stat.h...yes checkingforstdlib.h...yes checkingforstring.h...yes checkingformemory.h...yes checkingforstrings.h...yes checkingforinttypes.h...yes checkingforstdint.h...yes checkingforunistd.h...yes checkingsys/time.husability...yes checkingsys/time.hpresence...yes checkingforsys/time.h...yes checkingwhethertime.handsys/time.hmaybothbe included...yes checkingforgettimeofday...yes configure:creating./config.status config.status:creatingMakefile config.status:creatingconfig.h $ls autom4te.cache/config.h.inconfigure*Makefile autoscan.logconfig.logconfigure.acMakefile.in config.hconfig.status*epoch.c $make ccsO2Wallepoch.coepoch $ls autom4te.cache/config.h.inconfigure*epoch.c autoscan.logconfig.logconfigure.acMakefile config.hconfig.status*epoch*Makefile.in $./epoch 1077873582.855393 $

What is config.h?
/*config.h.Generatedbyconfigure.*/ /*config.h.in.Generatedfromconfigure.acbyautoheader.*/ /*Defineto1ifyouhavethe`gettimeofday'function.*/ #defineHAVE_GETTIMEOFDAY1 /*Defineto1ifyouhavethe<inttypes.h>headerfile.*/ #defineHAVE_INTTYPES_H1 /*Defineto1ifyouhavethe<memory.h>headerfile.*/ #defineHAVE_MEMORY_H1 /*Defineto1ifyouhavethe<stdint.h>headerfile.*/ #defineHAVE_STDINT_H1 /*Defineto1ifyouhavethe<stdlib.h>headerfile.*/ #defineHAVE_STDLIB_H1 /*Defineto1ifyouhavethe<strings.h>headerfile.*/ #defineHAVE_STRINGS_H1 /*Defineto1ifyouhavethe<string.h>headerfile.*/ #defineHAVE_STRING_H1 /*Defineto1ifyouhavethe<sys/stat.h>headerfile.*/ #defineHAVE_SYS_STAT_H1 /*Defineto1ifyouhavethe<sys/time.h>headerfile.*/ #defineHAVE_SYS_TIME_H1 /*Defineto1ifyouhavethe<sys/types.h>headerfile.*/ #defineHAVE_SYS_TYPES_H1 /*Defineto1ifyouhavethe<unistd.h>headerfile.*/ #defineHAVE_UNISTD_H1 /*Definetotheaddresswherebugreportsforthispackage shouldbesent.*/ #definePACKAGE_BUGREPORT"BUGREPORTADDRESS" /*Definetothefullnameofthispackage.*/ #definePACKAGE_NAME"FULLPACKAGENAME" /*Definetothefullnameandversionofthispackage.*/ #definePACKAGE_STRING"FULLPACKAGENAMEVERSION" /*Definetotheonesymbolshortnameofthispackage.*/ #definePACKAGE_TARNAME"fullpackagename" /*Definetotheversionofthispackage.*/ #definePACKAGE_VERSION"VERSION" /*Defineto1ifyouhavetheANSICheaderfiles.*/ #defineSTDC_HEADERS1 /*Defineto1ifyoucansafelyincludeboth<sys/time.h>and <time.h>.*/ #defineTIME_WITH_SYS_TIME1

Recap thus far...

autoscan Rename configure.scan to configure.ac autoheader Rename Makefile to Makefile.in autoconf ./configure make

Creating Makefile.in The steps

Create Makefile.am by hand Run `automake`

What is Makefile.am?
#Makefile.amforepoch.c bin_PROGRAMS=epoch epoch_SOURCES=epoch.c

Creating Makefile.in The first try


$ls epoch.cMakefile.am $autoscan $mvconfigure.scanconfigure.ac $autoheader $automake configure.ac:noproperinvocationofAM_INIT_AUTOMAKEwasfound. configure.ac:Youshouldverifythatconfigure.acinvokesAM_INIT_AUTOMAKE, configure.ac:thataclocal.m4ispresentinthetopleveldirectory, configure.ac:andthataclocal.m4wasrecentlyregenerated(usingaclocal). configure.ac:requiredfile`./installsh'notfound configure.ac:requiredfile`./mkinstalldirs'notfound configure.ac:requiredfile`./missing'notfound Makefile.am:requiredfile`./COPYING'notfound Makefile.am:requiredfile`./INSTALL'notfound Makefile.am:requiredfile`./NEWS'notfound Makefile.am:requiredfile`./README'notfound Makefile.am:requiredfile`./AUTHORS'notfound Makefile.am:requiredfile`./ChangeLog'notfound Makefile.am:requiredfile`./depcomp'notfound /usr/share/automake1.7/am/depend2.am:am__fastdepCCdoesnotappearinAM_CONDITIONAL /usr/share/automake1.7/am/depend2.am:AMDEPdoesnotappearinAM_CONDITIONAL $

What is AM_INIT_AUTOMAKE?
File:automake1.7.info,Node:Complete,Next:Hello,Prev:Examples,Up:E\ Asimpleexample,starttofinish ================================= Let'ssupposeyoujustfinishedwriting`zardoz',aprogramtomake yourheadfloatfromvortextovortex.You'vebeenusingAutoconfto provideaportabilityframework,butyour`Makefile.in'shavebeen adhoc.Youwanttomakethembulletproof,soyouturntoAutomake. Thefirststepistoupdateyour`configure.in'toincludethe commandsthat`automake'needs.Thewaytodothisistoaddan `AM_INIT_AUTOMAKE'calljustafter`AC_INIT': AC_INIT(zardoz,1.0) AM_INIT_AUTOMAKE ... Sinceyourprogramdoesn'thaveanycomplicatingfactors(e.g.,it doesn'tuse`gettext',itdoesn'twanttobuildasharedlibrary), you'redonewiththispart.Thatwaseasy! zzInfo:(automake1.7.info.gz)Complete,52linesTop

Dealing with AM_INIT_AUTOMAKE


1) Edit configure.ac 2) Run `aclocal` 3) automake 4) autoconf

Editing configure.ac
#*Autoconf* #Processthisfilewithautoconftoproduceaconfigurescript. AC_PREREQ(2.59) AC_INIT(FULLPACKAGENAME,VERSION,BUGREPORTADDRESS) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([epoch.c]) AC_CONFIG_HEADER([config.h]) #Checksforprograms. AC_PROG_CC #Checksforlibraries. #Checksforheaderfiles. AC_CHECK_HEADERS([sys/time.h]) #Checksfortypedefs,structures,andcompilercharacteristics. AC_HEADER_TIME #Checksforlibraryfunctions. AC_CHECK_FUNCS([gettimeofday]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT

Automake Sample session


$ls epoch.cMakefile.am $autoscan $mvconfigure.scanconfigure.ac $autoheader $viconfigure.ac $aclocal $automakeaddmissingcopy configure.ac:installing`./installsh' configure.ac:installing`./mkinstalldirs' configure.ac:installing`./missing' Makefile.am:installing`./COPYING' Makefile.am:installing`./INSTALL' Makefile.am:requiredfile`./NEWS'notfound Makefile.am:requiredfile`./README'notfound Makefile.am:requiredfile`./AUTHORS'notfound Makefile.am:requiredfile`./ChangeLog'notfound Makefile.am:installing`./depcomp' $autoconf $ls aclocal.m4config.h.inCOPYINGINSTALLMakefile.in autom4te.cache/configure*depcomp*installsh*missing* autoscan.logconfigure.acepoch.cMakefile.ammkinstalldirs* $

What is Makefile.in?
#Makefile.ingeneratedbyautomake1.7.9fromMakefile.am. #@configure_input@ #Copyright1994,1995,1996,1997,1998,1999,2000,2001,2002,2003 #FreeSoftwareFoundation,Inc. #ThisMakefile.inisfreesoftware;theFreeSoftwareFoundation #givesunlimitedpermissiontocopyand/ordistributeit, #withorwithoutmodifications,aslongasthisnoticeispreserved. #Thisprogramisdistributedinthehopethatitwillbeuseful, #butWITHOUTANYWARRANTY,totheextentpermittedbylaw;without #eventheimpliedwarrantyofMERCHANTABILITYorFITNESSFORA #PARTICULARPURPOSE. @SET_MAKE@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ VPATH=@srcdir@ pkgdatadir=$(datadir)/@PACKAGE@ pkglibdir=$(libdir)/@PACKAGE@ pkgincludedir=$(includedir)/@PACKAGE@ top_builddir=. am__cd=CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)"&&cd INSTALL=@INSTALL@ install_sh_DATA=$(install_sh)cm644 install_sh_PROGRAM=$(install_sh)c install_sh_SCRIPT=$(install_sh)c

./configure
$ls aclocal.m4config.h.inCOPYINGINSTALLMakefile.in autom4te.cache/configure*depcomp*installsh*missing* autoscan.logconfigure.acepoch.cMakefile.ammkinstalldirs* $./configure checkingforaBSDcompatibleinstall.../usr/bin/installc checkingwhetherbuildenvironmentissane...yes checkingforgawk...gawk checkingwhethermakesets$(MAKE)...yes checkingforgcc...gcc ... checkingsys/time.husability...yes checkingsys/time.hpresence...yes checkingforsys/time.h...yes checkingwhethertime.handsys/time.hmaybothbeincluded...yes checkingforgettimeofday...yes configure:creating./config.status config.status:creatingMakefile config.status:creatingconfig.h config.status:executingdepfilescommands $ls aclocal.m4config.h.inconfigure.acINSTALLMakefile.in autom4te.cache/config.logCOPYINGinstallsh*missing* autoscan.logconfig.status*depcomp*Makefilemkinstalldirs* config.hconfigure*epoch.cMakefile.amstamph1 $

What is in the Makefile?


#Makefile.ingeneratedbyautomake1.7.9fromMakefile.am. #Makefile.GeneratedfromMakefile.inbyconfigure. #Copyright1994,1995,1996,1997,1998,1999,2000,2001,2002,2003 #FreeSoftwareFoundation,Inc. #ThisMakefile.inisfreesoftware;theFreeSoftwareFoundation #givesunlimitedpermissiontocopyand/ordistributeit, #withorwithoutmodifications,aslongasthisnoticeispreserved. #Thisprogramisdistributedinthehopethatitwillbeuseful, #butWITHOUTANYWARRANTY,totheextentpermittedbylaw;without #eventheimpliedwarrantyofMERCHANTABILITYorFITNESSFORA #PARTICULARPURPOSE.

srcdir=. top_srcdir=. pkgdatadir=$(datadir)/fullpackagename pkglibdir=$(libdir)/fullpackagename pkgincludedir=$(includedir)/fullpackagename top_builddir=. am__cd=CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)"&&cd INSTALL=/usr/bin/installc install_sh_DATA=$(install_sh)cm644 install_sh_PROGRAM=$(install_sh)c install_sh_SCRIPT=$(install_sh)c

make and make install


$make cd.&&/bin/sh/home/vindaci/orgs/lugod/20040302 autotools_talk/examples/complete/missingrun autoheader touch./config.h.in cd.&&/bin/sh./config.statusconfig.h config.status:creatingconfig.h makeallam make[1]:Enteringdirectory `/home/vindaci/orgs/lugod/20040302 autotools_talk/examples/complete' ifgccDHAVE_CONFIG_HI.I.I.sO2Wall MTepoch.oMDMPMF".deps/epoch.Tpo"\ coepoch.o`testf'epoch.c'||echo './'`epoch.c;\ thenmvf".deps/epoch.Tpo"".deps/epoch.Po";\ elsermf".deps/epoch.Tpo";exit1;\ fi gccsO2Walloepochepoch.o make[1]:Leavingdirectory `/home/vindaci/orgs/lugod/20040302 autotools_talk/examples/complete' $makeinstalldryrun makeinstallexecaminstalldataam make[1]:Enteringdirectory `/home/vindaci/orgs/lugod/20040302 autotools_talk/examples/complete' : /bin/sh./mkinstalldirs/usr/local/bin list='epoch';forpin$list;do\ p1=`echo$p|sed's/$//'`;\ iftestf$p\ ;then\ f=`echo"$p1"|sed's,^.*/,,;s,x,x,;s/$//'`;\ echo"/usr/bin/installc$p/usr/local/bin/$f";\ /usr/bin/installc$p/usr/local/bin/$f||exit1;\ else:;fi;\ done make[1]:Nothingtobedonefor`installdataam'. make[1]:Leavingdirectory `/home/vindaci/orgs/lugod/20040302 autotools_talk/examples/complete' $ls aclocal.m4config.logepoch*Makefile.am autom4te.cache/config.status*epoch.cMakefile.in autoscan.logconfigure*epoch.omissing* config.hconfigure.acINSTALLmkinstalldirs* config.h.inCOPYINGinstallsh*stamph1 config.h.in~depcomp*Makefile $./epoch 1077932918.501751 $

The Ultimate Summary


1) Create sources, Makefile.am 2) `autoscan` 3) Rename configure.scan to configure.ac 4) `autoheader` 5) Add AM_INIT_AUTOMAKE to configure.ac 6) `aclocal` 7) `automakeaddmissingcopy` 8) `autoconf` 9) `./configure` 10) `make` 11) `makeinstall`

If you modify your source...


1) Run `autoscan` again 2) Compare configure.scan with configure.ac

Update configure.ac

3) Run `autoreconf`

Things to know...

Autoconf/Automake doesn't make a program portable YOU DO! Your program evolves to be more portable. You can add or write your own tests in m4. (Place them in acinclude.m4)

Resources

GNU Autoconf, Automake, and Libtool:

http://sources.redhat.com/autobook/

The GNU Autoconf Macro archive

http://www.gnu.org/software/ac-archive/

Autotools Tutorial for Beginners

http://www.cbreak.org/

You might also like