Qt5 Build System

From Qt Wiki
Revision as of 12:03, 10 December 2020 by Jobor (talk | contribs) (Copy qt-modules.md over)
Jump to navigation Jump to search


Qt5’s configure system

This is a description of the Qt5 qmake-based build system.

For Qt6, see Qt6 Build System.

For a description of terms used here, please see the Qt Build System Glossary.

configure.json

There are several instances of this file

top-level - SOURCE_ROOT/configure.json

For the whole of Qt. Only defines the “skip” command line option at the moment.

repo level - SOURCE_ROOT/qtbase/configure.json

Valid for all module within this repository.

module level - SOURCE_ROOT/qtbase/src/network/configure.json

Valid for this particular module.

repo level keys

  • files
  • subconfigs
  • commandline
  • libraries
  • testTypeDependencies
  • testTypeAliases
  • tests
  • features
  • earlyReport
  • report
  • summary

module level keys

  • module: The current module’s name. E.g. “network”
  • depends: list of module this module depends on
  • testDir: path to the config.tests directory, relative to this file
  • commandline: specification of command line arguments for configure
  • libraries: definitions of libraries that can be used with QMAKE_USE
  • tests: definition of configure tests
  • features: Qt features that can be enabled/disabled
  • condition: The module will be skipped if the condition is not met
  • report: Notes and warnings that are displayed if certain conditions are met.
  • summary: Defines what is displayed in configure’s summary output for this module.

commandline

This object defines the commandline options for the configure script.

custom

Here, we can register a custom commandline handler for configure arguments that do not fit into the rest of the declarative concept of configure.json. As of Qt 5.15, there can be exactly one custom commandline handler per

configure.json

. The custom handler is run before the actual command line processing. Example:

 commandline: { custom: qmakeArgs,  }

will trigger the callback

defineTest(qtConfCommandline_qmakeArgs) {
    contains(1, QMAKE_[A-Z0-9_]+ *[-+]?=.*) {
        config.input.qmakeArgs += $$1
        export(config.input.qmakeArgs)
        return(true)
    }
    return(false)
}

which filters out command line arguments that assign to QMAKE_* variables and puts them into an internal variable.

options

The keys in the

options

objects are the arguments that can be passed to configure. With

bindir: string,

we can do

configure -bindir bin

. The values of the

options

object are strings or objects. If they are strings, the string specifies the

type

of the argument:

bindir: string,

is equivalent to

bindir: {type: string},

The value of this configure argument lands in

config.input.bindir

.

name

For command-line options that do not form a valid variable name, one can define the internal variable name like this:

"static-runtime": { "name": "static_runtime" },

The result ends up in

config.input.static_runtime

in this example.

type

An option of type

foo

triggers a callback

qtConfCommandline_foo

in

qt_configure.prf

or

configure.pri

. There are the following pre-defined types:

Type Valid Values
boolean yes, no
enum one of multiple defined values
see below
string non-empty string
optionalString “yes”, if empty string
the string, otherwise
addString non-empty string
The argument can be passed multiple times.
The values is then a list of strings.
void does not accept a value

The type can be some arbitray string as illustrated by the type

redo

which is triggered by the

-redo

configure argument and calls

qtCommandline_redo

. That’s as customizable as it can get but is not to be confused with the

custom

command line option object above. The Gods of Naming Things Well just cried a bit. Enums have another key, named

values

, that can be a list of valid values:

pcre: { type: enum, values: [ no, qt, system ] },

But behold! We can also use a map as demonstrated by this little brain teaser:

release: { type: enum, debug, values: { yes: no, no: yes } },
values

Command-line options can specify a list of valid values.

linker: { type: optionalString, values: [ bfd, gold, lld ] },

If any other value is passed, an configure exits with an error.

prefix

This fantastically named commandline key is best described by an example:

"prefix": {
    "D": "defines",
}

What this does is: enable the user to to

configure -DFOO -DBAR

and stores the list

FOO BAR

in

config.input.defines

. Internally, this creates a command-line option of type

addString

.

assignments

Here we can define variables assignments the user can pass to configure.

With

assignments: { MYSQL_PATH: mysql.prefix },

we can do

configure MYSQL_PATH=/some/where

. The result is stored in

config.input.mysql.prefix

.

Every assignment that is not registered in this way will fail:

./configure NO=WAY
...
ERROR: Assigning unknown variable 'NO' on command line.

Note that variables beginning with

QMAKE_

are handled by

qtConfCommandline_qmakeArgs

as described above.

libraries

Is an object. Its keys are strings that can be passed to QMAKE_USE. Its values are objects again.

Example:

libraries: { corewlan: { label: CoreWLan, export: ",test: {lang:objc++,include: [ "CoreWLAN/CoreWLAN.h", "CoreWLAN/CWInterface.h" ],main:[CWInterface interfaceWithName:@"en2"];" }, sources: [ -framework CoreWLAN -framework Foundation ] },  }

- label: The display name for configure’s user output. - export: - test: the name of a test or an object defining a configure test for this library. Details below. - sources: Array of several “sources” where the library might be found. - headers: Array of string, containing relative paths to header files (as they would appear in #include directives). Configure tries to locate those headers using heuristics. If the headers cannot be located, the test fails. The generated test source code will contain include directives for these headers on success. Note that header files within frameworks cannot be located as of now. Use test.include instead.

test

Configure test for the library this object is located in.

If

test

is a string, then it’s the name of a subdirectory below config.tests containing a test project that is configured with qmake and then built. If

test

is an object, then the following keys are used:

  • lang: The programming language to be used. Valid values are [“c++”, “c”, “objc”, “objc++”]. Default is “c++”.
  • head: array of strings with custom code before includes
  • include: array of strings for which include directives are generated. E.g.
    ["vector"]
    
    produces
    #include <foo.h>
    
    .
  • tail: array of strings with custom code after includes
  • main: Array of strings that form the body of the main function of the test. The main function’s signature for C++ is the usual
    int main(int argc, char **argv)
    
    .
  • qmake: Array of strings with custom code for the test’s .pro file. Added after SOURCES. The special string
    @PWD@
    
    is replaced by the current config dir.

sources

A source is a generalized location of a library. Configure probes the sources sequentially. The first successful wins.

There are different types of sources: - inline: the library is specified inline in a ‘libs’ field. Overrides from the command line are accepted. Where “inline” means “this is just a string”. But hey, this can also be an object. - makeSpec: The library is provided by the qmake spec. This source type cannot fail. - pkgConfig: The library is found via pkg-config.

Sources are dispatched by type to

qtConfLibrary_$${type}

. The handlers for the types above are defined in qt_configure.prf. Modules can add their own type “foo” by adding

defineTest(qtConfLibrary_foo)

to their local configure.pri. The common keys of a source object are: - type: The type as described above. - condition: If the condition is false, the source fails. Usually some platform or toolchain check like

"config.msvc"

.

inline sources

Can be specified “inline” as string

sources: [-lz -lproxy]

or as object if you need to set additional properties

sources: [ { comment: longwinded rambling, libs: -lz -lproxy }]

With

builds

you can specify different libraries per build:

{
    "libs": "",
    "builds": {
        "debug": "-ldbus-1d",
        "release": "-ldbus-1"
    },
    "condition": "config.win32"
},
makeSpec sources
"sources": [
    { "type": "makeSpec", "spec": "NETWORK" }
]

Reads the variables QMAKE_LIBDIR_NETWORK, QMAKE_LIBS_NETWORK and QMAKE_INCDIR_NETWORK from the mkspec. This source is always successful.

pkgConfig sources
{ "type": "pkgConfig", "host": true, "args": "dbus-1 >= 1.2" },
  • host: boolean, run pkgConfig for host or target?
  • args: Arguments for pkgConfig.

tests

TO BE DONE

features

  • Options from highest to lowest significance
  • emitIf:
    • Defaults to true
    • Early check (checked before anything else)
    • Overrules every other option and will make the feature non-existent, if false. Note: this means that before using such a feature, you must replicate the condition of emitIf to avoid “feature X does not exist” errors.
    • If used in connection with enable or disable and evaluates to false: Will cause a warning, feature will be disabled
    • Commonly used to turn off features, that are not supported on certain platforms (Direct… on Linux)
  • enable/disable:
    • Default to false
    • Operate on input variables (corresponds to command line options : -feature-foo, -no-feature-foo, and command line options defined in configure.json)
    • Override autoDetect
    • If both are set to true, “disable” wins
    • If enable is true and “condition” is not met, will trigger an error
    • Used to explicitly enable/disable a feature from the command line
  • autoDetect:
    • Defaults to true
    • Only relevant if the feature is not enabled/disabled on the command line
    • If true: feature is enabled by default. But the condition decides about feature’s status. It’s not an error if the condition is false.
    • If false: feature is disabled by default. It can only be turned on manually with the -feature-foo configure switch.
  • condition:
    • Defaults to true
    • Requirements that have to be met in order to use this feature

testTypeDependencies

From the introducing commit c8b46d3989ded1368d40e487a141b3cfb3d968ba:

Some test types (like the compile tests) require that other features have been checked before, so that the compile test sets up the right environment. Implement this through a ‘testTypeDependencies’ section in the json file that explicitly encodes those dependencies for certain test types.

Example from qtbase:

testTypeDependencies: { linkerSupportsFlag: [ use_gold_linker ], compile: [ shared, use_gold_linker, compiler-flags, gcc-sysroot ], detectPkgConfig: [ cross_compile ], library: [ pkg-config ], getPkgConfigVariable: [ pkg-config ], neon: [ architecture ] },

The keys are test types. The values are lists of features.

testTypeAliases

Comment from the source code: >>> Test type aliasing means that one test type’s callback is called by another test type’s callback. Put differently, one callback forwards the call to another one. The former representation is more natural (and concise) to write, while the latter is more efficient to process. Hence, this function inverts the mapping. >>>

Example from qtbase:

testTypeAliases: { compile: [ library, architecture, x86Simd, x86SimdAlways ] },

The

architecture

test calls

qtConfTest_compile

and inspects the build result. The type

architecture

is declared as alias for

compile

. The

testTypeAliases

data is used together with

testTypeDependencies

to calculate the order in which the tests are run / features are evaluated. Putting everything together, in our example the

architecture

test must run after the features

shared

,

use_gold_linker

,

compiler-flags

and

gcc-sysroot

have been evaluated.

summary

TO BE DONE

configure.pri

Optional per module. This file is an extends qt_configure.prf. For example, in QtNetwork configure.pri defines qtConfLibrary_openssl which makes it possible to have libraries of type openssl in that module.

special qmake variables

There are certain qmake variables that only make sense in the context of the Qt build itself. Other qmake variables behave specially in the Qt build.

Qt modules related variables

Public and private modules

A normal module (e.g. QtNetwork) is split into a public and a private module. Usually, users depend on the public one:

QT += network

but you can also depend on the private one. Some tests do that, for example.

QT += network-private

The meaning of

QT

within Qt modules is overloaded.

Dependencies between Qt modules

With the following variables one can express dependencies between Qt modules:

Variable Meaning
QT
Public dependencies of the public module.
QT_PRIVATE
Private dependencies of the public module.
QT_FOR_PRIVATE
Public dependencies of the private module.

Public dependencies means the dependencies are exported. Private dependencies are not exported.

See the message of commit b8bee40726fc93db9a025324712de6fff6a084d5 for more information.


How to

Check for features

In .pro files

To check for a certain feature use the qtConfig test function:

qtConfig(icu): DEFINES += WE_USE_ICU

There are two ways of making a module’s (private) features available to your pro file: - add <module> (or it’s “-private” equivalent for private features) to QT - add <module> (or it’s “-private” equivalent for private features) to QT_FOR_CONFIG (this only adds the feature related functionality without private include paths)

In C++ code

To check for a certain feature use the QT_CONFIG macro. For example, to check for the private feature

icu

, do the following:

#if QT_CONFIG(icu) doStuffWithFoo(); #endif

This will only work correctly if the

QT_FEATURE_icu

macro is defined. It is defined in

qtcore-config_p.h

. Add the include

qglobal_p.h

for private features of QtCore. This file is also pulled in by any private header. If you already include other private headers from QtCore you may omit the include. Public features are defined in

qtcore-config.h

. Just include any QtCore header (or

qglobal.h

) to be able to check for those. The respective include files for other modules, e.g. QtNetwork, are called

qtnetworkglobal[_p].h

.