我们承担ROS,FastDDS等通信中间件,C++,cmake等技术的项目开发和专业指导和培训,有10年+相关工作经验,质量有保证,如有需要请私信联系。
CMake分两个阶段生成项目的构建系统:配置阶段(解析CMakeLists.txt)和生成阶段(实际生成构建环境)。生成器表达式在第二阶段进行计算,可以使用仅在生成时才能知道的信息来调整构建系统。生成器表达式在交叉编译时很有用,一些可用的信息只有解析CMakeLists.txt之后或者在多配置项目后获取,构建系统生成的所有项目可以有不同的配置。
生成器表达式对于在访问或操作文件路径时很出色。
CMake提供了三种类型的生成器表达式:
- 逻辑表达式,基本模式为
$<condition:outcome>
。condition为0表示false,1表示true - 信息表达式,基本模式为
$<information>
或$<information:input>
- 输出表达式,模式为
$<operation>
或$<operation:input>
这些表达式可能基于一些输入参数,生成一个输出,他们的输出可以直接在CMake命令中使用,也可以与其他生成表达式组合使用
生成器表达式是在生成构建系统时的表达式。生成器表达式在生成目标时使用,如 LINK_LIBRARIES, INCLUDE_DIRECTORIES, COMPILE_DEFINITIONS等,或者target_link_libraries(), target_include_directories(), target_compile_definitions()等。有如下格式 $<...>
生成器表达式在测试时非常方便,因为不必显式硬编码可执行程序的位置和名称,方便不同平台的移植。
查看cmake有哪些生成器:cmake --help,其中generators显示如下
使用-G切换生成器,如使用Ninja:
mkdir -p build
cd build
cmake -G Ninja ..
cmake --build .
布尔生成器表达式
布尔生成器表达式值为0或者1,主要为以下:
逻辑表达式
$<BOOL:string>
$<AND:conditions>
$<OR:conditions>
$<NOT:condition>
字符串比较
$<STREQUAL:string1,string2>
$<EQUAL:value1,value2>
$<IN_LIST:string,list>
$<VERSION_LESS:v1,v2>
$<VERSION_GREATER:v1,v2>
$<VERSION_EQUAL:v1,v2>
$<VERSION_LESS_EQUAL:v1,v2>
$<VERSION_GREATER_EQUAL:v1,v2>
变量查询
$<TARGET_EXISTS:target>
$<CONFIG:cfgs>
如果config时cfgs中的一个词条,则为1,否则为0。不区分大小写$<PLATFORM_ID:platform_ids>
platform_ids是逗号分隔的列表,如果platform_id是platform_ids中的一个则为1$<C_COMPILER_ID:compiler_ids>
$<CXX_COMPILER_ID:compiler_ids>
$<CUDA_COMPILER_ID:compiler_ids>
$<OBJC_COMPILER_ID:compiler_ids>
$<OBJCXX_COMPILER_ID:compiler_ids>
$<Fortran_COMPILER_ID:compiler_ids>
$<ISPC_COMPILER_ID:compiler_ids>
$<C_COMPILER_VERSION:version>
$<CXX_COMPILER_VERSION:version>
$<CUDA_COMPILER_VERSION:version>
$<OBJC_COMPILER_VERSION:version>
$<OBJCXX_COMPILER_VERSION:version>
$<Fortran_COMPILER_VERSION:version>
$<ISPC_COMPILER_VERSION:version>
$<TARGET_POLICY:policy>
$<COMPILE_FEATURES:features>
$<COMPILE_LANG_AND_ID:language,compiler_ids>
$<COMPILE_LANGUAGE:languages>
$<LINK_LANG_AND_ID:language,compiler_ids>
$<LINK_LANGUAGE:languages>
$<DEVICE_LINK:list>
$<HOST_LINK:list>
String-Valued生成器表达式
可以和其他的生成器表达式一起使用
转义字符
$<ANGLE-R>
$<COMMA>
$<SEMICOLON>
条件表达式
$<condition:true_string>
如果condition为1则字符串为true_string,否则为空$<IF:condition,true_string,false_string>
如果condition为1则为true_string,否则为false_string
字符串转换
$<JOIN:list,string>
将list加入到string中$<REMOVE_DUPLICATES:list>
$<FILTER:list,INCLUDE|EXCLUDE,regex>
根据regex从list中包含或删除$<LOWER_CASE:string>
将string转换成小写$<UPPER_CASE:string>
将string转换成大写$<GENEX_EVAL:expr>
$<TARGET_GENEX_EVAL:tgt,expr>
变量查询
$<CONFIG>
配置名$<PLATFORM_ID>
当前系统的cmake platform id$<C_COMPILER_ID>
C编译器ID$<CXX_COMPILER_ID>
C++编译器ID$<CUDA_COMPILER_ID>
$<OBJC_COMPILER_ID>
$<OBJCXX_COMPILER_ID>
$<Fortran_COMPILER_ID>
$<ISPC_COMPILER_ID>
$<C_COMPILER_VERSION>
$<CXX_COMPILER_VERSION>
依赖目标查询
查询由add_executable()
、add_library()
生成的目标。这个生成目标文件是个二进制文件
$<TARGET_NAME_IF_EXISTS:tgt>
如果目标存在则tgt为目标文件名,否则为空字符串$<TARGET_FILE:tgt>
二进制文件tgt 的全路径名$<TARGET_FILE_BASE_NAME:tgt>
$<TARGET_FILE_PREFIX:tgt>
$<TARGET_FILE_SUFFIX:tgt>
$<TARGET_FILE_NAME:tgt>
:会返回目标(如库或可执行的bin文件)的文件名,不包含路径,例如有一个目标是libmyso.so,$<TARGET_FILE_NAME:myso>
会得到libmyso.so$<TARGET_FILE_DIR:tgt>
$<TARGET_LINKER_FILE:tgt>
$<TARGET_LINKER_FILE_BASE_NAME:tgt>
$<TARGET_LINKER_FILE_PREFIX:tgt>
$<TARGET_LINKER_FILE_SUFFIX:tgt>
$<TARGET_LINKER_FILE_NAME:tgt>
$<TARGET_LINKER_FILE_DIR:tgt>
$<TARGET_SONAME_FILE:tgt>
$<TARGET_SONAME_FILE_NAME:tgt>
$<TARGET_SONAME_FILE_DIR:tgt>
$<TARGET_PDB_FILE:tgt>
$<TARGET_PDB_FILE_BASE_NAME:tgt>
$<TARGET_PDB_FILE_NAME:tgt>
$<TARGET_PDB_FILE_DIR:tgt>
$<TARGET_BUNDLE_DIR:tgt>
$<TARGET_BUNDLE_CONTENT_DIR:tgt>
$<TARGET_PROPERTY:tgt,prop>
$<TARGET_PROPERTY:prop>
$<INSTALL_PREFIX>
输出关联表达式
$<TARGET_NAME:...>
$<LINK_ONLY:...>
$<INSTALL_INTERFACE:...>
用于安装阶段使用的路径$<BUILD_INTERFACE:...>
用于构建阶段使用的路径,举例如下
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
只在构建阶段有效,包含的目录为指定目录
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>"
只在安装阶段有效
综上,这段代码的作用是,告知CMake在构建和安装阶段,应该使用哪些目录作为头文件查找目录,并将这些目录添加到目标项目的PUBLIC中,这意味着链接到该目标的其他目标也会继承这些包含目录。
$<MAKE_C_IDENTIFIER:...>
$<TARGET_OBJECTS:objLib>
:在生成共享库/静态库或可执行文件时,用于引用另一个目标(就是这里的objLib文件)的对象文件。
举例说明:假设你有两个目标,一个是库libA,它包含一些源文件,另一个是库libB,你想在其中复用libA的源文件编译生成的对象文件,但不想直接链接到libA。在这种情况下,你可以使用$<TARGET_OBJECTS:libA>
生成器表达式来引用libA的对象文件。
这样,库libB就会包含libA的源文件编译生成的对象文件,而不需要重新编译libA的源文件,也不会链接到libA。这个特性在大型项目中,当一些目标需要共享源文件,但又不希望这些目标之间存在链接依赖时,非常有用。
add_library(objLib OBJECT ${OBJLIB_SOURCES}) # 生成要编译的对象文件
add_library(obj STATIC ${SOURCES} $<TARGET_OBJECTS:objLib>) # 目标文件引用对象文件
$<SHELL_PATH:...>
$<OUTPUT_CONFIG:...>
$<COMMAND_CONFIG:...>