Have you ever wondered why so many files are shipped in a software source tarball for Linux? Or dreamt of making your own newly developed package highly portable across various Linux platforms? This article gives you a basic idea of how package makers/maintainers port their code to various platforms without too many changes to their code.
You’ve probably downloaded various package sources from the Internet and compiled (built) them when required to do so. The common steps are ./configure, make and sudo make install. If you just need to use a package, then these steps are usually sufficientbut its different if you are a package developer/maintainer. Besides designing and coding to develop the program, you need it to be able to port packages to various Linux-like platforms. Trust me: sometimes the second task is far tougher, if not handled properly.
Portability and GNU Autotools
Before going into the details, what is portability? Heres one possible definition: if you can write your code so that it can be run on a different environment without much effort, then your code is portable. There are factors that reduce code portability, like the differences in processors, operating systems, preprocessors, compilers, etc. Moreover, floating point issues, availability of dynamic libraries, differences in file-systems, etc, make portability a much bigger challenge. Linux supports different architectures. Sometimes its not possible to run a binary copied from another Linux machine; it needs to be compiled/built and installed on the target PCwhich sometimes requires more than just configure, make and make install.
Here’s where GNU Autotools comes in; it may increase your projects’ portability many times overeven to systems on which you have never run and tested your code. So, if you are planning to write an open source package targeting the UNIX/Linux platform, your best choice is to use GNU Autotools. If you’re only targeting Windows and will never need to port to Linux/UNIX in the future, then you can safely refrain from using Autotools.
GNU Autotools offers three main tools:
Autoconf, which is used to create the configure script automatically.
Automake, which is used to create flexible and consistent Makefiles.
Libtool, which helps create portable shared libraries.
Here, I will focus only on Autoconf and Automake.
Autoconf provides native support for C, C++, Objective C, Fortran, etc. Native support for Java is still not available in Autotools.
Configuring your project with Autoconf
The main purpose of using Autoconf is to generate a configure script suitable for the target system. Why we need a configure script is for portability. Although all Linux variants are similar, they aren’t identical. They have slightly different sets of header files, different lists of functions in the system libraries, etc. So, its the developers responsibility to check and resolve all these differences via a configuration script. The configure script generally performs different system-level capability checks, including machine information (host-name, version, etc), programs (bison, lex, etc), libraries, header files, typedefs, structures, compiler characteristics and library functions. Lets see how we can create a configure script using autoconf, with the simplest possible code:
/* hello_world.c */
#include<stdio.h>
int main(void)
{
printf(“hello world\n”);
return 0;
}
Our Makefile will look something like this:
all: hello_world
clean:
rm -rf hello_world
Now run the following commands:
$ autoscan
$ ls
autoscan.log configure.scan hello_world.c Makefile
$ mv configure.scan configure.ac
$ autoheader
$ ls
autom4te.cache autoscan.log config.h.in configure.ac hello_world.c Makefile
$ autoconf
$ ls
autom4te.cache autoscan.log config.h.in configure configure.ac hello_world.c Makefile
As you can see, autoconf has completed its work; configure and config.h.in have been created, as shown in Figure 1. (Files and commands in brackets in the figure are optional.) Autoconf includes the programs autoheader, autom4te, autoreconf, autoscan, autoupdate and ifnames. You can check the autoconf manual to learn about each program.
Now you are ready to run ./configure:
$ ./configure
checking for gcc… gcc
checking whether the C compiler works… yes
checking for C compiler default output file name… a.out
checking for suffix of executables…
checking whether we are cross compiling… no
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
configure: creating ./config.status
config.status: error: cannot find input file: `Makefile.in’
$ ls
autom4te.cache autoscan.log config.h.in config.log config.status configure configure.ac hello_world.c Makefile
Wait! You can’t run configure yet because it needs Makefile.in as input. How do we get Makefile.in? Let’s go a step further.
Using Automake
We can use automake to generate Makefile.in automatically, which in turn creates a portable Makefile (refer to Figure 2). First, create a Makefile.am; this can’t be done automatically, so use the simplest Makefile.am of two lines:
bin_PROGRAMS = hello _world
hello_world_SOURCES = hello_world.c
Edit configure.ac and add AM_INIT_AUTOMAKE below the AC_INIT directive. Next, use the following commands:
$ aclocal
$ automake –add-missing
$ touch NEWS README AUTHORS ChangeLog
$ ls
aclocal.m4 autom4te.cache ChangeLog config.log configure COPYING hello.c install-sh missing README AUTHORS autoscan.log config.h.in config.status configure.ac depcomp INSTALL Makefile.am NEWS
$ automake
$ ls
aclocal.m4 autom4te.cache ChangeLog config.log configure COPYING hello.c install-sh Makefile.in NEWS AUTHORS autoscan.log config.h.in config.status configure.ac depcomp INSTALL Makefile.am missing README
So, Makefile.in has been automatically created using automake.
Bringing together autoconf and automake
Let’s now do the steps once again with autoconf and automake. Create hello_world.c and Makefile.am as described above. Then run the following:
$ autoscan
$ mv configure.scan configure.ac
$ autoheader
Edit your configure.ac and add AM_INIT_AUTOMAKE. Then run the following:
$ aclocal
$ automake add-missing
$ touch NEWS README AUTHORS ChangeLog
$ automake
$ autoconf
$ ./configure
$ make
$ ./hello_world
What’s next?
Here I discussed a trivial hello world program, which doesn’t actually represent Autotools complexity nor the portability gained by using it. Instead, I described how to use Autotools. When you create your own code, you can add portability in the way described above.
References
[1] Autoconf manual: http://www.gnu.org/software/autoconf
manual/autoconf.html
[2] Automake manual: http://www.gnu.org/software/automake/
anual/automake.html
[3] Autotools: A Practitioner’s Guide to GNU Autoconf,
Automake, and Libtool, by John Calcote
[4] http://markuskimius.wikidot.com/programming:tut:autotools