How to Work with CMake
In brief, CMake is all about targets and properties
CMake Project Structureβ
A typical CMake project can be regarded to has three Tree:
Source Tree:
project_root
βββ CMakeLists.txt
βββ simple_example.cpp
βββ simple_lib.cpp
βββ simple_lib.hpp
Build Tree:
project_root
βββ CMakeLists.txt
βββ simple_example.cpp
βββ simple_lib.cpp
βββ simple_lib.hpp
βββ build
βββ CMakeCache.txt
Install Tree:
This tree is located in the CMAKE_INSTALL_PREFIX, of which default value is platform-dependent. By default, it is set to /usr/local on Unix-like systems (Linux, macOS) and C:/Program Files/<Project Name> on Windows..
To change it, you can pass -DCMAKE_INSTALL_PREFIX argument during CMake configuration step, like this:
cmake -B build -S . -DCMAKE_INSTALL_PREFIX=/my/custom/installation/path
Alternatively, you can change it by passing --prefix(it can be relative path) argument during CMake install step, like this:
cmake --install build --prefix "/my/custom/installation/path"
It's recommended to use a default install layout as GNUInstallDirs.
A install tree will look like as below if you'd like all things to be installed inside the project via cmake --install build --prefix "./install.
project_root
βββ CMakeLists.txt
βββ simple_example.cpp
βββ simple_lib.cpp
βββ simple_lib.hpp
βββ build
β βββ CMakeCache.txt
βββ install
βββ bin
β βββ executables
βββ sbin
β βββ sysadmin executables
βββ lib
β βββ compiled libraries (*.so (unix) or *.dll (windows))
β βββ library archive files (*.lib (windows))
βββ libexec
β βββ executables not directly invoked by user
βββ include
β βββ header files
βββ doc
βββ documentation
How CMake Worksβ
A typical workflow of CMake includes Configure, Build and Install steps, combined with the above mentioned Trees concepts.
Configurestep will generate a sort of configuration files, the most important ones among them areCMakeCache.txt,cmake_install.cmakeandMakefileif usingMakeas building system. With these generated configuration files, the later stepsBuildandInstallwill run according to them.Buildstep will generate the build binary directory.Installstep will generate the install binary directory.
How to make your package be found by others by find_package()β
package configuration files: find_package
RPATH in CMakeβ
CMake Variablesβ
There are some useful and important CMake variables that will be introduced here:
CMAKE_PREFIX_PATH
CMAKE_IGNORE_PATH
clang FAQβ
Find out clang include search pathβ
β― clang -x c -v -E /dev/null
...
#include "..." search starts here:
#include <...> search starts here:
/opt/homebrew/Cellar/llvm/17.0.1/lib/clang/17/include
/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk/System/Library/Frameworks (framework directory)
End of search list.
# 1 "/dev/null"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 420 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "/dev/null" 2
Add include search path to clangβ
Use environment variables C_INCLUDE_PATH for c and CPLUS_INCLUDE_PATH for c++.
clang:
β― C_INCLUDE_PATH=/opt/homebrew/include clang -x c -v -E /dev/null
...
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/opt/homebrew/include
/Library/Developer/CommandLineTools/usr/lib/clang/15.0.0/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
/Library/Developer/CommandLineTools/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
clang++:
β― CPLUS_INCLUDE_PATH=/opt/homebrew/include clang -x c++ -v -E /dev/null
...
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/opt/homebrew/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1
/Library/Developer/CommandLineTools/usr/lib/clang/15.0.0/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
/Library/Developer/CommandLineTools/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
Use -I flag,
β― clang -x c -I/opt/homebrew/include -v -E /dev/null
...
#include "..." search starts here:
#include <...> search starts here:
/opt/homebrew/include
/usr/local/include
/Library/Developer/CommandLineTools/usr/lib/clang/15.0.0/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
/Library/Developer/CommandLineTools/usr/include
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
Find out clang library search pathsβ
β― clang -Xlinker -v
...
Library search paths:
/usr/local/lib
Framework search paths:
ld: Undefined symbols:
_main, referenced from:
<initial-undefines>
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Add library search path to clangβ
Use environment variables LIBRARY_PATH,
β― LIBRARY_PATH=$LIBRARY_PATH:/usr/lib clang -Xlinker -v
...
Library search paths:
.
/usr/lib
/usr/local/lib
Framework search paths:
ld: Undefined symbols:
_main, referenced from:
<initial-undefines>
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Use -L flag:
β― clang -L/opt/homebrew/lib -Xlinker -v
OS X clang include lib search path
What is the difference? clang++ | clang -std=c++11β
CMake FAQβ
Add library search path to CMake globally in projectβ
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /opt/local/lib)LINK_DIRECTORIES(/opt/local/lib)
Referencesβ
CMake hands-on workshop β CMake Workshop
