How to Use the Autotools configure Command to Build Software from Source

These days, most users don’t need to build open source software from its source code, given the availability of package managers such as apt-get, rpm, etc. But there are many good reasons to want to build software from source. Perhaps the package manager offers an older version and you want the latest, greatest features. Maybe you want to ensure the software is built with specific optimizations or debugging flags. Or, perhaps you need to cross-compile for a different architecture. In any case, building software from source code is usually straightforward. 

In this article, I’ll explain what goes on behind this process to help you get the build that best suits your needs. I’ll focus mostly on software written in C/C++ or other compiled languages. Such software is usually distributed with a means to build it flexibly and portably, and there are two predominant build systems common today: those based on the GNU Autotools and those based on CMake. Autotools is by far the most commonly encountered method, and it is the official GNU build system.

Autotools

Autotools is a suite of complex tools (autoconf, automake, libtool) used by the developer to package the build. However, users typically are interested only in the end product of applying those tools, which is a Bash shell script conventionally named configure. For users, the build instructions for the software are often as simple as:

  1. Unwrap the software in a convenient directory.
  2. cd into that directory.
  3. Run the following three commands:
    ./configure
    make
    make install

That’s it—what could be simpler? There is of course more to the story, but let’s talk about what happens with the first of those three commands.

Hidden Complexity

The configure command is a large, complex shell script that runs and reports on a lengthy series of tests on your system. It looks in well-known locations for various header files, libraries, APIs, functions, etc. It uses this information to build a Makefile that is tailored to the specific architecture and operating system of your machine. The default target of the Makefile builds the software, and the install target properly installs the software and any supporting files. 

Sometimes, there’s an optional step to run a series of tests on the software itself to verify the integrity of the build, which should be run before the installation step:

    make check

The complexity implicit behind these simple commands raises several questions:

  • Where will the software be installed?
  • What optional features are included in the build?
  • What optional third-party packages will be incorporated?
  • How can I assist configure in finding certain requisite libraries or influence other aspects of the build?

To answer those questions, I recommend that before attempting a build, you run the command:

    ./configure --help

This command will produce output similar to the following, which is excerpted from the configure for the libcurl package. I’ve highlighted key bits of the output that align with the four questions above.

`configure' configures curl - to adapt to many kinds of systems.
 
Usage: ./configure [OPTION]... [VAR=VALUE]...

Defaults for the options are specified in brackets.

Configuration:
  -h, --help              display this help and exit
      --help=short        display options specific to this package
      --help=recursive    display the short help of all the included packages
text clipped . . . . . 
Installation directories:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [/usr/local]

By default, `make install' will install all the files in
`/usr/local/bin', `/usr/local/lib' etc.  You can specify
an installation prefix other than `/usr/local' using `--prefix',
for instance `--prefix=$HOME'.

Fine tuning of the installation directories:
  --bindir=DIR            user executables [EPREFIX/bin]
  --sbindir=DIR           system admin executables [EPREFIX/sbin]
  --libexecdir=DIR        program executables [EPREFIX/libexec]
  --includedir=DIR        C header files [PREFIX/include]
text clipped . . . . . 
Optional Features:
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --enable-http           Enable HTTP support
  --disable-http          Disable HTTP support
  --enable-ldap           Enable LDAP support
  --disable-ldap          Disable LDAP support
  --enable-ldaps          Enable LDAPS support
text clipped . . . . . 
Optional Packages:
  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
  --with-zlib=PATH        search for zlib in PATH
  --without-zlib          disable use of zlib
  --with-darwinssl        enable Apple OS native SSL/TLS
  --without-darwinssl     disable Apple OS native SSL/TLS
text clipped . . . . . 
Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>
  LIBS        libraries to pass to the linker, e.g. -l<library>
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
              you have headers in a nonstandard directory <include dir>
  CPP         C preprocessor
text clipped . . . . . 

Where Do Things Get Installed?

The first highlighted section answers the question of where things get installed. It tells us that by default, the package will be installed under /usr/local. That means binaries will go into /usr/local/bin, libraries under /usr/local/lib, header files under /usr/local/include, manual pages under /usr/local/man, miscellaneous files under /usr/local/share, etc. (Note that superuser privileges will likely be required to install in that location.)

We can change the root of that directory hierarchy by using the --prefix switch. We also see that there are other more specialized switches beyond --prefix that can be used to highly customize the installation, such that binaries can go in one place (--bindir), libraries in another (--libexecdir), and documentation in yet another (not shown). None of these are required to have a common root prefix. I personally never use those switches, as it does not make much sense to me to scatter package files about the filesystem.

Optional Features

The “Optional Features” section answers our second question. It lists switches that we can use to turn on or off optional behaviors of the software. As seen in the listing, these switches tend to have a consistent form of enable-FEATURE and disable-FEATURE. They often take arguments of the form enable-FEATURE=[no/auto/yes], where enable-FEATURE=no is synonymous with disable-FEATURE, and where auto indicates the feature will be included in the build if configure can find the supporting headers/libraries.

Occasionally you’ll see the option enable-FEATURE=DIR, where DIR is a directory root where supporting headers/libraries may be found, if they are not installed in well-known locations. It is not uncommon to see dozens of optional features switches; the 2D graphics library cairo, for example, has more than 60 such optional features.

Third-Party Packages

Our third question is addressed by the “Optional Packages” section. These switches also tend to have a consistent form of with-PACKAGE=[yes/no/DIR] and without-PACKAGE, where as before with-PACKAGE=no is identical to without-PACKAGE. There is not a sharp distinction between what is considered an optional feature versus an optional package, but packages tend to imply that some non-standard library is required in order for the software to support a certain feature. 

In our example output, the compression library zlib is an optional package, implying that if libcurl is built using that library, network protocols that support such compression will be enabled in the libcurl library. As before, an argument of DIR to the switch specifies the root directory for the headers/libraries of the optional package in cases when they are not installed in well-known directories. It is also not unusual to see large numbers of optional packages; for example, the geospatial processing software Gdal has more than a hundred.

Customize the Build

Finally, the section “Some influential environment variables” describes how to change the configure command’s default assumptions about the build, such as which compiler should be used or what optimization flags should be set, etc. Unlike switches, these variables are specified on the command line as VAR=VALUE pairs. Note that if multiple values are to be passed to a variable, the whole VALUE part should be quoted.

For example, passing options to the C compiler might look like CFLAGS=”-I/opt/include -O3”. The variables shown in the libcurl example are fairly common and generic; however, some packages also define unique and specific variables intended to identify the location of individual optional packages. We’ll see this in the example below.

Real-World Example

The example below shows how I build the Gdal package. Gdal is a large package that supports dozens of geospatial file formats, most of them optionally. In my particular application, I strive for the leanest build possible, so I want to exclude a number of formats that Gdal might find on my system. So, in this case, configure is invoked as:

./configure --prefix=/usr/local --disable-shared \
 --with-proj=/usr/local --without-pam --with-png=/usr/local \ 
--with-gif=internal --with-libtiff=internal --with-geotiff=internal \ 
--with-sqlite3=no --with-expat=no --with-curl=no --with-hdf5=yes \ 
--without-grib --with-freexl=no LDFLAGS=-L/uwr/local/lib \ 
HDF5_CFLAGS=-I/usr/local/include HDF5_LIBS=”-L/usr/local/lib -lhdf5” \ 
CXX=”g++ -std=c++11”

This example is fairly extreme, but it contains all of the elements discussed above. At least one optional feature is disabled. Several optional packages are included or excluded, and in some cases, directory paths are given to indicate where to find those packages’ header files and libraries. Two environment variables provide directives to the C++ compiler and the linker, and Gdal utilizes special environment variables for locating the HDF5 package. Note that the VALUE parts of several variables are quoted, as there are multiple pieces to the values.

Config.log

Rarely do I end up with a configure command line as complicated as the example above. But there may be times when you need to rebuild a software package and can’t recall the options you used. We noted that the purpose of configure is to generate Makefiles. In most cases, configure will also write two files, config.log and config.status. These are mostly intended for debugging purposes for the developer using Autotools to construct the build system. However, you can also refer to the config.log to see how configure was previously invoked.

Closing Comments

As I’ve shown, configure provides a great deal of flexibility and customization for a build. Understanding how it works and being aware of the options available to you can be very helpful when building software from source. 

In this article, I presented a rather complex example of configure in action, mostly to illustrate its features. However, I frequently build open source software, and in my experience, it is rarely more complicated than simply typing:

    ./configure

But remember to always do this first:

    ./configure --help

You might be surprised by your options.

FOSSlife Newsetter

Comments