[Development] New configuration system (details)

Lars Knoll Lars.Knoll at qt.io
Thu Jun 23 10:13:26 CEST 2016


here’s the promised 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 the details about how Qt can be configured. Actually I’m slightly lying with that, as there also is a configure.pri file that contains some qmake methods to handle special cases (specialised tests our output handling). 

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

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.

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:

frue/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.

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

Output deserves a separate section. 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
An 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. I’ll leave figuring out the details here as an exercise to the reader ;-)


More information about the Development mailing list