Static assembly of a dll library with QtQuick modules

Published on June 30, 2015

Static assembly of a dll library with QtQuick modules

Good day, readers. In this article, I will try to tell you as much as possible about how I built a static dll-library with QtQuick modules. Having scoured all the Internet, I still could not find a solution to my problem, but it turned out to be under my nose.

I'll start from the very beginning, namely: by weaning Qt from * .dll libraries. Operated: Qt-windows-x86-MinGW-5.5.0-rc, snapshot 95 from 2015.06.17 . Work Environment: Windows 8.1

I know that a decent handful of such articles have already been gathered, but what can I do ... I had to rebuild different versions of Qt four times before the dlls he collected began to load as they should. I’ll immediately warn you that QtWebKit will be cut in this assembly. If you already have a static Qt build, feel free to flip through this manual to the most interesting one .

So let's get started!
  1. Download the necessary software set:

    It is possible that Python and Ruby will not be needed at all, but because in all manuals they both appear as “mandatory” and we absolutely do not need surprises, we will install them.

  2. Install / unpack to any directory. I had it C: / Qt for Qt and its sources, and C: / dev for the rest of the software. When installing Qt, do not forget to check the Qt -> Tools -> MinGW checkbox .

    Installation configuration


    Source Components do not need to be installed, we downloaded them separately in the archive (probably already unpacked them?), And we will work with them.

    Tree
    • C: / dev / StrawberryPerl
    • C: / dev / Ruby22
    • C: / dev / Python34
    • C: /Qt/Qt5.5.0 - installed version of Qt
    • C: /Qt/qt-everywhere-opensource-src-5.5.0-rc - unpacked source


  3. Edit the qmake configuration:
    • open the qt-everywhere-opensource-src-5.5.0-rc / qtbase / mkspecs / win32-g ++ / qmake.conf file
    • we find the line
      QMAKE_LFLAGS =
      

      and replace it with:
      QMAKE_LFLAGS = -static -static-libgcc
      
      ( at 5.5.0-rc it was a 70 line )

  4. Mysterious bug with qmldebugger


    irrelevant in new versions, skip this step

    lib\libQt5Qml.a(qqmldebugserver.o):qqmldebugserver.cpp: undefined reference to `QTcpServerConnection::QTcpServerConnection()'
    

    We correct
    Из-за этого бага, собственно, мне и приходилось собирать две из четырёх версий Qt, пока не нашел в интернете описание самой проблемы. К сожалению, я так и не понял какое место должен был пропатчить этот патч (буду рад, если подскажете), поэтому поступил крайне радикально и некрасиво: вероломно вырезал проблемную строку из исходника. Я думаю практиковать такие деяния не стоит, но один раз можно =)
    P.s.: я не совсем уверен, что именно это в итоге спасло моё время и нервы, потому что одновременно с этим изменением, я добавил параметр -qml-debug к сборщику. Если вы хотите рискнуть и пожертвовать своим временем, то не меняйте исходник, а сконфигурируйте сборку с параметром -qml-debug, авось проблема станет неактуальной.

    Заходим в директорию qt-everywhere-opensource-src-5.5.0-rc\qtdeclarative\src\qml\debugger, открываем злосчастный файл qqmldebugserver.cpp и комментируем неугодную строку:
    #if defined(QT_STATIC) && ! defined(QT_NO_QML_DEBUGGER)
    // #include "../../plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h"  <---- комментируем это
    #endif
    



  5. Launch MinGW terminal
    Start -> All Programs -> Qt 5.5.0 -> 5.5 -> MinGW

    and feed him something like this:
    # НЕ ЗАБУДЬТЕ ПОМЕНЯТЬ ПУТИ НА СВОИ!
    set QTSRC=C:\Qt\qt-everywhere-opensource-src-5.5.0-rc
    set MINGWPATH=C:\Qt\Qt5.5.0\Tools\mingw492_32\bin
    set QTPREFIX=C:\Qt\5.5.0_Static
    set PYPATH=C:\dev\Python34
    set PERLPATH=C:\dev\Strawberry\perl\bin
    set RUBYPATH=C:\dev\Ruby22\bin
    

    where:
    QTSRC - the unpacked sources Qt
    MINGWPATH - the path to MinGW installed with Qt
    QTPREFIX - the place where the static assembly will be installed Qt
    PYPATH - path to the installed Python
    PERLPATH - path to the bin folder Perl
    RUBYPATH - path to the bin Ruby folder

    next:
    set QTDIR=%QTSRC%\qtbase
    set PATH=%PATH%;%MINGWPATH%;%PYPATH%;%PERLPATH%;%RUBYPATH%;%QTDIR%/bin
    cd %QTSRC%
    mkdir nomake
    move qtwebkit nomake
    move qtwebkit-examples nomake
    

    binaries search paths are set here, and the last three lines cut WebKit from the assembly (the -no-webkit flag disappeared from the configuration file somewhere). I want to note that to connect plugins without a tambourine it will not be enough to collect only qtbase, so we go to the folder with the source % QTSRC% and collect everything that is there.

  6. Launch the configurator:
    configure -static -release -opensource -confirm-license  -opengl desktop -no-angle -qml-debug  -c++11 -platform win32-g++ -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-freetype -no-openssl -make libs -make tools -nomake examples -nomake tests -prefix %QTPREFIX%
    

    shotakoe?
    • -static — без комментариев;
    • -release — указываем, что собирать будем только Release версию (если вам нужен и debug, то меняем на -debug);
    • -opensource -confirm-license — соглашаемся с лицензией;
    • -opengl desktop сборка для «настольников»;
    • -no-angle — «позволит избавится от libEGL, libGLES», спасибо Taraflex: Toster;
    • -qml-debug — разрешаем дебаг кумлы. Тот самый параметр, который возможно вылечивает бажиг с qmldebugger (пункт 4);
    • -c++11 — … — разрешаем использовать;
    • -platform win32-g++ — целевая платформа (да, только 32 бита);
    • -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-freetype — плюшки;
    • -no-openssl — отключаем ssl (мне он был не нужен);
    • -make libs — это нам пригодится для сборки dll-библиотеки;
    • -make tools — утилиты сомнительной необходимости, которые я все-же решил оставить. Вроде это assistant, designer и linguist. Если вам это не нужно, замените на -nomake tools;
    • -nomake examples -nomake tests — примеры и тесты. Собираются о-о-о-о-чень долго, так что лучше не включать;
    • -prefix %QTPREFIX% — указываем, куда будет установлена будущая сборка. (%QTPREFIX% был задан в самом начале пятого пункта);

    • если вам нужны еще какие-то модули, например, sqlite, то читайте README или воспользуйтесь командой configure -help, чтобы узнать какой параметр нужно добавить к конфигуратору.


  7. We start assembly:
    mingw32-make -k
    

    ps if you have a multi-core processor, you should tell the collector their number with the parameter -j [ number of cores - 1 ] . Those. for my 4-core processor, I ran the builder like this:
    mingw32-make -k -j3
    

    the parameter - k kind of tells the collector to stop if "something went wrong." This unpleasant situation did not affect me, so I will not argue.

  8. We start the installation:
    mingw32-make install
    

    after that we should have the % QTPREFIX% directory with the collected libraries.

  9. Add a kit for building statics:
    1. run QtCreator , which was installed with Qt5.5.0-rc
    2. go to the Tools> Options ...> Build and Run> Qt Versions tab , add a new qmake from the % QTPREFIX% \ 5.5.0 \ bin directory , call it something like this: " Qt% {Qt: Version} (% {Qt: Version} _Static) "and click the" Apply " button
      Qt versions


    3. go to the " Kits " tab , click " Add ", call it something like this: " Qt5.5.0-Static ", compiler: MinGW , profile: " Qt% {Qt: Version} (% {Qt: Version} _Static) " click the " OK " button
      Kits
      image



That, in fact, is all. And now, finally, the most interesting .


Static assembly of a dll library with QtQuick modules


Create a new project in QtCreator'e:
  • File> Create Project ...> Library> C ++ Library> Dynamic Library
  • select the build kit we created ( Qt5.5.0-Static )
  • open the file % project-name% _global.h


All the salt of the fact that the dll libraries were not statically collected ( more precisely, they were collected, but were inoperative ) was that the template ( TEMPLATE ) used to build the DLL ( lib ) does not include the linking of plugins. Therefore, all of them must be written manually in the header and .pro-file .
Getting a list of all the necessary plugins was easy:
  • create a new project " Qt Quick Application "
  • we compile it with the same Qt5.5.0-Static kit ( do not forget to specify the assembly type Release )
  • go to the directory with the assembled project: build- % project_name% -Qt5.5.0_Static-Release and see two files:
    1. % project_name% _plugin_import.cpp
    2. % project_name% _qml_plugin_import.cpp

    they contain a list of all plugins loaded for a regular Qml application, namely:
    #include <QtPlugin>
    Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
    Q_IMPORT_PLUGIN(QDDSPlugin)
    Q_IMPORT_PLUGIN(QICNSPlugin)
    Q_IMPORT_PLUGIN(QICOPlugin)
    Q_IMPORT_PLUGIN(QJp2Plugin)
    Q_IMPORT_PLUGIN(QMngPlugin)
    Q_IMPORT_PLUGIN(QTgaPlugin)
    Q_IMPORT_PLUGIN(QTiffPlugin)
    Q_IMPORT_PLUGIN(QWbmpPlugin)
    Q_IMPORT_PLUGIN(QWebpPlugin)
    Q_IMPORT_PLUGIN(QtQuick2Plugin)
    Q_IMPORT_PLUGIN(QTcpServerConnection)
    Q_IMPORT_PLUGIN(QGenericEnginePlugin)
    Q_IMPORT_PLUGIN(QNativeWifiEnginePlugin)
    Q_IMPORT_PLUGIN(QtQuick2WindowPlugin)
    

    all this trouble you need to add the library header file ( % project-name% _global.h

in the same directory, open the Makefile.Release file and get the necessary information from there, namely: a list of libraries that should be connected to the project:
LIBS        =        -lmingw32 -LC:/Qt/5.5.0_Static/lib -lqtmain -LC:/Qt/5.5.0_Static/qml/QtQuick.2 -lqtquick2plugin -LC:/Qt/5.5.0_Static/qml/QtQuick/Window.2 -lwindowplugin -LC:/Qt/5.5.0_Static/plugins/platforms -lqwindows -lwinspool -lshlwapi -lQt5PlatformSupport -lqtfreetype -LC:/Qt/5.5.0_Static/plugins/imageformats -lqdds -lqicns -lqico -lqjp2 -lqmng -lqtga -lqtiff -lqwbmp -lqwebp -LC:/Qt/5.5.0_Static/plugins/qmltooling -lqmldbg_qtquick2 -lQt5Quick -lQt5Gui -lcomdlg32 -loleaut32 -limm32 -lwinmm -lglu32 -lopengl32 -lgdi32 -lqtharfbuzzng -lqmldbg_tcp -lQt5Qml -LC:/Qt/5.5.0_Static/plugins/bearer -lqgenericbearer -lqnativewifibearer -lQt5Network -ldnsapi -lQt5Core -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lmpr -lqtpcre 

all this will need to be added to the .pro-file of your future project (the list may differ, depending on your version and what modules you turned on / off during the build of Qt, so it’s better to copy this list from your PC ). It does not hurt to add the path to the header files of the Qt static assembly:
INCLUDEPATH += C:/Qt/Qt5.5.0_Static/include



After you make these changes to the project, you can assemble the QtQuick “mini-framework” as a single DLL. What you will do with it, I do not know, but I hope someone will find this information useful :)

.pro file of my project 'MyDll'
QT += core widgets qml quick
CONFIG += dll
TEMPLATE = lib
TARGET = mydll
DEFINES += MYDLL_LIBRARY
SOURCES += mydll.cpp
HEADERS += mydll.h \
    objectfactory.h
INCLUDEPATH += C:/Qt/Qt5.5.0_Static/include
LIBS += -lmingw32\
-LC:/Qt/5.5.0_Static/lib -lqtmain\
-LC:/Qt/5.5.0_Static/qml/QtQuick.2 -lqtquick2plugin\
-LC:/Qt/5.5.0_Static/qml/QtQuick/Window.2 -lwindowplugin\
-LC:/Qt/5.5.0_Static/plugins/platforms -lqwindows -lwinspool -lshlwapi -lQt5PlatformSupport -lqtfreetype\
-LC:/Qt/5.5.0_Static/plugins/imageformats -lqdds -lqicns -lqico -lqjp2 -lqmng -lqtga -lqtiff -lqwbmp -lqwebp\
-LC:/Qt/5.5.0_Static/plugins/qmltooling -lqmldbg_qtquick2 -lQt5Quick -lQt5Gui -lcomdlg32 -loleaut32 -limm32 -lwinmm -lglu32 -lopengl32 -lgdi32 -lqtharfbuzzng -lqmldbg_tcp -lQt5Qml\
-LC:/Qt/5.5.0_Static/plugins/bearer -lqgenericbearer -lqnativewifibearer -lQt5Network -ldnsapi -lQt5Core -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 -lmpr -lqtpcre



mydll.h
#ifndef MYDLL_H
#define MYDLL_H
#include <QtPlugin>
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
Q_IMPORT_PLUGIN(QDDSPlugin)
Q_IMPORT_PLUGIN(QICNSPlugin)
Q_IMPORT_PLUGIN(QICOPlugin)
Q_IMPORT_PLUGIN(QJp2Plugin)
Q_IMPORT_PLUGIN(QMngPlugin)
Q_IMPORT_PLUGIN(QTgaPlugin)
Q_IMPORT_PLUGIN(QTiffPlugin)
Q_IMPORT_PLUGIN(QWbmpPlugin)
Q_IMPORT_PLUGIN(QWebpPlugin)
Q_IMPORT_PLUGIN(QtQuick2Plugin)
Q_IMPORT_PLUGIN(QTcpServerConnection)
Q_IMPORT_PLUGIN(QGenericEnginePlugin)
Q_IMPORT_PLUGIN(QNativeWifiEnginePlugin)
Q_IMPORT_PLUGIN(QtQuick2WindowPlugin)
#include <QGuiApplication>
#include <QQuickView>
class MyDll
{
...
};
#endif