At some point, most Linux developers need to master Autotools. For most of us, this is a fairly painful process, but like any good tool, Autotools is extremely useful and well worth learning. For example, if your program is set up correctly using Autotools, it will cross compile with almost zero effort in OpenEmbedded, or with slight effort manually. Compare this to the tedious effort of manually referencing toolchain locations, cross toolchain library and header file locations, etc. Despite first impressions, Autotools will make your life easier. This article contains a collection of tips on how to do standard operations using Autotools.
Minimal Autotools files required for a simple C application
AC_INIT([fooprog], [1.0], [firstname.lastname@example.org]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AC_PROG_CC AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT
bin_PROGRAMS = foo foo_SOURCES = foo.c
The above files will create a binary name foo (compiled from foo.c) when you run the following steps:
- touch NEWS AUTHORS ChangeLog
- autoreconf -i
How to add libraries to the link step
For example, if you want to link in the pthread library to your application, add the following line to Makefile.am:
foo_LDADD = -lpthread
How to add compiler options
You can easily add compiler options using the foo_CFLAGS or foo_CPPFLAGS variables.
foo_CFLAGS = -DMY_DEFINE
How to use pkg-config in Autotools
pkg-config is a helper tool that gives you library and include file information for various libraries installed. For example, to link to alsa and glib in your project:
PKG_CHECK_MODULES(PACKAGE, alsa glib-2.0) AC_SUBST(PACKAGE_CFLAGS) AC_SUBST(PACKAG_LIBS)
foo_CFLAGS = @PACKAGE_CFLAGS@ foo_LDADD = @PACKAGE_LIBS@
How to add a command line option to the configure script
AC_ARG_ENABLE(option-foo, [ --enable-option-foo help for option foo], [CFLAGS="$CFLAGS -DOPTION_FOO_DEFINE"], )
The above example sets a define on the compiler command line if configure is run with the –enable-option-foo command line option.
Disable shared libraries in your project
Add the following to configure.ac:
Pass a variable from configure.ac to Makefile.am
Often there is a need to pass a variable in configure.ac to a Makefile. This is done with the AC_SUBST macro:
foo2 = @VAR_FOO@
Installing data files
By default, Autotools will install executables built when you run “make install”. To install other non-executable files, you need to tell autotools explicitly about those files. The standard place to install data files for an application is in $(datadir)/appname.
fooextradir = $(datadir)/@PACKAGE@
fooextra_DATA = \ foo_data1.txt \ foo_data2.txt
The above will install the foo_data1.txt and foo_data2.txt files in the $(datadir)/fooprog directory. $(datadir) is typically /usr/share/ or /usr/local/share, but it can be anything.
How does my program know where $(datadir) is located
Because $(datadir) can be anywhere in the system, we need some way to tell the program where it was specified to be at time of compilation so that it can locate foo_data1.txt and foo_data2.txt. This can be done by passing a define at compile time:
AM_CFLAGS = -DDATADIR=\"$(datadir)\"
How to install data files during development without cluttering up my system directories
If you use the above method to install data files needed by your project, you may run into a case during development where you want to run the program from the build directory, but the program needs the data files at run time. Since, the program is looking for them in the location specified by the DATADIR define, they need to be installed. You could just run “make install”, but this would install them into /usr/local/share, require you to run as root, and clutter up your system directories. A much more elegant solution is to specify the install prefix at configure time to be a temporary “install” directory in your source tree. The –prefix option for configure requires an absolute directory, so the `pwd` trick is used to figure out what the current directory is.
./configure --prefix=`pwd`/install make install
Your project will now be installed in a directory in your source tree named ./install. This is also a nice way to test that the install for the project is working correctly as you can easily see everything that gets installed. Now, the program has been compiled to reference extra files in ./install and will run just fine from the build directory.