Подтвердить что ты не робот

Почему мой исполняемый файл вывода С++ настолько велик?

У меня довольно простой проект на С++, который использует библиотеку boost:: regex. Выход, который я получаю, составляет 3,5 МБ. Насколько я понимаю, я статически связываю все файлы с усилением .CPP, включая все функции/методы. Может быть, возможно каким-то образом поручить моему компоновщику использовать только необходимые элементы из 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();
}

Как вы думаете?

4b9b3361

Ответ 1

Вы скомпилировали с включенными символами отладки? Это может объяснять большую часть размера. Также как вы определяете размер двоичного файла? Предполагая, что вы на 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

EDIT: добавлены некоторые статические ссылки...

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

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

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

Ответ 2

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

Ответ 3

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

3.5Mb не так уж и много - в системе ПК такой размер может зависеть от ОС и т.д.

Ответ 4

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

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

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

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

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

Ответ 5

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

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

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

лучше

Ответ 6

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

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

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