Qt6 Build System: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
(Document the SYSTEM_LIBRARY option of qt_feature.)
 
Line 65: Line 65:
Defines a feature called <feature>. If a feature is enabled, <tt>QT_FEATURE_foo</tt> is set to <tt>ON</tt>. Users are supposed to control features by setting the <tt>FEATURE_foo</tt> variable to <tt>ON</tt> or <tt>OFF</tt> (note the absence of the <tt>QT_</tt> prefix).
Defines a feature called <feature>. If a feature is enabled, <tt>QT_FEATURE_foo</tt> is set to <tt>ON</tt>. Users are supposed to control features by setting the <tt>FEATURE_foo</tt> variable to <tt>ON</tt> or <tt>OFF</tt> (note the absence of the <tt>QT_</tt> prefix).


<code>qt_feature("<feature>" [PUBLIC] [PRIVATE]
<code>qt_feature("<feature>" [SYSTEM_LIBRARY] [PUBLIC] [PRIVATE]  
     [LABEL "<label>"]
     [LABEL "<label>"]
     [PURPOSE "<purpose>"]
     [PURPOSE "<purpose>"]
Line 75: Line 75:
     [EMIT_IF <condition>]
     [EMIT_IF <condition>]
)</code>
)</code>
<tt>SYSTEM_LIBRARY</tt> denotes a feature that controls the usage of a 3rdparty system library, e.g. <tt>system-libpng</tt>. Features that are marked like this can be toggled in bulk with the configure option <tt>-system-libs</tt> or <tt>-bundled-libs</tt>.


<tt>PUBLIC</tt> features belong to the public part of a Qt module ''Foo''. <tt>PRIVATE</tt> features belong to the module's private counterpart ''FooPrivate''. This is mostly relevant when testing for features in C++ code.
<tt>PUBLIC</tt> features belong to the public part of a Qt module ''Foo''. <tt>PRIVATE</tt> features belong to the module's private counterpart ''FooPrivate''. This is mostly relevant when testing for features in C++ code.

Latest revision as of 12:01, 19 June 2024


This is a description of the Qt6 CMake-based build system.

For Qt5, see Qt5 Build System.

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

When writing CMake code, beware of the CMake Language Pitfalls.

There is some historical information at CMake Port.

Configuration at CMake level

Qt6 uses CMake, and you can use plain CMake to configure Qt. For a more convenient way to configure Qt, use the configure script, which internals are described further down on this page.

The configure.cmake files

How Qt can be configure is defined in configure.cmake files. There can be multiple configure.cmake files in a repository:

  • configure.cmake at the top level of the repository
  • src/mymodule/configure.cmake in the subdirectory of a Qt module

The configure.cmake files typically contain the following things

  • qt_find_package calls to make 3rdparty libraries available
  • compile tests
  • feature definitions
  • entries for Qt's configure summary
  • messages that are conditionally displayed

Commands in configure.cmake

qt_find_package

This is a macro that wraps CMake's find_package and adds Qt-specific stuff.

qt_find_package(<PackageName>
    [PROVIDED_TARGETS target1 target2 ...]]
    [MODULE_NAME name QMAKE_LIB name]
)

PROVIDED_TARGETS lists targets that are provided by the package. The targets are promoted to global unless that's inhibited.

MODULE_NAME and QMAKE_LIB are meant to be specified together. MODULE_NAME denotes the Qt module name in QMake parlance this package belongs to. QMAKE_LIB is the corresponding library name that QMake understands.

qt_config_compile_test

qt_config_compile_test(name
    LABEL text
    [LIBRARIES library1 library2 ...]
    [C_STANDARD version]
    [CXX_STANDARD version]
    [COMPILE_OPTIONS option1 option2 ...]
    [PACKAGES package1 package2 ...]
    [CMAKE_FLAGS flag1 flag2 ...]
    [CODE source_code]
    [PROJECT_PATH path]
)

Builds either a string of source code or a whole project to determine whether the build is successful.

Sets a TEST_${name}_OUTPUT variable with the build output, to the scope of the calling function. Sets a TEST_${name} cache variable to either TRUE or FALSE if the build is successful or not.

One can either specify the source code of the test project with CODE or use PROJECT_PATH to point to a directory with a full CMake project.

qt_feature("<feature>" ...)

Defines a feature called <feature>. If a feature is enabled, QT_FEATURE_foo is set to ON. Users are supposed to control features by setting the FEATURE_foo variable to ON or OFF (note the absence of the QT_ prefix).

qt_feature("<feature>" [SYSTEM_LIBRARY] [PUBLIC] [PRIVATE] 
    [LABEL "<label>"]
    [PURPOSE "<purpose>"]
    [SECTION "<selection>"]
    [AUTODETECT <condition>]
    [CONDITION <condition>]
    [ENABLE <condition>]
    [DISABLE <condition>]
    [EMIT_IF <condition>]
)

SYSTEM_LIBRARY denotes a feature that controls the usage of a 3rdparty system library, e.g. system-libpng. Features that are marked like this can be toggled in bulk with the configure option -system-libs or -bundled-libs.

PUBLIC features belong to the public part of a Qt module Foo. PRIVATE features belong to the module's private counterpart FooPrivate. This is mostly relevant when testing for features in C++ code.

PURPOSE is the help text that's displayed on configure -list-features. A missing PURPOSE is the usual reason for a feature not being displayed on configure -list-features.

LABEL is a human-readable name that shortly describes the feature in the configure summary.

AUTODETECT determines whether the feature is opt-in or opt-out. The default is ON. Features that are supposed to be enabled explicitly by the user should have AUTODETECT OFF.

CONDITION specifies a condition that needs to be satisfied if the feature is turned on. If the user enables a feature but the condition is not satisfied, an error will be yielded. If the feature is auto-detected and the condition is not satisfied, there will be no error.

EMIT_IF If this evaluates to false, skip the feature completely. No cache variable for this feature will be recorded. This can be used to enable a feature on certain platforms only.

ENABLE Evaluates to a condition that will enable the feature. This is usually set to react on INPUT_foo values.

DISABLE is the complement of ENABLE.

qt_feature_definition("<feature>" "<name>" ...)

Makes a C++ define <name> available.

qt_feature_definition("<feature>" "<name>" [NEGATE] [VALUE "<value>"])

If <value> is set, the define will have this as value.

If NEGATE is given, the define is set only if the feature is disabled. Otherwise it is set only if it is enabled.

qt_configure_add_summary_section

qt_configure_add_summary_section(NAME "Things")

Adds a new section in the configure summary named "Things". Summary entries added after this call will be added to that section until qt_configure_end_summary_section() is called.

qt_configure_end_summary_section

qt_configure_end_summary_section()

Ends the currently active summary section.

qt_configure_add_summary_entry

qt_configure_add_summary_entry(
    ARGS <string>
    [TYPE feature|featureList|firstAvailableFeature]
    [MESSAGE <string>]
    [CONDITION <list>]
)

Adds an entry to the configure summary in the currently active summary section.

ARGS is a string that contains features, separated by spaces.

TYPE defaults to "feature". The different types have the following meaning:

  • feature: display whether the feature in ARGS is enabled. Display the feature's LABEL. MESSAGE is ignored. If the feature has no LABEL, use the feature's name.
  • featureList: display MESSAGE and the LABELs of the enabled features in ARGS.
  • firstAvailableFeature: display MESSAGE and the LABEL of the first of the enabled features in ARGS.

CONDITION can be used to conditionally suppress the display of the summary entry.

qt_configure_add_report_entry

qt_configure_process_add_report_entry(
    TYPE NOTE|WARNING|ERROR|FATAL_ERROR
    MESSAGE message
    [CONDITION condition]
)

Adds a message, warning or error to the configure summary.

CONDITION specifies whether to issue the report entry.

Common tasks

A simple feature

# from qtbase/configure.cmake
qt_feature("zstd" PUBLIC
    LABEL "Zstandard support"
    CONDITION WrapZSTD_FOUND
)

Characteristics of this feature:

  • available in C++ via qconfig.h, the public module header of QtCore
  • ON by default if libzstd is found

Testing the feature value in C++

Use the QT_CONFIG macro to test whether a feature is enabled.

#if QT_CONFIG(zstd)
#    include <zstd.h>
#endif

Testing the feature value in CMake

Use the QT_FEATURE_foo variable to test whether a feature is enabled.

if(QT_FEATURE_zstd)
    target_sources(mytarget PRIVATE compress_with_zstd.cpp)
endif()

Qt's configure script

Qt's configure script is a convenience interface that translates its command line options to CMake arguments.

Where configure's logic is implemented

Most of configure's logic is implemented in qtbase/cmake/QtProcessConfigureArgs.cmake. This is a CMake script that is run via cmake -P by configure/configure.bat.

Only very special configure options need to be implemented here. Most should be doable with the qt_cmdline.cmake configuration files.

qt_cmdline.cmake files

Most configure options are defined in qt_cmdline.cmake files throughout the repositories. Each Qt repository can have a top-level qt_cmdline.cmake file and several lower-level ones. For example, qtbase has the following files (at the time of writing):

qt_cmdline.cmake
src/corelib/qt_cmdline.cmake
src/gui/qt_cmdline.cmake
src/network/qt_cmdline.cmake
src/plugins/sqldrivers/qt_cmdline.cmake
src/printsupport/qt_cmdline.cmake
src/sql/qt_cmdline.cmake
src/testlib/qt_cmdline.cmake
src/widgets/qt_cmdline.cmake
src/xml/qt_cmdline.cmake

The top-level file must reference the lower-level files. This is similar to include statements or CMake's add_subdirectory calls.

qt_commandline_subconfig(src/corelib)
qt_commandline_subconfig(src/network)
qt_commandline_subconfig(src/gui)
qt_commandline_subconfig(src/sql)
qt_commandline_subconfig(src/xml)
qt_commandline_subconfig(src/widgets)
...

This is also necessary to let configure pick up the configure.cmake files in the subdirectories. The configure script needs to be aware of the features defined in those configure.cmake files.

What effect can configure options have?

Configure options can affect three things:

  • -foo could be directly translated to a CMake variable that is passed as -DNAME=value.
  • -foo and -no-foo could control the feature "foo".
  • --foo bar could set the variable INPUT_foo that can be used in configure.cmake or regular CMake files.

Commands available in qt_cmdline.cmake

qt_commandline_subconfig

qt_commandline_subconfig(path)

As outlined above, this is something like an include statement that pulls further qt_cmdline.cmake files. The parameter path is the path of a subdirectory where another qt_cmdline.cmake is located.

qt_commandline_option

qt_commandline_option(name
    TYPE type_name
    [NAME variable_name]
    [VALUE value]
    [VALUES value1 [value2 ...]]
    [MAPPING from1 to1 [from2 to2 ...]]
    [CONTROLS_FEATURE]
)

qt_commandline_custom

qt_commandline_custom(handler)

Registers a custom handler function. This was once used to handle QMAKE_xxx=yyy assignments. You really must do internal stuff in there.

This functionality should probably be removed.

qt_commandline_prefix

qt_commandline_prefix(D defines)

Add a configure option -D that sets the variable INPUT_defines. The user may pass multiple prefix arguments to configure. The values accumulate in INPUT_defines.

QtProcessConfigureArgs.cmake has special handling for all prefixes in qtbase.

Common tasks

How to add a command line option that controls a feature?
# configure.cmake
qt_feature("narf" PRIVATE)
# qt_cmdline.cmake
qt_commandline_option("narf" TYPE boolean)

Now, you can pass the options -narf, or -no-narf to configure or qt-configure-module.

How to add a command line option that sets a CMake variable?

To add a configure option -foo that translates into a CMake argument -DQT_FOO=ON one has to

  • add a qt_commandline_option(foo TYPE boolean) call in qt_cmdline.cmake
  • add a translate_boolean_input(foo QT_FOO) call in QtProcessConfigureArguments.cmake
  • add this mapping to configure-cmake-mapping.md

See QTBUG-123064 for an idea how to simplify this process.