1. Overview
As we know, Linux is available in a variety of distributions. All of them are built on top of the Linux kernel. Still, each distribution can vary in terms of modules and packages. In addition, users can change their system to such an extent that it becomes very different from the default installation. So, it’s important that a program installer should address these factors.
In this tutorial, we’ll use the autotools package to create an installer. In other words, we’ll create a build system that uses the make and make install commands. There are several steps we’ll be going through:
- create a small C program
- install the autoconf and automake packages
- create the configuration files
- execute the commands to create the build system
- test the build system
In the end, we’ll have a package ready to be installed on other Linux systems.
2. The C Program
To begin with, we’ll write a small C program. This program calculates the Fibonacci sequence. We enter an index and it returns the related Fibonacci number. The program consists of a source code file and a header file.
Initially, we’ll create a new directory with the name fibonacci and make it the current working directory:
$ mkdir fibonacci
$ cd fibonacci
This is the root directory of the package that we’re creating. Under this directory, we’ll create the src sub-directory to save our code.
Now, let’s examine the fibonacci.c file that contains the program’s code:
$ cat src/fibonacci.c
#include <stdio.h>
#include <stdlib.h>
#include "fibonacci.h"
int main( int argc, char* argv[] ) {
printf( "F%d: %d \n", atoi( argv[1] ),f( atoi(argv[1] )) );
}
int f( int n ) {
if (n <= 1 ) return n;
return f( n - 1 ) + f( n - 2 );
}
Indeed, we can see two functions:
- main() – base for program execution
- f() – calculation of a Fibonacci number
Next, let’s examine the fibonacci.h header file:
$ cat fibonacci.h
int f( int n );
As we can see, the header file contains the declaration of the f() function.
3. Toolset Installation
To create the build system, we’ll use the autoconf and automake packages.
In Ubuntu, we can install both packages with apt-get:
$ sudo apt-get install autoconf automake
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
...
In addition, we should install a C compiler, in case our system doesn’t already have one:
$ sudo apt install gcc
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
...
Now, we’re ready to move on and begin creating the installer.
4. The autoconf and automake Configuration Files
The main aim of the autoconf tool is to create a configure script. This is the script that creates a tailored Makefile for the end user’s system. Moreover, the autoconf tool requires a configure.ac file at the top-level directory of the program. The main purpose of this file is to describe the components of our program.
On the other hand, the main aim of the automake tool is to create the Makefile.in files. The configure script uses these files to create Makefile. Furthermore, automake also uses the Makefile.am files as input.
In brief, we’ll first create the Makefile.ac files. Then we’ll use the autoscan tool to generate a configure.ac template that we’ll edit to meet our needs.
4.1. Creating the Makefile Files
Firstly, we should create the main Makefile.am file in our top-level directory:
$ cat Makefile.am
SUBDIRS = src
As we can see, the SUBDIRS variable points to the src directory. Thus, automake will search src for other Makefile.am files.
So, let’s create Makefile.am in src:
$ cat ./src/Makefile.am
bin_PROGRAMS = fibonacci
fibonacci_SOURCES = fibonacci.c fibonacci.h
The bin_PROGRAMS variable indicates two things:
- the name of a program that needs to be included in the Makefile, in this case, the fibonacci program
- after the program is built, it should be copied to a bin directory such as /usr/local/bin
Furthermore, the fibonacci_SOURCES variable holds a list of the source files of the fibonacci program separated with space.
4.2. Creating the configure.ac File
Although we can create a configure.ac file from scratch, we’ll use the autoscan command to create a template instead. Then, we can edit the template to meet our needs.
First, we call the autoscan command in the top-level directory of our package:
$ autoscan
$ ls
autoscan.log configure.scan src
Indeed, we can see two new files:
- autoscan.log: logs of the command execution
- configure.scan: the created template file, which will later become configure.ac
Next, let’s see the initial contents of configure.scan:
$ cat configure.scan
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ( [2.71] )
AC_INIT( [FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS] )
AC_CONFIG_SRCDIR( [src/fibonacci.h] )
AC_CONFIG_HEADERS( [config.h] )
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES( [Makefile src/Makefile] )
AC_OUTPUT
As we can see, the file contains a set of macros that comply with the M4 macros language:
- AC_PREREQ: autoconf version
- AC_INIT: required macro, must be called before any other macro
- AC_CONFIG_SRCDIR: sets the source directory with a file the existence of which is verified
- AC_CONFIG_HEADERS: creates the relevant header file
- AC_PROG_CC: sets a C compiler to use
- AC_CONFIG_FILE: creates the listed files by copying the suitable .in files
- AC_OUTPUT: required macro, performs all actions
In addition, we can see that the tool found the two Makefile.in files that we created previously and added them to the AC_CONFIG_FILE macro.
4.3. Editing the configuration.scan File
Next, we edit the configuration.scan file by including the actual package name, version, and similar data. A key point here is to add the AM_INIT_AUTOMAKE macro. The AM_INIT_AUTOMAKE macro enables the creation of Makefile.in by the automake tool.
As a result, the configure.scan file is complete:
$ cat configure.scan
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ( [2.71] )
AC_INIT( [fibonacci], [1.0], [[email protected]] )
AM_INIT_AUTOMAKE( [-Wall -Werror foreign] )
AC_CONFIG_SRCDIR( [src/fibonacci.h] )
AC_CONFIG_HEADERS( [config.h] )
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES( [Makefile src/Makefile] )
AC_OUTPUT
Finally, we rename configure.scan to configure.ac.
5. Creating the Installer
At this point, we’re ready to run the autotool commands for creating the build system.
First, we call the aclocal command that creates the aclocal.m4 file:
$ aclocal
$ ls
Makefile.am aclocal.m4 autom4te.cache autoscan.log configure.ac src
Indeed, we can see that the command created an aclocal.m4 file. This file contains all macros required by autoconf.
Next, we run the autoheader command:
$ autoheader
$ ls
Makefile.am aclocal.m4 autom4te.cache autoscan.log config.h.in configure.ac src
Here, we can observe that the command produced the config.h.in file. This is a file that holds the C macros that the configure script uses.
After this, we run automake:
$ automake --add-missing
configure.ac:11: installing './compile'
configure.ac:6: installing './install-sh'
configure.ac:6: installing './missing'
src/Makefile.am: installing './depcomp'
In this example we used the –add-missing option that creates any missing files.
Finally, let’s run the autoconf command:
$ autoconf
$ ls
Makefile.am Makefile.in aclocal.m4 autom4te.cache autoscan.log compile config.h.in configure configure.ac depcomp install-sh missing src
Indeed, we can see a configure script in the output. At this point, the build system is ready. This means that we can create an archive of the directory, and provide it to end users.
6. The autoreconf Command Alternative
In the previous section, we used several commands to create the build system. However, we can just run the autoreconf command instead of them:
$ autoreconf --install
configure.ac:11: installing './compile'
configure.ac:6: installing './install-sh'
configure.ac:6: installing './missing'
src/Makefile.am: installing './depcomp'
The autoreconf command performs all the required steps to create the build system.
7. Testing the Package
Let’s verify that the package is ready to install via the usual configure–make–install procedure:
$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether the build environment is sane... yes
...
$ make
make all-recursive
make[1]: Entering directory '/home/ubuntu/fibonacci'
...
$ sudo make install
Making install in src
...
$ fibonacci 8
F8: 21
Indeed, we installed fibonacci on our system. The program was copied to the default bin directory.
8. Conclusion
In this article, we saw a complete example of how to create a build system with GNU autotools. Through this example, we learned the basic steps of creating an installer with GNU autotools.