我有一个库(Crypto ++),在编译库时总共将近50MB。
我使用了Crypto ++的源代码,并且只添加了我将在我的应用程序中使用的算法的源文件。 然后我创建了应用程序,并决定将Crypto ++编译为静态库,并将其链接到同一项目的克隆版本。
所以现在我有两个项目:
项目1:只有必要的源文件才能编译,只使用我需要的算法AES,SHA256等。
项目2:只有头文件和Crypto ++链接的静态库。
现在,当我编译这两个项目时,我应该(或者我一直认为)看到两个exes都具有相同的大小,因为链接器只将我在Project 2中使用的源链接到exe,基本上它会链接与我在Project 1上使用的文件完全相同。 但事实并非如此,我看到项目1与项目2的巨大差异...... 使用静态库的项目比使用源代码编译的项目大6.2倍。(两者都在发布模式下编译)
项目1(来源)大小:210kb 项目2(静态库)大小:1,303kb
这是为什么?我总是认为链接器应该只使用我在代码中引用的内容。这只是一个链接器效率低下吗?
有人可以启发我吗?
答案 0 :(得分:0)
链接器仅使用它引用的内容。您正在观察的行为是整个加密库构建为一个对象的直接结果。链接器别无选择,只能包含整个内容。如果您拥有库的源代码并将其与项目一起构建,链接器可以执行您期望的操作。
答案 1 :(得分:0)
我有一个库(Crypto ++),当编译库时,它总共有近50MB ......
是的,静态库带有所有符号。没有什么可以被丢弃,因为可能需要它。
如果您使用-g
,它还会带有调试信息。一些优化标志也会影响它。例如,-Os
最小化代码大小。
使用静态库的项目比使用源代码编译的项目大6.2倍。这是为什么?
我们需要查看您的程序,以及您的编译器和链接器切换以更好地解释正在发生的事情。根据这些数字,我猜测正在发生一些死代码剥离,但没有你想象的那么多:
项目1(源)大小:210kb项目2(静态库)大小:1,303kb
我总是认为链接器只能使用我在代码中引用的内容。这只是一个链接器效率低下吗?
构建Crypto ++库时,请使用make lean
配方。它添加了函数节(-ffunction-sections
)和数据节(-fdata-sections
),因此链接器可以更好地丢弃未使用的代码和数据。另请参阅Crypto ++ wiki上的GNUmakefile | Makefile Targets。
链接应用程序时,请使用相应的链接器开关。使用GCC / LD,那将是-Wl,--gc-sections
。在Apple / DYLD下,这将是-Wl,-dead_strip
。
您还可以剥离调试符号,这将进一步减少二进制文件大小。如果您使用符号构建或之后剥离它们,我不清楚。
如果您完全剥离并丢弃符号,那么堆栈跟踪将大部分无用。如果将符号保留在脱机文件中,则可能能够理解堆栈跟踪。另请参阅Crypto ++ wiki上的Debug Symbols。
以下是调查用户lean
目标的结果。另请参阅Crypto ++用户组的'make lean' target?。
测试计划 :
int main( int, char** ) {
Integer j("100000000000000000000000000000000");
j %= 1999;
cout << "j: " << j << endl;
return 0;
}
精益 (使用make lean
构建的库,与-Wl,--gc-sections
链接的程序):
$ ls -l integer.exe
-rwx------ 1 jwalton staff 162012 Jan 4 13:00 integer.exe
正常 (使用make
构建的库,没有特殊的链接器切换):
$ ls -l integer.exe
-rwx------ 1 jwalton staff 2636952 Jan 4 13:02 integer.exe
Crypto ++ 5.6.3发布后添加了lean
目标。如果需要,您需要从Master获取代码:
git clone https://github.com/weidai11/cryptopp.git cryptopp
或者,您可以从Commit 9696b9e5e79ff18a手动将以下补丁应用于GNUmakefile。在第270行左右添加:
+# Dead code stripping. Issue 'make lean'.
+ifeq ($(findstring lean,$(MAKECMDGOALS)),lean)
+ifeq ($(findstring -ffunction-sections,$(CXXFLAGS)),)
+CXXFLAGS += -ffunction-sections
+endif # CXXFLAGS
+ifeq ($(findstring -fdata-sections,$(CXXFLAGS)),)
+CXXFLAGS += -fdata-sections
+endif # CXXFLAGS
+ifneq ($(IS_DARWIN),0)
+ifeq ($(findstring -Wl,-dead_strip,$(LDFLAGS)),)
+LDFLAGS += -Wl,-dead_strip
+endif # CXXFLAGS
+else # BSD, Linux and Unix
+ifeq ($(findstring -Wl,--gc-sections,$(LDFLAGS)),)
+LDFLAGS += -Wl,--gc-sections
+endif # LDFLAGS
+endif # MAKECMDGOALS
+endif # Dead code stripping
以下食谱是:
+.PHONY: lean
+lean: libcryptopp.a cryptest.exe
+