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:
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.
Variable names are case-sensitive. Their values are of type string. The value of a variable is referenced via:
${variable_name}
and is evaluated inside a quoted argument
"${variable_name}/directory"
The main difference between macros and functions is, that macros are evaluated within the current context, while functions open a new scope within the current one. Thus, variables defined within functions are not known after the function has been evaluated. On the contrary, variables within macros are still defined after the macro has been evaluated.
CPack is an external tool allowing the fast packaging of built CMake projects by gathering all the required data straight from the CMakeLists.txt
files and the utilized installation commands like install_targets()
.
For CPack to properly work, the CMakeLists.txt
must include files or targets to be installed using the install
build target.
A minimal script could look like this:
# Required headers
cmake(3.0)
# Basic project setup
project(my-tool)
# Define a buildable target
add_executable(tool main.cpp)
# Provide installation instructions
install_targets(tool DESTINATION bin)
The find_package
way is compatible on all platform, whereas the pkg-config
way is available only on Unix-like platforms, like Linux and OSX.
A full description of the find_package
numerous parameters and options can be found in the manual.
Even though it is possible to specify many optional parameters such as the version of the package, not all Find modules properly uses all those parameters. If any undefined behaviour occur, it could be necessary to find the module in CMake's install path and fix or understand its behaviour.
Copy a file to another location and modify its contents.
configure_file(<input> <output>
[COPYONLY] [ESCAPE_QUOTES] [@ONLY]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
Copies a file to file and substitutes variable values referenced in the file content. If is a relative path it is evaluated with respect to the current source directory. The must be a file, not a directory. If is a relative path it is evaluated with respect to the current binary directory. If names an existing directory the input file is placed in that directory with its original name.
If the file is modified the build system will re-run CMake to re-configure the file and generate the build system again.
This command replaces any variables in the input file referenced as ${VAR} or @VAR@ with their values as determined by CMake. If a variable is not defined, it will be replaced with nothing. If COPYONLY is specified, then no variable expansion will take place. If ESCAPE_QUOTES is specified then any substituted quotes will be C-style escaped. The file will be configured with the current values of CMake variables. If @ONLY is specified, only variables of the form @VAR@ will be replaced and ${VAR} will be ignored. This is useful for configuring scripts that use ${VAR}.
Input file lines of the form “#cmakedefine VAR ...” will be replaced with either “#define VAR ...” or /* #undef VAR */ depending on whether VAR is set in CMake to any value not considered a false constant by the if() command. (Content of ”...”, if any, is processed as above.) Input file lines of the form “#cmakedefine01 VAR” will be replaced with either “#define VAR 1” or “#define VAR 0” similarly.
With NEWLINE_STYLE the line ending could be adjusted:
'UNIX' or 'LF' for \n, 'DOS', 'WIN32' or 'CRLF' for \r\n.
COPYONLY must not be used with NEWLINE_STYLE.
As you can see, you can do a lot with custom build targets and steps in cmake, but you should be careful in using them, especially when copying dlls. While it is convinient to do so, it can at times result in what is affectionately called "dll hell".
Basically this means you can get lost in which dlls your executable actually depends on, which ones its loading, and which ones it needs to run (maybe because of your computer's path variable).
Other than the above caveat, feel free to make custom targets do whatever you want! They're powerful and flexible and are an invaluable tool to any cmake project.
It is important to understand not every preprocessor should be defined in the config.h.in
. Preprocessor tags are generally used only to make the programmers life easier and should be used with discretion. You should research if a preprocessor tag already exists before defining it as you may run into undefined behavior on different system.