如何在CMake中覆盖链接导入库的INTERFACE_COMPILE_OPTIONS?
解决CMake中覆盖导入库编译标志的问题
正确的解决方法
方法1:直接修改第三方目标的INTERFACE_COMPILE_OPTIONS
最直接的方式是移除第三方导入库中不需要的编译标志。针对你的示例,可按如下操作:
project(sample) add_library(third-party INTERFACE IMPORTED) set_target_properties(third-party PROPERTIES INTERFACE_COMPILE_OPTIONS "-fno-rtti") # 移除第三方库中的-fno-rtti标志 get_target_property(THIRD_PARTY_OPTS third-party INTERFACE_COMPILE_OPTIONS) list(REMOVE_ITEM THIRD_PARTY_OPTS "-fno-rtti") set_target_properties(third-party PROPERTIES INTERFACE_COMPILE_OPTIONS "${THIRD_PARTY_OPTS}") add_executable(sample main.cpp) target_link_libraries(sample PUBLIC third-party) target_compile_options(sample PUBLIC "-frtti")
如果是深层依赖(比如third-party依赖的Foo带有-fno-rtti),只需找到对应的Foo目标,重复上述修改步骤即可。
方法2:利用CMAKE_CXX_FLAGS强制添加到编译命令末尾
若不想修改第三方目标,可将需要的编译标志添加到CMAKE_CXX_FLAGS末尾,确保它在所有依赖的INTERFACE选项之后生效:
project(sample) add_library(third-party INTERFACE IMPORTED) set_target_properties(third-party PROPERTIES INTERFACE_COMPILE_OPTIONS "-fno-rtti") # 将-frtti添加到全局编译标志末尾 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -frtti") add_executable(sample main.cpp) target_link_libraries(sample PUBLIC third-party)
这种方法会影响所有目标,适合全局都需要该标志的场景。
方法3:使用中间INTERFACE库调整选项顺序
如果只需要当前目标生效,可以创建一个中间INTERFACE库,将你的标志放在其中,然后让主目标先链接第三方库、再链接中间库:
project(sample) add_library(third-party INTERFACE IMPORTED) set_target_properties(third-party PROPERTIES INTERFACE_COMPILE_OPTIONS "-fno-rtti") # 创建中间库,添加需要的编译标志 add_library(rtti-enabler INTERFACE) target_compile_options(rtti-enabler INTERFACE "-frtti") add_executable(sample main.cpp) # 按顺序链接,确保-frtti在-fno-rtti之后出现 target_link_libraries(sample PUBLIC third-party rtti-enabler)
CMake会按照链接顺序处理INTERFACE选项,后链接的中间库的标志会出现在编译命令更靠后的位置,从而覆盖前面的冲突标志。
关于CMake选项顺序是否为bug
这不是bug,是CMake的有意设计。
CMake的规则是:目标自身的COMPILE_OPTIONS会先被添加到编译命令中,之后再添加所有依赖目标的INTERFACE_COMPILE_OPTIONS。这种顺序是为了保证依赖库的编译要求优先被满足——比如如果第三方库是用-fno-rtti编译的,链接它的目标必须使用相同选项才能避免链接错误。因此依赖的INTERFACE选项被赋予更高优先级是合理的。
内容的提问来源于stack exchange,提问作者user3667089
相关产品推荐
相关产品推荐

