使用CMakelist将多个静态库编译成动态库时找不到符号

 

https://www.cnblogs.com/zl1991/p/9437192.html

https://cmake.org/pipermail/cmake/2016-May/063509.html

根据以上两篇文章可以找到答案,但本文倾向于定位方法。

前置知识:

(1) ld 的链接规则是 "未定义的符号往后找"

(2)链接静态库时,只会将编译时用到的符号添加进动态库,有些符号是希望动态加载,在编译的时候并未显示调用。

这时需要将静态库全部链接。

举例:打算将liba.a,libb.a,libc.a,libd.a,libe.a,libf.a六个静态库,编译成libsix.so。

CMakelist这样写:

target_link_libraries(six a b c d e f)

此时如果libd.a这个静态库中的函数没有被任何人调用,通过nm 查看libsix.so的符号表,会发现没有libd.a的函数符号。原因就是因为:链接静态库时,只会将编译时用到的符号添加进动态库,没有用到的不会添加进来,以此来缩减动态库的体积。如果在a中的c文件中调用一个libd.a的函数,就会发现libsix.so有libd.a的符号了。

在libsix.so找不到,而在libd.a能找到,猜测问题出现的原因肯定是在链接的过程,链接的命令是ld,查询ld的的参数发现如下两个:

  --whole-archive
          For  each archive mentioned on the command line af-
          ter the --whole-archive option, include  every  ob-
          ject  file  in the archive in the link, rather than
          searching  the  archive  for  the  required  object
          files.   This  is  normally used to turn an archive
          file into a shared library, forcing every object to
          be included in the resulting shared library.

   --no-whole-archive
          Turn  off  the effect of the --whole-archive option
          for archives which  appear  later  on  the  command
          line.

还查到了 --whole-archive 和 --no-whole-archive 是ld专有的命令行参数,gcc 并不认识,要通gcc传递到 ld,需要在他们前面加-Wl字符串,
所以使用方发是:gcc -shared -o libsix.so -Wl,--whole-archive liba.a libb.a libc.a libd.a libe.a libf.a  -Wl --no-whole-archive 

在cmake生成的Makefile目录中执行make clean;make VERBOSE=1

/usr/bin/cc -o libsix.so -xxxxxxx  liba.a libb.a libc.a libd.a libe.a libf.a

因此修改CMakelist.txt

target_link_libraries(six a b c d e f) 改为

target_link_libraries(six -Wl,--whole-archive a b c d e f -Wl,--no-whole-archive)

再次编译,发现符号已经找到。

你可能感兴趣的:(日常笔记,cmake,makefile)