GCC C++"Hello World"程序 - > .exe在Windows上编译时大500kb.如何减小尺寸?

zer*_*ble 30 c++ size optimization gcc netbeans

我刚刚开始学习C++ - 我在Windows上使用nuwen的MingW版本,使用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;
} ///:~
Run Code Online (Sandbox Code Playgroud)

我的可执行文件大约1MB.当我将项目配置从Debug更改为Release时,使用-O1 -Os标志(沿途剥离调试符号),二进制大小从1MB减少到544KB.

我不是一个"大小怪物",但我只是想知道 - 有什么办法,我可以减少.exe的大小吗?我只是想,544KB对于这么简单的应用来说太多了.

Seg*_*ult 51

这里的问题不在于库,而在于
库的链接方式.当然,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
Run Code Online (Sandbox Code Playgroud)

使用完全相同的
构建选项生成不同大小的可执行文件.

答案在于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  
Run Code Online (Sandbox Code Playgroud)

你会发现他们唯一不同的地方(除了
临时目标文件的路径)在使用的选项中:

   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 
Run Code Online (Sandbox Code Playgroud)

你在顶部有罪魁祸首.-Bstatic是在
目标文件之后的选项,它可能看起来像这样:

"AppData\\Local\\Temp\\ccMUlPac.o" -Bstatic -lstdc++ -Bdynamic ....
Run Code Online (Sandbox Code Playgroud)

如果您使用这些选项并删除"不必要的"库,则
可以将可执行文件的大小从最小值减小934KB4.5KB最大值
.我得到了4.5KB通过-Bdynamic,该-O标志
和您的应用程序不能没有最关键的库,即
-lmingw32,-lmsvcrt,-lkernel32.那时你将得到一个25KB的可执行文件
.将其剥离到10KB并将其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
Run Code Online (Sandbox Code Playgroud)

结果(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)
Run Code Online (Sandbox Code Playgroud)

包含-Bstatic在默认构建选项中的可能原因
是为了获得更好的性能.我尝试astyle使用-Bdynamic并且
平均速度降低1秒,即使应用程序
比原始应用程序小(400KB对比UPXed时为93KB).

  • 这个答案远比接受的答案好得多. (15认同)

小智 23

#include <iostream>
Run Code Online (Sandbox Code Playgroud)

导致很多标准库被链接,至少用g ++.如果您真的关心可执行文件大小,请尝试使用printf或类似替换iostream的所有用法.这通常会以便利性和类型安全性为代价,为您提供更小,更快的可执行文件(我将您的可执行文件降低到大约6K).


Col*_*ard 10

不确定它对你多大的用处,但有人在减少简单的Windows .exe的大小方面做了大量的工作.

他们能够使用一些非常极端的方法创建一个简单的.exe,它将在133字节的现代版Windows上执行.

  • Linux ELF文件的等效练习:http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html (6认同)
  • 也许与他的问题没有直接关系,但非常感谢您分享您的发现! (2认同)

Ran*_*dai 9

你可以使用-s,我相信它也是在mingw中构建的.在cygwin上使用g ++ 3.4.4编译的简单hello world应用程序生成了476872字节的可执行文件,再次使用-s(删除不必要的数据)进行编译,将相同的可执行文件减少到276480字节.

使用g ++ 4.3.2在cygwin上使用相同的hello world应用程序生成了16495字节的可执行文件,使用strip将大小减小到4608字节.据我所知,最好使用更新版本的g ++.

MingW刚刚发布了gcc 4.4.0,所以如果可执行文件的大小很重要,那么我会考虑使用它.因为它表明-s可能有助于为您删除大部分调试信息,只有在生产用途时才建议使用.

  • 你真的尝试过使用std :: cout的例子吗?我认为这对最终的exe没有任何影响,只是意味着你可以在源代码中输入一个较短的名字. (3认同)

nos*_*nos 8

你得到了C++标准库,以及其他我认为静态链接的东西,因为mingw有自己的这些库的实现.

不要太在意它,当你制作更复杂的程序时,尺寸不会相应增长.