主工程文件
首先要创建工程的主要入口,也就是一个 CMakeLists.txt
文件。
构建工程时就需要指定这个文件的所在目录。
CMake 版本和策略
主工程文件首先要描述的就是对 CMake 的版本选择和全局策略开关。
主要涉及 cmake_minimum_required
和 cmake_policy
两个命令。
对整个工程使用的 CMake 特性进行约定。
cmake_minimum_required(VERSION 3.24)
全局变量
这部分定义工程需要的全局变量,如工程名、版本号等。
可以直接用 project
命令定义,也可以用 set
命令对变量进行指定。
project("base" VERSION 0.0.1)
将全局变量同步到 C++ 代码
如果有些全局变量希望可以共享给 C++ 代码,比如工程版本号,可以使用 configure_file
修改部分文件的代码,将全局变量赋给文件中的指定占位符。
创建一个 project_config.h.in
文件,写入以下内容。
constexpr int kBaseVersionMajor = @Base_VERSION_MAJOR@;
constexpr int kBaseVersionMinor = @Base_VERSION_MINOR@;
constexpr char kBaseVersion = @Base_VERSION@;
在 CMakeLists.txt 中增加生成文件的命令。
configure_file(global_config.h.in global_config.h)
构建后就会自动生成解析后的 global_config.h
文件供其他 C++ 源码使用。
全局编译选项
修改全局编译器配置,也可以使用默认配置不做修改。
这里指定默认的 C++ 语言标准版本。
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
添加自定义命令
如果有些构建的准备工作需要处理,比如将配置阶段生成的 project_config.h
拷贝到源文件目录,可以用 add_custom_command
命令添加自定命令。
add_custom_command(OUTPUT "project_config.h"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/project_config.h" "${CMAKE_CURRENT_SOURCE_DIR}"
DEPENDS "project_config.h.in"
VERBATIM)
这里添加 VERBATIM 阻止 CMake 默认的命令转义行为,可以防止不同平台出现的兼容性问题
添加可执行程序目标
这里构建一个简单的可执行文件。
add_executable(base_test "base_test.cpp" "project_config.h")
对于指定目标,可以进行编译选项配置和依赖配置等操作,具体需要看编译目标的需求。
目标构建事件
如果有些构建的准备工作需要在构建前后处理,可以用 add_custom_command
命令添加构建前事件进行处理。
比如进行文件签名等。
注意,虽然构建事件有
PRE_BUILD
,但是不同构建工具对这个事件的支持不太一样,对于大部分构建前的准备工作应该由自定义命令目标来实现,而不是PRE_BUILD
。
命令行
基本配置完成后,就可以允许 cmake
命令进行构建。
配置生成
先生成构建需要的配置文件。
mkdir build
cd build
cmake -S .. -B . -G Ninja
执行构建
从当前文件夹执行编译,构建目标输出,就可以生成需要的编译产物了。
cmake --build . --config Debug
创建库
如果这个工程的编译目标是一个库,而非可执行程序,可以使用 add_library
命令。
默认情况下,创建的是静态链接库。
add_library(libbase, lib_test.cpp lib_test.h)
使用库
要指定目标依赖的库,可以用 target_link_libraries
命令。这个命令会自动计算依赖关系和链接库产物。
同时,依赖库的头文件需要用 target_include_directories
指定,这样才能在编译时搜索到依赖库的头文件。
target_link_libraries(base_test PUBLIC libbase)
target_include_directories(base_test PUBLIC "${LibBase_SOURCE_DIR}")
这里的 PUBLIC 指的是是否传递被依赖的库的头文件目录可见性,如果该目标的导出头文件有用到依赖库的头文件,就需要指定为 PUBLIC
如果使用的是其他 CMake 工程的库,需要先包含那个工程。
add_subdirectory("../lib_project" lib_project)
这里指定了
add_subdirectory
的 binary_dir 参数,是因为包含非当前工程子目录的工程时,需要指定一个相对路径给 CMake,才能正确设置生成文件的相对路径。
参考
- [1] CMake Tutorial