我是一个完全的初学者,这就是我理解链接的方式:静态链接只复制实际使用的代码到可执行文件中。动态链接使用.dll,它可能包含许多应用程序从未使用过的代码。如果我错了,请纠正我:)
现在这是我的问题。我在我的应用程序中使用了一个开源库,但我只实现了它的一部分功能。为了使我的可执行文件+库的最终大小尽可能小,我应该使用静态或动态链接吗?如何确保不会复制不必要的代码?
谢谢!
答案 0 :(得分:4)
使用动态链接时,您实际上构建了[至少]两个二进制文件:程序本身(.exe)和一个dll。对于exe,编译器/链接器可以检测代码的未使用部分,并且仅产生输出中所需的最小值。但是,对于DLL,标记为导出的所有函数和变量(以及使这些函数工作所需的所有代码)都必须包含在输出中。那是因为编译器/链接器无法知道程序可以使用哪些函数(其中一些函数将来会被编写......)。
但是,由于看起来你将同时编写exe和dll,你可以选择要导出的内容,因此只包含必要的最小值。
编辑:在读取防范时我注意到实际上您正在考虑使用开源库,因此上述声明需要一些资格。
如果您按原样构建开源代码 (假设源代码包含DLL的构建版本),则可能包含所有公开声明的库函数。但是,您可以更改为导出声明的方法列表,从而获得尽可能少的二进制数。
使用动态链接可以节省整体所需的二进制数量,因为多个程序可以使用相同的dll。例如,绘制应用程序和视频游戏程序的图形可以共享相同的图形实用程序dll。
一般来说,选择是否使用动态链接并非如此重要。这个问题在过去更成为一个问题,CPU速度较慢(因此构建时间较长),而且内存,硬盘和分配带宽(带有软盘!等等)的其他限制。
现代经验法则是,在技嘉大小存储的这些日子和时代,选择静态链接,默认情况下为,除非 以下其中一项适用:
可能还有一些案例,但同样,除非对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)
静态链接将您引用的代码(可传递地)复制到可执行文件中。
动态链接会使您的程序处于或多或少的原始状态,并在运行时连接到系统库。
要最小化可执行文件的最终大小,请使用动态链接。