如何导出关联了接口库的静态库?
这个问题的核心原因是:静态库和共享库在CMake导出时的依赖处理逻辑完全不同。
对于共享库(SHARED),CMake会把PRIVATE依赖的INTERFACE库的编译选项直接应用到共享库的编译过程中,共享库编译完成后,导出时CMake不需要再保留这个INTERFACE库的依赖——毕竟其他项目用的是已经编译好的共享库,不需要这些编译选项来使用它。
但静态库(STATIC)不一样:CMake会认为静态库的所有依赖(哪怕是PRIVATE的INTERFACE库)都需要被纳入导出集,因为它默认静态库的依赖关系会影响到导入该库的项目构建流程(比如后续对静态库的重新编译、链接配置等)。所以当你导出Foo这个静态库时,CMake发现它依赖的compiler_flags没有被导出,就会抛出错误。
解决方法:把INTERFACE库也纳入导出集
你只需要把compiler_flags这个INTERFACE库也加入到install(TARGETS)的列表中,让它和Foo一起被导出即可。修改后的CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.21) project(my_project LANGUAGES C) # Example of interface library for compiler settings add_library(compiler_flags INTERFACE) target_compile_options(compiler_flags INTERFACE "-Wall") # Real library add_library(Foo STATIC foo.c) target_link_libraries(Foo PRIVATE compiler_flags) # 同时安装Foo和compiler_flags目标,并导出到FooTargets install(TARGETS Foo compiler_flags EXPORT FooTargets) # Install the configuration targets install( EXPORT FooTargets NAMESPACE Foo:: FILE FooTargets.cmake DESTINATION lib/cmake/Foo)
这样修改后,compiler_flags会被包含到FooTargets导出集里,CMake就能找到它的定义,不会再抛出错误。
补充说明
因为你用的是PRIVATE来链接compiler_flags,所以其他项目导入Foo::Foo时,不会自动继承compiler_flags的编译选项——这完全符合你的原始需求:编译选项只在构建Foo本身时生效,外部项目使用Foo静态库时不需要这些选项。
如果你希望外部项目链接Foo时也继承这些编译选项,只需要把PRIVATE改成PUBLIC或INTERFACE即可,但这是额外的扩展需求,根据你的问题场景,保持PRIVATE就足够了。
备注:内容来源于stack exchange,提问作者JtTest

