有时候我们想根据一些上下文情况设置一些东西。在cmake我们可以通过if判断条件去完成 也可通过一个生成表达式的东西完成。
generator-expressions官方文档
cmake有很多生成表达式,这里做一个简述。
最基础的表达式如下:
$
condition只能传0或者1,如果为1那么返回true_string 否则返回空字符串。如果你的condition不是0或者1那么你需要结合其他其他生成表达式进行嵌套完成。
需要注意的是表达式并会在生成构建系统文件的求值,而是在构建目标的时候计算,所以我们这里创建一个自定义目标进行输出。
cmake_minimum_required(VERSION 3.26)
project(learnC)
set(CMAKE_CXX_STANDARD 17)
#[[
由于$<1:FOO>和$<0:FOO>不会再创建构建系统的时候求值完成,所以我们构造一个自定义目标去打印
对应命令 cmake -B build -S . ;(cd build && cmake --build . -t genexdebug)
]]
add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "1 = $<1:FOO> , 0 = $<0:FOO>")
输出:
1 = FOO , 0 =
我们再看一个复杂的例子,下面的例子会用另一个生成表达式$
。我们会在这个例子中进行嵌套完成输出
cmake_minimum_required(VERSION 3.26)
project(learnC)
set(CMAKE_CXX_STANDARD 17)
#[[
$ 用于比较两个字符串是否相等如果相等返回1 否则0
$<$:isAppleClang> 可以理解为当前的编译器是否为AppleClang如果是那么输出isAppleClang
]]
add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "1 = $<$:isAppleClang> ")
输出
1 = isAppleClang
对于复杂的嵌套表达式可以利用变量进行分解。如下:
cmake_minimum_required(VERSION 3.26)
project(learnC)
set(CMAKE_CXX_STANDARD 17)
#抽出嵌套表达式到变量中
set(isAppleClangVar $)
set(myvar "$<${isAppleClangVar}:isAppleClang>")
#[[
$ 用于比较两个字符串是否相等如果相等返回1 否则0
$<$:isAppleClang> 可以理解为当前的编译器是否为AppleClang如果是那么输出isAppleClang
]]
add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "${myvar}")
其他表达式可参阅官方文档进行实践。
在我们安装文件的编译的时候,我们会有将其放入指定位置的需求。而cmake中install变派上用场了。install文档
这个函数的签名有很多我们这里只举例其中几个做说明
cmake_minimum_required(VERSION 3.26)
project(learnC)
set(CMAKE_CXX_STANDARD 17)
#是一个名为mycalc静态库
add_subdirectory(mycalclib)
add_executable(main main.cpp)
# 语法 install(TARGET [type] [DESTINATION <目录>]) 其中如果不说明type的话cmake会自动探测类型放入对应的目录
# 安装目标main到/usr/local/bin/main
install(TARGETS main DESTINATION bin)
# 安装目标到/usr/local/bin/main 由于我们声明main是RUNTIME 类别可以不需要声明DESTINATION
install(TARGETS main RUNTIME)
# 等价install(TARGETS main RUNTIME )
install(TARGETS main RUNTIME DESTINATION bin)
# 安装目标main到/usr/local/bin/main
install(TARGETS main)
# 由于mycalc是一个静态库会自动放入/usr/local/lib
install(TARGETS mycalc)
# 其他省略写法参考上面
# 由于头文件不是一个target只能使用其他语法导入饭庄
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include
)
你可以执行cmake --install .
去完成完成
cmake -B build -S . ;(cd build && cmake --build .&& cmake --install .)
有时候我们一个CMakeLists.txt
结构复杂超出我们的预期,我们期望拆分为更小的文件。而include
命令就是满足我们期望的。include
可以导入一个特定的明确路径的文件,也可以只指定模块名从指定的模块路径下查找。
模块路径有两个:
opt/homebrew/Cellar/cmake/3.27.4/share/cmake/Modules
我们看一个案例,假设我们有一下文件:
.
├── CMakeLists.txt
└── myTestModule2.cmake
1 directory, 2 files
#myTestModule2.cmake
set(hello "hello world")
#CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 导入方式1 ,设置模块路径然后可以去掉后缀名去导入
#set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
#include(myTestModule2)
# 导入方式2 写明指定路径文件
include(./myTestModule2.cmake)
# 输出导入的文件中定义的变量
message(${hello})
输出:
hello world
系统也给我们提供了很多有用模块比如CheckCXXSourceCompiles中提供了check_cxx_source_compiles
函数.
check_cxx_source_compiles
函数提供了一个检查指定的代码是否能正确编译
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# CheckCXXSourceCompiles在CMAKE自带的目录下。opt/homebrew/Cellar/cmake/3.27.4/share/cmake/Modules 导入目录
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include
int main() {
std::cout << \"Hello, world!\" << std::endl;
return 0;
}
" MY_SOURCE_COMPILES)
if (MY_SOURCE_COMPILES)
message("源文件编译成功!")
else()
message("源文件编译失败。")
endif()