Jan 112006
 

I recently began work on a C++ project which I intend to be widely distributed (maybe even ported to other operating systems). Instead of writing my own customized Makefiles which probably wouldn’t even build cleanly on another Linux system, I used GNU AutoConfig and AutoMake. I’ve read complaints about both automated build systems and custom Makefiles, but in my experience it’s the custom Makefiles that break most frequently.

Unfortunately, even with the vast amounts of documentation available on the web, there are some parts of automated build systems that you simply can’t get to work. In my case, I was building a single executable from a deep source tree. While there is plenty of documentation of separate executables and libraries in separate directories, I couldn’t find a single working example of a source tree being compiled into a single executable. I had to piece everything together by trial and error.

Here is the directory layout of my project:

.
|-- AUTHORS
|-- COPYING
|-- ChangeLog
|-- INSTALL
|-- Makefile.am
|-- NEWS
|-- README.in
|-- THANKS
|-- aclocal.m4
|-- config
|   |-- config.guess
|   |-- config.sub
|   |-- depcomp
|   |-- install-sh
|   `-- missing
|-- config.h.in
|-- configure
|-- configure.ac
|-- doc
|   |-- Makefile.am
|-- m4
|   |-- Makefile.am
|-- mkinstalldirs
|-- reconf
`-- src
    |-- Displayable.cpp
    |-- Displayable.h
    |-- EnemyFighter.cpp
    |-- EnemyFighter.h
    |-- EnemyFighterList.cpp
    |-- EnemyFighterList.h
    |-- Fighter
    |   |-- Fighter.cpp
    |   |-- Fighter.h
    |   |-- Weapon.cpp
    |   |-- Weapon.h
    |   |-- WeaponSystem.cpp
    |   |-- WeaponSystem.h
    |   `-- Weapons
    |       |-- LightLaser.cpp
    |       |-- LightLaser.h
    |       |-- MediumLaser.cpp
    |       `-- MediumLaser.h
    |-- FighterAmmo.cpp
    |-- FighterAmmo.h
    |-- FighterAmmoList.cpp
    |-- FighterAmmoList.h
    |-- Game.cpp
    |-- Game.h
    |-- GfxUtils.cpp
    |-- GfxUtils.h
    |-- Ground.cpp
    |-- Ground.h
    |-- GroundSegment.cpp
    |-- GroundSegment.h
    |-- HUD.cpp
    |-- HUD.h
    |-- ListItem.cpp
    |-- ListItem.h
    |-- Makefile.am
    |-- Screen.cpp
    |-- Screen.h
    `-- main.cpp

configure.ac

# Copyright (C) 2006 Eliot Eshelman 
#  
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without 
# modifications, as long as this notice is preserved.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

AC_INIT([BattlestarTUX],
        [0.0.1],
        [Eliot Eshelman spam@6by9.net],
        [BattlestarTUX])
AC_CONFIG_AUX_DIR(config)
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE([dist-bzip2])

LF_CONFIGURE_CC
LF_CONFIGURE_CXX
LF_HOST_TYPE
LF_SET_WARNINGS
AC_PROG_RANLIB

AC_CONFIG_FILES([
   Makefile
   README
   doc/Makefile
   m4/Makefile
   src/Makefile
])

AC_OUTPUT

Makefile.am

# Copyright (C) 2006 Eliot Eshelman 
#  
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without 
# modifications, as long as this notice is preserved.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

EXTRA_DIST = reconf configure
SUBDIRS = m4 src doc

src/Makefile.am

# Copyright (C) 2006 Eliot Eshelman 
#  
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without 
# modifications, as long as this notice is preserved.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

AUTOMAKE_OPTIONS = subdir-objects

INCLUDES = -I/usr/include -I/usr/include/SDL
AM_LDFLAGS = -L/usr/lib
LDADD = -lSDL -lSDL_image -lGL -lGLU

bin_PROGRAMS = battlestarTUX
battlestarTUX_SOURCES = Displayable.cpp \
                        Displayable.h \
                        EnemyFighter.cpp \
                        EnemyFighter.h \
                        EnemyFighterList.cpp \
                        EnemyFighterList.h \
                        FighterAmmo.cpp \
                        FighterAmmo.h \
                        FighterAmmoList.cpp \
                        FighterAmmoList.h \
                        Fighter/Fighter.cpp \
                        Fighter/Fighter.h \
                        Fighter/Weapon.cpp \
                        Fighter/Weapon.h \
                        Fighter/WeaponSystem.cpp \
                        Fighter/WeaponSystem.h \
                        Fighter/Weapons/LightLaser.cpp \
                        Fighter/Weapons/LightLaser.h \
                        Fighter/Weapons/MediumLaser.cpp \
                        Fighter/Weapons/MediumLaser.h \
                        Game.cpp \
                        Game.h \
                        GfxUtils.cpp \
                        GfxUtils.h \
                        Ground.cpp \
                        Ground.h \
                        GroundSegment.cpp \
                        GroundSegment.h \
                        HUD.cpp \
                        HUD.h \
                        ListItem.cpp \
                        ListItem.h \
                        Screen.cpp \
                        Screen.h \
                        main.cpp

Although you are always told to include a Makefile.am in every directory, it isn’t necessary in this case because all source subdirectories are specified in the src/Makefile.am file. Any additional data directories or libraries would need their own Makefile.am.

One of the more important lines in src/Makefile.am is AUTOMAKE_OPTIONS = subdir-objects, which specifies that object files should be placed in the same directory as the source. This causes “Fighter/Fighter.cpp” to be build to “Fighter/Fighter.o” instead of “Fighter.o”. Without “subdir-objects”, you will have errors during make when any source file in a subdirectory is encountered.

To include header files from different source directories, just include that directory as part of the name. Fighter.h would include Game.h with ‘#include “../Game.h”‘ and Game.h would include Fighter.h with ‘#include “Fighter/Fighter.h”‘. Remember not to use absolute path names or it won’t work at all on other systems.

Update 2008-10-05 10:38:43 For those who are interested, I’ve now moved to CMake, which is much cleaner and easier to use. It’s become fairly widely accepted, and is now used by the KDE team, so I hope using CMake won’t put other developers off.

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(to be displayed above your comment)

(for moderation; your e-mail address will not be made public)