GCC 怎么控制 .so/.dll 中导出的符号?这个方法比 --fvisibility 更好用!

在使用 GCC / G++ / MinGW 编译动态链接库的时候,我们常常会遇到需要控制导出符号的问题。比如,有时候我们想把一大堆依赖库塞进一个 .dll 文件里,这样就不会出现 .dll 依赖 .dll 的套娃现象,但是这样一来,编译器会自动把静态库里的所有函数都导出到 dll 里,然后动态链接库里就有了一大堆我们不需要的符号。

举个实际例子,我前段时间编译了 libass 的 DLL,它依赖 fontconfig,fontconfig 又依赖 expat,然后 libass 又依赖 libpng,libpng 依赖 zlib,导致最终生成的 DLL 里有一大堆 XML、zlib、png 和 FT_* 函数:

这个时候该怎么办呢?网上的文章大多会让你使用 gcc 的 -fvisibility=hidden 来控制符号的可见性。将所有其它符号设为不可见,就可以控制要导出的符号了。但是,实际编程中发现这样做需要大量修改源代码,加上 __declspec(dllexport) 定义。有没有更简单的方法呢?有,那就是今天要介绍的 version script。

version script 是 GNU 编译工具链中的一个非常有用的功能,它允许在编译的时候,使用文本文件来控制动态链接库中需要导出的符号,除此之外还有不少高级功能。version script 完整的规范定义在了 ld 工具的手册里(ftp.gnu.org/old-gnu/Man...),这里我们只是使用它控制导出符号的功能,因此只使用它的简化版。

下面我们就以一个实际例子来说明如何使用 version script 来控制符号导出。

这里我们以 libass 为例,首先,在 libass 的源代码根目录下新建一个文件,我们将它命名为 version-script.txt,内容如下:

cpp 复制代码
{
    global:
        ass_library_init;
    
    local:
        *;
};

上述代码表示的意思是:

  1. 我们将 ass_library_init 指定为 global,所以最终导出的 dll 文件里就只会出现 ass_library_init 这一个符号;
  2. 所有其他符号都被指定为 local,也就是不会被导出。

然后,我们在编译时,加上一个参数 -Wl,--version-script=version-script.txt,这样就可以使用 version script 来控制符号的导出了。

检查一下输出的结果:

简单吧?以这种方法,我们就可以轻松地控制导出的符号,无需对源代码进行大量的修改。同时,version script 还有很多高级功能,包括给库指定不同版本等等。感兴趣的读者可以自行阅读 ld 工具手册以了解更多内容。美团也写过一篇关于优化 .so 动态链接库的文章,认为 version script 方式有一些额外的好处:

  1. version script 方式可以控制编译进 so 的静态库的符号是否导出,visibility 和 attribute 方式都无法做到这一点。
  2. visibility 结合 attribute 方式需要在源码中标明每个需要导出的符号,对于导出符号较多的项目来说是很繁杂的。version script 把需要导出的符号统一地放到了一起,能够直观方便地查看和修改,对导出符号较多的项目也非常友好。
  3. version script 支持通配符,* 代表0个或者多个字符,? 代表单个字符。比如 my*; 就代表所有以 my 开头的符号。有了通配符的支持,配置 version script 会更加方便。
  4. 还有非常特殊的一点,version script 方式可以删除 __bss_start 这样的一些符号(这是链接器默认加上的符号)。

文中所使用的 DependenciesGui 工具可以在这里下载

相关推荐
AI+程序员在路上33 分钟前
Qt6中模态与非模态对话框区别
开发语言·c++·qt
岁忧5 小时前
(LeetCode 面试经典 150 题 ) 11. 盛最多水的容器 (贪心+双指针)
java·c++·算法·leetcode·面试·go
蜉蝣之翼❉11 小时前
CRT 不同会导致 fopen 地址不同
c++·mfc
aramae11 小时前
C++ -- STL -- vector
开发语言·c++·笔记·后端·visual studio
lixzest11 小时前
C++ Lambda 表达式详解
服务器·开发语言·c++·算法
_Chipen12 小时前
C++基础问题
开发语言·c++
灿烂阳光g12 小时前
OpenGL 2. 着色器
c++·opengl
AA陈超13 小时前
虚幻引擎UE5专用服务器游戏开发-20 添加基础能力类与连招能力
c++·游戏·ue5·游戏引擎·虚幻
mit6.82414 小时前
[Meetily后端框架] AI摘要结构化 | `SummaryResponse`模型 | Pydantic库 | vs marshmallow库
c++·人工智能·后端
R-G-B14 小时前
【02】MFC入门到精通——MFC 手动添加创建新的对话框模板
c++·mfc·mfc 手动添加创建新的对话框