//(this article is courtesy of Luciano Montanaro, mikelima at the
server: virgilio.it)//
Here are some thoughts and experiences on how to configure a minimal qt library that still supports kde3.2 (or most of it). I’m basing my experiments on the qt-copy version of the qt libraries, which can be found in KDE CVS tree. Currently they are at version 3.3. I’m using a SuSE 9.0 distribuition, with gcc 3.3.1 and glibc 2.3.2. The Qt library can be optimized, on a first level, by using the right configuration options. There are a number of modules that can be excluded, if some advanced features are not needed. The ./configure --help
command is useful to see what options we have available. Here are some interesting options
for the curious:
-version-script
Use a version script when linking the Qt library. Internal symbols will be marked as local. Requires a recent GNU binutils package. WARNING: Experimental, may be removed in future versions. This option is potentially very useful, but as it is marked experimental, I don’t currently recommend using it. In an embedded environment, however it can indeed save quite a bit of memory. It needs recent binutils to work, and it enables a version-script to hide library-private symbols, thus reducing memory occupation and link time.
-platform target
The operating system and compiler you are building on (linux-g++). This option can be used to change the operating system and compiler to build to. The build system for the qt library is a quite rigid, and to change compilation options you must modify some file under the mkspecs directory. The cleanest way is to duplicate for example the
“linux-g++” in a “tinylinux-g++” directory and to change the options there. Options worth testing for gcc (or g++) are -Os instead of -O2, to optimize for size, -funit-at-a-time and -fomit-frame-pointer.
-disable-<module>
Disable <module> where module is one of: styles tools kernel widgets dialogs iconview workspace network canvas table xml opengl sql. This option can be used to disable the inclusion of parts of the qt library. I think the opengl support could be disabled without problems, and probably we could do without the sql and table modules as well.
-no-ipv6
Do not compile IPv6 support. This could probably be used too… ipv6 is nowhere near ubiquitous. I doubt it would save much, anyway.
-dlopen-opengl
Qt uses dlopen(3) to resolve OpenGL functions (instead of linking with OpenGL libraries directly). This could be an alternative to completely disabling openGL support. OpenGL can still be used, but it is not linked at startup. However, given our target, I doubt that OpenGL would be supported in any useful way.
-release
Disable debugging and enable optimization. This is important to reduce code size, as you’ll see below.
Here are the result of some experiment I did.
Compiling with: stripped Library size:
KDE recommend options | 7967300 |
With -release | 7243592 |
As previous, plus -Os|6453064 | |
As previous, plus -funit-at-a-time | 6126760 |
As previous, plus -fomit-frame-pointer | 6108808 |
As previous, option -disable-opengl | 6065356 |
Other things to research
If only KDE applications are of interest, then most of the Qt dialogs are not needed. Disabling the file and print dialogs could cut off a sizable chunk of code. The QWorkspace widget should not be needed by KDE, however the Qt tools (the designer, at least) use it. I’m not sure if the memory gains are worth the effort, anyway. Qt 4 is said to be more modular, so some of the less used parts of Qt could will not be loaded anyway. Here is the script I used to compile the final version of the Qt library.
---- cut here -------- #! /bin/bash export QTDIR=$PWD export YACC='byacc -d' make -f Makefile.cvs ./configure -system-zlib -qt-gif -system-libpng -system-libjpeg \ -plugin-imgfmt-mng -thread -no-stl -no-exceptions -release -fast \ -prefix ~/test-qtlibs-small -platform tinylinux-g++ \ -disable-opengl -disable-workspace make sub-tools ---- cut here --------
…and here is the modified qmake.defs I used. To use it together with the above script, cp -a mkspecs/linux-g++ mkspecs/tinylinux-g++
,then copy it to mkspecs/tinylinux-g++/qmake.defs
---- cut here -------- # # # # qmake configuration for linux-g++ # MAKEFILE_GENERATOR = UNIX TEMPLATE = app CONFIG += qt warn_on release incremental link_prl QMAKE_INCREMENTAL_STYLE = sublib QMAKE_CC = gcc QMAKE_LEX = flex QMAKE_LEXFLAGS = QMAKE_YACC = yacc QMAKE_YACCFLAGS = -d QMAKE_YACCFLAGS_MANGLE = -p $base -b $base QMAKE_YACC_HEADER = $base.tab.h QMAKE_YACC_SOURCE = $base.tab.c QMAKE_CFLAGS = -pipe QMAKE_CFLAGS_DEPS = -M QMAKE_CFLAGS_WARN_ON = -Wall -W QMAKE_CFLAGS_WARN_OFF = -w QMAKE_CFLAGS_RELEASE = -Os -funit-at-a-time -fomit-frame-pointer QMAKE_CFLAGS_DEBUG = -g QMAKE_CFLAGS_SHLIB = -fPIC QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses QMAKE_CFLAGS_THREAD = -D_REENTRANT QMAKE_CXX = g++ QMAKE_CXXFLAGS = $$QMAKE_CFLAGS QMAKE_CXXFLAGS_DEPS = $$QMAKE_CFLAGS_DEPS QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD QMAKE_INCDIR = QMAKE_LIBDIR = QMAKE_INCDIR_X11 = /usr/X11R6/include QMAKE_LIBDIR_X11 = /usr/X11R6/lib QMAKE_INCDIR_QT = $(QTDIR)/include QMAKE_LIBDIR_QT = $(QTDIR)/lib QMAKE_INCDIR_OPENGL = /usr/X11R6/include QMAKE_LIBDIR_OPENGL = /usr/X11R6/lib QMAKE_LINK = g++ QMAKE_LINK_SHLIB = g++ QMAKE_LFLAGS = QMAKE_LFLAGS_RELEASE = QMAKE_LFLAGS_DEBUG = QMAKE_LFLAGS_SHLIB = -shared QMAKE_LFLAGS_PLUGIN = $$QMAKE_LFLAGS_SHLIB QMAKE_LFLAGS_SONAME = -Wl,-soname, QMAKE_LFLAGS_THREAD = QMAKE_RPATH = -Wl,-rpath, QMAKE_LIBS = QMAKE_LIBS_DYNLOAD = -ldl QMAKE_LIBS_X11 = -lXext -lX11 -lm QMAKE_LIBS_X11SM = -lSM -lICE QMAKE_LIBS_NIS = -lnsl QMAKE_LIBS_QT = -lqt QMAKE_LIBS_QT_THREAD = -lqt-mt QMAKE_LIBS_OPENGL = -lGLU -lGL -lXmu QMAKE_LIBS_OPENGL_QT = -lGL -lXmu QMAKE_LIBS_THREAD = -lpthread QMAKE_MOC = $(QTDIR)/bin/moc QMAKE_UIC = $(QTDIR)/bin/uic QMAKE_AR = ar cqs QMAKE_RANLIB = QMAKE_TAR = tar -cf QMAKE_GZIP = gzip -9f QMAKE_COPY = cp -f QMAKE_COPY_FILE = $(COPY) QMAKE_COPY_DIR = $(COPY) -r QMAKE_MOVE = mv -f QMAKE_DEL_FILE = rm -f QMAKE_DEL_DIR = rmdir QMAKE_STRIP = strip QMAKE_STRIPFLAGS_LIB += --strip-unneeded QMAKE_CHK_DIR_EXISTS = test -d QMAKE_MKDIR = mkdir -p ----- cut here --------
Other tips
The size of Qt drops by quite a bit also bycompiling it with -Os {-fomit-frame-pointer -funit-at-a-time}
and disabling the OpenGL classes. I have tested a bit more and if you don’t need xinerama support and antialiased text, you can add the options {-no-xinerama -no-xrender -no-xft}
. With these, libqt-mt.so shrinks to 5925200 bytes. A copy of konqueror linked to this library with {LD_PRELOAD=~/kde/qt-copy-local/lib/libqt-mt.so.3.1.1}
on an otherwise “normal” SuSE install, uses, according to top 21MB, versus 23 when using the standard library. Building against this library could improve still a bit, since libXft and libXrender are still linked to konqueror.