Using Autotools

There are many Linux distributions, shipping different libraries and tools to different locations. Developing software that is portable across several Posix-compatible operating systems is hard. Luckily, there are several build suites, designed to make the build process portable. One of them is Autotools. Autotools is a set of tools:

  • Autoconf – generates configuration script from a template (configure.ac) file. Generates Makefiles from Makefile.in files.
  • Automake – takes Makefile.am files as an input and generates Makefile.in files
  • Libtool – handles all the requirements for building shared libraries

Adding Autotools support

Creating configure.ac

Autoscan(1)
The first step in adding Autotools support to your project is to create configure.ac – template input file for Autoconf. The easiest way to create the file is to use the autoscan utility to generate it. autoscan examines the source files in the directory tree of the current directory and searches the source files for portability problems. It creates a file configure.scan.
The file generated by autoscan needs some modifications:

  • Edit the line
    AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])

    to include the name of the program or library, its version and the email to which users should send bug reports.

  • Add an invocation to AM_INIT_AUTOMAKE([OPTIONS]), it is required for the proper operation of the generated Makefiles.
  • List all Makefiles that have to be created in the AC_CONFIG_FILES macro, like below:
    AC_CONFIG_FILES([Makefile src/Makefile])
  • Optional: If you are building a library, add AC_PROG_RANLIB.
  • Optional: If you are using additional local Autoconf macros, specify their location: AC_CONFIG_MACRO_DIR(dir).

Makefile.am files

Each directory in the source tree must have a Makefile.am file. These files define variables, determining what needs to be built (executable, library), source files, installation location, etc.
The top level Makefile.am must specify which sub-directories are to be built, using the SUBDIRS variable:

SUBDIRS = list of sub-driectories
Binary Executable
bin_PROGRAMS = APPNAME

INCLUDES = \
        -I$(prefix)/include\
        -I$(top_srcdir)/include

APPNAME_SOURCES =\
	SourceFile1\
        SourceFileN

APPNAME_LDFLAGS = \
	-L$(prefix)/lib
   
APPNAME_LDADD = \
	$(PACKAGE_LIBS)\
	-lLibrary1\
        -lLibraryM

The bin_PROGRAMS variable specifies that we want to built a program, named APPNAME. It will be installed in the bin directory by make install.
The INCLUDES variable – the old name for AM_CPPFLAGS, used to add include paths, prefixed by -I.
The APPNAME_SOURCES variable specifies the source files, used to build the executable.
The APPNAME_LDFLAGS variable defines the flags that need to be passed to the linker. Usually -L flags to add a library search path.
The APPNAME_LDADD variable defines the libraries that the program links to. You can specify:

  • A library reference -lLIBNAME
  • A relative path to a static library ../LIB/PATH/libLIBNAME.a

Note: APPNAME should be replaced with the name of the program.

Static Library

Static libraries contain object code. They are linked with the application (executable) and become part of it. Static libraries have .a extension.

lib_LIBRARIES = libLIBNAME.a

INCLUDES = \
        -I$(prefix)/include\
        -I$(top_srcdir)/include

library_includedir = $(includedir)/LIBNAME

library_include_HEADERS=\
        $(top_srcdir)/include/LIBNAME/Header1.h\
        $(top_srcdir)/include/LIBNAME/HeaderN.h

libLIBNAME_a_SOURCES=\
        SourceFile1\
        SourceFileN

The lib_LIBRARIES variable specifies that we want to build a static library (.a) and defines it’s name. It will be installed in the lib directory by make install.
The INCLUDES variable – the old name for AM_CPPFLAGS, used to add include paths, prefixed by -I.
library_includedir specifies the directory where the header files (public interface) will be installed.
library_include_HEADERS lists the header files (public interface) that need to be copied to the library_includedir.
Additional arguments can be passes to the commpiler, using AM_CFLAGS, AM_CPPFLAGS, AM_CXXFLAGS variables.
The libLIBNAME_a_SOURCES variable specifies the source files, used to build the target.
Note: LIBNAME should be replaced with the name of the library without the lib prefix (i.e. dl).

Dynamic Library

Dynamic libraries are called shared objects (.so) in Linux. They are referenced by applications (executables), but do not become part of them. Dynamic libraries can be:

  • linked – must be available during the link phase. The application cannot start without the library.
  • loaded during execution (aka plug-ins), using dlopen on UNIX-like operating systems. The application can start in the absence of dynamically loaded libraries.
lib_LTLIBRARIES = libLIBNAME.la

INCLUDES = \
        -I$(prefix)/include\
        -I$(top_srcdir)/include

library_includedir = $(includedir)/LIBNAME

library_include_HEADERS=\
        $(top_srcdir)/include/LIBNAME/Header1.h\
        $(top_srcdir)/include/LIBNAME/HeaderN.h

libLIBNAME_la_SOURCES=\
	SourceFile1\
        SourceFileN

libLIBNAME_la_LDFLAGS = \
	-L$(prefix)/lib

libLIBNAME_la_LIBADD=\
	$(PACKAGE_LIBS)\
	-lLibrary1\
        -lLibraryM

The lib_LTLIBRARIES variable specifies that we want to build a dynamic library (.a) and defines it’s name. It will be installed in the lib directory by make install.
The INCLUDES variable – the old name for AM_CPPFLAGS, used to add include paths, prefixed by -I.
The libLIBNAME_la_SOURCES variable specifies the source files, used to build the target.
The libLIBNAME_la_LDFLAGS variable defines the flags that need to be passed to the linker. Usually -L flags to add a library search path.
The libLIBNAME_la_LIBADD variable defines the libraries that this library depends on. You can specify:

  • A library reference -lLIBNAME
  • A relative path to a static library ../LIB/PATH/libLIBNAME.a

Note: LIBNAME should be replaced with the name of the library without the lib prefix (i.e. dl).

Building

The commands that need to be executed to prepare a project for building are shown in the diagram below. The input files of each command are listed on the left side and the output is on the right.
Build(1)

aclocal
libtoolize
autoconf
autoheader
automake --add-missing 
./configure --prefix=/target/dir (/usr/local by default)
make
make install

These are a lot of commands, especially when working on a big project, having several libraries and executables – building the full source tree becomes a laborious process. I like to use a manual makefile to simplify the build. Imagine having a project with one application and two libraries. It’s directory structure is:

binThe output applications will be installed in this folder.
includeThe output header files will be installed in this folder.
libThe output libraries (.so, .a) will be installed in this folder.
sourceParent source folder
source/applicationSource code of the application
source/librarySource code of the first library
source/other_librarySource code of the second library
MakefileThe master makefile, listed below

A master makefile, simplifing the build process:

topdir=$(shell pwd)

subdirs=\
	./source/library/\
	./source/other_library/\
	./source/application/

all:
	@echo "Valid targets are:"
	@echo "	make prepare"
	@echo "	make build"
	@echo "	make clean"

prepare:
	for dir in $(subdirs); do \
		echo "$$dir" && cd $$dir && aclocal && autoconf && libtoolize && autoheader && automake -a && cd $(topdir);\
	done
	for dir in $(subdirs); do \
		cd $$dir && ./configure --prefix=$(topdir) && cd $(topdir);\
	done

clean: 
	for dir in $(subdirs); do \
		make -wC $$dir clean;\
	done

build: application

application: | library other_library
	make -wC ./source/application/
	make -wC ./source/application/ install

library: 
	make -wC ./source/library/
	make -wC ./source/library/ install

other_library:
	make -wC ./source/other_library/
	make -wC ./source/other_library/ install

The sample make file has three targets:

  • prepare – prepares the project by running aclocal, autoconf, automake and configuring each target. The prefix is the current folder.
  • build – builds the targets, the dependencies between them should be defined manually.
  • clean – cleans the targets.
You can leave a response, or trackback from your own site.

Leave a Reply