2022-02-01
Let's see how to set up GNU Autotools for building a new project!
Today we're starting a new project written in the C language.
The project will have a dependency to make it more interesting. We really can use any library, and for this example we'll pick the SDL library.
Last but not least, our project needs a name. Since libSDL is usually powering games, we could imagine our project is a game. Why not call it "Aventura"?
Prerequisites
Before starting, if you're not familiar with Autotools, take some time and go through the Autotools tutorial, an excellent slideshow by Alexandre Duret-Lutz.
Then we need to install all the packages we need.
Let's make sure we have Autotools. For Debian, that can be done with:
sudo apt install autoconf automake libtool gettext
Also, since we picked SDL as a project dependency, let's install the SDL development package:
sudo apt install libsdl2-dev
The implementation
-
Prepare the directory structure.
We need a
src
directory for the source code, where we begin with a single file,main.c
.. └── src └── main.c
-
Edit
src/main.c
and add the following code, which attempts to initialize the video subsystem of SDL and then cleans up and exits. It's like "Hello, World!" for SDL.#include "SDL.h" #include <stdio.h> int main (void) { if (SDL_Init (SDL_INIT_VIDEO) < 0) { fprintf (stderr, "SDL could not be initialized. SDL_Error: %s\n", SDL_GetError ()); return 1; } atexit (SDL_Quit); return 0; }
How would we compile this without Autotools?
A first attempt might be:
gcc -o src/aventura src/main.c
However that would not be enough, because
SDL.h
is most likely not located directly in a standard include directory (such as/usr/include
). It's probably under/usr/include/SDL2
.You could specify the include path with
-I
:gcc -I/usr/include/SDL2 -o src/aventura src/main.c
It would compile, but after that you'd get linker errors. You would need to explicitly link against SDL2 with
-lSDL2
:gcc -I/usr/include/SDL2 -o src/aventura src/main.c -lSDL2
An easier and more portable way of getting the build flags in place would be to use pkg-config.
First we would call
pkg-config --list-all
and look for "sdl" in its output:pkg-config --list-all | grep -i sdl
The above would tell us that the name of the package for SDL is
sdl2
, and we could use that name to get the build flags:pkg-config --cflags --libs sdl2
Then we could use the output of
pkg-config
in the call togcc
:gcc -o main $(pkg-config --cflags --libs sdl2) src/main.c
That's better, but at this point it's already too complicated to compile directly (and we just started). Better leave this to the build system.
-
Let's add one Makefile template (named
Makefile.am
) in the root directory and another one insrc
.touch {.,src}/Makefile.am
Now the project tree should look like this:
. ├── Makefile.am └── src ├── main.c └── Makefile.am
-
Edit the top level
Makefile.am
and add the following line, which tells Automake which subdirectories to build (in our case,src
).SUBDIRS = src
-
Edit
src/Makefile.am
and add the following two lines, which tell Automake the names of the binaries we want to build (in our case,aventura
) and the lists of source files to compile for each of these binaries (main.c
for now).bin_PROGRAMS = aventura aventura_SOURCES = main.c
- Run
autoscan
.This will produce
configure.scan
, which is can be used as a starting point forconfigure.ac
:# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.71]) AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_CHECK_FUNCS([atexit]) AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT
- Rename
configure.scan
toconfigure.ac
. - Edit
configure.ac
:- Fill the values for the project name, the version and the bug report address
- Call
AM_INIT_AUTOMAKE
-
Call
PKG_CHECK_MODULES
to define the dependency. This macro is an interface between autoconf andpkg-config
. We already know the name of the package issdl2
.
5c5,6 < AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) --- > AC_INIT([aventura], [0.1], [someone@example.com]) > AM_INIT_AUTOMAKE([foreign -Wall -Werror]) 12a14,20 > PKG_CHECK_MODULES( > [SDL2], > [sdl2 > 2.0.3], > [CFLAGS="$CFLAGS $SDL2_CFLAGS" > LIBS="$SDL2_LIBS $LIBS"], > AC_MSG_WARN($SDL2_PKG_ERRORS) > )
- Run
autoreconf --install
Now everything is ready.
You can run ./configure
followed by make
.
The executable is ./src/aventura
.