Add Targets for lots of Small Executables

Introduction

This cmake module provides a function add_executables that simplifies the process of adding multiple small executable targets to a CMake project. It is particularly useful for projects that include a large number of example programs or test utilities, where each executable is defined in its own source file.

Usage

The function signature is as follows:

add_executables(PATH [PATH ...]
                [LIBRARIES <lib1> <lib2> ...]
                [COMBINED_TARGET [optional_target_name (default: "all_examples")]] )

This processes source files found in the provided path arguments and generates corresponding executable targets.

The path arguments can be directories or individual source files. If a directory is provided, the function will process all the source files found in the directory and its subdirectories. Source files are assumed to have a supported C/C++ extension (.c, .cc, .cxx, .cpp, .C, .c++).

To use this function, we expect each source file found in the provided paths to generate a standalone executable program (so Foo.cpp will generate an executable called Foo).

For example, if we pass a directory that has a file Foo.cpp, the function will create a target Foo that compiles Foo.cpp and links the object file to the libraries from the LIBRARIES argument.

Suppose the project looks like:

project/
├── .git
├── CMakeLists.txt
├── cmake
│   └── add_executables.cmake
├── examples
│   ├── Bar01.cpp
│   ├── Bar02.cpp
│   ├── Bar03.cpp
│   ├── Foo01.cpp
│   └── Foo02.cpp
└── ...

and your CMakeLists.txt file has some lines like

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(add_executables)
add_executables(examples
                LIBRARIES nlohmann_json::nlohmann_json)

then CMake will create individual targets for Bar01, Bar02, Bar03, Foo01, and Foo02 and link them to the library nlohmann_json.

Combined Target

The combined target is useful when you want to build all the executables at once from a single command.

If the optional COMBINED_TARGET <target_name> argument is provided, the function will also create a target with the name <target_name> that depends on all the individual executable targets created from the source files. The <target_name> is optional, and if not provided, it defaults to all_examples.

The combined target is a utility, meaning you can use it to build all the executables from one command but it isn’t an actual executable itself.

The above example can be modified to create a combined target called all_tools like this:

add_executables(examples
                LIBRARIES nlohmann_json::nlohmann_json
                COMBINED_TARGET all_tools)

Now, running cmake --build . --target all_tools will build all the individual executables found in the examples directory.

Rationale

Library developers often develop an extensive set of simple command-line tools that demonstrate or test various features of their library. This is how one ends up with a directory like the examples above.

The add_executables function makes it easy to grow that collection of executables without worrying about adding them to some CMakeLists.txt file.

Back to top