如何在CMake的Xcode项目中为特定目标及架构配置OSX_DEPLOYMENT_TARGET与编译选项
问题场景
在Make项目中,我们可以通过以下方式轻松修改特定目标的OSX_DEPLOYMENT_TARGET:
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "osx deployment target") # mylib的部署目标为11.0 add_subdirectory(mylib) # 但测试程序依赖的某个外部库是基于12.0编译的,因此需要将测试程序的部署目标设为12.0 find_package(external) set_property( TARGET external APPEND PROPERTY INTERFACE_COMPILE_OPTIONS -mmacosx-version-min=12.0 PROPERTY INTERFACE_LINK_OPTIONS -mmacosx-version-min=12.0) add_executable(mytest main.cpp) target_link_libraries(mytest PUBLIC mylibs external)
但在Xcode项目中,OSX_DEPLOYMENT_TARGET是通过-target x86_64-apple-macos12.0和-target arm64-apple-macos12.0这类参数控制的。当mytest是包含x86_64和arm64的通用二进制时,尝试用以下代码为不同架构传递对应-target参数却无效:
set_property( TARGET external APPEND PROPERTY INTERFACE_COMPILE_OPTIONS -target $<$<STREQUAL:$<TARGET_PROPERTY:OSX_ARCHITECTURES>,x86_64:x86_64-apple-macos12.0>> $<$<STREQUAL:$<TARGET_PROPERTY:OSX_ARCHITECTURES>,arm64:arm64-apple-macos12.0>> PROPERTY INTERFACE_LINK_OPTIONS -target $<$<STREQUAL:$<TARGET_PROPERTY:OSX_ARCHITECTURES>,x86_64:x86_64-apple-macos12.0>> $<$<STREQUAL:$<TARGET_PROPERTY:OSX_ARCHITECTURES>,arm64:arm64-apple-macos12.0>> )
同时还有一个通用问题:如何通过CMake为不同架构传递不同的编译选项?
解决方案
针对Xcode中通用二进制的部署目标设置
Xcode生成器中,CMake的OSX_DEPLOYMENT_TARGET属性会自动映射到Xcode项目的部署目标设置,无需手动添加-target参数。如果需要为特定目标覆盖全局部署目标,可以直接设置目标的OSX_DEPLOYMENT_TARGET属性,CMake会自动为每个架构生成正确的-target参数:
# 为mytest设置部署目标为12.0,CMake会自动处理x86_64和arm64的-target参数 set_target_properties(mytest PROPERTIES OSX_DEPLOYMENT_TARGET "12.0" )
如果必须通过接口属性传递(比如依赖外部库的情况),可以使用CMake的架构生成表达式,注意TARGET_PROPERTY:OSX_ARCHITECTURES在通用二进制构建时是一个列表,不能直接用STREQUAL匹配。正确的做法是使用$<TARGET_ARCH>生成表达式(CMake 3.19+支持):
set_property( TARGET external APPEND PROPERTY INTERFACE_COMPILE_OPTIONS $<$<OR:$<TARGET_ARCH:x86_64>,$<TARGET_ARCH:i386>>:-target x86_64-apple-macos12.0> $<$<TARGET_ARCH:arm64>:-target arm64-apple-macos12.0> PROPERTY INTERFACE_LINK_OPTIONS $<$<OR:$<TARGET_ARCH:x86_64>,$<TARGET_ARCH:i386>>:-target x86_64-apple-macos12.0> $<$<TARGET_ARCH:arm64>:-target arm64-apple-macos12.0> )
通用架构特定编译选项设置
要为不同架构传递不同的编译选项,核心是利用CMake的生成表达式,针对不同架构进行条件判断:
- 使用
$<TARGET_ARCH:ARCH>(CMake 3.19+)直接匹配目标架构:
add_executable(mytest main.cpp) # 为x86_64添加特定编译选项 target_compile_options(mytest PRIVATE $<$<TARGET_ARCH:x86_64>:-mavx2> $<$<TARGET_ARCH:arm64>:-mcpu=apple-m1> ) # 为不同架构设置不同链接选项 target_link_options(mytest PRIVATE $<$<TARGET_ARCH:x86_64>:-Wl,-some-x86-option> $<$<TARGET_ARCH:arm64>:-Wl,-some-arm-option> )
- 对于较旧版本的CMake(低于3.19),可以遍历
CMAKE_OSX_ARCHITECTURES变量来实现:
foreach(arch IN LISTS CMAKE_OSX_ARCHITECTURES) if(arch STREQUAL "x86_64") target_compile_options(mytest PRIVATE "$<$<CONFIG:Release>:-mavx2>") elseif(arch STREQUAL "arm64") target_compile_options(mytest PRIVATE "$<$<CONFIG:Release>:-mcpu=apple-m1>") endif() endforeach()
需要注意的是,在Xcode生成器中,CMake会自动将架构特定的选项分配合到对应的编译目标中,无需手动拆分通用二进制的编译流程。
内容的提问来源于stack exchange,提问作者user3667089

