Qt6 Build System: Difference between revisions
No edit summary |
(Document the SYSTEM_LIBRARY option of qt_feature.) |
||
(21 intermediate revisions by the same user not shown) | |||
Line 11: | Line 11: | ||
There is some historical information at [[CMake Port]]. | 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 <tt>configure.cmake</tt> 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 <tt>configure.cmake</tt> 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 === | === Commands in configure.cmake === | ||
==== qt_find_package ==== | |||
This is a macro that wraps CMake's <tt>find_package</tt> and adds Qt-specific stuff. | |||
<code> | |||
qt_find_package(<PackageName> | |||
[PROVIDED_TARGETS target1 target2 ...]] | |||
[MODULE_NAME name QMAKE_LIB name] | |||
)</code> | |||
<tt>PROVIDED_TARGETS</tt> lists targets that are provided by the package. The targets are promoted to global unless that's inhibited. | |||
<tt>MODULE_NAME</tt> and <tt>QMAKE_LIB</tt> are meant to be specified together. | |||
<tt>MODULE_NAME</tt> denotes the Qt module name in QMake parlance this package belongs to. <tt>QMAKE_LIB</tt> 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 <tt>TEST_${name}_OUTPUT</tt> variable with the build output, to the scope of the calling function. Sets a <tt>TEST_${name}</tt> cache variable to either <tt>TRUE</tt> or <tt>FALSE</tt> if the build is successful or not. | |||
One can either specify the source code of the test project with <tt>CODE</tt> or use <tt>PROJECT_PATH</tt> to point to a directory with a full CMake project. | |||
==== qt_feature("<feature>" ...) ==== | ==== qt_feature("<feature>" ...) ==== | ||
Defines a feature called <feature>. | 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>" [SYSTEM_LIBRARY] [PUBLIC] [PRIVATE] | |||
[LABEL "<label>"] | |||
[PURPOSE "<purpose>"] | |||
[SECTION "<selection>"] | |||
[AUTODETECT <condition>] | |||
[CONDITION <condition>] | |||
[ENABLE <condition>] | |||
[DISABLE <condition>] | |||
[EMIT_IF <condition>] | |||
)</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>PURPOSE</tt> is the help text that's displayed on <tt>configure | |||
-list-features</tt>. A missing <tt>PURPOSE</tt> is the usual reason | |||
for a feature not being displayed on <tt>configure | |||
-list-features</tt>. | |||
<tt>LABEL</tt> is a human-readable name that shortly describes the | |||
feature in the configure summary. | |||
<tt>AUTODETECT</tt> determines whether the feature is opt-in or | |||
opt-out. The default is <tt>ON</tt>. Features that are supposed to be | |||
enabled explicitly by the user should have <tt>AUTODETECT OFF</tt>. | |||
<tt>CONDITION</tt> 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. | |||
<tt>EMIT_IF</tt> 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. | |||
< | <tt>ENABLE</tt> Evaluates to a condition that will enable the feature. | ||
This is usually set to react on <tt>INPUT_foo</tt> values. | |||
<tt> | <tt>DISABLE</tt> is the complement of <tt>ENABLE</tt>. | ||
==== qt_feature_definition("<feature>" "<name>" ...) ==== | ==== qt_feature_definition("<feature>" "<name>" ...) ==== | ||
Line 47: | Line 118: | ||
If <tt>NEGATE</tt> is given, the define is set only if the feature is disabled. Otherwise it is set only if it is enabled. | If <tt>NEGATE</tt> 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 ==== | |||
<code> | |||
qt_configure_process_add_report_entry( | |||
TYPE NOTE|WARNING|ERROR|FATAL_ERROR | |||
MESSAGE message | |||
[CONDITION condition] | |||
)</code> | |||
Adds a message, warning or error to the configure summary. | |||
<tt>CONDITION</tt> specifies whether to issue the report entry. | |||
=== Common tasks === | |||
==== A simple feature ==== | |||
<code> | |||
# from qtbase/configure.cmake | |||
qt_feature("zstd" PUBLIC | |||
LABEL "Zstandard support" | |||
CONDITION WrapZSTD_FOUND | |||
) | |||
</code> | |||
Characteristics of this feature: | |||
* available in C++ via <tt>qconfig.h</tt>, the public module header of QtCore | |||
* <tt>ON</tt> by default if <tt>libzstd</tt> is found | |||
==== Testing the feature value in C++ ==== | |||
Use the <tt>QT_CONFIG</tt> macro to test whether a feature is enabled. | |||
<code> | |||
#if QT_CONFIG(zstd) | |||
# include <zstd.h> | |||
#endif | |||
</code> | |||
==== Testing the feature value in CMake ==== | |||
Use the <tt>QT_FEATURE_foo</tt> variable to test whether a feature is enabled. | |||
<code> | |||
if(QT_FEATURE_zstd) | |||
target_sources(mytarget PRIVATE compress_with_zstd.cpp) | |||
endif() | |||
</code> | |||
== Qt's configure script == | == Qt's configure script == | ||
Line 76: | Line 217: | ||
qt_commandline_subconfig(src/widgets) | 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? === | === What effect can configure options have? === | ||
Line 103: | Line 244: | ||
==== qt_commandline_custom ==== | ==== qt_commandline_custom ==== | ||
qt_commandline_custom(handler) | 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 ==== | ||
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 === | === Common tasks === | ||
===== How to add a command line option that controls a feature? ===== | ===== How to add a command line option that controls a feature? ===== | ||
<code> | |||
# configure.cmake | |||
qt_feature("narf" PRIVATE) | |||
</code> | |||
<code> | |||
# qt_cmdline.cmake | |||
qt_commandline_option("narf" TYPE boolean) | |||
</code> | |||
Now, you can pass the options <tt>-narf</tt>, or <tt>-no-narf</tt> to <tt>configure</tt> or <tt>qt-configure-module</tt>. | |||
==== How to add a command line option that sets a CMake variable? ==== | ==== How to add a command line option that sets a CMake variable? ==== | ||
To add a configure option <tt>-foo</tt> that translates into a CMake argument <tt>-DQT_FOO=ON</tt> one has to | |||
* add a <tt>qt_commandline_option(foo TYPE boolean)</tt> call in <tt>qt_cmdline.cmake</tt> | |||
* add a <tt>translate_boolean_input(foo QT_FOO)</tt> call in <tt>QtProcessConfigureArguments.cmake</tt> | |||
* add this mapping to <tt>configure-cmake-mapping.md</tt> | |||
See [https://bugreports.qt.io/browse/QTBUG-123064 QTBUG-123064] for an idea how to simplify this process. |
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.