cmake error: includes target which requires target that is not in the export set,解决静态库的PRIVATE依赖导出问题

问题描述

最近在使用 interface libraries时出了个小问题。
示例如下,我希望target not_exported只是作为fse_cas_static 的private类的依赖库内部使用,不希望在config file中导出对它的依赖。

# 创建静态库
add_library(fse_cas_static STATIC ${_SOURCE_FILES})
# 创建interface libraries
add_library(not_exported INTERFACE)
target_link_libraries(fse_cas_static PRIVATE not_exported)

# 安装脚本,生成导出文件fse-targets.cmake
install(TARGETS fse_cas_static EXPORT fse-targets DESTINATION lib)
# 安装导出文件fse-targets.cmake
install(EXPORT fse-targets DESTINATION lib/cmake/Exp)

而且在cmake运行脚本时出错:

CMake Error: install(EXPORT “fse-targets” …) includes target “fse_cas_static” which requires target “not_exported” that is not in the export set.

意思就是not_exported这个我不希望export的target没有被export所以报错。

问题溯源

我明明把在target_link_libraries中指定了PRIVATE,就是不希望not_exportedtarget被export啊,怎么还会被要求export呢?

在google上找到了答案:

The private dependencies of a static library still need to be exported because they are needed to properly link the consumers of the static library. This applies even to interface libraries because their INTERFACE_LINK_LIBRARIES might specify something that provides symbols needed by the static library.
静态库的私有依赖仍然需要被导出,因为静态库的使用者需要它们才能正确链接静态库。这适用于接口库(interface libraries),因为它们的INTERFACE_LINK_LIBRARIES 属性可能会指定一些东西来提供静态库所需的符号。

摘自《Export of STATIC library with PRIVATE non-target dependencies broken》

解决方案

原因是知道了,上面的写法肯定是不对的,但是我确实不希望not_exported被导出啊。该怎么解决呢?

我想到cmake-generator-expressions,
既然我只是希望在编译静态库fse_cas_static的时候让引入not_exported那么可以用cmake-generator-expressions中的$来解决这个问题,$表达的基本意义就是只在编译期返回...的内容,否则为空字符串。

所以我们可以用$表达对上面脚本中的语句target_link_libraries(fse_cas_static PRIVATE not_exported)
中的not_exported加一个限定,改为

target_link_libraries(fse_cas_static PRIVATE $<BUILD_INTERFACE:not_exported>)

意思就是只在fse_cas_static编译的时候引入依赖not_exported,在 INSTALL 阶段这个值为空,不存在not_exported,就解决了问题,cmake不再报错,编译也正常进行。
最后生成的fse-targets.cmake中可以看到\$这样的代码,应该是$这部分在生成export文件时转换生成的。

# Create imported target fse_cas_static
add_library(gdface::fse_cas_static STATIC IMPORTED)
set_target_properties(fse_cas_static PROPERTIES
  INTERFACE_COMPILE_DEFINITIONS "FSE_IS_A_DLL=0;CASSDK"
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
  INTERFACE_LINK_LIBRARIES "\$;cassdk_THFeature"
  INTERFACE_POSITION_INDEPENDENT_CODE "ON"
)

你可能感兴趣的:(cmake,script,CMake进阶)