链接和文件大小

时间:2009-09-20 01:16:48

标签: language-agnostic linker

我是一个完全的初学者,这就是我理解链接的方式:静态链接只复制实际使用的代码到可执行文件中。动态链接使用.dll,它可能包含许多应用程序从未使用过的代码。如果我错了,请纠正我:)

现在这是我的问题。我在我的应用程序中使用了一个开源库,但我只实现了它的一部分功能。为了使我的可执行文件+库的最终大小尽可能小,我应该使用静态或动态链接吗?如何确保不会复制不必要的代码?

谢谢!

4 个答案:

答案 0 :(得分:4)

使用动态链接时,您实际上构建了[至少]两个二进制文件:程序本身(.exe)和一个dll。对于exe,编译器/链接器可以检测代码的未使用部分,并且仅产生输出中所需的最小值。但是,对于DLL,标记为导出的所有函数和变量(以及使这些函数工作所需的所有代码)都必须包含在输出中。那是因为编译器/链接器无法知道程序可以使用哪些函数(其中一些函数将来会被编写......)。

但是,由于看起来你将同时编写exe和dll,你可以选择要导出的内容,因此只包含必要的最小值。

编辑:在读取防范时我注意到实际上您正在考虑使用开源库,因此上述声明需要一些资格。

如果您按原样构建开源代码 (假设源代码包含DLL的构建版本),则可能包含所有公开声明的库函数。但是,您可以更改为导出声明的方法列表,从而获得尽可能少的二进制数。

使用动态链接可以节省整体所需的二进制数量,因为多个程序可以使用相同的dll。例如,绘制应用程序和视频游戏程序的图形可以共享相同的图形实用程序dll。

一般来说,选择是否使用动态链接并非如此重要。这个问题在过去更成为一个问题,CPU速度较慢(因此构建时间较长),而且内存,硬盘和分配带宽(带有软盘!等等)的其他限制。

现代经验法则是,在技嘉大小存储的这些日子和时代,选择静态链接,默认情况下为,除非 以下其中一项适用:

  • DLL是第三方公开可用的DLL(即最终用户可以独立更新您自己的更新周期的DLL)。
  • 通常不使用应用程序的几个部分,并且底层逻辑可以“存放”在DLL中,从而缩短运行时间(当用户不使用底层专用/高级功能时)
  • 该程序是一套程序的一部分,其中几个程序具有足够的共性,可以共享。
  • 希望有多个版本的应用程序。例如,您可以实现应用程序的基本/免费/限制版本,以及功能齐全的版本。假设您管理程序以使用相同的API调用任一版本的功能,可以仅在DLL中封装不同的行为,允许付费用户仅下载“premium dll”并仅替换另一个(不安装)需要)。
  • 该软件是测试版,并且希望向最终用户发送多个修订版。 (与上面一样,dll交换而不是重新安装很好)。
  • 应用程序的不同部分用不同的语言编写。在这种情况下,通常可以使用静态链接(通过强制编译器就调用约定等达成一致),但DLL方法也可以简化这种合作。
  • 该软件由不同的程序员/团队制作。 DLL提供了责任的隐含描述。

可能还有一些案例,但同样,除非对DLL有一些现有需求,否则静态链接也同样好。

答案 1 :(得分:2)

如果使用动态链接,则必须将整个DLL包含在分布式应用程序中,无论它有多大。如果使用静态链接,链接器应该*仅将您在 代码中使用的函数链接到可执行文件中,如上所述。

AFAIK,只要您没有使用DLL导出的每个函数,与(可执行文件+ DLL)的大小相比,与静态库链接将始终导致较小的可执行文件。换句话说,如果你比较只是可执行文件,动态链接的可执行文件会更小,但如果你比较整个软件包,静态链接会更小。

*我不知道任何连接器链接库中的每个函数 - 大连接器(MS,GNU)肯定会链接所需的最小量,但这并不是说没有一些蹩脚的连接器会将所有内容联系起来,无论它是否被使用。

答案 2 :(得分:1)

进一步使事情复杂化还有更多选择。

首先,您可以使用静态和动态链接的混合。动态链接目标系统的libc和libm(基本C和数学库)是正常的。对于大多数目标平台,您可以保证它们将出现在任何功能系统上。如果他们不在那里,那么你的应用程序将不会运行......但实际上没有其他任何东西都可以运行。将不会有任何shell或脚本引擎尝试启动您的程序。

从那里取决于它。例如,在使用“curses”的UNIX / Linux编程中,通常会动态链接到 curses ncurses 库。但是,有一些版本的curses有可选的库提供更高级别的抽象(例如“pad”)。最好将这些额外的位静态链接到可执行文件中,这样就可以减少对用户的依赖。

另一种形式的动态链接是运行时动态链接(通过 dlopen()和相关函数)。在这种情况下,您可以根据自己的配置选项,命令处理等选择性地打开并链接到各种库。您可以在Apache Web服务器(它仅尝试加载 mod_rewrite 模块,如果配置文件包含对它的引用)以及Perl和Python(加载.so ...共享对象)中看到这一点。 ..分别使用DynaLoader bootstrap 和本机 import 命令。)

(显然,当你加载像 mod_perl mod_python 之类的东西时,依赖关系会变得很有趣,而这些依赖于运行调用其他 dlopen()的代码操作......一些可能正在加载XML库等等。)

通常,您只需动态链接您的应用程序并记录生成的依赖项(并且可能提供适合您支持的目标的安装脚本或打包)。通常这对大多数项目来说已经足够了。特殊情况是指您正在编译内核之类的东西,或者目标是嵌入式系统等等。

如果您想了解有关创建自己的自定义链接描述文件的更多信息,那么最佳起点可能是:Using ld: The GNU Linker

答案 3 :(得分:0)

静态链接将您引用的代码(可传递地)复制到可执行文件中。

动态链接会使您的程序处于或多或少的原始状态,并在运行时连接到系统库。

要最小化可执行文件的最终大小,请使用动态链接。