2010-05-15 147 views
10

我有一个非常简单的C++项目,该项目采用的boost :: regex库。我得到的输出是3.5Mb的大小。据我所知我静态链接所有boost.CPP文件,包括所有功能/方法。也许有可能以某种方式指示我的链接器只使用来自boost的必要元素,而不是所有元素?谢谢。为什么我的C++输出可执行文件太大了?

$ c++ —version 
i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5659) 

这是size说:

$ size a.out 
__TEXT __DATA __OBJC others dec hex 
1556480 69632 0 4296504912 4298131024 100304650 

我试图strip

$ ls -al 
... 3946688 May 21 13:20 a.out 
$ strip a.out 
$ ls -al 
... 3847248 May 21 13:20 a.out 

PS。这就是我的代码是如何组织的(也许这是造成这个问题的主要原因):

// file MyClass.h 
class MyClass { 
    void f(); 
}; 
#include "MyClassImpl.h" 

// file MyClassImpl.h 
void MyClass::f() { 
    // implementation... 
} 

// file main.cpp 
#include "MyClass.h" 
int main(int ac, char** av) { 
    MyClass c; 
    c.f(); 
} 

你觉得呢?

+4

也许您正在构建调试信息插入可执行文件。尝试在启用优化的情况下构建。 – AraK 2010-05-15 06:48:12

+0

您是否正在编译优化? – jalf 2010-05-15 12:58:42

+0

我正在使用标志-O3 – yegor256 2010-05-16 05:53:04

回答

15

你编译启用调试符号?这可能占据大部分的规模。另外你如何确定二进制文件的大小?假设你在一个类UNIX平台,您使用直“ls -l”或“size”命令。如果二进制文件包含调试符号,那么这两者可能会有很大的不同。例如,这里正在建设的Boost.Regexcredit_card_example.cpp”例如,当我得到的结果。

$ g++ -c -g -O3 foo.cpp 

$ ls -l foo.o 
-rw-r--r-- 1 void void 622476 2010-05-20 10:40 foo.o 

$ size foo.o 
    text data  bss  dec  hex filename 
    49119  4  40 49163 c00b foo.o 

编辑:在刚生成的对象文件

$ g++ -g -O3 foo.cpp -lboost_regex-mt 

$ ls -l a.out 
-rwxr-xr-x 1 void void 483801 2010-05-20 10:36 a.out 

$ size a.out 
    text data  bss  dec  hex filename 
    73330  492  336 74158 121ae a.out 

出现类似的结果增加了一些静态链接结果...

这里的二进制文件的大小时,静态链接。这是更接近你在说什么:

$ g++ -static -g -O3 foo.cpp -lboost_regex-mt -lpthread 

$ ls -l a.out 
-rwxr-xr-x 1 void void 2019905 2010-05-20 11:16 a.out 

$ size a.out 
    text data  bss  dec  hex filename 
1204517 5184 41976 1251677 13195d a.out 

这也有可能是许多大尺寸从其他图书馆来Boost.Regex库依赖。在我的Ubuntu框中,Boost.Regex共享库的依赖关系如下:

$ ldd /usr/lib/libboost_regex-mt.so.1.38.0 
     linux-gate.so.1 => (0x0053f000) 
     libicudata.so.40 => /usr/lib/libicudata.so.40 (0xb6a38000) 
     libicui18n.so.40 => /usr/lib/libicui18n.so.40 (0x009e0000) 
     libicuuc.so.40 => /usr/lib/libicuuc.so.40 (0x00672000) 
     librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0x001e2000) 
     libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x001eb000) 
     libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x00110000) 
     libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x009be000) 
     libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x00153000) 
     libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x002dd000) 
     /lib/ld-linux.so.2 (0x00e56000) 

ICU库可以得到相当大的。除了调试符号外,也许它们是二进制大小的主要贡献者。此外,在静态连接的情况下,它看起来像Boost.Regex库自身由大对象文件:

$ size --totals /usr/lib/libboost_regex-mt.a | sort -n 
     0  0  0  0  0 regex_debug.o (ex /usr/lib/libboost_regex-mt.a) 
     0  0  0  0  0 usinstances.o (ex /usr/lib/libboost_regex-mt.a) 
     0  0  0  0  0 w32_regex_traits.o (ex /usr/lib/libboost_regex-mt.a) 
    text data  bss  dec  hex filename 
    435  0  0  435  1b3 regex_raw_buffer.o (ex /usr/lib/libboost_regex-mt.a) 
    480  0  0  480  1e0 static_mutex.o (ex /usr/lib/libboost_regex-mt.a) 
    1543  0  36 1579  62b cpp_regex_traits.o (ex /usr/lib/libboost_regex-mt.a) 
    3171  632  0 3803  edb regex_traits_defaults.o (ex /usr/lib/libboost_regex-mt.a) 
    5339  8  13 5360 14f0 c_regex_traits.o (ex /usr/lib/libboost_regex-mt.a) 
    5650  8  16 5674 162a wc_regex_traits.o (ex /usr/lib/libboost_regex-mt.a) 
    9075  4  32 9111 2397 regex.o (ex /usr/lib/libboost_regex-mt.a) 
    17052  8  4 17064 42a8 fileiter.o (ex /usr/lib/libboost_regex-mt.a) 
    61265  0  0 61265 ef51 wide_posix_api.o (ex /usr/lib/libboost_regex-mt.a) 
    61787  0  0 61787 f15b posix_api.o (ex /usr/lib/libboost_regex-mt.a) 
    80811  8  0 80819 13bb3 icu.o (ex /usr/lib/libboost_regex-mt.a) 
116489  8  112 116609 1c781 instances.o (ex /usr/lib/libboost_regex-mt.a) 
117874  8  112 117994 1ccea winstances.o (ex /usr/lib/libboost_regex-mt.a) 
131104  0  0 131104 20020 cregex.o (ex /usr/lib/libboost_regex-mt.a) 
612075  684  325 613084 95adc (TOTALS) 

你可以得到高达60万〜从Boost.Regex未来别说如果部分或全部的那些目标文件被链接到你的二进制文件。

+1

+1用'-O2 -g'尝试使用boost :: spirit。 250LoC - > 20M,不用开玩笑。这些符号如此之长,会使valgrind崩溃。模板调试符号不会乱七八糟。 – academicRobot 2010-05-21 05:00:45

+0

如何禁用输出中的调试信息? – yegor256 2010-05-21 11:11:59

+2

不要使用-g或-ggdb标志进行编译。或者,在你的可执行文件上运行'strip -g'来去掉调试符号(注意,运行exe时没有加载调试信息,不会影响你的RAM,因为它们保存在可执行文件中) – nos 2010-05-21 11:20:58

2

如果您是静态链接,那么大多数链接器将只包含所需的对象。

3.5MB没有那么大 - 在PC系统上,因此规模可能依赖于OS等

+0

我的源代码只是10KSLOC,boost-regex是另一个6KSLOC。这个代码(16KSLOC)如何产生3.5Mb的可执行文件? – yegor256 2010-05-16 05:58:58

+4

@Vin模板,运行时,预处理器加起来。 loc不是很有意义 – Anycorn 2010-05-20 18:27:04

+7

所有这些骚动约3.5 MB ... – 2010-05-20 19:49:58

1

如果您的链接顺序设置正确(大多数依赖后紧跟最小依赖),链接器应该只抓取程序实际使用的符号。此外,很多(但不是全部,我不能说正则表达式)提升功能是仅由于模板使用的标题。

更可能是调试信息/符号表/ etc在您的二进制文件占用空间。模板名称(例如iostream和标准容器)非常长,并在符号表中创建较大的条目。

你不说你使用的是什么操作系统,但如果它是一个Unix操作系统作为测试你其实可以strip您的二进制文件的副本,以去除所有多余的信息,看看还剩下些什么:

cp a.out a.out.test 
strip a.out.test 
ls -l a.out* 

在我测试的一个二进制文件中,它删除了大约90%的文件大小。请注意,如果你这样做的话,任何内核都将毫无用处,而没有未被解析的二进制文件的副本进行调试 - 你将不会有任何符号名称或任何东西,只是程序集和地址。 3.5 MB在现代真的是一个小文件。最有可能的是,即使只有10Ksloc的源代码也有很多调试/符号信息。

+0

无需剥离二进制文件来确定大小而不用调试符号和相关的文件,只需要使用'size'命令,如我的回答中所描述的那样 – Void 2010-05-20 18:33:52

5

-O3标志不会优化您的代码的大小,而是执行速度。所以也许例如一些循环展开会导致更大的文件。尝试编译一些其他优化标志。 -Os标志将针对小型可执行文件进行优化。

+0

这也是一个好的方面。编译Boost.Regex“'credit_card_example.cpp'”示例在动态和静态链接的情况下,'-Os'将二进制文件的大小降低了大约20K(参见我对“-O3”结果的回答)。无论如何,如果它降低了@ Vincenzo的二进制文件大小显着。当然,这是值得一试。 – Void 2010-05-20 18:47:47

+0

+1,我不知道-Os选项使尺寸更小,绝对是未来的好信息! – shuttle87 2010-05-24 06:39:48

0

如果您有ldd可用,您可以使用它来检查您是否真的与所有boost库链接。

另一种可能性是尺寸是仅使用头文件库的副作用,许多boost库都是这种类型的,并且包含它们可以嵌入更多可以相信的代码。由于使用了几个不同的模板参数,您还可以生成某种组合爆炸。

为了获得更好的诊断效果,您应该尝试使用正则表达式创建一个非常短的程序,并查看您获得的大小。如果你的程序真的很短3.5莫很大。我目前的projet可执行文件也使用BOOST(但不是正则表达式)并且大小相同。但是我说的是大约20000行C++。因此,应该有一个地方捕捉。

1

你说你有3个文件。 对我来说,MyClassImpl.h可能是一个.cpp,因为它包含了实现。无论如何,如果你实际上编译了两个文件,包括boost :: regex,你将会得到两倍于boost :: regex的大小(如果你在两个文件中使用相同的功能,你将有两倍的大小空间成本)。

这是由于大多数增强功能都是内联模板。

best,

相关问题