CMakeCheatsheet
CMake Cheatsheet -- A gentle introduction to CMake
CMake - Creating a simple C++ project
CMake is a tool for configuring how a cross-platform source code project should be built on a given platform.
A small project could be organized like this:
This project contains two source files located in the src directory and one header file in the include directory in the same directory.
When running CMake on this project you are asked to for a binary directory. It is best practice to create a new directory since this directory will contain all files related to building the project. If something goes wrong, you can delete the folder and start over.
Running CMake will not create the final executable, but instead, it will generate project files for Visual Studio, XCode or makefiles. Use these tools to build the project.
Understanding CMakeLists.txt
Creating project files using CMake requires a file, which describes how the project is structured and how it should be built.
For example 1 the file looks like this:
First, the minimum version of CMake is defined. Then the project name is defined using the command . A project can contain multiple targets (either executables or libraries). This project defines a single executable target called , which is created by compiling and linking the two source files and files.
When the two source files are compiled the compiler will search for the header file since both source files depend on this using a . Since the file is located in the same located as the source file, the compiler will not have any problems finding the file.
The CMake Scripting Language
The CMakeLists.txt describes the build process using a command based programming language. The commands are case insensitive and take a list of arguments.
CMake script also has variables. Variables can either be defined by CMake or can be defined in the CMake script. The command set a given parameter to a value. The command print out the value to the console. To get the value of a variable use , which substitutes the variable name with its value.
All variable values are a text string. Text strings can be evaluated as boolean expressions (e.g. when used in and ). The values "FALSE", "OFF", "NO", or any string ending in "-NOTFOUND" evaluates be false - everything else to true.
Text strings can represent multiple values as a list by separating entities using a semicolon.
Lists can be iterated using the command :
Exposing compile options
CMake allows the end user (who runs CMake) to modify some values of some variables. This is usually used to defined properties of the build such as locations of files, machine architecture, and string values.
The command set the variable to the default value - but allows the value to be changed by the cmake user when configuring the build. The type should be one of the following:
FILEPATH = File chooser dialog.
PATH = Directory chooser dialog.
STRING = Arbitrary string.
BOOL = Boolean ON/OFF checkbox.
INTERNAL = No GUI entry (used for persistent variables).
In the following example, the user can configure if "Hello" or an alternative string should be printed based on the configuration variables hello and other_msg.
The values that the CMake user enters will be saved in the text file as key-value pairs:
Complex projects
Some project both contains multiple executables and multiple libraries. For instance when having both unit tests and programs. It is common to separate these subprojects into subfolders. Example:
The main contains the basic project settings but then includes the subprojects:
First the library Foo is compiled from the source in the directory:
Finally, the executable Hello is compiled and linked to the Foo library
note that the target name is used here - not the actual path. Since the main.cpp references to header file Foo.hpp the somelib directory is added to the header search path:
Searching for source files
Use the to automatically search for files within a directory given one or more search patterns. Note that in the example below, both source files and header files are added to the project. This is not needed for compiling the project, but it is convenient when using an IDE since this also adds the header files to the project.
Runtime resources
Often runtime resources (such as DLLs, game-assets and text files) are read relative to the executable. One solution is to copy resources into the same directory as the executable. Example:
In this project, the source files assume that the resource is located in the same directory as the executable:
The CMakeLists.txt make sure to copy the file.
Note: One problem with this approach is if you modify the original resources, then you need to run CMake again.
External libraries
External libraries basically come in two flavors; dynamically linked libraries (DLLs) which are linked with the binary at runtime and statical linked libraries which are linked at compile time.
Static libraries have the most simple setup. To use one, the compiler needs to know the location of where to locate the header files and the linker need to know the location of the actual library. Unless the external libraries are distributed along with the project it is usually not possible to know their location - for this reason, it is common to use cached variables, where the CMake user can change the location. Static libraries have the file ending .lib on Windows and .a on most other platforms.
Dynamically linked libraries work similar to statical linked libraries. On Windows, it is still needed to link to a library at compile time, but the actual linking to the DLL happens at compile time. The executable file needs to be able to find the DLL file in the runtime linkers search path. If the DLL is not a system library, an easy solution is to copy the DLL next to the executable. Working with DLL often requires platform specific actions, which CMake support using the built-in variables , , .
Automatically locating libraries
CMake also contains a feature to automatically find libraries (based on a number of suggested locations) using the command . However, this feature works best on macOS and Linux.
C++ version
The C++ version can be set using the commands:
Defining preprocessor symbols
Use the to add preprocessor symbols to the project.
This will create the symbols and , which can be used in the source code:
Last updated