win32, unix,win32-g++,win32-msvc,CONFIG, etc. in Qt .pro file

win32, unix,win32-g++,win32-msvc,CONFIG, etc. in Qt .pro file are called conditions. Multiple conditions can be combined with colons. Conditions are followed by one or more expressions. Multiple expressions should be enclosed with a pair of curly braces. The expression(s) will be evaluated if all conditions are evaluated to true. For example,

win32:message("on windows")
unix:message("on Linux")

The above .pro file will print “on windows” if running qmake on Windows platform, and print “on Linux” if qmake is run on Linux. But you know, there are multiple building tool chains on Windows such as MSVC, MingW. They can even co-exist on the same machine. If you want to do different things when building your project with different building tools, you can use win32-g++(for mingw) and win32-msvc(for Miscrosoft Visual Studio):

win32-g++:{
  libs+=lib1
}

win32-msvc*:{
  libs+=lib2
}

Here, when you build your project with Mingw, it will link against lib1, and when you build the project using MSVC(regardless of the MSVC version), it will link against a different lib.

Newbies may write the following .pro file:

debug:{
  libs+=debuglib
}

release:{
  libs+=releaselib
}

They hope when they build the project in Qt Creator in debug mode, it will link the debug version of the library, and if they build a release version of the project, it will link to the release version of the lib. Unfortunately, this will not work in most cases in Qt Creator. You will find that in both the debug and the release mode, it will link against both the debug version and the release version of the lib, which is not what you want.

The above code is equivalent to the code below:

CONFIG(debug):libs+=debuglib
CONFIG(release):lib+=releaselib

The condition debug or CONFIG(debug) is to test if “debug” occurs in the CONFIG string. In debug mode, Qt Creator may invoke qmake as follows:

qmake yourproject.pro -spec win32-g++ "CONFIG+=debug" "CONFIG+=qml_debug"

Before qmake processes your .pro file, it has already loaded many configure files which may already fill CONFIG with “debug” or/and “release”. The command parameters are processed at a later time so “CONFIG+=debug” will add another “debug” to CONFIG near the end. So before testing CONFIG(debug), the CONFIG string may look like:

lex yacc debug exceptions depend_includepath testcase_targets import_plugins import_qpa_plugin windows file_copies qmake_use qt warn_on release link_prl debug_and_release debug_and_release_target precompile_header shared release mingw gcc copy_dir_files debug qml_debug console

Note the third to last “debug” is added by the command line parameter of qmake, but before that both “debug” and “release” already occur. This will lead to the evaluation of both CONFIG(debug) and CONFIG(release) being true. The final result is both the debug version and the release version of the lib are linked into your program. The correct usage is:

CONFIG(debug,debug|release):libs+=debuglib
CONFIG(release,debug|release):libs+=releaselib

Now we use the two-parameter version of the CONFIG builtin. The CONFIG builtin function may as well be a switch case rather than a function. Its code is in evaluateBuiltinConditional in qmakebuiltins.cpp.

case T_CONFIG: {
        if (args.count() < 1 || args.count() > 2) {
            evalError(fL1S("CONFIG(config) requires one or two arguments."));
            return ReturnFalse;
        }
        if (args.count() == 1)
            return returnBool(isActiveConfig(args.at(0).toQString(m_tmp2)));
        const QStringList &mutuals = args.at(1).toQString(m_tmp2).split(QLatin1Char('|'));
        const ProStringList &configs = values(statics.strCONFIG);

        for (int i = configs.size() - 1; i >= 0; i--) {
            for (int mut = 0; mut < mutuals.count(); mut++) {
                if (configs[i] == mutuals[mut].trimmed())
                    return returnBool(configs[i] == args[0]);
            }
        }
        return ReturnFalse;

We can see the two-parameter version of CONFIG check the words in CONFIG backwards against the words in the second parameter of CONFIG. If one word of CONFIG matches one word of the second parameter, it further compares it to the first parameter of CONFIG and returns the comparison result. So if you have a typo like:

CONFIG(release,debug|relaese):libs+=releaselib

,you will never link the release lib even you are working in release mode because qmake cannot find a match against the second parameter.

The single-parameter version of CONFIG is even more fragile. It does not split CONFIG into words but tries to find the sub-string (the parameter) directly in CONFIG. So CONFIG(release) is evaluated to true if CONFIG=…debug_and_release…

We find everybody is using CONFIG(release,debug|release), but none explains it clearly, for example, in this post.

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