使用cmake强制链接静态库无效。

6
我们有一个多项目cmake设置,其中包括一些IMPORTED静态库。对于我们的一个可执行文件,我们需要强制链接这些IMPORTED库中的所有符号,因此我们需要在该库名称之前向编译器传递-Wl,-force_load。请注意,这些导入库之间存在依赖关系,因此它们需要按正确顺序放置在链接命令行中。这些依赖关系是通过根CMakeLists.txt中的set_target_properties(fake_2 PROPERTIES INTERFACE_LINK_LIBRARIES ...)声明的。
我们曾经使用相当标准的target_link_libraries(lib_a PUBLIC -Wl,-force_load fake_4),但事实证明,cmake将-Wl,-force_load视为相当任意的链接器标志,如果你将其应用于几个库,则会出现以下问题:
target_link_libraries(lib_a PUBLIC -Wl,-force_load fake_4)
target_link_libraries(lib_a PUBLIC -Wl,-force_load fake_3)

它不一定会将这些链接器标志应用于fake_4fake_3。在某些情况下,它将去重该标志并仅将其应用于其中一个库。尝试修复此问题的方式如下:

target_link_libraries(lib_a PUBLIC "-Wl,-force_load $<TARGET_PROPERTY:fake_4,IMPORTED_LOCATION>")

引起链接器标志位放置在库的前面,但是Cmake无法识别导入的库,因此忽略它们之间的依赖关系。
可以在此处找到一个完整的示例项目,展示了这些问题: https://github.com/REVLUTION/cmake-example 注意: 这个问题被转移到了Cmake论坛讨论版块中,如果你想看一些评论。

据我所知,-force_load 对于链接到应用程序的动态库是有意义的(默认情况下,dll-s 是惰性加载的)。静态库只是成为可执行文件的一部分,因此它们没有单独的“加载”过程。 - Marek R
通常情况下,当您链接静态库时,只有在其他代码中使用的符号才会被保留。-force_load 告诉编译器包括所有符号,即使它们似乎没有被使用。这对于像 TensorFlow 这样的东西是必要的,因为在编译时无法知道将调用哪些函数集合。 - Oliver Dain
2个回答

0

0

编辑:根据评论,看起来这实际上并不起作用。


蛋糕讨论论坛发布了一个解决问题的答案。我在这里重新发布以便于方便访问。

正如Alain Martin所说:

我想那是因为你需要两者兼备:
  • target_link_libraries(utils_video_encode_decode_ffmpeg PUBLIC avfilter) 用于“常规”依赖
  • target_link_libraries(utils_video_encode_decode_ffmpeg PUBLIC "-Wl,-force_load $<TARGET_PROPERTY:avfilter,IMPORTED_LOCATION>") 用于“强制加载”
将它们组合起来:
target_link_libraries(utils_video_encode_decode_ffmpeg
  PUBLIC
    avfilter
      "-Wl,-force_load $<TARGET_PROPERTY:avfilter,IMPORTED_LOCATION>"
)

我认为这个方法大部分时间都可以工作,但不能保证一定有效。假设avfilter依赖于其他库,比如bzip。cmake会重新排列链接顺序,以确保在链接行中avfilter出现在bzip之前,以便它所需的符号被链接。但是没有任何东西使用avfilter,因此链接器会删除所有它的符号,从而也删除了所有的bzip符号。简而言之,“-l/usr/lib/avfilter -lbzip -Wl,-force_load -l/usr/lib/avfilter”无法工作,并且没有任何保证这种情况不会发生。 - Oliver Dain
1
原来这个解决方案还有第二个问题:如果你使用了库中的某些符号而不是其他符号,那么在链接时会出现重复符号错误,因为第一个链接保留了你使用的符号,而第二个强制链接则重新定义了它们。 - Oliver Dain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接