《Modern CMake》读书笔记
Running CMake
Building a project
mkdir build
cd build
cmake ..
make # cmake --build .
or
cmake -S . -B build
cmake --build build
install
# from build directory
make install
cmake --build . --target install
cmake --install .
# from source directory
make -C build install
cmake --build build --target install
cmake --install build
Picking a compiler
CC=clang Cxx=clang++ cmake ..
Picking a generator
cmake --help
Generators
The following generators are available on this platform:
Unix Makefiles = Generates standard UNIX makefiles.
Ninja = Generates build.ninja files.
Watcom WMake = Generates Watcom WMake makefiles.
CodeBlocks - Ninja = Generates CodeBlocks project files.
CodeBlocks - Unix Makefiles = Generates CodeBlocks project files.
CodeLite - Ninja = Generates CodeLite project files.
CodeLite - Unix Makefiles = Generates CodeLite project files.
Eclipse CDT4 - Ninja = Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.
KDevelop3 = Generates KDevelop 3 project files.
KDevelop3 - Unix Makefiles = Generates KDevelop 3 project files.
Kate - Ninja = Generates Kate project files.
Kate - Unix Makefiles = Generates Kate project files.
Sublime Text 2 - Ninja = Generates Sublime Text 2 project files.
Sublime Text 2 - Unix Makefiles
= Generates Sublime Text 2 project files.
cmake -G "Unix Makefiles"
Setting options
Verbose and partial builds
cmake --build build --verbose
VERBOSE=1 make
CMake 行为准则(Do’s and Don’ts)
CMake 应避免的行为
接下来的两个列表很大程度上基于优秀的 gist Effective Modern CMake. 那个列表更长且更详细,也非常欢迎你去仔细阅读它。
- 不要使用具有全局作用域的函数:这包含 link_directories、 include_libraries 等相似的函数。
- 不要添加非必要的 PUBLIC 要求:你应该避免把一些不必要的东西强加给用户(-Wall)。相比于 PUBLIC,更应该把他们声明为 PRIVATE。
- 不要在file函数中添加 GLOB 文件:如果不重新运行 CMake,Make 或者其他的工具将不会知道你是否添加了某个文件。值得注意的是,CMake 3.12 添加了一个 CONFIGURE_DEPENDS 标志能够使你更好的完成这件事。
- 将库直接链接到需要构建的目标上:如果可以的话,总是显式的将库链接到目标上。
- 当链接库文件时,不要省略 PUBLIC或PRIVATE 关键字:这将会导致后续所有的链接都是缺省的。
CMake 应遵守的规范
- 把 CMake 程序视作代码:它是代码。它应该和其他的代码一样,是整洁并且可读的。
- 建立目标的观念:你的目标应该代表一系列的概念。为任何需要保持一致的东西指定一个 (导入型)INTERFACE 目标,然后每次都链接到该目标。
- 导出你的接口:你的 CMake 项目应该可以直接构建或者安装。
- 为库书写一个 Config.cmake 文件:这是库作者为支持客户的体验而应该做的。
- 声明一个 ALIAS 目标以保持使用的一致性:使用 add_subdirectory 和 find_package 应该提供相同的目标和命名空间。
- 将常见的功能合并到有详细文档的函数或宏中:函数往往是更好的选择。
- 使用小写的函数名: CMake 的函数和宏的名字可以定义为大写或小写,但是一般都使用小写,变量名用大写。
- 使用 cmake_policy 和/或 限定版本号范围: 每次改变版本特性 (policy) 都要有据可依。应该只有不得不使用旧特性时才降低特性 (policy) 版本。
Introduction to the basics
Minimum Version
CMakeLists.txt
cmake_minimum_required(VERSION 3.25)
Setting a project
project(MyProject VERSION 1.0
DESCRIPTION "Very nice project"
LANGUAGES CXX)
Make an executable
add_executable(one two.cpp three.h)
Making a library
add_library(one STATIC two.cpp three.h)
Targets are your friend
target_include_directories(one PUBLIC include)
add_library(another STATIC another.cpp another.h)
target_link_libraries(another PUBLIC one)
Dive in
cmake_minimum_required(VERSION 3.8)
project(Calculator LANGUAGES CXX)
add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)
target_include_directories(calclib PUBLIC include)
target_compile_features(calclib PUBLIC cxx_std_11)
add_executable(calc apps/calc.cpp)
target_link_libraries(calc PUBLIC calclib)
如何组织你的项目
- project
- .gitignore
- README.md
- LICENCE.md
- CMakeLists.txt
- cmake
- FindSomeLib.cmake
- something_else.cmake
- include
- project
- lib.hpp
- src
- CMakeLists.txt
- lib.cpp
- apps
- CMakeLists.txt
- app.cpp
- tests
- CMakeLists.txt
- testlib.cpp
- docs
- CMakeLists.txt
- extern
- googletest
- scripts
- helper.py
Example
# Almost all CMake files should start with this
# You should always specify a range with the newest
# and oldest tested versions of CMake. This will ensure
# you pick up the best policies.
cmake_minimum_required(VERSION 3.1...3.21)
# This is your project statement. You should always list languages;
# Listing the version is nice here since it sets lots of useful variables
project(
ModernCMakeExample
VERSION 1.0
LANGUAGES CXX)
# If you set any CMAKE_ variables, that can go here.
# (But usually don't do this, except maybe for C++ standard)
# Find packages go here.
# You should usually split this into folders, but this is a simple example
# This is a "default" library, and will match the *** variable setting.
# Other common choices are STATIC, SHARED, and MODULE
# Including header files here helps IDEs but is not required.
# Output libname matches target name, with the usual extensions on your system
add_library(MyLibExample simple_lib.cpp simple_lib.hpp)
# Link each target with other targets or add options, etc.
# Adding something we can run - Output name matches target name
add_executable(MyExample simple_example.cpp)
# Make sure you link your targets with this command. It can also link libraries and
# even flags, so linking a target that does not exist will not give a configure-time error.
target_link_libraries(MyExample PRIVATE MyLibExample)
为 CMake 项目添加特性
set(default_build_type "Release")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE
STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
参考
- GitHub: https://gitlab.com/CLIUtils/modern-cmake
- Read Online: https://cliutils.gitlab.io/modern-cmake