wiki:pm-autotools-intro

Version 18 (modified by stefan, 9 years ago) (diff)

update on configuration header files

Table of Contents

  1. Working With the GNU Autotools
    1. Introduction
    2. The configure.ac Files
    3. The Makefile.am Files
    4. Running the Autotools
    5. Which Files Should be in the Subversion Repository?
    6. Working On Your Project
  2. Autotools Basics
    1. autoconf
    2. automake
    3. libtool
  3. Basic Structure of the configure.ac File
    1. General Concepts
    2. Beginning of a configure.ac file
    3. The Body of the configure.ac File
    4. The End of the configure.ac File
  4. The Package Base Directory configure.ac File
  5. The Project Directory configure.ac File
    1. Initialization of Tools and Compilers
    2. Check for other COIN-OR Components
    3. Checks for some specific System Libraries
    4. Check for User Libraries
    5. Generation of Links for Data Files
    6. Project Specific Tests
  6. Introduction of Automake Concepts
  7. The Package Base Directory Makefile.am File
  8. The Project Main Directory Makefile.am File
  9. The Source Directories Makefile.am Files
    1. Beginning of the Makefile.am File
    2. Building a Library
    3. Building a Program
    4. Additional Flags
    5. Installation of Header Files
  10. The Test Directory Makefile.am File
    1. Beginning of the File
    2. Compilation of the Unit Test Program
    3. The Test Target
    4. House Cleaning
  11. The pkg-config configuration files of a project
    1. Introduction
    2. The .pc file of an installed COIN-OR project library
    3. The .pc file of an uninstalled COIN-OR project library
    4. The NO pkg-config case
  12. Using the Correct Version of the Autotools
  13. Brief Tutorial on Switching from BuildTools 0.5 to 0.7
    1. What Needs to be Edited
    2. Externals to Dependencies
    3. Changes to Installation Directories
    4. Changes to autotools files
    5. Changes to configuration header files
  14. Hints, tricks, bugs, and suggestions
    1. Using autoreconf

Autotools Basics

This page gives a general introduction to the autotools, in the specific context of using them in COIN-OR. If you want to use them, first make sure that you are using the correct version of the autotools.

autoconf

The goal of autoconf is to provide developers of open source software with an easy way to ensure the portability of their code. Autoconf knows how to perform tests to find out platform and compiler dependent properties, for example, the presence of particular program, library, or header files.

Anyone who has downloaded and installed a GNU package has seen the configure step in the installation process ("... type ./configure ..."). Autoconf is the software that generates the rather complicated shell script, configure, from a simple input file, configure.ac. The configure script is a shell script for sh, the basic shell that is available on every UNIX-like system (including Linux, Cygwin, and MSys). So that it will work on every system known to the autotools developers, it assumes only the least common denominator over all sh implementations. Configure scripts can be very long --- it takes a lot of simple shell commands to accomplish complicated tests.

Autoconf uses the macro processor m4 to generate the configure script from the configure.ac file. In configure.ac you specify autoconf macros, some of which take arguments. In a sense these macros can be understood as subroutines, but it's a bit more subtle than that. Keep firmly in mind that macros in configure.ac are expanded when the autotools are run, in the project manager's development environment, to create the configure shell script. The shell commands in the configure script are run by the user, in their environment, to adapt the source code and build process to the user's environment. An easy and frustrating conceptual mistake, when using the autotools, is to expect shell code to execute during macro expansion.

Template Files

When run by the user, the configure script will generate output files based on templates for these files. A template file typically has the extension .in. Template files contain strings (autoconf output variable names) surrounded by @. For example, Makefile is generated from Makefile.in. The autoconf variable for the name of the C compiler is CC, and in Makefile.in you will find a line like

CC = @CC@

The generated Makefile will then contain this line, with @CC@ replaced by the name of the C compiler (cc, cl, gcc, etc.) appropriate for the build environment, as determined by the configure script.

You don't have to create most template files; they are generated by the various autotools. For example, automake automatically generates Makefile.in from Makefile.am and configure.ac.

Another template file found in many COIN-OR projects are the pkg-config configuration files prjct.pc.in, used to generate prjct.pc. The generated file includes information on dependencies of the project and which compiler and linker flags are required to link against the project. For example, the OSI project uses the template file osi.pc.in; it contains the lines

prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@/coin
includedir=@includedir@/coin

Name: Osi
Description: COIN-OR Open Solver Interface
URL: https://projects.coin-or.org/Osi
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lOsi @OSILIB_PCLIBS@
Cflags: -I${includedir}
Requires: @OSILIB_PCREQUIRES@

When the user requests that OSI is configured, the resulting osi.pc file contains

prefix=/home/johndoe/Coin-Osi/build
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include/coin

Name: Osi
Description: COIN-OR Open Solver Interface
Version: 0.105
Libs: -L${libdir} -lOsi 
Cflags: -I${includedir}
Requires: coinutils 

Configuration Header Files

Some output files generated by the configure script are worth separate mention. The configuration header file (you may have noticed the config.h file in GNU packages) can be used to convey information about the configuration run to the source code of the package. Some examples:

  • System calls, such as those for obtaining the CPU time, are different on different platforms, and the header files in which they are declared are also different. The configure script can test for the presence of header files and functions.
  • The configure script can test for the presence of libraries and functions in libraries. In the CoinUtils package, if configure is run with the --enable-gnu-packages argument, it checks whether the compression library libz is available.
  • The user of a package can specify certain aspects of the configuration when configure is run, for example, the set of available linear programming solvers, and where their libraries and header files reside.
  • The AC_INIT macro in the configure.ac file leads information about the package name and package version number in the header file, so these parameters to be maintained only in the configure.ac file.

The configure script will place #define statements in the configuration header files. These can simply define a symbol or set a symbols to a specific value (such as the path to a default directory). However, since the define statements in different projects may define the same symbols (e.g., PACKAGE_NAME or HAVE_ZLIB), it is undesirable to install the config header files and requiring them for building against the package. On the other hand, sometimes it is necessary to convey some information about a package configuration via the header file to users of that package.

Therefore, in COIN-OR, the convention is to use two header files, a private header file which has the defines for all symbols that are needed to build the package, and a public header file which has the defines only for symbols that may be required by a user of the package. The private header file uses the name config.h and must not be installed. The public header file uses the name config_prjct.h and can be installed. However, it is important that the public header defines only symbols with unique names, so conflicts from including several header files are avoided.

To complicate things further, COIN-OR wants to make it possible to compile COIN-OR code in environments which do not support autotools (e.g., MS Developer Studio). In these systems, the config.h and config_prjct.h are substituted by header files config_default.h and config_prjct_default.h that define a set of default symbols. A user may then have to adjust these files for her system.

The logic which of the four header files to include in which situation is implemented in a fifth header file PrjctConfig.h. In any source code, none of the config*.h files should be included, but always the file PrjctConfig.h. It ensures that in an autotools based setup, the file config.h is included whenever the project itself is build and otherwise (i.e., someone builds against the project) the file config_prjct.h is included. Further, in a non-autotools based setup, it includes either config_default.h or config_prjctdefault.h. The distinction is made by two defines that may be specified as arguments in the compiler command line. These ensure that in an autotools setup with configuration header files, always the symbol HAVE_CONFIG_H is defined. Further, the symbol Prjct_BUILD is defined whenever a file belonging to project Prjct is build.

As an example, the CoinUtilsConfig.h contains

#ifndef __COINUTILSCONFIG_H__
#define __COINUTILSCONFIG_H__

#ifdef HAVE_CONFIG_H
#ifdef COINUTILS_BUILD
#include "config.h"
#else
#include "config_coinutils.h"
#endif

#else /* HAVE_CONFIG_H */

#ifdef COINUTILS_BUILD
#include "config_default.h"
#else
#include "config_coinutils_default.h"
#endif

#endif /* HAVE_CONFIG_H */

#endif /*__COINUTILSCONFIG_H__*/

The files config.h and config_coinutils.h are created by the autotools scripts at the end of configure from template files config.h.in and config_coinutils.h.in, because CoinUtils' configure.ac file contains the statement

AC_CONFIG_HEADER([inc/config.h inc/config_coinutils.h])

Further, the template file config.h.in is generated automatically by autoheader when the project manager calls the autotools. Therefore, only the public header file config_coinutils.h needed to be setup, which can be done by copying interesting lines from the private header file. In case of CoinUtils, the public header is

/* inc/config_coinutils.h.in.  */

/* Version number of project */
#undef COINUTILS_VERSION

/* Major Version number of project */
#undef COINUTILS_VERSION_MAJOR

/* Minor Version number of project */
#undef COINUTILS_VERSION_MINOR

/* Release Version number of project */
#undef COINUTILS_VERSION_RELEASE

/* Define to 64bit integer type */
#undef COIN_INT64_T

/* Define to integer type capturing pointer */
#undef COIN_INTPTR_T

/* Define to 64bit unsigned integer type */
#undef COIN_UINT64_T

After a user run configure, the #undef statements are replaced by corresponding #define statements, depending on the outcome of tests performed by configure.

For a non-autotools based setup, the files config_default.h and config_coinutils_default.h are provided. The public header config_coinutils_default.h is currently

/* Version number of project */
#define COINUTILS_VERSION  "trunk"

/* Major Version number of project */
#define COINUTILS_VERSION_MAJOR   9999

/* Minor Version number of project */
#define COINUTILS_VERSION_MINOR   9999

/* Release Version number of project */
#define COINUTILS_VERSION_RELEASE 9999

/*
  Define to 64bit integer types. Note that MS does not provide __uint64.

  Microsoft defines types in BaseTsd.h, part of the Windows SDK. Given
  that this file only gets used in the Visual Studio environment, it
  seems to me we'll be better off simply including it and using the
  types MS defines. But since I have no idea of history here, I'll leave
  all of this inside the guard for MSC_VER >= 1200. If you're reading this
  and have been developing in MSVS long enough to know, fix it.  -- lh, 100915 --
*/
#if _MSC_VER >= 1200
# include <BaseTsd.h>
# define COIN_INT64_T INT64
# define COIN_UINT64_T UINT64
  /* Define to integer type capturing pointer */
# define COIN_INTPTR_T ULONG_PTR
#else
# define COIN_INT64_T long long
# define COIN_UINT64_T unsigned long long
# define COIN_INTPTR_T int*
#endif

and the private header file is config_default.h is

/* include the COIN-OR-wide system specific configure header */
#include "configall_system.h"

/* include the public project specific macros */
#include "config_coinutils_default.h"

/***************************************************************************/
/*             HERE DEFINE THE PROJECT SPECIFIC MACROS                     */
/*    These are only in effect in a setting that doesn't use configure     */
/***************************************************************************/

/* Define to the debug sanity check level (0 is no test) */
#define COIN_COINUTILS_CHECKLEVEL 0

/* Define to the debug verbosity level (0 is no output) */
#define COIN_COINUTILS_VERBOSITY 0

/* Define to 1 if bzlib is available */
/* #define COIN_HAS_BZLIB */

/* Define to 1 if zlib is available */
/* #define COIN_HAS_ZLIB */

#ifdef _MSC_VER
/* Define to be the name of C-function for Inf check */
#define COIN_C_FINITE _finite

/* Define to be the name of C-function for NaN check */
#define COIN_C_ISNAN _isnan
#endif

Since both files need to be setup by the user, here the private header includes the public header to avoid redundancy. Further, a header configall_system.h is included that tries to provide commonly used defines.

automake

Automake generates Makefile.in template files for autoconf. The generated makefiles are very powerful; for example, they support automatic header file dependency tracking, if this information can be somehow obtained from the compiler. The makefiles work with any UNIX make, they have targets like install, uninstall, clean, distclean, and dist.

Makefiles generated by automake can work recursively and support parallel compilation (e.g., with the -j flag of GNU make). Also, it is possible to specify conditional content in the Makefile, the activation of which depends on the output of a test performed by the configure script. This facility is limited, but it's portable (again, think 'least common denominator' over all known implementations of make).

As a user of automake, you write an input file, called Makefile.am, for each Makefile.in you want to create. In Makefile.am you tell automake what you want to build (a program, a library, etc.), and what source code files are required to build this target. Automake will take it from there. There are ways to specify more information, e.g., if additional libraries are required for linking.

libtool

Libtool helps to build static and shared libraries on different platforms. It works together with autoconf and automake, so that you usually don't need to interact with it directly. Still, a bit of background information will help you understand its role.

Like configure, libtool is a shell script. It's generated when configure is run in the user's environment and contains the correct commands to compile code, create libraries, and link programs. Automake assumes that it will work through libtool. In the output produced during compilation and linking, you first see the libtool command line, then the command executed from the libtool script.

Libtool generates auxiliary files: .lo files correspond to object files, and .la files correspond to libraries. These files are instructions (in plain ascii) that libtool leaves for itself for later use. The compiled object files and fully or partially linked libraries are hidden in a .libs subdirectory. (The command 'make install' will move the hidden programs and libraries to the installation directory.)