目录
- 使用与平台无关的文件操作
- 构建时运行自定义命令
- 编译和链接命令
- 生成器表达式
使用与平台无关的文件操作
这个例子中解压缩Eigen打包文件,并相应的为目标设置包含目录
cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
project(recipe-01 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)add_custom_target(unpack-eigenALLCOMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/eigen-3.4.0.tar.gz # 并不会真正解压一个实体目录出来COMMAND ${CMAKE_COMMAND} -E rename eigen-3.4.0 eigen # 这里会报错:Error renaming from "eigen-3.4.0" to "eigen": Directory not emptyWORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}COMMENT "Unpacking eigen"
)add_executable(linear-algebra linear-algebra.cpp
)add_dependencies(linear-algebra unpack-eigen)
target_include_directories(linear-algebraPRIVATE${CMAKE_CURRENT_BINARY_DIR}/eigen # 上面rename 命令所在行删掉后,这里为啥还是能找到eigen?
)
代码中使用到eigen-3.4.0.tar.gz中的源代码文件,但没有实体解压就可以引用到。
构建时运行自定义命令
cmake提供了三个选项来在构建时执行自定义命令
- add_custom_command:编译目标,生成输出文件
- add_custom_target 这个命令的执行没有输出
- 构建目标前后,add_custom_command的执行可以没有输出
编译和链接命令
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
project(recipe-06 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(OpenMP)
if(OpenMP_FOUND)message(STATUS "package found")set(_scratch_dir ${CMAKE_CURRENT_BINARY_DIR}/omp_try_compile)
else()message(STATUS "package not found")
endif()try_compile(omp_taskloop_test_1${_scratch_dir}SOURCES${CMAKE_CURRENT_SOURCE_DIR}/taskloop.cppLINK_LIBRARIESOpenMP::OpenMP_CXX
)message(STATUS "result of try_compile: ${omp_taskloop_test_1}")include(CheckCXXSourceCompiles)
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/taskloop.cpp _snippet)
set(CMAKE_REQUIRED_LIBRARIES OpenMP::OpenMP_CXX)
check_cxx_source_compiles("${_snippet}" omp_taskloop_test_2)
unset(CMAKE_REQUIRED__LIBRARIES)
message(STATUS "Result of check_cxx_source_compiles: ${omp_taskloop_test_2}")
- 要编译的代码片段必须作为CMake变量传入,大多数情况下必须使用file(READ …)来读取,然后代码片段被保存到构建目录的 CMakeFiles/CMakeTmp 子目录中
- 微调编译和链接,必须通过设置以下CMAKE变量进行:
- CMAKE_REQUIRED_FLAGS :设置编译器标志
- CMAKE_REQUIRED_DEFINITIONS :设置预编译宏
- CMAKE_REQUIRED_INCLUDES:设置包含目录列表
- CMAKE_REQUIRED_LIBRARIES:设置可执行目标能够链接的库列表
- 调用
check_<lang>_compiles_function
之后,必须手动取消对这些变量的设置,确保后续使用中不会保留当前的内容
生成器表达式
CMake分两个阶段生成项目的构建系统:配置阶段(解析CMakeLists.txt)和生成阶段(实际生成构建环境)。生成器表达式在第二阶段进行计算,可以使用仅在生成时才能知道的信息来调整构建系统。生成器表达式在交叉编译时很有用,一些可用的信息只有解析CMakeLists.txt之后或者在多配置项目后获取,构建系统生成的所有项目可以有不同的配置。
生成器表达式对于在访问或操作文件路径时很出色。
CMake提供了三种类型的生成器表达式:
- 逻辑表达式,基本模式为 $condition:outcome 。condition为0表示false,1表示true
- 信息表达式,基本模式为 $ 或 $information:input
- 输出表达式,模式为$ 或 $operation:input 这些表达式可能基于一些输入参数,生成一个输出,他们的输出可以直接在CMake命令中使用,也可以与其他生成表达式组合使用