智能链接

智能链接(ld/gcc 文档称之为移除无用代码)将避免将未使用的代码链接到最终可执行文件中。

问题是 GNU 链接器可以执行该操作,通常(使用 GCC)只在编译单元级别时执行。换言之,当只使用一个文件时,它仍会在整个单元中链接。

较新的 binutils 使用部分移除无用的代码,但是问题在于它增加了对 binutils 的版本要求,这对于操作系统来说是一个特殊的问题,如经典的 MacOS,较旧的 Mac OS X 版本,O/2 等。该功能也不是很稳定。

使用旧版的智能链接,FPC 为单元中的每个符号生成.o来规避这一点。因此,每个过程,方法,变量或类型常量都有自己的.o。那么这会造成一个单元有上千个.o文件(Windows单元大约有20000-30000),并且.o文件被添加到使用 GNU AR 的.a存档中。

总之这是一个很复杂的过程:

  1. 一个单元由 fpc 编译成多个汇编源(.s)文件。

  2. 通过调用 AS 来组装,以生成大量的.o文件。

  3. 由 AR 归档为一个 .a文件。

……这就是为什么智能链接高效得益于 binwriter,这使得 FPC 直接写入.a,而不是多次调用 AS。

除了压缩代码,当一个单元与共享库(unix.so或win32.dll)接口调用某些未使用的,智能链接将会解决这个问题。例如,如单元包含了在较新 Windows 版本中内容,而你的程序并没有使用这些,并且你使用的是 Windows 98。如果不用智能链接,整个 Windows单元将被链接,并且链接器将无法在 Windows98 kernel32.dll 和 user32.dll 中调用Windows 高版本的内容。

在尝试智能链接时要小心。通常人们会忘记单元初始化(包括有问题的单元及其使用的单元)以及初始化使用的类,过程和函数始终链接在一起,并且单元总是被初始化(即使它们未使用),因为编译器不初始化对程序运行的影响为零。

需要注意的一点是:在 C 中,.o文件通常对应一个.c或.cpp文件,因此一个.a包含与<n> .c相对应的<n> .o。然而,根据 FPC,当单元智能链接(.pp,.pas)时,最终写入的文件是包含大量.o的.a。因此FPC .a仅对应一个单元 1。.o与.a没有智能链接是相同的单元。

旧版的智能连接存在一个已知问题是它的内存使用情况。 Ld 不能很好地管理很多(100000+)小对象文件(.o),并且内存需求大大增加。 智能链接一个完全静态 Lazarus是不可能的,因为它超出了操作系统普通进程 512 MB 内存的限制,粗略估计所需的内存是 1.5 GB。 在极端情况下,内存使用是最终可执行文件大小的50到100倍。

似乎 ld 现在可以移除无用代码,编译器需要采用它,在拥有自己的内部链接器方面也存在一些问题。该系统的优点是 LD 使用的内存较少,而且.a文件将消失(在新方法中,智能链接的数据被添加到.o文件中)。然而,对于不是最新 binutils 的操作系统,无论这种速度有多快,老式的智能链接仍然需要很长时间。

1

就目前而言,库生成会随着发展而改变,但不会在 2.4 之前。