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#
Version | Release Date |
---|---|
3.9 | 2017-07-18 |
3.8 | 2017-04-10 |
3.7 | 2016-11-11 |
3.6 | 2016-07-07 |
3.5 | 2016-03-08 |
3.4 | 2015-11-12 |
3.3 | 2015-07-23 |
3.2 | 2015-03-10 |
3.1 | 2014-12-17 |
3.0 | 2014-06-10 |
2.8.12.1 | 2013-11-08 |
2.8.12 | 2013-10-11 |
2.8.11 | 2013-05-16 |
2.8.10.2 | 2012-11-27 |
2.8.10.1 | 2012-11-07 |
2.8.10 | 2012-10-31 |
2.8.9 | 2012-08-09 |
2.8.8 | 2012-04-18 |
2.8.7 | 2011-12-30 |
2.8.6 | 2011-12-30 |
2.8.5 | 2011-07-08 |
2.8.4 | 2011-02-16 |
2.8.3 | 2010-11-03 |
2.8.2 | 2010-06-28 |
2.8.1 | 2010-03-17 |
2.8 | 2009-11-13 |
2.6 | 2008-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)
-
cmake_minimum_required(VERSION 2.4)
sets a minimum CMake version required to evaluate the current script. -
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.
- With
add_executable(app main.cpp)
a build targetapp
is created, which will invoke the configured compiler with some default flags for the current setting to compile an executableapp
from the given source filemain.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.