cmake

Getting started with cmake

Remarks#

CMake is a tool for defining and managing code builds, primarily for C++.

CMake is a cross-platform tool; the idea is to have a single definition of how the project is built - which translates into specific build definitions for any supported platform.

It accomplishes this by pairing with different platform-specific buildsystems; CMake is an intermediate step, that generates build input for different specific platforms. On Linux, CMake generates Makefiles; on Windows, it can generate Visual Studio projects, and so on.

Build behavior is defined in CMakeLists.txt files - one in every directory of the source code. Each directory’s CMakeLists file defines what the buildsystem should do in that specific directory. It also defines which subdirectories CMake should handle as well.

Typical actions include:

  • Build a library or an executable out of some of the source files in this directory.
  • Add a filepath to the include-path used during build.
  • Define variables that the buildsystem will use in this directory, and in its subdirectories.
  • Generate a file, based on the specific build configuration.
  • Locate a library which is somewhere in the source tree.

The final CMakeLists files can be very clear and straightforward, because each is so limited in scope. Each only handles as much of the build as is present in the current directory.

For official resources on CMake, see CMake’s Documentation and Tutorial.

Versions#

VersionRelease Date
3.92017-07-18
3.82017-04-10
3.72016-11-11
3.62016-07-07
3.52016-03-08
3.42015-11-12
3.32015-07-23
3.22015-03-10
3.12014-12-17
3.02014-06-10
2.8.12.12013-11-08
2.8.122013-10-11
2.8.112013-05-16
2.8.10.22012-11-27
2.8.10.12012-11-07
2.8.102012-10-31
2.8.92012-08-09
2.8.82012-04-18
2.8.72011-12-30
2.8.62011-12-30
2.8.52011-07-08
2.8.42011-02-16
2.8.32010-11-03
2.8.22010-06-28
2.8.12010-03-17
2.82009-11-13
2.62008-05-05

CMake Installation

Head over to CMake download page and get a binary for your operating system, e.g. Windows, Linux, or Mac OS X. On Windows double click the binary to install. On Linux run the binary from a terminal.

On Linux, you can also install the packages from the distribution’s package manager. On Ubuntu 16.04 you can install the command-line and graphical application with:

sudo apt-get install cmake
sudo apt-get install cmake-gui

On FreeBSD you can install the command-line and the Qt-based graphical application with:

pkg install cmake
pkg install cmake-gui

On Mac OSX, if you use one of the package managers available to install your software, the most notable being MacPorts (MacPorts) and Homebrew (Homebrew), you could also install CMake via one of them. For example, in case of MacPorts, typing the following

sudo port install cmake  

will install CMake, while in case you use the Homebrew package manger you will type

brew install cmake

Once you have installed CMake you can check easily by doing the following

cmake --version

You should see something similar to the following

cmake version 3.5.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).

Switching between build types, e.g. debug and release

CMake knows several build types, which usually influence default compiler and linker parameters (such as debugging information being created) or alternative code paths.

By default, CMake is able to handle the following build types:

  • Debug: Usually a classic debug build including debugging information, no optimization etc.
  • Release: Your typical release build with no debugging information and full optimization.
  • RelWithDebInfo:: Same as Release, but with debugging information.
  • MinSizeRel: A special Release build optimized for size.

How configurations are handled depends on the generator that is being used.

Some generators (like Visual Studio) support multiple configurations. CMake will generate all configurations at once and you can select from the IDE or using --config CONFIG (with cmake --build) which configuration you want to build. For these generators CMake will try its best to generate a build directory structure such that files from different configurations do not step on each other.

Generators that do only support a single configuration (like Unix Makefiles) work differently. Here the currently active configuration is determined by the value of the CMake variable CMAKE_BUILD_TYPE.

For example, to pick a different build type one could issue the following command line commands:

cmake -DCMAKE_BUILD_TYPE=Debug path/to/source
cmake -DCMAKE_BUILD_TYPE=Release path/to/source

A CMake script should avoid setting the CMAKE_BUILD_TYPE itself, as it’s generally considered the users responsibility to do so.

For single-config generators switching the configuration requires re-running CMake. A subsequent build is likely to overwrite object files produced by the earlier configuration.

Simple “Hello World” Project

Given a C++ source file main.cpp defining a main() function, an accompanying CMakeLists.txt file (with the following content) will instruct CMake to generate the appropriate build instructions for the current system and default C++ compiler.

main.cpp (C++ Hello World Example)

#include <iostream>

int main()
{
    std::cout << "Hello World!\n";
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.4)

project(hello_world)

add_executable(app main.cpp)

See it live on Coliru

  1. cmake_minimum_required(VERSION 2.4) sets a minimum CMake version required to evaluate the current script.

  2. project(hello_world) starts a new CMake project.

This will trigger a lot of internal CMake logic, especially the detection of the default C and C++ compiler.

  1. With add_executable(app main.cpp) a build target app is created, which will invoke the configured compiler with some default flags for the current setting to compile an executable app from the given source file main.cpp.

Command Line (In-Source-Build, not recommended)

> cmake .
...
> cmake --build .

cmake . does the compiler detection, evaluates the CMakeLists.txt in the given . directory and generates the build environment in the current working directory.

The cmake --build . command is an abstraction for the necessary build/make call.

Command Line (Out-of-Source, recommended)

To keep your source code clean from any build artifacts you should do “out-of-source” builds.

> mkdir build
> cd build
> cmake ..
> cmake --build .

Or CMake can also abstract your platforms shell’s basic commands from above’s example:

> cmake -E make_directory build
> cmake -E chdir build cmake .. 
> cmake --build build 

“Hello World” with multiple source files

First we can specify the directories of header files by include_directories(), then we need to specify the corresponding source files of the target executable by add_executable(), and be sure there’s exactly one main() function in the source files.

Following is a simple example, all the files are assumed placed in the directory PROJECT_SOURCE_DIR.

main.cpp

#include "foo.h"

int main()
{
    foo();
    return 0;
}

foo.h

void foo();

foo.cpp

#include <iostream>
#include "foo.h"

void foo()
{
    std::cout << "Hello World!\n";
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.4)

project(hello_world)

include_directories(${PROJECT_SOURCE_DIR})
add_executable(app main.cpp foo.cpp)  # be sure there's exactly one main() function in the source files

We can follow the same procedure in the above example to build our project. Then executing app will print

>./app
Hello World!

“Hello World” as a library

This example shows how to deploy the “Hello World” program as a library and how to link it with other targets.

Say we have the same set of source/header files as in the https://stackoverflow.com/documentation/cmake/862/getting-started-with-cmake/22391/hello-world-with-multiple-source-files#t=201610310659039267444 example. Instead of building from multiple source files, we can first deploy foo.cpp as a library by using add_library() and afterwards linking it with the main program with target_link_libraries().

We modify CMakeLists.txt to

cmake_minimum_required(VERSION 2.4)

project(hello_world)

include_directories(${PROJECT_SOURCE_DIR})
add_library(applib foo.cpp)
add_executable(app main.cpp)
target_link_libraries(app applib)

and following the same steps, we’ll get the same result.


This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow