How does qmake generate include path?

If you have read my post “Where does Qt find header files“, you have known that qmake will generate some include paths in the makefile to compile your project. For example, if you build the qt gui module in the qt src with the command:

cd c:\mybuild\qtbase\src\gui
..\..\bin\qmake c:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\gui\

You will find the following include paths in the generated Makefile.Debug:

INCPATH       = -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\gui -I. -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\include -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\include\QtGui -I..\..\include -I..\..\include\QtGui -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\include\QtGui\5.12.1 -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\include\QtGui\5.12.1\QtGui -I..\..\include\QtGui\5.12.1 -I..\..\include\QtGui\5.12.1\QtGui -Itmp -I.tracegen\debug -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\include\QtCore\5.12.1 -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\include\QtCore\5.12.1\QtCore -I..\..\include\QtCore\5.12.1 -I..\..\include\QtCore\5.12.1\QtCore -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\include\QtCore -I..\..\include\QtCore -I.moc\debug -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\3rdparty\libpng -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\3rdparty\harfbuzz-ng\include -IC:\Qt\Qt5.12.1\5.12.1\Src\qtbase\mkspecs\win32-g++

I did not write any INCLUDEPATH  in the, how does qmake add so many include paths in the makefile? Those programmers are good at creating technical barriers by hiding things. I will reveal what is under the hood for you.

All start from the qmake variable _QMAKE_CONF_. This is not a qmake variable set in some .pro/.prf/.pri file, but created in the C++ code of qmake:

bool QMakeEvaluator::loadSpec()
valuesRef(ProKey("_QMAKE_CONF_")) << ProString(m_conffile);

qmake finds the configure file(.qmake.conf=>m_conffile) in the directory the .pro file resides(c:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\gui), its parent directory, its grand-parent directory, …, till the root directory(C:\), in order. In this case, it finds the .qmake.conf as C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\.qmake.conf.

During parsing c:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\gui\, qmake meets the following line:


qt_module.prf will load qt_build_paths.prf which has the following line:


Now, the qmake variable MODULE_BASE_INDIR is set to c:\Qt\Qt5.12.1\5.12.1\Src\qtbase. Then qt_module.prf loads qt_module_headers.prf which creates the variable MODULE_INCLUDES whose content is: MODULE_INCLUDES:$$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/QtGui

qt_module.prf continues to load qt_module_pris.prf which creates qt_lib_gui.pri and qt_lib_gui_private.pri in C:\mybuild\qtbase\mkspecs\modules-inst, and qt_lib_gui.pri(so called forwarding module .pri file) in C:\mybuild\qtbase\mkspecs\modules. Notice a line when creating the content of the forwarding module .pri file qt_lib_gui.pri:


So the qt_lib_gui.pri will have the following line in it:

QT_MODULE_INCLUDE_BASE =C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/include

The forwarding  qt_lib_gui.pri has two lines to include  qt_lib_gui.pri and qt_lib_gui_private.pri in C:\mybuild\qtbase\mkspecs\modules-inst, respectively. One of the lines in C:\mybuild\qtbase\mkspecs\modules-inst\qt_lib_gui.pri is:


During the build pass, the files in C:\mybuild\qtbase\mkspecs\modules and C:\mybuild\qtbase\mkspecs\modules-inst will be read so QT.gui.includes will get the correct value:

C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/include C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/include/QtGui C:/mybuild/qtbase/include C:/mybuild/qtbase/include/QtGui

The load order of .prf files during the build pass is: C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\mkspecs\win32-g++\qmake.conf –> C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\mkspecs\features\qt_config.prf which loads all .pri in C:\mybuild\qtbase\mkspecs\modules. You can get to know this in my post “what .prf files are automatically loaded by qmake?

Back to qt_module.prf, it will append what is in QT.gui.includes and QT.gui_private .includes, and a temporary directory tmp to INCLUDEPATH. The value of INCLUDEPATH is now:

C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/include C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/include/QtGui C:/mybuild/qtbase/include C:/mybuild/qtbase/include/QtGui C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/include/QtGui/5.12.1 C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/include/QtGui/5.12.1/QtGui C:/mybuild/qtbase/include/QtGui/5.12.1 C:/mybuild/qtbase/include/QtGui/5.12.1/QtGui tmp

It is now similar to that in the Makefile. As qmake loads CONFIG features, more include paths are appended to  INCLUDEPATH . For example, when loading CONFIG feature moc.prf, .moc\debug is added to INCLUDEPATH.

Let’s check how C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\3rdparty\libpng is slipped into the include paths. You should run qmake against C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\3rdparty\libpng\ before running qmake against c:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\gui\ There is a line in


qt_helper_lib will create qt_ext_libpng.pri in C:\mybuild\qtbase\mkspecs\modules\. We can see how it prepares the content of qt_ext_libpng.pri:


As MODULE_INCLUDEPATH is set to the current directory(C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\3rdparty\libpng\) in, the generated qt_ext_libpng.pri contains the following line:

QMAKE_INCDIR_LIBPNG = C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/src/3rdparty/libpng

qt_ext_libpng.pri will be loaded when running qmake against c:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\gui\ as already talked about. loads the image.pri as follows:


image.pri will add libpng to QMAKE_USE_PRIVATE.

During loading the CONFIG(qmake_use) feature file(qmake_use.prf) for, it will append the content of QMAKE_INCDIR_LIBPNG to INCLUDEPATH:


So, you will see C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\3rdparty\libpng in INCLUDEPATH. The occurrence of C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\3rdparty\harfbuzz-ng\include in INCLUDEPATH is similar.

Now let me show you how C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\include\QtCore\xxxx get into INCLUDEPATH. Near the beginning of, there is a line:

QT = core-private

Qt contains the modules the gui module depends on. Although Qt contains only core-private, core-private depends on core, so gui depends on both core-private and core. You can get to know this by looking at C:\mybuild\qtbase\mkspecs\modules-inst\qt_lib_core_private.pri which was generated when qmaking the core module.

QT.core_private.depends = core

qt_lib_core_private.pri also contains:

QT.core_private.includes = $$QT_MODULE_INCLUDE_BASE/QtCore/5.12.1 $$QT_MODULE_INCLUDE_BASE/QtCore/5.12.1/QtCore

qt_lib_core.pri contains:


During the stage of loading CONFIG(qt) feature qt.prf for, QT.core.includes/QT.core_private.includes will be read into MODULE_INCLUDES which is appended to INCLUDEPATH.

This reminds us that if you include a module’s headers in your app/lib’s source code, you must include the module name into QT, otherwise, you will get “No such file or directory” during the compiling which means it cannot find the headers of the module. After adding the module name to QT, you also need to qmake the module to generate qt_lib_xxx.pri, otherwise when qmaking your app/lib, qt.prf will complain “Unknown module(s) in QT:xxx”. Let’s take a qt bug for example. If you have not built C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\platformsupport\windowsuiautomation before building C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\plugins\platforms\windows, the qmake could succeed but the compiling will fail with the error:

C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\plugins\platforms\windows\uiautomation\qwindowsuiabaseprovider.h:50:10: fatal error: QtWindowsUIAutomationSupport/private/qwindowsuiawrapper_p.h: No such file or directory
 #include <QtWindowsUIAutomationSupport/private/qwindowsuiawrapper_p.h>

This is because the module windowsuiautomation_support-private which possesses  QtWindowsUIAutomationSupport/private/qwindowsuiawrapper_p.h  is not added into QT. You may find the following code in C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\plugins\platforms\windows\uiautomation\uiautomation.pri:

qtHaveModule(windowsuiautomation_support-private): \
    QT += windowsuiautomation_support-private

But since we’ve not qmaked c:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\platformsupport\windowsuiautomation\, we have not gotten qt_lib_windowsuiautomation_support_private.pri, so qtHaveModule will return false. Since QT does not contain windowsuiautomation_support-private, qt.prf will not find the error that windowsuiautomation_support-private was not qmaked and the qmake for C:\Qt\Qt5.12.1\5.12.1\Src\qtbase\src\plugins\platforms\windows\ will succeed, but the compiling will fail. The correct code would be:

!qtHaveModule(windowsuiautomation_support-private): error("windowsuiautomation_support-private was not qmaked!")

The above code would make qmake fail in the first place and force you to build windowsuiautomation beforehand.

So far we’ve found two methods to include a module/lib – by adding the lib name to  QMAKE_USE_PRIVATE/QMAKE_USE, or by adding the module name to QT/QT_PRIVATE.

Things are not over yet. To get it harder to find all include paths, they slip extra include paths in C++ code of qmake:


Now the include paths include the directory you run qmake(.) and the spec directory C:/Qt/Qt5.12.1/5.12.1/Src/qtbase/mkspecs/win32-g++



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