Don’t Listen to the Autotools Haters
Being an avid C and Unix Geek, I decided to ignore all the hate out there about GNU Autotools and try it for myself. For those of you that don’t know the GNU Autotools suite consists of Autoconf, Automake and Libtool. You’ll see some major criticisms out there from people saying it’s way too complex, challenging, hard to use as well as all sorts of other criticisms. Let’s face it though, build systems are complex. I’ve used all sorts of them. Communities love to re-invent the wheel and build their own tool but at the end of the day to support everything is a massive endeavor.
My Approach to Learning Autotools
My approach was to first read the book Autotools by John Calcote. I will vouch for it being a good book with lots of great info. It definitely opens the mind and gives you a great idea for what is possible, the challenges for building user-space applications on Unix systems, issues around supporting all the different Unix platforms and how much flexibility you can build into an application to make it deployable on a large scale. What the book doesn’t help too much with is starting and using projects easily, and it is pretty easy. For this the plain old Automake Hello World really goes a long way. There are so many details out there; but this tutorial really made it easy for me. In this blog post I’ll basically go over the steps to create an Autotools Project.
My Reasons for Learning Autotools
Here are my reasons for learning Autotools:
- Gain a better understanding of build systems and the build process
- Gain a better understanding of the Unix System
- Gain a better system of the C libraries on Unix Systems
- Every Time I build a project where GNU Make is needed I end up re-inventing what Autotools already does. Using Autotools gives you a huge amount out of the box.
- Get the benefit of having C projects buildable, installable and portable on any Unix System
- Be able to integrate with many different C libraries and packages
The benefits you’ll get
If you’ve ever “built from source” or downloaded and installed a tarball you’ve basically used Autotools. It’s the famous 3 step process:
sudo make install
This basically ensures your system can build an application from source, then builds the application, then installs the application binaries that were built. This just touches the tip of the iceberg. With these 3 steps you can more or less rest assured any Unix user on any Unix platform can build and install the application using the standard 3 steps above. These steps are supported as convention by the entire Unix community to build and install from source.
An Example Hello World
Before we dive in there are a number of files you need to have for any autotools project to start
- README - where info goes about your project and you need it, and should have it anyways
- configure.ac - this file is basically M4 macros to expand create the glorious
- Makefile.am - this file is processed into a global Makefile and gives
automakea way to know where items like the source folder lies
- src/Makefile.am a makefile in your source folder with your C source
C files in the src folder - the actual code in your project
That’s not too bad right? You’ll get so much out of the box and only need 4 files. Let’s look inside each one:
A file explaining what our project is all about
A Hello World for Autotools
Where M4 Macros are placed to expand into our configure script
AC_INIT([athw], [1.0], [email@example.com]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AC_PROG_CC AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT
The top-level Makefile for your project.
SUBDIRS = src dist_doc_DATA = README
Source Level Makefile Macro src/Makefile.am
Source Level Makefile Macro.
bin_PROGRAMS = helloworld helloworld_SOURCES = main.c
The C Source for a Hello World
Initializing the Autotools Hello World Project
Now that we’ve gotten the boiler plate up and running let’s see what this new autotools system can do. From the GNU Hello World referenced above it tells us to run the following:
Once this command is run without errors you will see a good number of files now in your project directory including a Makefile at the top level as well as one in the src level. A configure script can also be found.
Configuring the Project
Great we’ve done a autoreconf and our project is setup. Now we can simply run our configure script. This script checks the build environment and ensures that we can build it. Let’s see the output from an Arch-Linux System:
$ ./configure checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /usr/bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking whether make supports nested variables... yes 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 checking whether gcc understands -c and -o together... yes checking whether make supports the include directive... yes (GNU style) checking dependency style of gcc... gcc3 checking that generated files are newer than configure... done configure: creating ./config.status config.status: creating Makefile config.status: creating src/Makefile config.status: creating config.h config.status: executing depfiles commands
If another user on another system tried to run the configurate script and got an error, the script would give a decently user-friendly error message on how the system needs to be changed to fix it. Above, you can see some
no answers, but the
configure script adapts and can handle many different scenarios from Linux, FreeBSD, ArchLinux, to OS X and any Unix System for that matter.
Building the Project
Now it’s all setup check out how easy it is to build.
$ make make all-recursive make: Entering directory '/home/lloydroc/athw' Making all in src make: Entering directory '/home/lloydroc/athw/src' gcc -DHAVE_CONFIG_H -I. -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 helloworld main.o make: Leaving directory '/home/lloydroc/athw/src' make: Entering directory '/home/lloydroc/athw' make: Leaving directory '/home/lloydroc/athw' make: Leaving directory '/home/lloydroc/athw'
Installing the program
Now we can install this program on our system and all users can use it. Again it works on any Unix-flavor. Check it out:
Note: we can just run without installing system wide by simply doing
$ src/helloworld hello world!
Installing System Wide
$ sudo make install Making install in src make: Entering directory '/home/lloydroc/athw/src' make: Entering directory '/home/lloydroc/athw/src' /usr/bin/mkdir -p '/usr/local/bin' /usr/bin/install -c helloworld '/usr/local/bin' make: Nothing to be done for 'install-data-am'. make: Leaving directory '/home/lloydroc/athw/src' make: Leaving directory '/home/lloydroc/athw/src' make: Entering directory '/home/lloydroc/athw' make: Entering directory '/home/lloydroc/athw' make: Nothing to be done for 'install-exec-am'. /usr/bin/mkdir -p '/usr/local/share/doc/athw' /usr/bin/install -c -m 644 README '/usr/local/share/doc/athw' make: Leaving directory '/home/lloydroc/athw' make: Leaving directory '/home/lloydroc/athw' $ which helloworld /usr/local/bin/helloworld lloydrochester :: ~/athw » helloworld hello world! $
An uninstall is simple
$ sudo make uninstall Making uninstall in src make: Entering directory '/home/lloydroc/athw/src' ( cd '/usr/local/bin' && rm -f helloworld ) make: Leaving directory '/home/lloydroc/athw/src' make: Entering directory '/home/lloydroc/athw' ( cd '/usr/local/share/doc/athw' && rm -f README
Where to Go from Here
Using this in your normal project workflow is going to give many benefits for ease of use, system compatibility, portability, and flexibility for the application. The following, however, is not addressed
- Under what conditions would a
autoreconf --installand/or a
./configureneed to be re-run?
- What files should be under version control to distribute this program?
- What changes need to be made to integrate system libraries and 3rd Party Libraries?
- How can unit testing be performed?
- How do I add in more source and can I build multiple programs inside a single Autotools project?
Thanks for Reading!