BuildSystem » History » Revision 10

« Previous | Revision 10/12 (diff) | Next »
fixeria, 03/14/2023 10:43 PM

The Build System

The build system is basically a suite of tools that helps developers to "translate" source code files into executable binaries and libraries. Examples of such systems are GNU Make, GNU Autotools, CMake, QMake, and Ninja. The majority of Osmocom projects is employing GNU Autotools, except these very few using CMake (mostly GNU Radio related projects) and hand-written Makefiles. Thus this page will be focusing on the GNU Autotools, which is supposed to make things simple for all of us, but sometimes becomes a PITA and a source of confusion for many.

GNU Autotools Essentials

GNU Autotools includes the following tools:

  • Automake - a tool for automatically generating files,
  • Autoconf - a tool for generating configure scripts, and
  • Libtool - a tool for building static and shared libraries.

These tools are usually available in package repositories of many Linux distributions.

GNU Autotools Basic Usage

The usual sequence of commands is as follows:

$ autoreconf -fi
$ ./configure
$ make
$ make check  # optionally
$ sudo make install

autoreconf scans the current directory for and taking them as the input, converts files to, and generates the configure script. The configure script performs dozens of checks, finds suitable compilers and linkers, scans for files and generates the usual Makefile files from them. Finally, make follows the rules listed in automatically generated Makefile files, and invokes compilers, linkers, and other tools on the source files.

GNU Autotools For Developers

This Work-in-Progress section is for those who want to understand and write their own and files. It's not a complete guide and definitely not for beginners, please refer to documentation of the respective GNU projects. The main focus here in on common problems and corner cases we faced during development.

Weird syntax

Yes, it is. Even worse, while a typical mostly contains specifically-named variables listing source files and their dependencies (i.e. libraries), employs rather archaic m4 language, so you may often find yourself googling the basic syntax of simple constructs like conditional statements and never remembering them. The good news is that you can include the usual Makefile-like rules in files, but this should be avoided unless it's absolutely necessary due to potential portability problems. variables

There are not that many of them, but it's easy to get confused.


  • bin_PROGRAMS - executable files, which will be installed during make install
  • noinst_PROGRAMS - executable files, which will not be installed during make install
  • check_PROGRAMS - executable files, which will only be compiled during make check and will not be installed during make install

TIP: It's recommended to use check_PROGRAMS for tests, so that they won't be compiled during make all.


There exist static and shared libraries, see
Libtool adds another layer of discrimination: regular static libraries (.a) and libtool archives (.la), see

  • lib_LTLIBRARIES - list of shared libraries (libtool .*la archives, later *.so files), to be installed during make install
  • noinst_LTLIBRARIES - list of static libraries (libtool .*la archives), not installed during make install
  • noinst_LIBRARIES - list of static libraries (regular .a archives), not installed during make install

libtool *.la libraries can depend on other libraries, regular *.a libraries cannot. Here is an example:

# static libtool library, not going to be installed
libosmo_foo_la_SOURCES = src/foo.c
libosmo_foo_la_LIBADD = $(TALLOC_LIBS)

# shared libtool library, to be installed, depends on
libosmo_bar_la_SOURCES = src/bar.c
libosmo_bar_la_LIBADD = \
        $(LIBOSMOGSM_LIBS) \

In the example above (dynamic lib) depends on (static lib). Among with LIBOSMOCORE_LIBS and LIBOSMOGSM_LIBS, the resulting will additionally depend on $(TALLOC_LIBS) because it's a dependency of

NOTE: It's recommended to list repository-local libs ( in the example above) first, not after any of the external dependencies (e.g. $(LIBOSMOCORE_LIBS)). Otherwise you may experience weird problems when running binaries within the repository, loading system-installed libs instead of the local ones.


  • AM_CPPFLAGS is for the preprocessor flags like -I$(top_srcdir)/include or -DHAVE_FOOBAR
  • AM_CFLAGS is for the C compiler flags applying to C source files only
    • This is where you put stuff like $(LIBOSMOCORE_CFLAGS)
    • Avoid putting -O3, -g, -ggdb there, let the user decide of these flags
      • One exception is -Wall, and sometimes -g in tests
  • AM_CXXFLAGS is similar to AM_CFLAGS, but applies to C++ source files only

These variables apply to all binaries and libraries within the current file.
You can overwrite them using per-binary/-library osmo_app_CPPFLAGS, osmo_app_CFLAGS, and osmo_app_CXXFLAGS variables.

AM_CPPFLAGS = -I$(top_srcdir)/include

# global AM_CPPFLAGS and AM_CFLAGS apply to osmo-app
bin_PROGRAMS = osmo-app
osmo_app_SOURCES = src/app.c

# osmo-app wants to have additional CFLAGS

# osmo-app wants to redefine global CFLAGS

NOTE: In some projects you may see both preprocessor flags and compiler flags in AM_CPPFLAGS. This works because the compiler usually comes with a preprocessor, and the resulting Makefile rule looks like this: $(CC) $(AM_CPPFLAGS) $(AM_CFLAGS) .... Though it's still desirable to have preprocessor and compiler flags in the proper variables, at least for the sake of clarity.


  • AM_LDFLAGS is for the liker flags like -version-info, -no-install, -no-undefined
  • lib_or_app_LDFLAGS is a list of liker flags either for a library or for a binary, overrides AM_LDFLAGS
  • LDADD is a list of libraries that implicitly applies to all binaries and libs within the current file (unless overridden)
  • osmo_app_LDADD is a list of libraries for osmo-app binary (not for libraries), overrides LDADD
  • libosmo_lib_LIBADD is a list of libraries for libosmo-lib library (not for binaries), overrides LDADD

Here is an example of osmo-app depending on both libosmo-{foo,bar} from the same repository:

bin_PROGRAMS = osmo-app
osmo_app_SOURCES = src/app.c

osmo_app_LDADD = \
        $(top_builddir)/src/ \
        $(top_builddir)/src/ \
        $(LIBOSMO_ZOO_LIBS) \

NOTE: It's a common mistake to put libraries into LDFLAGS, please use the LIBADD/LDADD variables for that. The key difference is that AM_LDFLAGS appears first in the linker's command line, while the LDADD/LIBADD ones appear last. By having libraries listed in AM_LDFLAGS, you may experience weird problems running tests from check_PROGRAMS, which may load system-installed libraries instead of the repository-local ones.

TIP: It's a good practice to put -no-install to AM_LDFLAGS in tests/ This option should be used for any executables which are used only for testing, or for generating other files and are consequently never installed. By specifying this option, we are telling Libtool that the executable it links will only ever be executed from where it is built in the build tree. Libtool is usually able to considerably speed up the link process for such executables.

TIP: Using -no-undefined (AM_LDFLAGS) is desirable for libraries which do not depend on external symbols defined in apps linking against them.

Files (0)

Updated by fixeria 12 months ago · 10 revisions

Add picture from clipboard (Maximum size: 48.8 MB)