Qt Commercial Support Weekly #19: How to Write Your Own Static Library with Qt

Qt Commercial customers have a great advantage to safely compile Qt statically and create their own static libraries and applications. Here, I have gathered some practicalities related to working with statically-linked Qt. Hopefully, this provides you a good starting point when you need to use static linking! In case you face problems, you know where to find us - Qt Commercial Support Portal.

 

Note: This blog is best viewed with Mozilla Firefox. Internet Explorer is giving errors on the code snippet.

Building Qt with Static Linking

First of all, Qt must be configured and compiled to use static linking. That's easy to do with the configure option -static. When you are building Qt, you just need to remember that all Qt modules do not support static linking due to the licensing policy – and this also concerns Qt Commercial customers. These modules are Phonon, QtWebkit and QtHelp. On Mac, there is a known bug which leads to a Qt internal error ‘qt_menu.nib could not be loaded’. Until QTBUG-5952 has been properly fixed, you need to copy the qt_menu.nib directory from $QTDIR/src/gui/mac/qt_menu.nib into the resources directory; for example like this: cp –r /path/to/qt/src/gui/mac/qt_menu.nib application.app/Contents/Resources.

Even if Qt has been compiled with -static option, it still can have dependencies to the compiler-specific runtime libraries. Dependency walker on Windows and ldd on Linux are handy tools for checking which libraries your executive depends on. In case you want to avoid the dependencies to the runtime libraries, you can edit the qmake.conf file on $QTDIR/mkspecs/<your platform>. There you will find the QMAKE_LFLAGS variables which are used for passing flags to the linker.

If you are using mingw compiler on Windows, you can modify the qmake.conf to have:

               

             QMAKE_LFLAGS = -static -static-libgcc

Option -static on QMAKE_LFLAGS eliminates the dependency to the runtime library mingwm10.dll.  It is good to also use a configure option -no-exceptions - so that exceptions are not allowed – as mingwm10.dll is not in place for taking care of memory handling. Option -static-libgcc on QMAKE_LFLAGS removes the dependency to libgcc_s_dw2-1.dll.

For MSVC compilers, Qt defines MD option by default on qmake.conf. So, Qt links against dynamic C/C++ runtime libraries – also when Qt is configured with -static option. You can affect this by changing all MD's on qmake.conf to MT's.

GCC 4.5 supports linker options -static-libgcc and -static-libstdc++. On Linux you can utilize these to eliminate the runtime library dependencies to libstdc++ and libgcc_s libraries:

 

              QMAKE_LFLAGS = -static-libgcc –static-libstdc++

Of course it would be much more convenient to have support for a configure option, which allows you to eliminate the runtime library dependencies without a manual qmake.conf file editing. This has been proposed to be implemented into Qt and you can find the Qt bug report with the id QTBUG-18497.

In general, static linking is controlled by the linker. Based on the qmake.conf file information Qt writes the rules into the Makefile to suggest the static linking. What if there are both dynamic and static libraries available for some library while linking? That case the linker will prefer to link against the dynamic library and if there is no static version available at all, the linker simply links against dynamic library without reporting any error or warning.

Writing Your Own StaticApplication and Library

When starting to write your own static application or library, you should check a few essential things on the project (.pro) file. For a static application, you can use 'app' TEMPLATE as usual and 'static' option for the CONFIG variable:

              TARGET = MyStaticApp
              TEMPLATE = app
              CONFIG += static

When writing a static library, you should use the 'lib' TEMPLATE and 'staticlib' option for the CONFIG variable:

              TARGET = MyStaticLib
              TEMPLATE = lib
              CONFIG += staticlib

This way the qmake knows that it needs to generate a Makefiles for the static linking. However, if you for some reason must have both static and shared library versions of your library, you need to create separate project files for them. Qmake does not support 'staticlib' and 'dll' CONFIG options at the same time. In case you do add both 'staticlib' and 'dll' to CONFIG, it uses the first option.

The generated library file name will depend on the used platform. On Windows the library name will be *.a if you are using mingw compiler and *.lib when MSVC compiler is used. On Linux the generated library will be *.a.

When you write a shared library you must take care of exporting and importing the symbols. With static libraries this is not needed at all. So, you can write the static library code and just use it from your application or other libraries. One issue is still good to know: how to initialize the resource file on a static library. If your static library contains a resource file you can initialize it by calling Q_INIT_RESOURCE():

              void MyStaticLibClass::doSomething()
              {
                  Q_INIT_RESOURCE(myresourcefile);

Of course, you will need the usual RESOURCES qmake variable on the project file.

Qt has lots of plugins located usually in their standard subdirectory under $QTDIR/plugins. Most of these plugins can be also be used with statically linked Qt (see the complete list of statically available plugins from the Qt on-line documentation!). Only two things are required: on your project file you will indicate with QTPLUGIN variable which static plugins your project will use and then on the actual code, you will import the plugin with Q_IMPORT_PLUGIN macro:


              MyStaticApp.pro or MyStaticLib.pro:
               QTPLUGIN     += qjpeg
                             qgif

              MyStaticLibClass.cpp:

              Q_IMPORT_PLUGIN(qjpeg)
              Q_IMPORT_PLUGIN(qgif)

              void MyStaticLibClass::doSomething()
              {
                  // do something nice with the plugins
              }

Have you written your own custom plugin? It can also be used from a static application and library. Now you have to do three things. First, update the plugin's project so that it has:

              CONFIG += plugin static

indicating it is a static plugin. Then, update your static application or library project file to have LIBS variable indicating where your custom plugin is located. Finally, use the Q_IMPORT_PLUGIN on your static application or library just like stated above. But note!  QTPLUGIN variable must not be used with custom plugins – it is meant for Qt standard plugins only.

Some of you may use other tools than qmake to generate the Makefiles. If so, you should remember to define the QT_STATICPLUGIN preprocessor macro.

Enjoy Qt – both shared and statically linked! :)


Comments