qmake module dependency – $$sort_depends and $$resolve_depends

There exists dependency relationship between qt modules. Some modules can only be built after some other modules are built. This is not only because some modules use the libs/header files of other modules, but also because the generation of makefile(by qmake) for module in question needs the .pri files(in mkspecs/modules/ and mkspecs/modules-inst/) produced by qmake when building other modules.

The $$sort_depends and $$resolve_depends are used to sort the original module list based on their dependency relationship.

modules = $$sort_depends(modules, module., .depends .recommends .serialize)

The first parameter is the list of modules to be processed. The second parameter is a prefix. The third parameter is a list of suffixes.  For each module in modules, sort_depends/resolve_depends will look its dependency modules in module.thismodule.depends, module.thismodule.recommends, and module.thismodule.serialize.

The two builtin qmake functions(E_SORT_DEPENDS, E_RESOLVE_DEPENDS) call

void QMakeEvaluator::populateDeps(
        const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes,
        const ProString &priosfx,
        QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
        QMultiMap<int, ProString> &rootSet) const

. The results are saved in dependencies, dependees, and rootSet. Specifically, for every module in deps, dependencies[module] is the list of its dependency modules. dependees[module] is the list of modules that are dependent on this module. Those modules that depend on no module are saved in rootSet.

After constructing the dependency relationship for all modules, $$sort_depends and $$resolve_depends will output the sorted module list, i.e., the rootSet modules are put at the end of the list. The modules depending on the rootSet modules are put before the rootSet modules. In the final module list,  modules are always dependent on following modules.

The difference between sort_depends and resolve_depends is that resolve_depends may find new modules that the modules in the first parameter depends on but are not in the first parameter, while  sort_depends never adds such modules to the result list.

The modules under the qt source directory have the following dependency:

qtqa qtdoc qttranslations qtwebview qtwebbrowser qtwebengine qtscript GammaRay neptune3-ui qttools qtfeedback qtwinextras qtcharts qtdatavis3d qtvirtualkeyboard qtspeech qtivi qtmultimedia qtxmlpatterns qtlocation qtquickcontrols qtquickcontrols2 qtgraphicaleffects qtsensors qtsystems qtdocgallery qtpim qtconnectivity qtapplicationmanager qtwayland qt3d qtgamepad qtwebchannel qtwebglplugin qtwebsockets qtcanvas3d qtpurchasing qtscxml qtremoteobjects qtknx emulator qtopcua qmllive qtdeclarative qtsvg qtactiveqt qtimageformats qtserialbus qtserialport qtandroidextras qtx11extras qtmacextras qtnetworkauth qtmqtt qtsimulator qtauto-deployment-server qtbase qtrepotools

The dependency relationship is explicitly specified in C:\Qt\Qt5.12.1\5.12.1\Src\.gitmodules using depends/recommends property. The sorted list is reversed to form the SUBDIRS variable, which is used to generate the Makefile for SUBDIRS  template. The generated Makefile will guarantee the modules in SUBDIRS are built in order.

The module dependency is also manually specified for modules in C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\(in C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\src.pro). For example:

src_gui.depends += src_3rdparty_harfbuzzng
src_gui.depends += src_angle
src_gui.depends += src_3rdparty_libpng
src_gui.depends += src_tools_qvkgen

And the occurrences and the order of modules in SUBDIRS are also manually specified in  C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\src.pro.

The SUBDIRS for qtbase source is:

src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_qfloat16_tables src_3rdparty_pcre2 src_corelib src_tools_qlalr src_winmain src_network src_sql src_xml src_testlib src_dbus src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml src_concurrent src_3rdparty_harfbuzzng src_3rdparty_libpng src_3rdparty_freetype src_tools_qvkgen src_gui src_platformsupport src_platformheaders src_openglextensions src_tools_uic src_widgets src_printsupport src_opengl src_plugins

which indicates if you want to build plugins, you should build 3rdparty_freetype first.

From the above examples, we know that for SUBDIRS projects, the module dependency is specified using the .depends property manually. In lib/app projects, the dependency is specified using the QT variable. For example, in C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\gui\gui.pro, you will find “QT = core-private”, qmake will get to know gui depends on core(i.e., MODULE_DEPENDS, get rid of the suffix “-private”), and write this information as “QT.gui.depends = core” in C:\build\qtbase\mkspecs\modules-inst\qt_lib_gui.pri. Other app/modules that depend on gui will load qt_lib_gui.pri in the qmaking stage. If they cannot find qt_lib_gui.pri, qmake will fail with the error “Unknown module(s) in QT” in the first place, and you cannot even go to the compiling stage.

We’ve talked about the dependency among modules. Inside a module, there is another kind of dependency – lib dependency. For example, when you qmake c:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\platformsupport\fontdatabases\fontdatabases.pro, you may see this error:

Project ERROR: Library ‘freetype’ is not defined.

This is because fontdatabase_support module needs the freetype lib. How do I know it? In C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\platformsupport\fontdatabases\freetype\freetype.pri, there is  a line:

QMAKE_USE_PRIVATE += freetype

QMAKE_USE/QMAKE_USE_PRIVATE are used to specify the what libs the current module uses. When loading the qmake_use feature(qmake_use.prf), if qmake cannot find the QMAKE_LIBS_FREETYPE definition(an empty value is enough), qmake will complain the above error. How to generate the  QMAKE_LIBS_FREETYPE definition? This variable is generated by qmake when you build the freetype lib(C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\3rdparty\freetype\freetype.pro) ,and saved in C:\build\qtbase\mkspecs\modules\qt_ext_freetype.pri. To generate such a .pri file, you should add the following line in your lib’s .pro file such as freetype.pro does:

load(qt_helper_lib)

Apart from QMAKE_LIBS_FREETYPE, other variables such as QMAKE_INCDIR_FREETYPE, QMAKE_DEFINES_FREETYPE, QMAKE_LIBS_FREETYPE_DEBUG, QMAKE_LIBS_FREETYPE_RELEASE are also generated in that file.

With qt_ext_freetype.pri in place, you can qmake c:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\platformsupport\fontdatabases\fontdatabases.pro without problem.

If you like my content, please consider buying me a coffee. Buy me a coffeeBuy me a coffee Thank you for your support!
Posted in

Leave a Reply