Reducing Executable Size

From WxWiki

Jump to: navigation, search

Even though disk space and RAM are practically dirt-cheap nowadays smaller executables lead to better cache usage, and can be faster. Moreover, users may be downloading over slow modems, and for paid hosting, server bandwidth might be minimized.

Contents

[edit] General tips

  1. Only link libraries you actually use (e.g. if you don't use rich text and HTML, don't include the wxWidgets libraries that contain them). Obviously, making a monolithic build prevents this.
  2. Make a 'release build' instead of a 'debug build':
    • Windows : Use 'BUILD=release' as an argument while executing the makefile in wxWidgets 2.8 and later.
    • UNIX : it's the default; see configure settings for full details.
  3. Turn on optimizations for your compiler to optimize for size:
  4. Don't include components you do not use
    • UNIX : while running './configure' (see ./configure --help for details)
      • Sometimes configure options will cause compiler errors because parts of the library aren't properly #ifdef'ed. Usually these are simple to fix, and patches are appreciated.
    • Windows : by editing include/wx/msw/setup.h manually if using MSVC
    • It's been reported that disabling exceptions ('--enable-no_exceptions' with configure) can make quite a difference.
    • The libtiff library occupies between 200-300k of code and data. Consider removing tiff support from your program to save space.
    • Non-monolithic builds will provide many separate libs; only include those of them you actually use. Example : if you use only features of wxCore, you only need to link against the wxBase and wxCore libraries; see http://docs.wxwidgets.org/trunk/page_libs.html (this also means that monolithic builds are not good for size since they include all components and you can't select which ones you want)
  5. Use an executable packer like UPX (e.g. with "-9" and "--ultra-brute" flags) or ASPack. Note that packing affects the startup time of an executable because the entire executable has to be paged.
  6. If you link dynamically (e.g., use wxWidgets as a DLL), you'll end up with a smaller executable, but you'll be required to distribute the wxWidgets DLL, too, which can be quite big. This might be a good option when distributing multiple wxWidgets programs as part of a package, but if you are only distributing one application, you will end up with a simpler package if you statically link wxWidgets since the linker will automatically strip out components that your application doesn't use that it doesn't strip when you create a DLL.
  7. Use Microsoft Visual C++ instead of gcc (Cygwin or Mingw) on Windows. It does produce smaller and faster executables.
  8. Most installers compress the executable for distribution.

[edit] Windows Specific

MSDN documentation page for Microsoft VisualC++ compiler options: http://msdn.microsoft.com/en-us/library/19z1t1wy.aspx

Win32 Release libraries built by Visual Studio use around 1.2mb of space in your executable when compiled in release mode with the default options. By aggressively stripping options from setup.h it is possible to reduce the size of the library to about 400k, and still have a fairly functional library.

If using Visual Studio 2005, the free MSVC .NET 2003 Toolkit, or older professional Visual C++ editions that come with the optimizing compiler, you can set optimizations to "Minimize Size" instead of "Maximize Speed" (see project properties).

Also, if you have a lot of experience with C/C++ and don't mind delving into some black magic, you can eliminate C runtime stubs and strip other libraries. Don't forget extern "C" _fltused; if using floats. You need to make a function for creating large arrays (it's part of the source in c standard library that comes with MSVC).

See also http://www.nopcode.com/AggressiveOptimize.shtml for a header and some other settings you can set manually to reduce executable size by changing linker alignment and padding.

See Trimming wxWidgets Aggressively for some notes and numbers about reducing executable size under Windows for wxWidgets 2.6 & 2.8

[edit] GCC Specific

GCC documentation page for optimization options: http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

  1. Strip your binary
    • Pass the -s flag to gcc while building your executable
    • Or use strip --strip-all SOMEBINARY[.exe] on the executable if using GCC (any platform; on OS X, omit the --strip-all flag) - this might work better than -s in case of static librairies since it will also remove symbols linked in.
    • (Linux only?) Passing --remove-section=.comment and --remove-section=.note to strip saved me 0.31% by removing many copies of "GCC: (GNU) 4.0.1 20050727 (Red Hat 4.0.1-5)"
  2. Pass -ffunction-sections -fdata-sections to the compiler while building and -Wl,--gc-sections to the linker (see http://utilitybase.com/article/show/2007/04/09/225/Size+does+matter:+Optimizing+with+size+in+mind+with+GCC)

[edit] Examples and results

In the following tests wx2.9 was used, but the general trend holds for all wxWidgets versions and in general for any piece of software!

[edit] Test #1

# wxGTK compiled with:
#   ./configure --disable-debug --disable-shared
#   make
$ ls -l minimal
-rwxr-xr-x 1 frm frm 4,3M 2009-02-11 17:04 minimal*
$ size minimal
   text    data     bss     dec     hex filename
3698330   10436   49692 3758458  39597a minimal
$ strip --strip-all minimal
$ ls -l minimal
-rwxr-xr-x 1 frm frm 3,6M 2009-02-11 17:23 minimal*
$ strip --remove-section=.comment --remove-section=.note minimal
$ ls -l minimal
-rwxr-xr-x 1 frm frm 3,6M 2009-02-11 17:28 minimal*

I.e. using --strip-all provided a 17% improvement. Removing the .comment and .note sections didn't produce any noticeable enhancement.

[edit] Test #2

Now, let's test the -ffunctions-sections & co options:

# wxGTK compiled with:
#   export CXXFLAGS="-ffunction-sections -fdata-sections"
#   export LDFLAGS="-Wl,--gc-sections"
#   ./configure --disable-debug --disable-shared
#   make
$ ls -l minimal
-rwxr-xr-x 1 frm frm 3,1M 2009-02-11 17:34 minimal*
$ strip --strip-all minimal
$ ls -l minimal
-rwxr-xr-x 1 frm frm 2,6M 2009-02-11 17:36 minimal*

As you can see, using the -ffunctions-sections option when compiling and the -Wl,--gc-sections option when linking produces great results. The final executable (after stripping) is 30% smaller than the one obtained in test #1!

[edit] Test #3

Now, let's test the -Os option (together with the -ffunction-sections option):

# wxGTK compiled with:
#   export CXXFLAGS="-ffunction-sections -fdata-sections -Os"
#   export LDFLAGS="-Wl,--gc-sections"
#   ./configure --disable-debug --disable-shared
#   make
$ ls -l minimal
-rwxr-xr-x 1 frm frm 2,5M 2009-02-11 18:35 minimal*
$ strip --strip-all minimal
$ ls -l minimal
-rwxr-xr-x 1 frm frm 1,8M 2009-02-11 18:35 minimal*

The final executable (after stripping) is 50% smaller than the one obtained in test #1!

[edit] Conclusions

The tests showed that:

  1. you should always run strip --strip-all on the final executable (assuming that you don't care about symbol informations): this alone usually gives a 20-30% improvement
  2. if possible, compile all libraries that you're going to statically link in your program with the -ffunction-sections -fdata-sections -Os options and remember to link with the -Wl,--gc-sections option; this gives a 30-50% improvement

Please note also that the results of tests #1-#3 were obtained without disabling (at configure-time) any wxWidgets feature. If you play with the --enable-* options of wxWidgets configure you'll get even better results (see the #General tips).

Personal tools