Introduction

Overview

Teaching: 10 min
Exercises: 0 min
Questions
  • What is the difference between a build system and a build system generator?

Objectives
  • Learn about build systems and build system generators.

  • Understand why CMake is used.

  • Newer CMake is better.

Building code is hard. You need long commands to build each part of your code; and you need do to this on many parts of your code.

So people came up with Build Systems; these had ways to set up dependencies (such as file A needs to be built to build file B), and ways to store the commands used to build each file or type of file. These are language independent (mostly), allowing you to setup builds of almost anything; you can use make to build LaTeX documents if you wish. Some common build systems include make (the classic pervasive one), ninja (a newer one from Google designed in the age of build system generators), invoke (a Python one), and rake (Ruby make, nice syntax for Ruby users).

However, this is:

Enter Build System Generators (hereby labeled BSGs for brevity). These understand the concepts of your programming language build; they usually support common compilers, languages, libraries, and output formats. These usually write a build system (or IDE) file and then let that do the actual build. The most popular BSG is CMake, which stands for Cross-platform Make. But as we’ve just shown, it is not really in the same category as make. Other BSGs include Autotools (old, inflexible), Bazel (by Google), SCons (older Python system), Meson (young Python system, very opinionated), and a few others. But CMake has unparalleled support by IDEs, libraries, and compilers. It also scales very well, with small projects able to pick it up easily (modern CMake, anyway), and massive projects like the CERN experiments being able to use it for thousands of modules.

Note that both CMake and Make are custom languages rather than being built in an existing language, like rake and SCons, etc. While it is nice to consolidate languages, the requirement that you have an external language installed and configured was too high for any of these to catch on for general use.

To recap, you should use CMake if:

(More) Modern CMake

CMake has really changed dramatically since it was introduced around 2000. And, by the time of 2.8, it was available in lots of Linux Distribution package managers. However, this means there often are really old versions of CMake “available by default” in your environment. Please, please upgrade and design for newer CMake. No one likes writing or debugging build systems. Using a newer version can cut your build system code in less than half, reduce bugs, integrate better with external dependents, and more. Installing CMake can be as little as one line, and doesn’t require sudo access. See more info here.

Somehow, this is difficult to understand, so I’ll shout it to make it clearer. Writing Modern CMake reduces your chances of build problems. The tools CMake provides are better than the ones you will try to write yourself. CMake works with more compilers, in more situations, than you do. So if you try to add a flag, you’ll likely get it wrong for some compilers or OSs, but if you can use a tool CMake gives you instead, then that’s CMake’s business to get right and not yours.

It’s not a big deal to install a newer CMake. The issues people open for “this is broken” far outnumber the issues people open because you required a CMake newer than they want to run (I think I’ve only seen one of those, and they came around when they saw the feature they would have to give up).

Example of Modern CMake

Bad 2.8 style CMake: Adding a C++11 flag manually. This is compiler specific, is different for CUDA, and locks in a set version, rather than a minimum version.

If you require CMake 3.1+, you can set CXX_STANDARD, but only on a final target. Or you can manually list compile_features for individual C++11 and C++14 features, and, and all targets using yours will get at least that level set on them.

If you require CMake 3.8+, you can just use compile_features to set a minimium standard level, like cxx_std_11, instead of manually listing a bunch of features. This was used for C++17 and later C++20 and C__23, exclusively.

Selecting a minimum in 2023:

What minimum CMake should you run locally, and what minimum should you support for people using your code? Since you are reading this, you should be able to get a release in the last few versions of CMake; do that, it will make your development easier. For support, there are two ways to pick minimums: based on features added (which is what a developer cares about), or on common pre-installed CMakes (which is what a user cares about).

Never select a minimum version older than the oldest compiler version you support. CMake should always be at least as new as your compiler.

What minimum to choose - OS support:

What minimum to choose - Features:

Other sources

There are some other places to find good information on the web. Here are some of them:

Key Points

  • Build systems describe exactly how to build targets.

  • Build system generators describe general relationships.

  • Modern CMake is simpler and reduces the chance of build problems.