如何在CMake生成器表达式的条件中使用目标架构的现代方案?
现代CMake中在生成器表达式里判断目标架构的方案
CMake官方确实没有直接提供用于生成器表达式的目标架构变量,但可以通过一套健壮的自定义检测脚本,配合原生生成器表达式语法实现需求,以下是具体方案:
健壮的目标架构检测脚本
把这段脚本放在project()命令之前执行,它会自动检测目标架构并统一命名,同时处理原生编译和交叉编译场景:
# 检测目标架构并设置全局缓存变量 if(NOT DEFINED CMAKE_TARGET_ARCH) # 交叉编译优先使用CMAKE_SYSTEM_PROCESSOR,原生编译用主机架构 if(CMAKE_CROSSCOMPILING) set(_TARGET_ARCH "${CMAKE_SYSTEM_PROCESSOR}") else() set(_TARGET_ARCH "${CMAKE_HOST_SYSTEM_PROCESSOR}") endif() # 统一架构命名,消除不同平台的命名差异 string(TOLOWER "${_TARGET_ARCH}" _TARGET_ARCH_LOWER) if(_TARGET_ARCH_LOWER MATCHES "x86_64|amd64") set(CMAKE_TARGET_ARCH "x86_64" CACHE STRING "Target architecture" FORCE) elseif(_TARGET_ARCH_LOWER MATCHES "arm|armv7") set(CMAKE_TARGET_ARCH "arm" CACHE STRING "Target architecture" FORCE) elseif(_TARGET_ARCH_LOWER MATCHES "aarch64|arm64") set(CMAKE_TARGET_ARCH "arm64" CACHE STRING "Target architecture" FORCE) elseif(_TARGET_ARCH_LOWER MATCHES "i386|i686") set(CMAKE_TARGET_ARCH "x86" CACHE STRING "Target architecture" FORCE) else() # 未知架构保留原始标识,方便后续扩展 set(CMAKE_TARGET_ARCH "${_TARGET_ARCH}" CACHE STRING "Target architecture" FORCE) endif() unset(_TARGET_ARCH) unset(_TARGET_ARCH_LOWER) endif()
在生成器表达式中使用
检测完成后,用CMake原生的$<STREQUAL:...>生成器表达式做条件判断,比你之前的变通方案更规范可靠:
示例1:添加架构专属源文件
add_executable(my_app src/common.cpp $<$<STREQUAL:${CMAKE_TARGET_ARCH},arm>:src/src_for_arm.cpp> $<$<STREQUAL:${CMAKE_TARGET_ARCH},arm64>:src/src_for_arm64.cpp> $<$<STREQUAL:${CMAKE_TARGET_ARCH},x86_64>:src/src_for_x64.cpp> )
示例2:设置架构专属编译选项
target_compile_options(my_app PRIVATE $<$<STREQUAL:${CMAKE_TARGET_ARCH},arm>:-march=armv7-a> $<$<STREQUAL:${CMAKE_TARGET_ARCH},arm64>:-march=armv8-a> )
注意事项
- 脚本必须放在
project()之前执行,确保架构检测结果在项目配置初期就确定 - 交叉编译时,要保证工具链文件正确设置了
CMAKE_SYSTEM_PROCESSOR,如果未设置,可手动通过-DCMAKE_SYSTEM_PROCESSOR=arm这类参数指定 - 可根据需求扩展脚本中的架构匹配规则,比如添加riscv、powerpc等架构的判断
内容的提问来源于stack exchange,提问作者Sergey Kolesnik
相关产品推荐
相关产品推荐

