Программа GCC C ++ «Hello World» -> .exe имеет большой размер 500 КБ при компиляции в Windows. Как я могу уменьшить его размер? - PullRequest
29 голосов
/ 25 июня 2009

Я только недавно начал изучать C ++ - я использую версию MingW nuwen в Windows, используя NetBeans в качестве IDE (у меня также есть MSDN AA версия MSVC 2008, хотя я ее не очень использую) часто).

При компиляции этой простой программы:

#include <iostream>
using namespace std;

int dog, cat, bird, fish;

void f(int pet) {
  cout << "pet id number: " << pet << endl;
}

int main() {
  int i, j, k;
  cout << "f(): " << (long)&f << endl;
  cout << "dog: " << (long)&dog << endl;
  cout << "cat: " << (long)&cat << endl;
  cout << "bird: " << (long)&bird << endl;
  cout << "fish: " << (long)&fish << endl;
  cout << "i: " << (long)&i << endl;
  cout << "j: " << (long)&j << endl;
  cout << "k: " << (long)&k << endl;
} ///:~

мой исполняемый файл был размером около 1 МБ. Когда я изменил конфигурацию проекта с Debug на Release , использовал флаги -O1 -Os (убирая символы отладки по пути), размер двоичного файла был уменьшен с 1 МБ до 544 КБ.

Я не "фанат размера", но мне просто интересно - есть ли способ, которым я мог бы уменьшить размер .exe еще больше? Я просто думаю, что 544KB слишком много для такого простого приложения).

Ответы [ 13 ]

46 голосов
/ 04 февраля 2014

Проблема здесь не столько в библиотеке, сколько в способе
библиотека связана. Конечно, iostream - это библиотека среднего размера, но я не
думаю, что он может быть настолько огромным, что заставить программу генерировать исполняемый файл
900KB больше аналогичного, использующего функции C. Тот, кто виноват
это не iostream, а gcc. Точнее, виноват static linking.

Как бы вы объяснили эти результаты (с вашей программой):

g++ test.cpp -o test.exe              SIZE: 935KB
gcc test.cpp -o test.exe -lstdc++     SIZE: 64.3KB

Различные размеры исполняемых файлов генерируются с одинаковым
Варианты сборки.

Ответ заключается в том, как gcc связывает объектные файлы.
Когда вы сравниваете результаты этих двух команд:

g++ -v test.cpp -o test.exe // c++ program using stream functions  
gcc -v test.c -o test.exe   // c program that using printf  

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

   C++(iostream) | C(stdio)
-------------------------------
-Bstatic         |  (Not There)
-lstdc++         |  (Not There)
-Bdynamic        |  (Not There)
-lmingw32        | -lmingw32 
-lgcc            | -lgcc 
-lmoldname       | -lmoldname 
-lmingwex        | -lmingwex 
-lmsvcrt         | -lmsvcrt 
-ladvapi32       | -ladvapi32 
-lshell32        | -lshell32 
-luser32         | -luser32 
-lkernel32       | -lkernel32 
-lmingw32        | -lmingw32 
-lgcc            | -lgcc 
-lmoldname       | -lmoldname 
-lmingwex        | -lmingwex 
-lmsvcrt         | -lmsvcrt 

У тебя есть виновник прямо наверху. -Bstatic это опция, которая приходит
точно после объектного файла, который может выглядеть примерно так:

"AppData\\Local\\Temp\\ccMUlPac.o" -Bstatic -lstdc++ -Bdynamic ....

Если вы поэкспериментируете с опциями и удалите «ненужные» библиотеки,
Вы можете уменьшить размер исполняемого файла с 934KB до 4.5KB max
в моем случае. Я получил это 4.5KB, используя -Bdynamic, флаг -O
и наиболее важные библиотеки, без которых ваше приложение не может жить, т.е.
-lmingw32, -lmsvcrt, -lkernel32. Вы получите 25KB исполняемый файл на этом
точка. Раздень его до 10КБ и UPX до 4.5KB-5.5KB.

Вот Makefile для игры, для ударов:

## This makefile contains all the options GCC passes to the linker
## when you compile like this: gcc test.cpp -o test.exe
CC=gcc

## NOTE: You can only use OPTIMAL_FLAGS with the -Bdynamic option. You'll get a
## screenfull of errors if you try something like this: make smallest type=static
OPTIMAL_FLAGS=-lmingw32 -lmsvcrt -lkernel32

DEFAULT_FLAGS=$(OPTIMAL_FLAGS) \
-lmingw32 \
-lgcc \
-lmoldname \
-lmingwex \
-lmsvcrt \
-ladvapi32 \
-lshell32 \
-luser32 \
-lkernel32 \
-lmingw32 \
-lgcc  \
-lmoldname \
-lmingwex \
-lmsvcrt


LIBRARY_PATH=\
-LC:\MinGW32\lib\gcc\mingw32\4.7.1 \
-LC:\mingw32\lib\gcc \
-LC:\mingw32\lib\mingw32\lib \
-LC:\mingw32\lib\

OBJECT_FILES=\
C:\MinGW32\lib\crt2.o \
C:\MinGW32\lib\gcc\mingw32\4.7.1\crtbegin.o

COLLECT2=C:\MinGW32\libexec\gcc\mingw32\4.7.1\collect2.exe

normal:
    $(CC) -c test.cpp
    $(COLLECT2) -Bdynamic $(OBJECT_FILES)  test.o -B$(type) -lstdc++ -Bdynamic  $(DEFAULT_FLAGS) $(LIBRARY_PATH) -o test.exe

optimized:
    $(CC) -c -O test.cpp
    $(COLLECT2) -Bdynamic $(OBJECT_FILES)  test.o -B$(type) -lstdc++ -Bdynamic  $(DEFAULT_FLAGS) $(LIBRARY_PATH) -o test.exe

smallest:
    $(CC) -c -O test.cpp
    $(COLLECT2) -Bdynamic $(OBJECT_FILES)  test.o -B$(type) -lstdc++ -Bdynamic  $(OPTIMAL_FLAGS) $(LIBRARY_PATH) -o test.exe

ultimate:
    $(CC) -c -O test.cpp
    $(COLLECT2) -Bdynamic $(OBJECT_FILES)  test.o -B$(type) -lstdc++ -Bdynamic  $(OPTIMAL_FLAGS) $(LIBRARY_PATH) -o test.exe
    strip test.exe
    upx test.exe

CLEAN:
    del *.exe *.o

Результаты (YMMV):

// Not stripped or compressed in any way
make normal    type=static     SIZE: 934KB
make normal    type=dynamic    SIZE: 64.0KB

make optimized type=dynamic    SIZE: 30.5KB
make optimized type=static     SIZE: 934KB

make smallest  type=static     (Linker Errors due to left out libraries)
make smallest  type=dynamic    SIZE: 25.6KB 

// Stripped and UPXed
make ultimate type=dynamic    (UPXed from 9728 bytes to 5120 bytes - 52.63%)
make ultimate type=static     (Linker Errors due to left out libraries)

Возможная причина включения -Bstatic в параметры сборки по умолчанию
для лучшей производительности. Я попытался построить astyle с -Bdynamic и получил
снижение скорости в среднем на 1 секунду, даже если приложение работало
меньше, чем оригинал (400 КБ против 93 КБ при UPXed).

21 голосов
/ 25 июня 2009

#include <iostream>

вызывает связывание большого количества стандартной библиотеки, по крайней мере, с g ++. Если вы действительно обеспокоены размером исполняемого файла, попробуйте заменить все случаи использования iostreams на printf или аналогичные. Это, как правило, дает вам меньший, более быстрый исполняемый файл (я получил ваш около 6K) за счет удобства и безопасности типов.

10 голосов
/ 25 июня 2009

Не уверен, насколько он будет вам полезен, но кто-то проделал довольно большую работу по уменьшению размера простого Windows .exe .

Они смогли создать простой .exe-файл, который будет выполняться в современной версии Windows размером 133 байта, используя некоторые очень экстремальные методы.

9 голосов
/ 25 июня 2009

Вы можете использовать -s, который, я считаю, также встроен в mingw. Простое приложение hello world, скомпилированное с использованием g ++ 3.4.4 на cygwin, произвело исполняемый файл размером 476872 байта, снова скомпилированный с -s (удаляет ненужные данные), уменьшил тот же исполняемый файл до 276480 байтов.

То же самое приложение hello world на cygwin, использующее g ++ 4.3.2, произвело исполняемый файл размером 16495 байт, а использование strip уменьшило размер до 4608 байт. Насколько я вижу, вероятно, лучше использовать более свежую версию g ++.

MingW только что выпустил gcc 4.4.0, поэтому, если важен размер исполняемого файла, я бы подумал об этом. Как это указывает, -s, вероятно, поможет убрать большую часть отладочной информации для вас, что рекомендуется, только если это для производственного использования.

8 голосов
/ 25 июня 2009

Вы получаете стандартную библиотеку C ++ и другие вещи, которые, я думаю, статически связаны, поскольку у mingw есть своя реализация этих библиотек.

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

4 голосов
/ 25 июня 2009

По сути, вы ничего не можете сделать, чтобы уменьшить этот размер .exe с помощью базового дистрибутива mingw. 550kb - это как можно меньше, потому что mingw и gcc / g ++ в целом плохо разбирают неиспользуемые функции. Около 530 КБ этого из библиотеки msvcrt.a.

Если вы действительно хотите в нее войти, вы можете перестроить библиотеку msvcrt.a с параметрами компилятора -ffunction-section -fdata-section, а затем использовать параметры компоновщика -Wl, - gc-section, когда связывание вашего приложения, и это должно быть в состоянии убрать много всего этого оттуда. Но если вы только изучаете C ++, перестройка этой библиотеки может быть немного продвинутой.

Или вы можете просто использовать MSVC, который отлично подходит для удаления неиспользуемых функций. Тот же самый фрагмент кода, скомпилированный с MSVC, производит exe-файл 10 КБ.

2 голосов
/ 18 марта 2013

Если вам нужны небольшие исполняемые файлы, Tiny C скомпилирует исполняемый файл размером 1536 байт для printf («Hello world!») TinyC - это только C, а не C ++, и, как известно, он компилируется быстрее и дает более медленные исполняемые файлы, чем gcc.

Редакция: Я только что попробовал cout <"Hello World!" в DevC ++ (связывает Mingw 4.8 и Ide), и я получил исполняемый файл 4,5 МБ !! </p>

2 голосов
/ 26 июня 2009

Если вы используете утилиту «nm» или какую-либо другую программу, которая показывает, что находится в вашем .exe, вы увидите, что он содержит тонны классов, которые кто-то может захочет использовать, но которые вы не используете «т.

2 голосов
/ 25 июня 2009

Я повторил ваш тест, используя Cygwin и g ++. Ваш код скомпилирован в 480k с -O2. Запуск strip на исполняемом файле уменьшил его до 280k.

В общем, я подозреваю, что ваша проблема заключается в использовании заголовка . Это приводит к подключению довольно большой библиотеки. Также обратите внимание, что cout << x делает гораздо больше, чем просто печать. Существуют локали, ручьи и всякие вещи под капотом.

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

2 голосов
/ 25 июня 2009

Вы всегда можете запустить UPX на вашем exe после того, как вы его создали.

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