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

前端 未结 14 2243
遇见更好的自我
遇见更好的自我 2020-11-27 04:29

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 u

相关标签:
14条回答
  • 2020-11-27 05:04

    I replicated your test using Cygwin and g++. Your code compiled to 480k with -O2. Running strip on the executable reduced it to 280k.

    In general, though, I suspect your problem is the use of the <iostream> header. This causes a fairly large library to be linked in. Also, note that cout << x does a lot more than just printing. There are locales and streams and all sorts of under-the-hood stuff.

    If however, having a small executable size is a real, mission-critical objective, then avoid it and use printf or puts. If it's not, then I would say pay the one-time cost of iostream and be done with it.

    0 讨论(0)
  • 2020-11-27 05:09

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

    0 讨论(0)
  • 2020-11-27 05:10

    Not sure how much use it will be to you, but someone has done quite a lot of work on reducing the size of a simple Windows .exe.

    They were able to create a simple .exe that will execute on a modern version of Windows in 133 bytes, by using some very extreme methods.

    0 讨论(0)
  • 2020-11-27 05:12

    You could always run UPX on your exe after you have created it.

    0 讨论(0)
  • 2020-11-27 05:13

    Basically, there's not really anything you can do to reduce that .exe size with a base distribution of mingw. 550kb is about as small as you can get it, because mingw and gcc/g++ in general are bad at stripping unused functions. About 530kb of that is from the msvcrt.a library.

    If you really wanted to get into it, you might be able to rebuild the msvcrt.a library with -ffunction-sections -fdata-sections compiler options, and then use the -Wl,--gc-sections linker options when linking your app, and this should be able to strip a lot of that stuff out of there. But if you're just learning C++, rebuilding that library may be a bit advanced.

    Or you could just use MSVC, which is great at stripping unused functions. That same bit of code compiled with MSVC produces a 10kb exe.

    0 讨论(0)
  • 2020-11-27 05:14

    The

    #include <iostream>
    

    causes a lot of the standard library to be linked in, at least with g++. If you are really concerned about executable size, try replacing all uses of iostreams with printf or similar. This will typically give you a smaller, faster executable (I got yours down to about 6K) at the cost of convenience and type-safety.

    0 讨论(0)
提交回复
热议问题