Qt Configuration System

From Qt Wiki
Jump to: navigation, search

Qt 5.10 introduced a new configuration system:

The goal of the new system is twofold. First of all, we are seeing a large need, especially with our embedded users, to customise how Qt is being built. Many of them have size restrictions or rather hard testing requirements, where being able to limit the functionality available in Qt is extremely helpful. We had such a system (see src/corelib/global/qfeatures.txt) before, but it was disconnected from the configure script, wasn’t really maintained since Qt 4 times, and had quite many limitations that I hope to solve with the new system.

Secondly, we have had to deal for a long time with two different configuration systems. We had a monster of a shell script for unix, and an Qt based executable on Windows. Changes to Qt often required changing both, and it was very easy to sneak subtle errors in. Maintainability of the old system was in general very poor.

- Lars Knoll (on the Qt development mailing list)

Overview

The new system basically moves most of the configuration handling from the shell script over to a declarative json file (currently configure.json) that is being processed by qmake. The change aims to be a 1 to 1 (or at least as close as possible) mapping of the old shell script to the new system.

Detailed Description

Here’s a look at the details of the new system, in case you need to implement your own configure tests or want to add configurability to Qt.

We now have one global configuration file qtbase/configure.json, that contains much what the old configure.sh and configure.exe did. There is also a configure.pri file that contains some qmake methods to handle special cases (specialised tests our output handling). Individual modules also have separate configure.json and/or configure.pri files.

You can find the infrastructure for the whole system in qtbase/mkspecs/features/qt_configure.prf. The system basically works through two main systems.

  1. The first one is a callback infrastructure, where all “type” fields provided in the json file actually refer to callback functions in qmake that do the actual handling. This allows you to e.g. implement your own custom test function in a .pri file and refer to that from the json. qt_configure has callbacks for the most common tasks, so you won’t need this feature in most cases. If you want to know how such custom callbacks can look like, have a look at configure.pri.
  2. The other central piece is an expression evaluator, that is being used to evaluate conditions. It allows you to test for rather complex conditions (like e.g. “config.win32 && tests.mysql && features.opengl”) and is being used in many places. The evaluator understands boolean operators (!, && and ||), comparison operators (== and !=), braces and different types of arguments:
true/false 
boolean values
‘foo’ 
The string literal foo
config.foo 
Variables in the qmake CONFIG var (usually used for platform dependent stuff like config.unix)
tests.foo 
Boolean whether the test foo succeeded
tests.foo.bar 
Variable bar, set by tests.foo
features.foo 
boolean whether feature foo is available
features.foo.bar 
variable bar set by features.foo
arch.foo 
architecture (like x86, arm, etc)
input.foo 
input variable (set by command line handling)
far.foo 
Any variable set in qmake
call.foo 
return value of the replace function foo in qmake

This gives you quite some options to define conditions and dependencies between features. The system automatically runs the configure test, if you ask for tests.foo, so dependency handling is fully transparent.

configure.json

Now let’s have a look at configure.json:

The file contains a couple of sections. The first one is called “files”, and contains definitions for the output files. You should not need to touch this one.

The next section contains the command line parameters that you can pass to the configuration system. It basically defines the valid command line arguments that configure will recognise. They are being mapped to a config.input.option value in qmake, that is then being used in the next step of defining the features we will use for Qt.

Typical entries looks like

"harfbuzz": { "type": "enum", "values": [ "no", "qt", "system" ] },
"headersclean": "boolean",


This means harfbuzz is an option that can take a selection of args (-no/-qt/-system), whereas headersclean is a boolean argument (-headersclean and -no-headersclean accepted). The second form is a shorthand for

"headersclean”: { “type”: “boolean” }


Note that the type variable refers to a callback. In this case a test function qtConfCommandline_boolean.


Then comes a section with tests. Those define all the configure tests that so far have been executed by the shell script. The definition of a typical test looks like:

 "fontconfig": {
        "description": "Fontconfig”,
        "type": "compile”,
        "test": "unix/fontconfig”,
        "pkg-config-args": "fontconfig freetype2”,
        "libs": "-lfontconfig -lfreetype"
} 

This basically defines a configure test for fontconfig. It’s a compile test, the test being in config.tests/unix/fontconfig. It’ll try to use pig-config to determine the correct LIBS and CFLAGS to compile and link against the library, and there is a fallback for the libs in case fontconfig can’t be found.

Again, the type variable refers to a callback (qtConfTest_compile in this case).

After that we have the central section that defines all the features. Let’s take one example:

"icu": {
       "description": "ICU”,
       "autoDetect": "!config.win32”,
       "condition": "tests.icu”,
       "output": [ "publicQtConfig” ]
},


This defines the icu feature. It’s not auto-detected on windows, requires the ice configure test to pass, and will then generate one output called publicQtConfig. Here are some details of the fields:

description
A short description of the feature. Used by the summary section below
autoDetect
Should evaluate to a boolean value whether to automatically detect the feature. Defaults to true
emitIf
Skip the feature completely if this evaluated to false (don’t evaluate conditions or outputs). Defaults to true.
enable
Evaluates to a condition that will enable the feature (defaults to “input.feature == yes”)
disable
the opposite, (defaults to “input.feature == no”)
condition
A condition that determines whether the feature is enabled/disabled. Will generate an error if it conflicts with the enable field above
output
Different types of output to generate. Also here you can define arbitrary callbacks, but the standard types should cover most needs:
“publicQtConfig" 
Add the feature name to the QT_CONFIG variable in the public pri file (here qconfig.pri)
“publicConfig" 
Add the feature name to the CONFIG variable in the public pri file (here qconfig.pri)
"privateConfig" 
Same for the private pri (qmodule.pri)
“feature” 
Defines a feature. Adds it to QT_CONFIG if available, sets QT_NO_FEATURE otherwise


{ “type”: “define”, “name”: “FOO”, “value”: “expression” }
       #define FOO expression in the public header file, expression is evaluated
{ “type”: “libs”, “test”: “configtest” }
       Output QMAKE_LIBS/CFLAGS_FEATURE defining parameters required to use an external library

In addition, there are varAssign, varAppend and varRemove to assign, append and remove values from qmake variables

All outputs can have a ‘negative’: true/false field (default false), that would reverse when output is being generated (usually only if the feature is available, and a ‘condition’ field.

Finally there are two sections called ‘earlyReport’ and ‘report’. Use ‘report’ unless you know what you’re doing. These sections allow you to define conditions under which notes, warnings or errors are being reported back to the user.

Finally, there’s a summary section, that defines the configure summary we’re reporting back to the user. Lars leaves figuring out the details here as an exercise to the reader ;-)

Reference

Sections in configure.json files

Section Explanation
module Name of module.
testDir Relative path to config.tests dir. Default is "./config.tests".
condition Condition for whole module.
files Contains definitions for the output files.
subconfigs Paths to additional configure.json files in subdirectories to include.
commandline Command line parameters that the user can pass to the configuration system.
libraries Checks for system libraries.
testTypeDependencies  ?
testTypeAliases  ?
tests Configure tests.
features Definition of features.
earlyReport Define conditions under which notes, warnings or errors are being reported back to the user. Use report unless you know what you're doing.
report Define conditions under which notes, warnings or errors are being reported back to the user.
summary Configure summary shown to the user.