静态库链接程序VS源代码编译程序巨大的差异

时间:2016-04-02 03:08:45

标签: c++ static size crypto++

我有一个库(Crypto ++),在编译库时总共将近50MB。

我使用了Crypto ++的源代码,并且只添加了我将在我的应用程序中使用的算法的源文件。 然后我创建了应用程序,并决定将Crypto ++编译为静态库,并将其链接到同一项目的克隆版本。

所以现在我有两个项目:

项目1:只有必要的源文件才能编译,只使用我需要的算法AES,SHA256等。

项目2:只有头文件和Crypto ++链接的静态库。

现在,当我编译这两个项目时,我应该(或者我一直认为)看到两个exes都具有相同的大小,因为链接器只将我在Project 2中使用的源链接到exe,基本上它会链接与我在Project 1上使用的文件完全相同。 但事实并非如此,我看到项目1与项目2的巨大差异...... 使用静态库的项目比使用源代码编译的项目大6.2倍。(两者都在发布模式下编译)

项目1(来源)大小:210kb 项目2(静态库)大小:1,303kb

这是为什么?我总是认为链接器应该只使用我在代码中引用的内容。这只是一个链接器效率低下吗?

有人可以启发我吗?

2 个答案:

答案 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
+