编译c++ so注意点

     每一个 c++ 程序编译完成都会依赖 libstdc++,众所周知,与 glibc 不同的是,libstdc++ 与 gcc 的版本是绑定的。这个特性所带来的麻烦其中之一是,使用高版本 gcc 编译出来的程序,直接放到低版本 gcc 的环境中是无法运行的,需要把对应的 libstdc++.so 同时拷贝过去才能正常运行。

什么是菱形依赖?

    一个菱形依赖的典型案例:A库依赖C1,B库依赖了C2,这两个C的版本是无法兼容的,造成用户程序无法同时链接A库和B库。

编译c++ so注意点

解决菱形依赖的总体思想

     菱形依赖导致用户无法接入 so 的根本原因在于符号冲突,造成符号冲突的原因是用户在编译自己的程序时,从我们的 so 和用户自己的程序或依赖库中,存在相同符号的不同实现。因此我们的目标就是让用户从我们的 so 中找不到存在冲突的符号。为了达到这个目的,我们需要采用如下两个步骤:

1.  将所有的依赖打入一个so中

     如果我们的so动态依赖了其它的动态库,而用户如果依赖了这个库的其它版本,那么这会不可避免的产生菱形依赖。因此在第一步,我们需要尽量将我们的所有依赖库,以静态依赖的方式打到一个so里面,不把我们所以依赖的字库直接暴露给用户。
方法是在链接这个so的时候,把所有需要的.a 都链接上。
    因此这个so几乎需要包含我们依赖的全部,由于gcc在编译so时并没有要求所有的符号都要包含在里面,因此我们需要手动check这个so 还有哪些未定义的符号,方法是使用命令:ld **.so

2.  只导出相关符号

    gcc 在编译 so 时,默认所有符号都会导出。gcc 在链接时提供一个叫 version-script 选项指定一个文件,可以在这个文件中指定哪些符号是需要导出的。

    由于 C++ 的接口通常相当复杂,并且符号难以捉摸,强烈建议大家 so 的 API 接口使用 C 来实现,让用户的接入更加干净。

静态链接 libstdc++

    由于按默认方式编译出的 so 会依赖当前 gcc 版本的 libstdc++,因此我们可以在链接这个 so 时,使用 '-Bstatic -lstdc++ -Bdynamic' 选项把 stdc++ 静态编入到这个 so 里面。事实证明将 gcc-4.9.2 的 stdc++ 打入 so 中后是可以在 7u 上正常运行的。


总体步骤

    1. 使用 C 接口封装 API;
    2. 编写 version-script,仅包含需要暴露的 API;
    3. 编译 so 时静态链接所有的依赖库;
    4. 链接选项增加 '-Bstatic -lstdc++ -Bdynamic' 将当前版本的 libstdc++ 包含进 so.

相关文章:

  • 2021-09-14
  • 2022-12-23
  • 2021-11-08
  • 2021-08-08
  • 2021-08-10
  • 2022-01-15
  • 2022-12-23
  • 2021-12-29
猜你喜欢
  • 2021-08-04
  • 2021-06-01
  • 2022-12-23
  • 2021-12-30
  • 2022-02-02
  • 2021-05-31
相关资源
相似解决方案