Sample project for the article "How To Build a Cross-Platform C++ Project With Autotools" at
Switch branches/tags
Nothing to show
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
doc Initial commit Dec 1, 2017
examples Initial commit Dec 1, 2017
scripts Initial commit Dec 1, 2017
src Initial commit Dec 1, 2017
AUTHORS Initial commit Dec 1, 2017
ChangeLog Initial commit Dec 1, 2017 Initial commit Dec 1, 2017
README Modified Readme file Dec 1, 2017 Initial commit Dec 1, 2017
autoscan.log Initial commit Dec 1, 2017


How To Build a Multiplatform, GNU-Compliant C++ Project

Project structure
We will illustrate the process with a simple project called helloWorld. Our project will build a very simple "hello world" program that will just show a message on screen. It contains a shared library:, and a main program that calls this shared library.

Additionally, there will be some extra scripts (to be installed but not compiled), a man page for the main application, some documentation, examples and sample data.

The project should be structured in the following way:

sources in src/
documentation in doc/
man pages in man/
some scripts in scripts/ (in this directory, we will add files that need to be executed but not compiled)
examples in examples/
Our src/ directory will contain just three source files:

#include "helloWorld.h"
int main() {
    return 0;
#include <iostream>
#pragma once
namespace helloWorld {
    void printHelloWorldMessage();
#include "helloWorld.h"
namespace helloWorld {
    void printHelloWorldMessage() {
        std::cout << "Hello world, helloWorld() called in the helloWorld namespace." << std::endl;
Depending on our operating system, we need to follow a different process for installing autotools.

On linux based systems (i.e: Debian), all you need to do is installing the required packages (as root):

# aptitude install autotools-dev autoconf automake libtool

On Mac OS X, we can use brew for this:

$ brew install autoconf automake libtool

In order to install Brew on Mac OS X, you just need to run this command:

$ /usr/bin/ruby -e "$(curl -fsSL"

More detailed instructions and information on Brew can be found here.

Generating The Project Configuration
In this step, we will generate the required configuration files and the files for the different parts of our project.

These files will set the rules to indicate autoconf and automake which files should be included and how to process them.

Run autoscan:

$ autoscan

autoscan tries to produce a suitable file (autoconf's driver) by performing simple analyses on the files in the package. This is enough for the moment (many people are just happy with it as permanent).

Use AutoScan file as initial Configuration file

Autoscan actually produces a configure.scan file, so let it have the name autoconf will look for:

$ mv configure.scan

Modify the Configuration file

Now we need to adjust the generated configuration file to add some info, like the name and version of our package:

$ vim

We will modify this initial file to adapt it to our project.

First, we will modify the AC_INIT property that defines the package name, version and bug reporting email address. Replace:


AC_INIT([helloWorld], [1.0], [])
Also, we will change the ACCONFIGSRCDIR to point to our main.cpp file. Replace:


Additionally, we will add some properties that will create the link between autoconf and automake. One of them will be the AMINITAUTOMAKE variable, where you will specify the package name and version again. Also, AC_OUTPUT, where we will specify the Makefile files to be generated by autoconf in all of our directories.

Last, we will add some checks to make sure that the system where our project is going to be built has a proper compiling environment for C++ and can link shared libraries.

The final file should look like this:

# Process this file with autoconf to produce a configure script.
AC_INIT([helloWorld], [1.0], [])

# Checks for programs.

# Checks for libraries.

# Checks for typedefs, structures, and compiler characteristics.

# Output Makefile files.
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile examples/Makefile man/Makefile scripts/Makefile])
Create the root

Now it's time to create the root, the seed for our root Makefile. It will specify the directories where automake should look for Makefile files.

$ vim

AM_CXXFLAGS = -fPIC -Wall -Wextra
SUBDIRS = src doc examples man scripts
Other options here include commonly used settings for most projects.

Create the in the src/ directory

The src directory is where we keep all our source files (.cpp and .h). We want our application to be called helloWorld. Let's see how the generator for our source dir looks like.

$ vim src/

AUTOMAKE_OPTIONS = subdir-objects

bin_PROGRAMS = helloWorld

helloWorld_SOURCES = main.cpp
helloWorld_LDADD =

libHelloWorld_la_LDFLAGS = -version-info 0:0:0
libHelloWorld_la_SOURCES = helloWorld.cpp helloWorld.h
As you can see, after defining some global options, we set the initial binary for the project, helloWorld, with the property bin_PROGRAMS.

Next, we define the sources and the libraries that should be included in this helloWorld object, with the _SOURCES and _LDADD properties respectively. Note how we use the extension .la instead of .so for the shared library. This is a convention.

Then, we define our small library (lib_LTLIBRARIES), set some flags (libHelloWorldlaLDFLAGS) and specify its source files. That's all we need. If you were to add additional source files, you will add them to helloWorld_SOURCES, and repeat the same process for libHelloWorld in order to add more libraries.

Create the in the man/ directory

Next step, we'll add the man page for our helloWorld executable.

We will create a very simple man page with this content:

.\" Manpage for helloWorld.
.\" Contact for comments or help.
.TH man 1 "30 Nov 2017" "1.0" "helloWorld man page"
helloWorld \- simple hello world example application
helloWorld is a simple test application to show how to build a C++ example project with Autotools for multiplatform compilation and use.
helloWorld does not take any arguments.
No known bugs.
Ignacio Nieto Carvajal (
Write that down in a file called helloWorld.1 (The man page number 1 is a convention, because our App is considered a "User command").

Now it's time to write our man/

$ vim man/

man_MANS = helloWorld.1
Create the in the scripts/ directory

Now we will create a makefile.a, for our scripts directory.

$ vim scripts/

Create files

echo "Hello World!"

echo "Goodbye world!"
Create the in the examples/ directory

In the examples directory, we can add configuration sample files, data examples, or any other kind of resource we might want to add.

In this example, we will add a dummy sample configuration file called

version = 1.0
author = Ignacio Nieto Carvajal <>
Then, we will generate the

$ vim examples/

exampledir = $(datarootdir)/doc/@PACKAGE@
example_DATA =
We can add as many files as we want (separated by whitespaces) in example_DATA.

Create the in the doc/ directory

In order to set a doc directory, we need to specify a variable that will depend on the name of the project specified in, @PACKAGE@.

Then, we add a doc_DATA variable with the files we want to include. We will use two dummy files: and changelog.

$ vim doc/

docdir = $(datadir)/doc/@PACKAGE@
doc_DATA = changelog
Integrating Autoconf and Automake
Next, we need to build our configure file. In order to do that, we need to follow a series of steps:

First, let's call libtoolize to add the file to link the shared libraries. In Mac OS X, it's called glibtoolize:

$ glibtoolize

Whereas in linux-based systems, it's called just libtoolize:

$ libtoolize

Next, we need to call aclocal:

$ aclocal

This command will generate the aclocal.m4 that contains all necessary information (including macros) needed for automake. Now we need to run autoheader to generate the configuration headers:

$ autoheader

Then, we can call autoconf to generate the configure command.

$ autoconf

Next, let's call automake then:

$ automake --add-missing

This command will go through all our directory structure and generate, for every file, a corresponding file. And voila! 👏🏻 Our multiplatform configure file is generated and ready to use in any GNU-compliant environment.

Let's see how to use it:

Invoking Configure And Make
First thing we need to do is calling configure:

$ ./configure

It will read our file and scan all the required libraries and dependencies. If a dependency or library is missing, the proper error message will be delivered.

For every we generated previously, as specified in AC_OUTPUT, it will generate the plaform-dependent Makefile file.

Now, we just can run make to build our project:

$ make

If everything goes well, we will generate all the libraries and executable files. Now we can install our project to be available for the entire system (as superuser):

# make install

This command will tipically put the binaries in /usr/local/bin, the libraries in /usr/local/lib, the man pages in /usr/local/man and the docs in our @PACKAGE@ defined directory: /usr/local/share/helloWorld.

You can also uninstall everything by calling make uninstall (as superuser):

# make uninstall

Congratulations! You have built a multiplatform, GNU-compliant C++ project 😎.