Monday, May 27, 2019

Introduction to the GNU Build System


Brief

Chances are that if you've ever obtained a software product that defined a 3-step installation procedure of 'configure', 'make' and 'make install', then you've utilized the GNU Build Environment (also known as autotools). This environment has become the de facto standard in deploying software from source on Posix-like systems. The goal of this paper is to introduce you to the build environment enough to incorporate it into your own software products.

Introduction

The GNU Build System (also known as autotools) is a suite of tools authored by Gnu used to make portable software products. The build system will be viewed from two perspectives; 1) the user perspective as the user of the product, and 2) the developers perspective as the developer of the product. The remainder of this paper will discuss the system from both perspectives.


Discussion

To begin understanding the GNU Build Environment, you must first view it from two perspectives; that of the user, and that of the developer.

User Perspective

After obtaining the software archive, the user simply wants to configure, build, test and install the product. The easier this is to do, the more likely the user will use the product. A competing objective however is to not sacrifice flexibility. The GNU build environment offers both flexibility as well as simplicity from the user perspective. The user proceeds with a 3-step procedure.

Step 1 – Configure

This step is responsible for interrogating the users system and makes note of the systems environment, platform, architecture and the existence of required features that the software product requires. A plethora of configurable parameters are available to the user in specifying how the product will be installed. A notable example of a configurable parameter is the location of which the product will be installed. Each configurable parameter has a specified default and specifying an alternative is only necessary if the default is not acceptable.
Successful execution of the configuration script results in a customized Makefile for the users system. This allows the user to proceed to the next step; building the software from source. If however, the configuration script fails to locate essential features on the users system the user must resolve the issue(s) and repeat this step until successful.

Step 2 – Make

The generated Makefile from step 1 supports this step as well as the final installation step. The makefile is populated with the discovered specifics of the users system discovered in the previous step. The default makefile target builds the software, allowing the user to test and confirm the system before proceeding to the installation step. If the user finds that the product does not meet the users needs he/she can simply stop at this step and discontinue installation deleting the temporary source archive at their convenience. If the product is deemed worth installing the user proceeds to the final step.

Step 3 – Make Install

The third and final step involves installing the product which involves copying the binaries, documentation, libraries and like to their final destinations. While these destinations can be specified at time of configuration, the defaults generally specify a subdirectory of /usr. As a result, this step normally requires superuser (root on *nix variants).

Developers Perspective

The remainder of this section will guide you step-by-step through an example, which incorporates the build environment.

We start by creating a subdirectory, which will be the location of our product. This is necessary because throughout the course of this procedure a good number of files will be generated as well as directories.

localhost:~$ mkdir autotools/
localhost:~$ cd autotools/

Before we go further it is important to understand our primary goal, which is to give the user the previously defined experience. The initial interface for the user is the 'configure' script, all other interfaces (e.g. Makefile) are auto-generated from this script with input files that will present themselves shortly. The creation of the configuration script therefore is our goal of all to come.

To produce a configuration script for a software product you create a configure.ac file that contains invocations of the autoconf macros. The macros interrogate the system testing for features necessary for the software product. For reasons that will be explained later generate the configure.ac file as specified:

Step-1

localhost:~/autotools$ cat configure.ac
AC_PREREQ(2.59)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AM_INIT_AUTOMAKE(someApp,2.1)
AC_CONFIG_HEADER([config.h])
AC_PROG_CC
AC_OUTPUT(Makefile)

Also generate the following files as specified:

localhost:~/autotools$ cat myMain.c
#include <stdio.h>
#include "myMath.h"

int main()
{
const double radius=15.0;
const double area =
areaOfCircle(radius);
printf("(%s:%d) the area of a circle” +
with radius %.2lf ft == %.2lf”+
ft^2\n",
__FILE__,__LINE__,radius,area);
}

localhost:~/autotools$ cat myMath.h
#ifndef MYMATH_H
#define MYMATH_H
double areaOfCircle (double radius);
#endif

localhost:~/autotools$ cat myMath.c
#include "myMath.h"
#include <math.h>

double areaOfCircle (double radius)
{
const double retVal =
pow(radius,2.0)*M_PI;
return retVal;
}

localhost:~/autotools$ cat Makefile.am
bin_PROGRAMS=someApp
someApp_SOURCES=myMain.c myMath.c

Autoconf is a tool that generates the configure script from directives in the configure.ac file. Autoconf is a macro expander, an application that repeatedly performs macro expansions on input replacing macro declarations with macro bodies and at end produces a pure sh configuration script. Since sh is available on Posix-like systems, this ensures the highest degree of portability. The next step is done specifically because autoconf is a macro expander.

Step-2

localhost:~/autotools$ aclocal
localhost:~/autotools$ ls
aclocal.m4 configure.ac myMain.c myMath.h autom4te.cache Makefile.am myMath.c

Notice after executing aclocal the existence of aclocal.m4 and autom4te.cache. The application aclocal creates the file aclocal.m4 by combining stock installed macros, user defined macros to define all the macros required by configure.ac. The autom4te.cache directory is simply a cache for the other tools so later invocations of autoheader, automake, or other tools will not require re-processing configure.ac. This can result in speed-ups of 30x or better. This cache directory may be deleted as you wish and will be regenerated upon execution of autoconf, our next step.

Step-3

localhost:~/autotools$ autoconf
localhost:~/autotools$ ls
aclocal.m4 configure Makefile.am myMath.c autom4te.cache configure.ac myMain.c myMath.h

After execution of autoconf, the configure script exists and we are a good way toward home. The GNU coding standards require the existence of a few files to include NEWS, README, AUTHORS, and ChangeLog. The absence of these files will cause a good deal of warnings in the future so we will generate them in this next step.

Step-4

localhost:~/autotools$ touch NEWS README AUTHORS ChangeLog
localhost:~/autotools$ ls
aclocal.m4 autom4te.cache configure Makefile.am myMath.c NEWS
AUTHORS ChangeLog configure.ac myMain.c myMath.h README

Step-5

The next step will create a template file for C-style #define statements for configure to use. The execution of autoheader will result in the generation of config.h.in file which will later be used by configure.

localhost:~/autotools$ autoheader
localhost:~/autotools$ ls
aclocal.m4 ChangeLog configure.ac myMath.c README AUTHORS config.h.in Makefile.am myMath.h autom4te.cache configure myMain.c NEWS

Step-6

One last step Sparky and you've got an environment. Automake is a tool that automatically generates a Makefile.in that is compliant with GNU Coding Standards.

localhost:~/autotools$ automake -a
lsconfigure.ac:3: installing `./missing'
configure.ac:3: installing `./install-sh'

Makefile.am: installing `./INSTALL'
Makefile.am: installing `./COPYING'
Makefile.am: installing `./depcomp'
localhost:~/autotools$ ls
aclocal.m4 config.h.in depcomp Makefile.in myMath.h
AUTHORS configure INSTALL missing NEWS
autom4te.cache configure.ac install-sh myMain.c README
ChangeLog COPYING Makefile.am myMath.c

Now without knowing the details of what is really going on, you've now got a configure script that gives the user the experience we earlier described. We can now reexamine our steps in a bit more detail.

Step-1 Revisited

Configure.ac
localhost:~/autotools$ cat -n configure.ac
1 AC_PREREQ(2.59)
2 AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
3 AM_INIT_AUTOMAKE(someApp,2.1)
4 AC_CONFIG_HEADER([config.h])
5 AC_PROG_CC
6 AC_OUTPUT(Makefile)
7


Line 3 is of particular significance, which specifies the name of the product someApp and product version 2.1. The product and version are of particular interest when distributing the product. Line 4 specifies that you want a config.h.in file to be generated by autoheader. If this line does not exist autoheader will fail in creating the file.
I'll leave the details of the remaining lines undefined, you may look them up at your convenience.


Makefile.am
localhost:~/autotools$ cat -n Makefile.am
1 bin_PROGRAMS=someApp
2 someApp_SOURCES=myMain.c myMath.c
3
This file defines a template for automake to generate the Makefile.in file. Line 1 specifies the name of the application, the following line specifies the sources that define the application. These two lines indirectly result in the necessary Makefiles to build, distribute, and install the product. The needs to author your own Makefiles are no longer required since this method is far more portable.

Step-2 Revisited

Not much to revisit in this step. It simply defines all macros required by configure.ac.


Step-3 Revisited

Autoconf parses the configure.ac file and generates the configure script.


Step-4 Revisited

The created files in step 4 are in compliance with the GNU Coding Standards. They should be populated as per conventions located at www.gnu.org.


Step-5 Revisited

The autoheader step acts on the directive on line 4 of the configure.ac which simply put says you to create a template header for configure (config.h.in). This template will later be used to generate a config.h file that can be imported in your applications source. Various macro definitions that identify the existence of features and files are located in this file. These directives can be used to make portable code.


Step-6 Revisited

Automake helps create portable Makefile(s) which are then processed by the make utility. It takes the Makefile.am file as input and generates a Makefile.in as output. This file is later used by configure.



Conclusion

You’ve now configured a product to adhere to the GNU Build Environment.

Place yourself in the user role specifying. configure, make,& make install will result in installing the product.

Place yourself in the developer role, specifying ‘make dist’ will result in a compressed tarball with your product, ready for distribution.


References



2 comments:

  1. Autotools is still in use, but CMake seems to be the de-facto build system for C and C++ projects, don't you think? I couldn't resist checking trends on Google [1] (unscientific, I know). My initial comment was based more on recent experience with open source packages.

    [1] https://trends.google.com/trends/explore?date=all&geo=US&q=cmake,autotools

    ReplyDelete
    Replies
    1. Whelp, I can't disagree with that. The trend line certainly shows more search interest in CMake. Personally, I have little experience in CMake, but should probably change that. Good news; I'm glad the post sparked some interest and conversation. Bad news; I have a couple more posts revolving around autotools in the pipeline.

      Delete