Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bloated EXE sizes, and unwanted dependencies with Qt/MingW

I'm trying to figure out how to shrink the sizes of EXE files compiled under the newest QT SDK (4.8.2) (mingw/g++ based). I was working on a vanilla c++ console app that has a simple loop and only #includes iostream, when I noticed that the exe's it generated are about 465kb; way bigger than they should be! Commenting out all the stream stuff brings it down to the expected 5kb range (although the remaining code would be mostly dead). This doesn't seem right at all, especially since another, full project I'm working on has a QGLwidget, windowing, a dozen data structures and ~3000 statements and only clocks in at about 126Kb. Is there some setting or flag I'm missing? Here's the .pro, while the cpp is trivial and Qt-free (basically getline and cout with a half dozen char swaps):

TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += main.cpp
QMAKE_CXXFLAGS_RELEASE += -O2
QMAKE_CXXFLAGS_RELEASE += -Os

I've tried a few other configurations, and it's definitely compiling in release mode (debug is >3Mb), but I can't figure out why it's so bloated.

I've also looked at the PE header, and I see that it's importing some functions from libgcc_s_dw2-1.dll and mingwm10.dll, and it'd be nice if I could eliminate those dependencies altogether as well, especially since neither one should be required anyway. I can make the libgcc one go away(at the expense of 17kb of exe size) by adding QMAKE_LFLAGS_RELEASE += -static to the .pro, but the mingwm10.dll stays either way, calling a single function.

Based on the overall bloating, and all the useless framework stuff that the compiler is trying to sneak in (networking, at least). I'm guessing it's just a matter of a couple settings that are askew, particularly with some of the default compiler flags like -DQT_LARGEFILE_SUPPORT or -mthreads. Here is the compile output (bullets added for emphasis):

  • 14:04:00: Running steps for project conTest...
  • 14:04:00: Configuration unchanged, skipping qmake step.
  • 14:04:01: Starting: "C:\QtSDK\mingw\bin\mingw32-make.exe"
  • C:/QtSDK/mingw/bin/mingw32-make -f Makefile.Release
  • mingw32-make[1]: Entering directory `C:/Documents and Settings/Administrator/My Documents/QT/conTest'
  • g++ -c -O2 -O2 -Os -frtti -fexceptions -mthreads -Wall -DUNICODE -DQT_LARGEFILE_SUPPORT -I"c:\QtSDK\Desktop\Qt\4.8.1\mingw\mkspecs\win32-g++" -o release\main.o main.cpp g++ -Wl,-s -Wl,-subsystem,console -mthreads -o release\conTest.exe release/main.o
  • mingw32-make[1]: Leaving directory `C:/Documents and Settings/Administrator/My Documents/QT/conTest'
  • 14:04:10: The process "C:\QtSDK\mingw\bin\mingw32-make.exe" exited normally.
like image 440
Ghost2 Avatar asked Sep 16 '12 18:09

Ghost2


2 Answers

One of the problems with using mingw is that the w32 version of binutils doesn't support dead code stripping (it removes the parts of the libraries that you don't actually use.) In order to bring down the sizes of my executables, I had to patch and build binutils from source using the patches here:

http://sourceware.org/bugzilla/show_bug.cgi?id=11539

It helped. But for it to work, you will need to rebuild everything using:

-fdata-sections -ffunction-sections

in the compile flags of everything (including GCC, Qt, other libraries and your own application) and:

-Wl,--gc-sections

in the link flags of your application only. It was worth it for me, as previously my executables would weigh in at about 20MB and now that's been halved and they're about 10MB. This includes all libraries (I link statically), including Qt, SDL, and various media libraries (like Vorbis, mpg123, FLAC and others.)

Although I imagine that if you build on Windows, it's not gonna be easy to do all that. I used Linux to build w32 cross-compile versions of everything, which is way easier.

like image 104
Nikos C. Avatar answered Sep 29 '22 08:09

Nikos C.


I would say to add in the -s command. That command strips the compiled binary file of all debuging symbols. Typically when you're compiler compiles something, it leaves the names of classes and function in the .exe file as a lookup. Those symbols will include all included headers. So you're .exe file will have symbols from iostream, including functions and classes.

MinGW has nm.exe which can be executed from cmd to list all the symbols in a file. Along with the strip.exe to strip already created files of their symbols.

like image 37
Wolfgang Skyler Avatar answered Sep 29 '22 08:09

Wolfgang Skyler