2009-09-20 85 views
1

我是一个完整的初学者,这是我理解链接的方式:静态链接仅将实际使用的代码复制到可执行文件中。动态链接使用可能包含许多应用程序永远不会使用的代码的.dll。请纠正我,如果我错了:)链接和文件大小

现在这是我的问题。我在我的应用程序中使用了一个开源库,但我只实现其部分功能。为了让我的可执行文件+库的最终大小尽可能小,我应该使用静态链接还是动态链接?我怎样才能确保没有不必要的代码被复制?

谢谢!

回答

4

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

但是,既然看起来你会写出exe和dll(s),你可以选择将要导出的内容,因此只包含必要的最小值。

编辑:在readproofing我注意到,实际上你正在考虑使用开源库,所以上述声明需要一些限定条件。

如果构建了开放的源代码原样(假设来源包括DLL构建),它可能会包括所有库的公开宣称的功能。但是,您可能会更改声明用于导出的方法列表,并因此获得尽可能少的二进制数。

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

一般而言,关于使用动态链接的选择与否,并非如此重要。。这个问题在过去是一个问题,CPU速度较慢(因此编译时间较长)以及有关内存,硬盘和分发带宽(使用软盘!等)的其他限制。

拇指的现代规则,在这些日子里和年龄GB级的存储,是挑静态链接,默认情况下,除非以下的一个适用:

  • 该DLL一个第三方公共DLL(即最终用户可以独立更新自己的更新周期)
  • 应用程序的几个部分通常不被使用,并且底层逻辑可以在DLL中“存储” ,从而实现整体较小的运行时足迹(当用户不使用底层sp时特色/高级功能。
  • 该程序是一套程序的一部分,其中几个程序具有足够的可共享的通用性。
  • 希望有多个版本的应用程序。例如,您可以实现应用程序的基本版/免费版/限制版,以及全功能版。假设您管理程序使用相同的API调用任一版本的功能,那么独特的行为可以单独封装在DLL中,允许付费用户仅下载“高级DLL”,而仅替换另一个(无需安装需要)。
  • 该软件是测试版,有人希望将多个版本发送给最终用户。 (如上所述,DLL交换,而不是重新安装是很好的)。
  • 应用程序的不同部分用不同的语言编写。在这种情况下,通常可以使用静态链接(通过强制编译器同意调用约定等),但DLL方法也可能会缓解这种合作。
  • 该软件由不同的程序员/团队制作。 DLL提供了一个隐含的责任描述。

可能还有一些情况,但是除非有一些现有的DLL需求,否则静态链接也是一样好。

+0

如果你只有一个你正在发布的程序,那么我可以同意静态链接。如果你正在分发一套可以使用共享库的程序,那么你很快就会浪费运行时内存以及磁盘空间。即使机器确实拥有大量内存,您几乎总能从内存的更高效使用中受益 - 而共享库往往会促进内存的更高效使用。 – 2009-09-20 03:11:50

+0

表示同意,请参阅回复中的“除非”点#3。 – mjv 2009-09-20 03:36:09

2

如果使用动态链接,则必须将整个DLL包含在分布式应用程序中,但它可能很大。如果您使用静态链接,则链接器应*只将您在代码中使用的函数链接到可执行文件中,如上所述。 AFAIK,只要不使用DLL导出的每个函数,与(可执行文件+ DLL)的大小相比,与静态库的链接总是会导致更小的可执行文件。换句话说,如果你比较只是的可执行文件,动态链接的将会更小,但是如果你比较整个软件包,静态链接将会更小。我不知道任何连接器链接库中的每个功能 - 大连接器(MS,GNU)肯定会链接所需的最小量,但这并不是说没有一些蹩脚的链接器会将所有内容链接起来,而不管它是否被使用。

0

静态链接将您引用的代码传递到您的可执行文件。

动态链接会使程序停留在原来的状态,并在运行时连接到系统库。

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

+1

你是对的使用DLL会导致一个较小的可执行文件,但他希望最小化可执行文件*加上库*的大小。你很困惑。 – Joren 2009-09-20 01:26:10

+0

是的,但是如果您只计算您的程序涉及的代码,那么这两种情况下的大小(可执行文件+库)是相同的。如果你计算所有的库代码,不管你是否使用它,好吧,当然,静态会变小。但其他代码已经存在于系统中,对吗?其他程序正在使用它,对吗?所以它是完全占用的大小不应该收取任何一个程序... 如果你认为系统上没有其他人会使用该库,那么你可能想要做静态和动态链接的组合。 – DigitalRoss 2009-09-20 01:35:31

+0

我应该注意到,有些人静态链接他们分发的程序,以避免地狱。它浪费了一些内存,因为现在用户在内存中有两个printf(3)等,但该应用程序可能更有可能工作。 “ – DigitalRoss 2009-09-20 01:37:24

1

使问题变得更复杂,还有更多的选择。

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

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

动态链接的另一种形式是运行时动态链接(通过dlopen()的和相关函数)。在这种情况下,您可以选择性地打开并链接到各种库,具体取决于您自己的配置选项,命令处理等。你可以看到Apache Web服务器(它只尝试加载mod_rewrite模块,如果配置文件包含对它的引用)以及Perl和Python(加载.so ...共享对象...与DynaLoader 引导程序和原生程序分别导入命令)。

(很明显的依赖性变得有趣,当你有阿帕奇加载像的mod_perlmod_python的这反过来,正在运行调用其他dlopen()的操作的代码......其中一些可能加载XML图书馆等)。

通常情况下,您只需动态链接应用程序并记录生成的依赖关系(也可以根据您的支持目标提供适当的安装脚本或打包)。通常这对大多数项目都是足够的。特殊情况是当你编译内核之类的东西时,或者目标是嵌入式系统等。

如果你想了解更多关于创建自定义链接描述文件的信息,那么最好的出发点可能是:Using ld: The GNU Linker