C++ C和C++;静态链接:只是一个副本?
当有人静态链接一个.lib时,链接器会将lib的全部内容复制到最终的可执行文件中,还是只复制目标文件中使用的函数?某种程度上。不过,它还需要修复所有函数调用指针。尤其是当这些函数调用存在于静态库之外(即在另一个静态库或可执行文件中)时。链接器是在古代发明的,当时内存特别宝贵。它们的主要功能之一是删减不使用的模块。这种能力一直延续到今天C++ C和C++;静态链接:只是一个副本?,c++,c,linker,static-linking,C++,C,Linker,Static Linking,当有人静态链接一个.lib时,链接器会将lib的全部内容复制到最终的可执行文件中,还是只复制目标文件中使用的函数?某种程度上。不过,它还需要修复所有函数调用指针。尤其是当这些函数调用存在于静态库之外(即在另一个静态库或可执行文件中)时。链接器是在古代发明的,当时内存特别宝贵。它们的主要功能之一是删减不使用的模块。这种能力一直延续到今天 一些库函数依赖其他函数是很常见的,所有依赖项都将被链接。它将只使用使用过的函数和符号(除非另有说明,但这可能很棘手) 附带问题: 这实际上可能是一个问题,如果你的
一些库函数依赖其他函数是很常见的,所有依赖项都将被链接。它将只使用使用过的函数和符号(除非另有说明,但这可能很棘手) 附带问题:
这实际上可能是一个问题,如果你的f.ex。有一些类只是将自己注册到工厂。没有人直接调用这些类,因此它们不会被包含,因此不会在工厂中注册。有很多方法可以解决这个问题(通常是在引用源文件的头文件中声明一些匿名变量)。取决于链接器。有些链接器很懒惰,只是把整个库都放进去了。另一个极端是链接器,它只向可执行文件中插入必要的代码 示例测试是编写一个使用
put
的程序,并与使用printf
的程序进行比较。如果可执行文件大小相同,则更像是一个懒惰的链接器
例子:
puts_test.cpp
#include <cstdio>
using namespace std;
int main(void)
{
puts("Hello World\n");
return 0;
}
#包括
使用名称空间std;
内部主(空)
{
放置(“Hello World\n”);
返回0;
}
printf_test.cpp
#include <cstdio>
using namespace std;
int main(void)
{
printf("%s\n", "Hello World");
return 0;
}
#包括
使用名称空间std;
内部主(空)
{
printf(“%s\n”、“你好世界”);
返回0;
}
在上面的示例中,put
函数不需要额外的代码来解析格式字符串或将数字转换为文本。这是基线,因为它需要最小的库函数
使用printf
的示例需要更多功能。printf
函数需要解析格式字符串并输出文本
预期结果是printf
可执行文件应该大于put
可执行文件。大多数编译器都会为printf
函数引入所有代码,以解析符号(例如用于显示float
s),即使未使用该部分代码。更智能(且成本更高)的编译器将分解printf
功能,只包含使用或需要的部分。在上面的例子中,编译器应该只包括处理文本的部分,而不包括格式化整数和浮点值的代码
惰性编译器或在调试模式下,将复制puts
示例的整个库,从而使可执行文件大小相同
符号比较
*nix平台和Cygwin提供了从可执行文件获取符号的工具。一个这样的实用程序是nm
。对每个可执行文件运行nm
,将输出定向到文本文件。比较这两个文本文件。惰性编译器应该具有相同的符号;但它们的位置可能不同(这对问题不重要) - 整个图书馆--编号
- 只是你调用的函数--编号
- 还有别的吗--是。
通常,一个给定的对象模块将包含多个函数,如果其中一些函数没有被您调用的函数调用,您将得到一些您不需要的函数(和数据对象)。链接器通常不会在构建最终可执行文件之前删除死代码。也就是说,它(通常)将链接所有符号,无论它们是否在最终可执行文件中使用。但是,链接器通常会显式地提供优化设置,您可以使用这些设置强制链接器进行额外的尝试 对于GCC,这分两个阶段完成:
你想要苹果派还是草莓蛋糕?有点像。@nightcracker:我说“有点像”,因为链接过程的一个主要部分是将内容从静态库复制到最终的可执行文件中。函数指针修正也会发生在函数剥离时。说“链接过程的一个主要部分实际上是将静态库中的内容复制到最终的可执行文件中。但是它将…”是错误的。链接器的基本定义是解析函数调用指针。未解析符号是指尚未解析的符号。不是吗
gcc -Os -fdata-sections -ffunction-sections test.cpp -o test.o -Wl,--gc-sections
/Gy
/OPT:REF