Getting started with Autotools – GNU Build System on Debian

The_GNU_logo
If you eat and drink open source, chances are high that you might have downloaded an open source project code, only to see files like: aclocal.m4, configure.ac, Makefile.am, Makefile.in and what not. You might have also used commands like ./configure, make etc but what are these files? Does they really belong to the project you download? Do I need to understand them? In this blog post I look forward to answer all your question, as well as introduce you to not so popular Autotools – A GNU Build System.

Setting up Autotools on Debian?
Before we go ahead and understand what Autotools is, we will try building a HelloWorld package. Lets get started by setting up Autotools on debian machine.

  • apt-get install build-essential
  • gcc –version (verifying install)
  • g++ –version (verifying install)
  • apt-get install automake autoconf

You have your environment ready. Lets start packaging the HelloWorld package.

Hello World Source Code
Download full source code from here

We will need to create 5 files for our basic HelloWorld package. Start by creating a directory structure like this:
HelloWorld
    – configure.ac
    – Makefile.am
    – README
    – src
        – Makefile.am
        – helloworld.c

src/helloworld.c

#include <config.h>
#include <stdio.h>

int main (void) {
    puts ("Hello World!");
    puts ("This is " PACKAGE_STRING ".");
    return 0;
}

Note we don’t have a config.h file but still we include it here. In actual config.h will be autogenerated by the autotools, when we build the package. Similarly, PACKAGE_STRING will be a pre-defined variable inside config.h.

src/Makefile.am

bin_PROGRAMS = helloworld
hello_SOURCES = helloworld.c

Here we tell the build system to generate a binary named helloworld using the sources defined below i.e. helloworld.c

Makefile.am

SUBDIRS=src
dist_doc_DATA=README

Here we give information about the various sub-directory. For a bigger project you might have a man directory, data directory etc. Also we tell the build to package README file with the build.

README

This is a demonstration HelloWorld package for GNU Automake.
Type `info Automake' to read the Automake manual.

configure.ac

AC_INIT([helloworld], [1.0], [emailid@provider.com])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
 Makefile
 src/Makefile
])
AC_OUTPUT

Don’t leave the post on seeing the above file. We will go through each and every one of them. configure.ac contains a series of M4 macros that will expand to some shell code to finally generate the configure script. Autotools have utilities like automake and autoconf (details below) which read this file to generate intermediate and final build files. The variables starting with AC_ are Autoconf macros and those starting with AM_ are Automake macros.

  1. AC_INIT: Initializes autoconf. It takes 3 input parameters: Name of the package, Version of the package and Contact address for bug reports
  2. AM_INIT_AUTOMAKE: Initializes automake. It can take a number of available input parameters. -Wall -Werror specifically tells automake to turn on all warnings and report them as error. While development we will keep error reporting turned on. foreign tells automake that this package doesn’t follow GNU standard. As per GNU standards we should also distribute files like ChangeLog, AUTHORS and at this stage we don’t want automake to complaint about them.
  3. AC_PROG_CC: This line tells configure script to search available C compilers and define variable CC with its name. Later on many intermediate files will use this variable CC for building binary files.
  4. AC_CONFIG_HEADERS: It tells the configure script to generate a config.h file which is pre-included by helloworld.c. Generated config.h will have content like this:
    /* config.h.  Generated from config.h.in by configure.  */
    /* config.h.in.  Generated from configure.ac by autoheader.  */
    
    /* Name of package */
    #define PACKAGE "helloworld"
    
    /* Define to the address where bug reports for this package should be sent. */
    #define PACKAGE_BUGREPORT "emailid@provider.com"
    
    /* Define to the full name of this package. */
    #define PACKAGE_NAME "helloworld"
  5. AC_CONFIG_FILES: This tells configure script list of files from which it should generate it’s *.in templates. This variable is also used by automake utility to know list of Makefile.am it should process. (Note: Each directory should have a Makefile.am file and as you keep adding new directories keep adding them to AC_CONFIG_FILES, else build will not consider your new directories while building packages.
  6. AC_OUTPUT: It is a closing command that actually produces the part of the script in charge of creating the files registered with AC_CONFIG_HEADERS and AC_CONFIG_FILES.

Building a Hello World package for distribution
Lets create our first package for distribution.

  1. cd path/to/helloworld/directory: Migrate to the project directory
  2. autoreconf –install: This command initiates the build system. You should see something like this as output:
    configure.ac:2: installing `./missing'
    configure.ac:2: installing `./install-sh'
    src/Makefile.am: installing `./depcomp'
    

    Also if you scan through the HelloWorld directory, you will find a lot of new files being generated by the build system. Particularly you will see a Makefile.in being generated for each Makefile.am. Apart from these files of interest are configure and config.h.in.

  3. ./configure: It utilizes *.in files generated by the previous step to build the Makefile, src/Makefile and config.h. You should see something like this on your console:
    checking for a BSD-compatible install... /usr/bin/install -c
    checking whether build environment is sane... yes
    checking for a thread-safe mkdir -p... /bin/mkdir -p
    checking for gawk... no
    checking for mawk... mawk
    checking whether make sets $(MAKE)... yes
    checking for gcc... gcc
    
  4. make
  5. src/helloworld: This will output this on the console.
    Hello World!
    This is helloworld 1.0.
  6. make distcheck: This utility finally creates the helloworld-1.0.tar.gz package for distribution. You should see this on your console on running this utility:
    ================================================
    helloworld-1.0 archives ready for distribution:
    helloworld-1.0.tar.gz
    ================================================

Installing distributed HelloWorld package

  1. Copy the generated package into your temp directory and then issue the following commands
  2. tar -xzvf helloworld-1.0.tar.gz
  3. cd helloworld-1.0
  4. ./configure
  5. make
  6. make install

make install will copy the helloworld binary into the /usr/local/bin directory. Try running helloworld from command line and you should see a similar output, as we saw above while building the package. Further it also copies the README file under /usr/local/share/doc/helloworld directory. If your built package includes the man directory, it gets copied to /usr/local/share/man automatically.

What is Autotools?
Autotools is a build system developed by GNU which helps you distribute your source code across various Unix systems. The files you are wondering about are auto generated by the Autotools.

Autotools is a combination of several utilities made available by GNU, including:

  1. Autoconf
  2. Automake

There are many others which can be listed above, but for this blog post we will restrict ourselves to Automake and Autoconf only.

Autoconf
autoconf process files like configure.in to generate a configure script. When we run the configure script, it reads other template files like Makefile.in to generate a final output file, in this case Makefile

Automake
It reads all Makefile.am and generate corresponding Makefile.in, used by the configure script as described above.

Happy Packaging!