Hello CMake

by daniel packard

Prerequisites:

This post assumes you are familiar with:

  • C/C++
  • at least one C/C++ build tool, system, or IDE (gcc/g++, gnu make, xcode, visual studio, etc)

Installing CMake

Instructions available: here
Installers available: here

What is CMake?

According to the CMake project (emphasis mine):

CMake is an open-source, cross-platform family of tools designed to build, test and package software. CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and generate native makefiles and workspaces that can be used in the compiler environment of your choice.

-- cmake.org , December 2020

In short, CMake helps you manage the build configuration for portable C/C++ software projects.

Motivation for CMake

For maintainers / contributors of software projects:

If you want to write code that can be used on multiple platforms (Mac, Linux, Windows, etc), one option is to provide a build configuration for every platform you want to support:

  • Makefile for GNU/Linux
  • Xcode workspace for Mac
  • Visual Studio solution for windows

If you're unfamiliar with the particulars of every platform, it might be impossible for you to support all of them. Even if you are familiar with all of these tools, over time you'll find yourself replicating small changes in build configurations across the multiple platforms, not to mention the inevitable drift between platforms 😬. You also can't see the future. What platforms and tools might exist 5 years from now?

For consumers / users of software projects:

Even more commmonly, if you want to reuse code that someone else has written you'd better hope they have also written a build configuration that supports your platform and tools of choice. Otherwise, you're in for a wild ride trying to piece together your own build from scratch.

That's where CMake come in — you can target (nearly) every platform and (nearly) every toolset, even ones that don't exist yet, with a single unified build configuration written in CMake. And for consumers it's consistent. You don't have to decipher eleventy dozen ad-hoc attempts at multi-platform build support.

Example 0: The Anatomy of a CMake Project

We'll start with the simplest possible project, containing just two files:

  1. main.cpp – the source code for a simple command line executable
  2. CMakeLists.txt – a CMake build configuration

image

The source for this example is available as a GitHub gist. Let's take a closer look.

The source file, main.cpp, contains exactly what you might expect from a hello, world program.

The more interesting part here is the CMake build configuration, contained in CMakeLists.txt.

In this case, there are exactly 3 lines of configuration:

  • line 1: cmake_minimum_required(VERSION 3.15)
    • Every CMake build configuration should start with a minimum required version. When in doubt, use the current version number of your CMake executable (cmake --version)
  • line 2: project(HelloCMake)
    • This tells CMake you are defining a new project named HelloCMake
  • line 4: add_executable(hello main.cpp)
    • This tells CMake to add a single executable named hello that is the result of compiling main.cpp

Easy-peasy. Now how is it used to build the software?

  • Step 1: clone the gist
git clone https://gist.github.com/daniel-packard/4756acc129365f9d26d6ffbfe6738276 hello-cmake
  • Step 2: open the CMake GUI

image

  • Step 3: Locate the source code directory, using the Browse Source button
    • Note: you should select the directory containing your source code and CMakeLists.txt.

image

  • Step 4: Locate the build directory, using the Browse Build button
    • By convention CMake encourages "out of tree" builds, meaning you select a different build directory. This helps with keeping your workspace tidy, and your build artifacts organized (i.e. easy to delete), and lets you do side-by-side builds for different platforms (e.g. by having two different build output directories: build-ios, build-x64-windows)
    • in this case, I am creating a subdirectory inside my project called build

image

  • Step 5a: Press the Configure button
    • Follow the prompts to select your "generator" and compiler toolchain.
    • In this case I'm building with Visual Studio 16 2019 and using the default native compiler toolchain

image

  • Step 5b: Results of "Configure"
    • Pressing Finish (if successful) will load the CMake build configuration and presents you with any configurable options/settings
    • In this case, there are only a couple built-in options from CMake. We'll come back to them later.

image

  • Step 6: Press Generate to produce the build configuration
    • For me, this creates a visual studio solution

image

  • Step 7: Build your project
    • In my case, this involves: opening the solution, setting "hello" as the startup project, and pressing the "play" button

image

Success!

... or is it? Please send questions/problems to [email protected], and we'll develop a companion trouble-shooting guide.

Example 0 Recap

  • Downloaded a project containing some source code and a CMakeLists.txt build configuration
  • Configured the project using CMake for Visual Studio 2019, using my native compiler toolchain
  • Generated a build configuration for my tools/platform of choice
  • Built and ran the hello command line tool using Visual Studio

Example 1: Library with Examples

Software Development CMake, c++, c