In this Series
Table of contents
Explore the intricacies of Autotools for build automation. Already know Autotools? Discover how Earthly can upgrade your builds with containerized consistency and parallel execution. Try Earthly now.
Autotools is one of the most widely adopted code packaging and shipping tools available to developers on Linux. While there are alternatives, such as CMake, SCons, and BJam, they don’t quite match Autotools in ease of use, power, and versatility.
At its base, Autotools can help make your application more portable, give it the versatility to be installed on many different systems, and can automatically procure scripts to check where elements are, like the compiler for your program. In this article, you will learn how to use Autotools to package up an application and ship it.
Components of Autotools
Autotools is made up of three unique components:
Using these tools, you will create two files,
Makefile.in. These files are present in any project shipped using Autotools and are usually quite large and complex. Luckily, you don’t have to write them yourself—instead you’ll be writing the files
Makefile.am, which will automatically generate the files you need.
Autoconf is written in M4sh, using
m4 macros. If you’ve heard of this before, then great! If you haven’t, no worries.
m4sh provides some macros you can use when creating your
configure.ac script and are part of why you can generate a massive
configure script without having to write too much actual code.
The way it works is that you create a
configure.ac script in which you define various settings like release name, version, which compiler to use, and where it should output files. Once you’ve written your script, you run it through
autoconf to create your final
configure script. The purpose of
autoconf is to collect information from your system to populate the
Makefile.in template, which is created using
Makefile.am script creates
Makefile.in. The principles behind this are the same as with
configure.ac: write a simple script in order to create a complex file. Automake is the component you’ll use to create the Makefile, a template that can then be populated with
Automake does so using variables and primaries. An example of such a primary is
bin_PROGRAMS = helloworld, where the primary is the
_PROGRAMS suffix. This primary gives
automake some knowledge about your program, like where you want the produced binary to be installed.
In this case, you’re telling
automake to install the
helloworld binary in the path defined by the
bindir. You may notice we didn’t define a
bindir variable, because that variable is built into
automake and is typically the default binary directory of your system.
Other examples of primaries are
_SCRIPTS, which you can use when you want a script, rather than a binary to be installed somewhere, and
_DATA, when you have extra data files you want included in your installation. There are many more that you will find once you start using Autotools and figure out what your needs are.
One last thing to mention is that although
Makefile.in is special in that it contains all of these primaries, it’s still a regular Makefile. Meaning you can write your own custom make targets if you want. For example, if you want to have a custom
clean target that deletes specific files, you can do so easily.
This is the smallest component in the Autotools suite, but it’s very important. You learned in the previous section that
m4 macros to be configured. But where do these
m4 macros come from? They’re generated by running the
aclocal command. Simple as that. If you don’t run
aclocal before running
autoconf, you’ll get an error complaining about missing macros.
Now that you know the basic principles of how the Autotools suite is put together, it’s time to see it all in action and create a small C program that you can compile and ship.
Writing the Source Program
The first thing you need is the program you want to compile and ship. Autotools is compatible with many different projects and languages, but for this example you’ll be working in
C, which is most commonly used. If you’re not familiar with
C, don’t worry, it’s very simple. Here’s your sample code:
int argc, char* argv)
As you can see, it simply includes a standard in/standard out library and then prints
Hello World\n. Let’s start with
autoconf to configure this project.
When writing your
configure.ac file, there are a lot of options to choose from. You can get very specific about how you want your script to be configured, but some configurations need to be set. The first of these is
AC_INIT. This tells
autoconf what the name of your application is, what version it is, and who’s the maintainer. For this example, you’ll write:
AC_INIT([helloworld], [0.1], [firstname.lastname@example.org])
autoconf is generally used alongside
automake, it’s not necessary, so you need to initialize that by writing:
Now that the generic options are initialized, you can get more specific with what you want. You need to specify what compiler you want the
configure script to use. You do this by writing:
This will tell the
configure script to look for a
C compiler. For other applications, you may need more dependencies to build your program. By using the
AC_PATH_PROG macro, you can make
autoconf look for specific programs in a user’s
PATH. At this point, there are only two steps needed to finish your basic
autoconf that it should find a file called
Makefile.in and replace placeholders according to what we’ve specified. This can be things like version or maintainer.
AC_OUTPUT is the last thing you want to put in your
configure.ac script, as it tells
autoconf to output the final
configure script. In the end, your
configure.ac file should contain the following:
AC_INIT([helloworld], [0.1], [email@example.com])
Making the Makefile
automake, you’ll have to adhere to a set of standards. One of these is that source files for a project are located in the
src folder. In this project, you have a single
main.c file in our root directory, so you need to tell
AUTOMAKE_OPTIONS = foreign
You need to tell
automake what you want your compiled binary to be called. In this case, you want it to be called
helloworld, so write the following:
bin_PROGRAMS = helloworld
Only one thing left, and that is to tell
automake what files are needed to compile your application. Do this by writing:
helloworld_SOURCES = main.c
Notice how the first part is the name of your application followed by the
SOURCES primary. Now
automake knows all that it needs to know, and your
Makefile.am is ready to use.
Creating Final Scripts
Once you’ve written your
Makefile.am, it’s relatively straightforward to distribute your application. Remember to start by running
aclocal so you can run
autoconf. Once you’ve run
autoconf, you can run
automake --add-missing to build your
The reason for the
--add-missing flag is to tell
automake to automatically generate all of the additional files required, as usually you need more than just
Makefile.am and would have to manually enter in the other files.
At this point, you have all you need to distribute your program. Before moving on on, here’s a short recap showing the commands you should’ve run by now:
Distributing the Program
Distributing your application can seem like a daunting task, but Autotools makes it super easy. All you have to do is run
make dist after you’ve run the configure scripts above. This will produce a tarball, which you can then ship to your customers.
You’ve learned how to use Autotools for compiling and distributing your application across different systems. Moving forward, consider exploring automation and further integration of Autotools into your workflow. Autotools offers a well-documented, time-tested system familiar to many developers, making your application more user-friendly and widely accessible.If you are looking for a solution to avoid the complexities of Makefile, check out Earthly. Earthly takes the best ideas from Makefile and Dockerfile, and provides understandable and repeatable build scripts, minus the head-scratching parts of the Makefile.