I just recently started learning C++ - I am using nuwen's version of MingW on Windows, using NetBeans as an IDE (I have also MSDN AA Version of MSVC 2008, though I don't use it very often).
When compiling this simple program:
#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; } ///:~
my executable was about 1MB big. When I changed project configuration from Debug to Release, used -O1 -Os flags ( stripping debugging symbols along the way ), binary size was reduced from 1MB to 544KB.
I am not a "size freak", but I am just wondering - is there any way, that I could reduce .exe size even more? I just think, that 544KB is just too much for such a simple application ).
Another reason executables can be large is if you have turned on debugging (again via a compiler option). In at least one well known compiler, this option can increase the executable size by up to a factor of 10. You have to consult your compiler manuals or the vendor's technical support for a more detailed answer.
You need to use the which command to locate c compiler binary called gcc. Usually, it is installed in /usr/bin directory.
GCC stands for GNU Compiler Collections which is used to compile mainly C and C++ language. It can also be used to compile Objective C and Objective C++.
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 is900KB
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With