Gcc C++ "Hello World" Program -> .Exe Is 500Kb Big When Compiled on Windows. How to Reduce Its Size

GCC C++ Hello World program - .exe is 500kb big when compiled on Windows. How can I reduce its size?

The problem here is not so much with the library as it is with the way the

library is linked. Granted, iostream is a moderately huge library but I don't

think it can be so huge as to cause a program to generate an executable that is

900KB larger than a similar one that uses C functions. The one to blame

is not iostream but gcc. More accurately, static linking is to be blamed.

How would you explain these results(with your program):

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

Different sizes of executables are being generated with exactly the same

build options.

The answer lies in the way gcc links the object files.

When you compare the outputs from these two commands:

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

you'll find out that the only places they differ(apart from the paths to the

temporary object files) is in the options used:

   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

You've got your culprit right there at the top. -Bstatic is the option that comes

exactly after the object file which may look something like this:

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

If you play around with the options and remove 'unnecessary' libraries,

you can reduce the size of the executable from 934KB to 4.5KB max

in my case. I got that 4.5KB by using -Bdynamic, the -O flag

and the most crucial libraries that your application can't live without, i.e

-lmingw32, -lmsvcrt, -lkernel32. You'll get a 25KB executable at that

point. Strip it to 10KB and UPX it to around 4.5KB-5.5KB.

Here's a Makefile to play with, for kicks:

## 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

Results(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)

A possible reason for the inclusion of -Bstatic in the default build options

is for better performance. I tried building astyle with -Bdynamic and got

a speed decrease of 1 second on average, even though the application was way

smaller than the original(400KB vs 93KB when UPXed).

How to reduce the size of executable produced by MinGW g++ compiler?

Flags to use:

  • -s like you've been doing to strip symbols
  • -lstdc++_s to specify dynamically linking against the libstdc++.dll
  • -Os to optimize the binary for size.

By default mingw static links to libstdc++.a on Windows.

Note that the lstdc++_s flag is only in MinGW with GCC > 4.4, I believe.

GCC: Empty program == 23202 bytes?

Don't follow its suggestions, but for amusement sake, read this 'story' about making the smallest possible ELF binary.



Related Topics



Leave a reply



Submit