Setting up Automake

In this tutorial, you will learn:

  • How to generate a Makefile saying which files to compile

  • How to check for the libraries your program needs

This tutorial is part of the Setting up a real-life GTK application series. If you don't want to follow along with the previous parts, simply copy the app-skeleton1 directory from the tutorial's code examples. Or, you can start from the beginning.

Now to move on to Automake, the other major component of our build system. After we get Automake set up, we can start writing some source code.

Make is a program that reads a file called Makefile that describes how to compile source code into executable code. The contents of a Makefile depend upon the compiler you use, the system you are on, and many other things. Makefiles can also get quite long if you want to implement all the standard make targets described in the previous section.

This is where Automake comes in. Automake allows you to write the Make code in a more abstract, platform-independent way. Automake looks for Automake files named Makefile.am, and changes them into almost-Makefiles named Makefile.in. These almost-Makefiles are then transformed into real Makefiles when you run configure.

Creating a Makefile.am

To get started, copy your app-skeleton1 directory to a new app-skeleton2 directory, or just rename it if you like. For now, just put one line in Makefile.am:

The special SUBDIRS variable tells Automake to look for another Makefile.am in the src subdirectory as well. The resulting Makefile will also look for src/Makefile and call it recursively as well.

Recursive Make

A famous paper by Peter Miller has a title that speaks volumes about what some people think about writing your Makefiles recursively: Recursive Make Considered Harmful. Read it and follow its advice if you like; it's not more or less difficult than the approach shown here. In practice, however, most projects use recursive make, so it's important to be familiar with it at least.

Since we are telling Automake to go into the src directory, we should also put something there for it to find. We need a Makefile.am, but perhaps more importantly, we need some source code. We are going to be writing our own application starting in the next section, but until then we need some "placeholder" source code. We will use the "Hello World" example from the GTK tutorial. Instead of retyping it or copying and pasting it from the browser, we will fetch it the way real hackers do it: the lazy way! Create a src directory, cd to it, and type in your terminal:

wget http://git.gnome.org/browse/gtk+/plain/examples/hello-world.c

Now we can create a Makefile.am to compile this source code. Write in src/Makefile.am (be careful to get the right file, don't use the one in the parent directory):

bin_PROGRAMS = app-skeleton
app_skeleton_SOURCES = hello-world.c

Automake works mostly by setting variables. SUBDIRS was an example of one. Many other Automake variables have names consisting of two parts. For example, a variable named something_PROGRAMS is a list of executable programs for Automake to build. The something part tells where to install the programs when you run make install. So bin_PROGRAMS = app-skeleton means that Automake should generate a Makefile that builds a program named app-skeleton and installs it in /usr/local/bin. (Unless you decide it should be called something else and installed somewhere else; Automake's Makefiles are highly customizable using configure, but I will leave explaining that to one of the Autotools tutorials I mentioned previously.)

By the same tack, app_skeleton_SOURCES = hello-world.c means that the program named app-skeleton should be built from the source file hello-world.c, which we just downloaded. (If the name of the program contains characters that are not legal in a variable name, Automake replaces them with underscores.)

We must now instruct configure to generate our newly-written Makefile. Replace the AC_CONFIG_FILES call in configure.ac with this:

AC_CONFIG_FILES([
	Makefile
	src/Makefile
])

Finally, we also need to tell configure to look for a suitable C compiler. Add the single command AC_PROG_CC after the AM_INIT_AUTOMAKE line. (CC stands for C Compiler.)

Then, run autoreconf and ./configure. The output from configure is a little longer (you can see that it is checking for a C compiler) and more files have appeared when it is done. So far, so good. But when we run make, we get a screen full of errors: all of the GTK functions used in the file are undefined, and the compiler cannot find the gtk/gtk.h header.

Defining our libraries

We need to define what libraries the program will use. This is done in configure.ac, so that configure can look for these libraries and put their locations into the Makefile. We will also take this opportunity to organize configure.ac and introduce a few more Autoconf macros.

Divide the configure.ac file into four sections:

  • Initialization, in which we do preparations for initializing the build system;

  • Shopping list, in which we tell Autoconf what tools we would like to use. The resulting configure script will go look for those tools and complain if they are not installed;

  • Libraries, in which we list what libraries we are using. Again, configure will complain if these libraries are not installed;

  • and Output, where we output all the results of these checks so that Make can use them.

Comments

You can use comments, which start with the # character, to divide up the file. Autoconf comments can also be started by the letters dnl (which stands for Delete until New Line.) The difference between the two is that dnl comments are ignored completely by Autoconf, whereas # comments are copied into the generated configure file. This can be useful if there is an error in configure and you want to find out which section of configure.ac is causing it.

In the Initialization section, write:

AC_INIT([App Skeleton], [2], [philip.chimento@gmail.com])
AC_CONFIG_SRCDIR([src/hello-world.c])
AM_INIT_AUTOMAKE([-Wall foreign])
AM_SILENT_RULES([yes])

We have changed the version number to 2 here. There are also two new macros:

AC_CONFIG_SRCDIR

This is a safety check to make sure the source tree actually contains the source code that it should. As an argument, put the name of a unique source file in your program; here we put our only source file.

AM_SILENT_RULES

The generated Makefiles use very long compiler command lines. Normally, you don't need to see these, and large swathes of garbage scrolling across your terminal can actually obscure error and warning messages. AM_SILENT_RULES adds the capability to your Makefiles to suppress the build commands, instead printing just a short summary. The yes argument turns this behavior on by default. A Real Programmer might write AM_SILENT_RULES([no]) and then lesser mortals could run ./configure --enable-silent-rules to get the quiet building behavior.

If you have silent rules turned on, and you want to examine the command lines after all, perhaps to track down an error, you can run make V=1 to get the command lines back temporarily. (V stands for Verbose.)

In the Shopping List section, write:

AC_PROG_CC
PKG_PROG_PKG_CONFIG

The new macro here is PKG_PROG_PKG_CONFIG. It adds the pkg-config program to our shopping list of tools. This macro doesn't start with AC_ or AM_, so it doesn't originate from Autoconf or Automake. Instead, the prefix PKG_ identifies it as belonging to the macros that pkg-config provides when you install it.

The Libraries section is where we use pkg-config:

PKG_CHECK_MODULES([APP_SKELETON], [
	glib-2.0
	gtk+-3.0
])

The PKG_CHECK_MODULES macro takes a program name, in this case APP_SKELETON as its first argument, and a list of pkg-config modules as its second. A module is the name of a library as it is known to pkg-config. This macro uses pkg-config to look for these libraries, and creates two variables: APP_SKELETON_CFLAGS which contains the C compiler flags required for compiling with these libraries, and APP_SKELETON_LIBS which contains the linker flags. These variables are available from inside the Makefiles.

These module names specify that we are using the 2.0 series of the GLib library and the 3.0 series of the GTK+ library. If you don't know the module name of a library, you can always look in /usr/share/pkgconfig and /usr/lib/pkgconfig to see if there is a .pc that corresponds to the library name. Some libraries aren't configurable by pkg-config; there are other ways to check for libraries, but I won't describe them here.

Finally, the Output section is the same as before:

AC_CONFIG_FILES([
	Makefile
	src/Makefile
])
AC_OUTPUT

After that, we need to use the APP_SKELETON_CFLAGS and APP_SKELETON_LIBS variables in our Makefile.am. Edit src/Makefile.am so that it looks like this:

AM_CFLAGS = $(APP_SKELETON_CFLAGS)
bin_PROGRAMS = app-skeleton
app_skeleton_SOURCES = hello-world.c
app_skeleton_LDADD = $(APP_SKELETON_LIBS)

The AM_CFLAGS variable contains the compiler flags to be added to all compilations defined in this Makefile.am. Conversely, the app_skeleton_LDADD variable tells Automake the linker flags to use when linking the app-skeleton program.

Now when we rebuild, everything should work fine. Note that we only have to type make to rebuild; the magic of the generated Makefile (now a whopping 22 kilobytes) makes sure that configure is regenerated and rerun, which also regenerates the Makefile.

You can run the executable app-skeleton to verify that it does what it should: shows a window with a Hello World button which, when pressed, prints Hello World to the terminal and exits.

Now that we have a build system in place, there are a few more bits of infrastructure we need to examine: installation and internationalization.