почему мой выходной исполняемый файл C ++ такой большой? - PullRequest
12 голосов
/ 15 мая 2010

У меня довольно простой проект на C ++, в котором используется библиотека boost :: regex. Вывод, который я получаю, имеет размер 3,5 Мб. Как я понимаю, я статически связываю все файлы .CPP boost, включая все функции / методы. Может быть, можно как-то проинструктировать мой компоновщик использовать не все необходимые элементы из boost, а не все? Спасибо.

$ 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

пс. Вот как организован мой код (возможно, это основная причина проблемы):

// 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();
}

Что вы думаете?

Ответы [ 6 ]

17 голосов
/ 20 мая 2010

Вы скомпилировали с включенными символами отладки? Это может составлять большую часть размера. Кроме того, как вы определяете размер двоичного файла? Предполагая, что вы находитесь на платформе UNIX, вы используете прямую команду "ls -l" или "size". Эти два могут дать очень разные результаты, если двоичный файл содержит символы отладки. Например, вот результаты, которые я получаю при создании примера Boost.Regex" credit_card_example.cpp ".

$ 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++ -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++ -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)

Вы можете получить до ~ 600 Кбайт только от Boost.Regex, если некоторые или все эти объектные файлы будут связаны с вашим двоичным файлом.

6 голосов
/ 20 мая 2010

Флаг -O3 не оптимизирует ваш код по размеру, а скорее по скорости выполнения. Так, может быть, например некоторое развертывание цикла вызовет больший файл. Попробуйте скомпилировать с другим флагом оптимизации. Флаг -Os оптимизируется для небольшого исполняемого файла.

2 голосов
/ 15 мая 2010

Если вы статически связываете, то большинство компоновщиков будут включать только те объекты, которые вам нужны.

3,5 МБ не так уж и много - на ПК, поэтому размер может зависеть от ОС и т. Д.

1 голос
/ 25 мая 2010

Вы говорите, что у вас есть 3 файла. Для меня MyClassImpl.h, вероятно, является .cpp, поскольку он содержит реализацию.

В любом случае, если вы на самом деле компилируете два файла, включая boost :: regex, у вас будет в два раза больше, чем boost :: regex (точно, если вы используете одинаковую функциональность в обоих файлах, вы будете в два раза дороже в космосе).

Это связано с тем, что большинство расширенных функций являются встроенными шаблонами.

лучший

1 голос
/ 20 мая 2010

Если у вас правильно установлен порядок ссылок (наиболее зависимый, за которым следует наименее зависимый), компоновщик должен захватывать только те символы, которые фактически использует ваша программа. Кроме того, многие (но не все, и я не могу говорить о регулярных выражениях) функции повышения доступны только для заголовков из-за использования шаблонов.

Скорее всего, отладочная информация / таблица символов / и т. Д. Занимает место в вашем двоичном файле. Имена шаблонов (например, iostream и стандартные контейнеры) очень длинные и создают большие записи в таблице символов.

Вы не говорите, какую операционную систему вы используете, но если это тестовый вариант Unix, вы можете strip копию вашего двоичного файла, чтобы удалить всю дополнительную информацию и посмотреть, что осталось:

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

В одном тестируемом бинарном файле было удалено около 90% размера файла. Обратите внимание, что если вы сделаете это, любые ядра будут довольно бесполезны без копии необработанного двоичного файла для отладки - у вас не будет никаких имен символов или чего-либо, только сборки и адреса. 3,5 МБ - действительно крошечный файл в наше время. Скорее всего, так много информации об отладке / символах даже из 10Ksloc источника.

0 голосов
/ 20 мая 2010

если у вас есть доступный ldd, вы можете использовать его, чтобы проверить, действительно ли вы связываетесь со всеми буст-библиотеками.

Другая возможность заключается в том, что размер является побочным эффектом от использования библиотек только заголовков, многие дополнительные библиотеки являются такими же, и их включение может включать в себя больше кода, в который вы можете поверить. Вы также можете создать некий комбинаторный взрыв из-за использования нескольких различных параметров шаблона.

Чтобы получить лучшую диагностику, вы должны попытаться создать действительно короткую программу с использованием регулярных выражений и посмотреть, какой размер вы получите. Если ваша программа действительно короткая, 3.5 Mo довольно велика. Мой текущий исполняемый файл projet также использует BOOST (но не регулярное выражение) и имеет примерно такой же размер. Но я говорю о 20000 строк C ++. Следовательно, где-то должен быть подвох.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...