When I recently started to work with CMake for a C++ project, I did find it challenging to get started with. The documentation is comprehensive but can be overwhelming. There are of course multiple helpful articles and tutorials around, but I was already struggling with the simplest commands.
This article is mainly for the people, who use CMake for the first time. I will try to use as less words and to be as clear as possible. Surely it will not be complete and I can not guarantee full correctness. Comments and corrections are welcome!
Find the whole source code at Github: https://github.com/digitsensitive/cmake-starter
CMake is an extensible, open-source system that manages the build process in an operating system and in a compiler-independent manner (taken from the official website). There are alternative tools.
This all sounds good. But seriously, what is CMake exactly and why should I use it?
You should use it, because with one configuration file (CMakeLists.txt) you can generate standard build files to be used by a native build environment (f.e. Make, Apple’s Xcode, Qt Creator, Ninja, Microsoft Visual Studio) to create the actual building (= your application). You can get full flexibility and make your project more future-proof.
CMake has minimal dependencies, requiring only a C++ compiler on its own build system.
Enough general talk: Let’s create our first (very complicated!) C++ project:
int main() {
return 0;
}
This is our main.cpp file and I have placed it into a folder called src. Additionally we need a folder named build in the root.
We place our CMake configuration file (CMakeLists.txt) in the root. This is our final folder tree structure:
.
├── CMakeLists.txt
├── build
└── src
└── main.cpp
At this point make sure you have CMake installed on your computer!
For the rest of this article, we will focus on creating our first simple configuration file. You can find the whole configuration file in the source code repository linked in the article.
cmake_minimum_required(VERSION 3.18.1)
At first you should set the minimum required
CMake version.
If your local version of CMake is lower than the minimum, it will stop
processing the project and report an error. You might want to set three
variables VERSION_MAJOR
, VERSION_MINOR
and VERSION_REVISION
and use them
(as it is in the
github repository).
set(CMAKE_CXX_STANDARD 11)
Next we set the variable
CMAKE_CXX_STANDARD
to define the C++ standard whose features we request to build the project.
Supported values are 98
, 11
, 14
, 17
, and 20
.
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Now we want to set the C++ standard to be required. For this we set the variable
CMAKE_CXX_STANDARD_REQUIRED
to ON
.
project(myProject VERSION 0.1.0)
We can now
set our project name
and the version (optional). More optional variables are DESCRIPTION
,
HOMEPAGE_URL
and LANGUAGES
. From now on you can refer to your project name
with the variable PROJECT_NAME
, which is recommended to minimize typing
errors.
add_executable(${PROJECT_NAME} src/main.cpp)
Finally we
add an executable
to our project, for which we use our predefined variable PROJECT_NAME
. We also
add a list of our source files.
At this point we are done with our basic CMakeLists.txt file.
cmake_minimum_required(VERSION 3.18.1)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(myProject VERSION 0.1.0)
add_executable(${PROJECT_NAME} main.cpp)
With our CMakeLists.txt file we finished our project. We can now generate the standard build files (= a project build system). Open your terminal and navigate to the empty build folder.
cmake ..
With cmake
you access the
command-line interface
of the buildsystem generator CMake. With the ..
you hand over the path to the
source. This path must contain a CMakeLists.txt
file. Now you should have your
build files!
Finally we want to build the executable file. I use make
, so I simply have to
run the following command in the build folder:
make
If you like you can replace this line and use this instead:
cmake --build
This will call make
or whatever build tool you are using.
This is it. There would be much more to write. But I guess that is enough for a start. Comments or corrections are always welcome!
After publishing this story I received important and helpful advises. I want to sum it up here:
include_directories
and use
target_include_directories
instead. You will have to call
add_executable
before. The problem with include_directories
is, that it operates on the
directory level. This means that all the targets on that level inherit the
properties. That makes it difficult to control.I just began to read about Modern CMake and can recommend the following ressources: