2010-05-15 112 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,

相關問題