Syncqt: Difference between revisions
mNo edit summary |
|||
(19 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
syncqt is Qt's internal build tool that helps generating build and deployment artifacts such as: | syncqt is Qt's internal build tool that helps generating build and deployment artifacts such as: | ||
== syncqt work modes == | *CaMeL case header files named by public C++ symbols located in public module header files, e.g. <code>#include <QtCore/QCoreApplication></code> because <code>QCoreApplication</code> is a public symbol / class | ||
*Header file that contains the module version information, and named as <code><module>Version</code>, e.g. <code>QtCoreVersion</code> | |||
*A Linux linker (LD) version script, if applicable | |||
*Aliases or copies of header files categorised into a few different header types: <code>public/private/qpa/rhi</code> | |||
==syncqt work modes== | |||
Usually, you don't need to run syncqt directly, but use either module-specific or one of the special targets, that are created by the Qt build system. Two syncqt target types reflect two modes that syncqt is running in: | Usually, you don't need to run syncqt directly, but use either module-specific or one of the special targets, that are created by the Qt build system. Two syncqt target types reflect two modes that syncqt is running in: | ||
The 'header' mode is the regular one that processes only those header files that are specified as syncqt argument. syncqt can be run in the 'header' mode <module>_sync_headers targets, e.g. Core_syncqt_headers. | *Header mode | ||
*All mode | |||
The 'header' mode is the regular one that processes only those header files that are specified as syncqt argument. Within a build system, syncqt can be run in the 'header' mode <module>_sync_headers targets, e.g. Core_syncqt_headers. | |||
The 'all' mode is the special one that you don't need to use while developing Qt. It processes all public header files that are found on the file system, recursively. syncqt can be run in 'all' mode using <module>_sync_all_public_headers. This mode is mostly useful when generating documentation, where the processing of private-like header files is not important. | The 'all' mode is the special one that you don't need to use while developing Qt. It processes all public header files that are found on the file system, recursively. syncqt can be run in 'all' mode using <module>_sync_all_public_headers. This mode is mostly useful when generating documentation, where the processing of private-like header files is not important. | ||
Both modes have meta targets that can be used to run syncqt for all modules in specific modes: | Both modes have meta build system targets that can be used to run syncqt for all modules in specific modes: | ||
* sync_headers | |||
* sync_all_public_headers | *sync_headers | ||
*sync_all_public_headers | |||
== Types of Qt header files == | ==Types of Qt header files== | ||
As you may notice in Qt we separate header files into two basic types public and private. As a Qt contributor, you should already know that private headers have a | As you may notice in Qt we separate header files into two basic types – public and private. | ||
As a Qt contributor, you should already know that private headers have a <code>_p</code> suffix and | |||
the API exposed by these headers doesn't guarantee cross-version source compatibility or ABI compatibility. | |||
Also, some exceptions don't follow this generic <code>_p</code> convention, but | |||
you will never see these header files in the module include directories. | |||
All private header files land inside version specific private includes directory, | |||
like <code>include/QtCore/<version>/QtCore/private/</code>. | |||
From the syncqt perspective, these header file types have different processing and as a result, syncqt produces different artifacts. | From the syncqt perspective, these header file types have different processing and, as a result, syncqt produces different artifacts. | ||
There are also special header types such as QPA and RHI headers, that are processed by syncqt | There are also special header types such as QPA and RHI headers, that | ||
are processed by syncqt like the [[#Private header files|private header files]], but deployed to the <code>include/Qt<Module>/<version>/Qt<Module>/qpa/</code> and <code>include/Qt<Module>/<version>/Qt<Module>/rhi/</code> directories, respectively. | |||
== Private header files == | ==Private header files== | ||
=== Checks === | ===Checks=== | ||
For private header files, the only sanity check that syncqt does is the "We meant it." check. Private header files should have a disclaimer that is named "We meant it." | For private header files, the only sanity check that syncqt does is the "We meant it." check. | ||
Private header files should have a disclaimer that is named "We meant it." – | |||
WARNING: | if this disclaimer is missing in a freshly added private header file syncqt will warn you as follows: | ||
{{WarningBox|text=WARNING: <file name> does not have the "We mean it." warning}} | |||
=== Artifacts === | ===Artifacts=== | ||
syncqt only produces the build time header file aliases in the build directory | For private headers, syncqt only produces the build-time header file aliases in the build directory. | ||
These aliases allow using conventional paths in include directives but | |||
are never installed or delivered as part of a Qt distribution. | |||
Also, syncqt collects the symbols defined in private headers and generates the ld linker version scripts for Qt modules on Linux platforms. | Also, syncqt collects the symbols defined in private headers and | ||
generates the <kbd>ld</kbd> linker version scripts for Qt modules on Linux platforms. | |||
=== Deployment path === | ===Deployment path=== | ||
<code>include/Qt<Module>/<version>/Qt<Module>/private/</code> | |||
== Public header files == | ==Public header files== | ||
=== Checks === | ===Checks=== | ||
User-facing public headers require a more accurate sanity check from syncqt. syncqt runs the following checks on these files: | User-facing public headers require a more accurate sanity check from syncqt. syncqt runs the following checks on these files: | ||
;Private header inclusion check | |||
:It's prohibited to include private header files in the public one. syncqt makes the preliminary check of include statements and throws the critical error if this has a place to be: | :It's prohibited to include private header files in the public one. syncqt makes the preliminary check of include statements and throws the critical error if this has a place to be: | ||
{{WarningBox|text=ERROR: <file name>:<line number> includes private header <private header name>}} | |||
ERROR: | |||
;Wrapping QT_<BEGIN|END>NAMESPACE check | |||
:All Qt API need to be wrapped with QT_ | :All Qt API need to be wrapped with <code>QT_<BEGIN|END>NAMESPACE</code> macros. This allows building and using Qt with an extra namespace. syncqt detects either missing macros or their inconsistent use and throws one of the errors if this has a place to be: | ||
{{WarningBox|text=WARNING: <file name> does not include QT_BEGIN_NAMESPACE}} | |||
WARNING: | |||
;Use of the full include qualifiers | |||
:For public header files we follow the common rule that full relative include path should be used when including header files that belong to the Qt modules. Developers should prefer using | :For public header files we follow the common rule that full relative include path should be used when including header files that belong to the Qt modules. Developers should prefer using <code>#include <QtCore/QObject></code> but not <code>#include <QObject></code> in public header files. syncqt detects include directives that don't follow this convention and throws the error: | ||
{{WarningBox|text=WARNING: <file name>:<line number> includes QObject when it should include QtCore/QObject}} | |||
WARNING: | |||
=== Artifacts === | ===Artifacts=== | ||
syncqt uses public headers to produce the following artifacts: | syncqt uses public headers to produce the following artifacts: | ||
* Deprecated header files | *CaMeL case header file aliases | ||
:CaMeL case header files are aliases named after public Qt classes. syncqt uses public symbols, like classes, structures, typedefs, and aliases from header files and produces CaMeL case header files based on this input. | |||
*Deprecated header files | |||
:In situations when some public header files are not relevant anymore and should be removed, they should be marked as deprecated first so users have time to adapt their code and use the header file replacement. See [[#Pragma deprecates]] | :In situations when some public header files are not relevant anymore and should be removed, they should be marked as deprecated first so users have time to adapt their code and use the header file replacement. See [[#Pragma deprecates]] | ||
* Version header file | *Version header file | ||
:Header file that contains macros definitions with the module version information. This information is used by Qt versioning macros, but it's also possible to use them in user code directly. | :Header file that contains macros definitions with the module version information. This information is used by Qt versioning macros, but it's also possible to use them in user code directly. | ||
* "Master" header file | *"Master" header file | ||
:Header file with the | |||
:Header file with the <code>Qt<Module></code> name. The file contains the includes of all public header files provided by the module. syncqt also checks if the public header contains <code>QT_REQUIRE_CONFIG</code> macros call and guards the header file including directive with corresponding <code>QT_CONFIG</code> check. | |||
Also, syncqt produces the build time header file aliases in the build directory that allow using conventional paths in include directives. These aliases are never installed nor delivered as part of Qt distribution. | Also, syncqt produces the build time header file aliases in the build directory that allow using conventional paths in include directives. These aliases are never installed nor delivered as part of Qt distribution. | ||
=== Deployment path === | ===Deployment path=== | ||
<code>include/Qt<Module></code> | |||
== Pragmas == | ==Pragmas== | ||
It's possible to control the syncqt behavior and output using the special C++ pragmas. To avoid any compilation error you should use these syncqt-specific pragmas as follows: | It's possible to control the syncqt behavior and output using the special C++ pragmas. To avoid any compilation error you should use these syncqt-specific pragmas as follows: | ||
<syntaxhighlight lang="C++"> | |||
#ifdef 0 | |||
# pragma <pragma name> | |||
#endif | |||
</syntaxhighlight> | |||
===Pragma qt_deprecates=== | |||
</ | ====Syntax==== | ||
<syntaxhighlight lang="C++"> | |||
#pragma qt_deprecates(<deprecated header file>[,<major.minor>]) | |||
</syntaxhighlight> | |||
====Description==== | |||
==== Description ==== | |||
Pragma indicates that the header file where this pragma is used replaces the one mentioned in pragma. The replaced header file will be generated containing a warning with the deprecation notice. | Pragma indicates that the header file where this pragma is used replaces the one mentioned in pragma. The replaced header file will be generated containing a warning with the deprecation notice. | ||
For example in qttestglobal.h there is(or was) the following code: | For example in qttestglobal.h there is(or was) the following code: | ||
< | <syntaxhighlight lang="C++"> | ||
#if 0 | |||
# pragma qt_deprecates(qtest_global.h) | |||
#endif | |||
</syntaxhighlight> | |||
</ | |||
syncqt will generate the qtest_global.h header file with #include <QtTest/qttestglobal.h> and the warning that says that the file is deprecated and QtTest/qttestglobal.h should be used instead. | syncqt will generate the qtest_global.h header file with <code>#include <QtTest/qttestglobal.h></code> and the warning that says that the file is deprecated and <code>QtTest/qttestglobal.h</code> should be used instead. | ||
Adding the version argument to the pragma will also limit the deprecated header file lifetime. Once Qt reaches the version that is set as the second argument, the deprecated header file will not be generated by syncqt, but syncqt will show the warning when compiling the Qt itself. | Adding the version argument to the pragma will also limit the deprecated header file lifetime. Once Qt reaches the version that is set as the second argument, the deprecated header file will not be generated by syncqt, but syncqt will show the warning when compiling the Qt itself. | ||
=== Pragma qt_sync_skip_header_check === | ===Pragma qt_sync_skip_header_check=== | ||
==== Syntax ==== | ====Syntax==== | ||
< | <syntaxhighlight lang="C++"> | ||
#pragma qt_sync_skip_header_check | |||
</ | </syntaxhighlight> | ||
==== Description ==== | ====Description==== | ||
This pragma tells syncqt that it should ignore any errors that are found in a header file. Please use this pragma only if you are confident that the header matches the Qt's requirements. | This pragma tells syncqt that it should ignore any errors that are found in a header file. Please use this pragma only if you are confident that the header matches the Qt's requirements. | ||
=== Pragma qt_sync_stop_processing === | ===Pragma qt_sync_stop_processing=== | ||
==== Syntax ==== | ====Syntax==== | ||
< | <syntaxhighlight lang="C++"> | ||
#pragma qt_sync_stop_processing | |||
</ | </syntaxhighlight> | ||
==== Description ==== | ====Description==== | ||
This pragma tells syncqt that it should stop any header processing from the point where the pragma is found. syncqt stops both checking the header file for errors and collecting artifacts to generate additional header files. | This pragma tells syncqt that it should stop any header processing from the point where the pragma is found. syncqt stops both checking the header file for errors and collecting artifacts to generate additional header files. | ||
=== Pragma qt_sync_suspend_processing === | ===Pragma qt_sync_suspend_processing=== | ||
==== Syntax ==== | ====Syntax==== | ||
< | <syntaxhighlight lang="C++"> | ||
#pragma qt_sync_suspend_processing | |||
</ | </syntaxhighlight> | ||
==== Description ==== | ====Description==== | ||
When syncqt faces this pragma in code it temporarily suspends checking the header file for error and collecting artifacts to generate additional header files. The processing can be resumed by the [[#Pragma qt_sync_resume_processing|qt_sync_resume_processing]] pragma. If qt_sync_suspend_processing is not followed by qt_sync_resume_processing the behavior of qt_sync_suspend_processing is the same as the behavior of [[Pragma qt_sync_stop_processing|qt_sync_stop_processing]]. | When syncqt faces this pragma in code it temporarily suspends checking the header file for error and collecting artifacts to generate additional header files. The processing can be resumed by the [[#Pragma qt_sync_resume_processing|qt_sync_resume_processing]] pragma. If <code>qt_sync_suspend_processing</code> is not followed by <code>qt_sync_resume_processing</code> the behavior of <code>qt_sync_suspend_processing</code> is the same as the behavior of [[Pragma qt_sync_stop_processing|qt_sync_stop_processing]]. | ||
=== Pragma qt_class === | ===Pragma qt_class=== | ||
==== Syntax ==== | ====Syntax==== | ||
< | <syntaxhighlight lang="C++"> | ||
#pragma qt_class(<symbol>) | |||
</ | </syntaxhighlight> | ||
==== Description ==== | ====Description==== | ||
The pragma requests generating of the header file alias with the ''symbol'' name. For example, use the following code in qassert.h: | The pragma requests generating of the header file alias with the ''symbol'' name. For example, use the following code in qassert.h: | ||
< | <syntaxhighlight lang="C++"> | ||
#pragma qt_class(QtAssert) | |||
</ | </syntaxhighlight> | ||
syncqt generates the ''QtAssert'' header file with the inclusion of qassert.h. | syncqt generates the ''QtAssert'' header file with the inclusion of qassert.h. | ||
Line 151: | Line 162: | ||
'''Note:''' syncqt doesn't detect the file name collisions at the moment when this topic is written, so conflicting files will be overwritten in undefined order. | '''Note:''' syncqt doesn't detect the file name collisions at the moment when this topic is written, so conflicting files will be overwritten in undefined order. | ||
=== Pragma qt_no_master_include === | ===Pragma qt_no_master_include=== | ||
==== Syntax ==== | ====Syntax==== | ||
< | <syntaxhighlight lang="C++"> | ||
#pragma qt_no_master_include | |||
</ | </syntaxhighlight> | ||
==== Description ==== | ====Description==== | ||
The pragma indicates to syncqt that the header file shouldn't be included in the module's master header file. | The pragma indicates to syncqt that the header file shouldn't be included in the module's master header file. | ||
== CMake integration == | ==CMake integration== | ||
syncqt is part of the Qt build system and it runs implicitly for all Qt modules that are created using the | syncqt is part of the Qt build system and it runs implicitly for all Qt modules that are created using the <code>qt_internal_add_module</code> command and other <code>qt_internal_</code> command that imply the <code>qt_internal_add_module</code> call. | ||
There are not too many arguments of the | There are not too many arguments of the <code>qt_internal_add_module</code> command that controls the syncqt behavior. | ||
=== NO_SYNC_QT === | ===NO_SYNC_QT=== | ||
Skips syncqt processing of the module header files. | Skips syncqt processing of the module header files. | ||
=== <PRIVATE|QPA|RHI>_HEADER_FILTERS === | ===<PRIVATE|QPA|RHI>_HEADER_FILTERS=== | ||
Indicates accepts the CMake regular expression as an argument and indicates how header files of the corresponding type should be filtered from others. | Indicates accepts the CMake regular expression as an argument and indicates how header files of the corresponding type should be filtered from others. | ||
=== HEADER_SYNC_SOURCE_DIRECTORY === | ===HEADER_SYNC_SOURCE_DIRECTORY=== | ||
The source directory for the header sync procedure. Header files outside this directory will be ignored by syncqt. | The source directory for the header sync procedure. Header files outside this directory will be ignored by syncqt. |
Latest revision as of 14:06, 18 August 2023
syncqt is Qt's internal build tool that helps generating build and deployment artifacts such as:
- CaMeL case header files named by public C++ symbols located in public module header files, e.g. because
#include <QtCore/QCoreApplication>
is a public symbol / classQCoreApplication
- Header file that contains the module version information, and named as , e.g.
<module>Version
QtCoreVersion
- A Linux linker (LD) version script, if applicable
- Aliases or copies of header files categorised into a few different header types:
public/private/qpa/rhi
syncqt work modes
Usually, you don't need to run syncqt directly, but use either module-specific or one of the special targets, that are created by the Qt build system. Two syncqt target types reflect two modes that syncqt is running in:
- Header mode
- All mode
The 'header' mode is the regular one that processes only those header files that are specified as syncqt argument. Within a build system, syncqt can be run in the 'header' mode <module>_sync_headers targets, e.g. Core_syncqt_headers.
The 'all' mode is the special one that you don't need to use while developing Qt. It processes all public header files that are found on the file system, recursively. syncqt can be run in 'all' mode using <module>_sync_all_public_headers. This mode is mostly useful when generating documentation, where the processing of private-like header files is not important.
Both modes have meta build system targets that can be used to run syncqt for all modules in specific modes:
- sync_headers
- sync_all_public_headers
Types of Qt header files
As you may notice in Qt we separate header files into two basic types – public and private.
As a Qt contributor, you should already know that private headers have a
_p
suffix and
the API exposed by these headers doesn't guarantee cross-version source compatibility or ABI compatibility.
Also, some exceptions don't follow this generic
_p
convention, but
you will never see these header files in the module include directories. All private header files land inside version specific private includes directory,
like
include/QtCore/<version>/QtCore/private/
.
From the syncqt perspective, these header file types have different processing and, as a result, syncqt produces different artifacts.
There are also special header types such as QPA and RHI headers, that
are processed by syncqt like the private header files, but deployed to the
include/Qt<Module>/<version>/Qt<Module>/qpa/
and
include/Qt<Module>/<version>/Qt<Module>/rhi/
directories, respectively.
Private header files
Checks
For private header files, the only sanity check that syncqt does is the "We meant it." check. Private header files should have a disclaimer that is named "We meant it." – if this disclaimer is missing in a freshly added private header file syncqt will warn you as follows:
WARNING: <file name> does not have the "We mean it." warning |
Artifacts
For private headers, syncqt only produces the build-time header file aliases in the build directory. These aliases allow using conventional paths in include directives but are never installed or delivered as part of a Qt distribution.
Also, syncqt collects the symbols defined in private headers and generates the ld linker version scripts for Qt modules on Linux platforms.
Deployment path
include/Qt<Module>/<version>/Qt<Module>/private/
Public header files
Checks
User-facing public headers require a more accurate sanity check from syncqt. syncqt runs the following checks on these files:
- Private header inclusion check
- It's prohibited to include private header files in the public one. syncqt makes the preliminary check of include statements and throws the critical error if this has a place to be:
ERROR: <file name>:<line number> includes private header <private header name> |
- Wrapping QT_<BEGIN|END>NAMESPACE check
- All Qt API need to be wrapped with macros. This allows building and using Qt with an extra namespace. syncqt detects either missing macros or their inconsistent use and throws one of the errors if this has a place to be:
QT_<BEGIN|END>NAMESPACE
WARNING: <file name> does not include QT_BEGIN_NAMESPACE |
- Use of the full include qualifiers
- For public header files we follow the common rule that full relative include path should be used when including header files that belong to the Qt modules. Developers should prefer using but not
#include <QtCore/QObject>
in public header files. syncqt detects include directives that don't follow this convention and throws the error:#include <QObject>
WARNING: <file name>:<line number> includes QObject when it should include QtCore/QObject |
Artifacts
syncqt uses public headers to produce the following artifacts:
- CaMeL case header file aliases
- CaMeL case header files are aliases named after public Qt classes. syncqt uses public symbols, like classes, structures, typedefs, and aliases from header files and produces CaMeL case header files based on this input.
- Deprecated header files
- In situations when some public header files are not relevant anymore and should be removed, they should be marked as deprecated first so users have time to adapt their code and use the header file replacement. See #Pragma deprecates
- Version header file
- Header file that contains macros definitions with the module version information. This information is used by Qt versioning macros, but it's also possible to use them in user code directly.
- "Master" header file
- Header file with the name. The file contains the includes of all public header files provided by the module. syncqt also checks if the public header contains
Qt<Module>
macros call and guards the header file including directive with correspondingQT_REQUIRE_CONFIG
check.QT_CONFIG
Also, syncqt produces the build time header file aliases in the build directory that allow using conventional paths in include directives. These aliases are never installed nor delivered as part of Qt distribution.
Deployment path
include/Qt<Module>
Pragmas
It's possible to control the syncqt behavior and output using the special C++ pragmas. To avoid any compilation error you should use these syncqt-specific pragmas as follows:
#ifdef 0
# pragma <pragma name>
#endif
Pragma qt_deprecates
Syntax
#pragma qt_deprecates(<deprecated header file>[,<major.minor>])
Description
Pragma indicates that the header file where this pragma is used replaces the one mentioned in pragma. The replaced header file will be generated containing a warning with the deprecation notice. For example in qttestglobal.h there is(or was) the following code:
#if 0
# pragma qt_deprecates(qtest_global.h)
#endif
syncqt will generate the qtest_global.h header file with
#include <QtTest/qttestglobal.h>
and the warning that says that the file is deprecated and
QtTest/qttestglobal.h
should be used instead.
Adding the version argument to the pragma will also limit the deprecated header file lifetime. Once Qt reaches the version that is set as the second argument, the deprecated header file will not be generated by syncqt, but syncqt will show the warning when compiling the Qt itself.
Pragma qt_sync_skip_header_check
Syntax
#pragma qt_sync_skip_header_check
Description
This pragma tells syncqt that it should ignore any errors that are found in a header file. Please use this pragma only if you are confident that the header matches the Qt's requirements.
Pragma qt_sync_stop_processing
Syntax
#pragma qt_sync_stop_processing
Description
This pragma tells syncqt that it should stop any header processing from the point where the pragma is found. syncqt stops both checking the header file for errors and collecting artifacts to generate additional header files.
Pragma qt_sync_suspend_processing
Syntax
#pragma qt_sync_suspend_processing
Description
When syncqt faces this pragma in code it temporarily suspends checking the header file for error and collecting artifacts to generate additional header files. The processing can be resumed by the qt_sync_resume_processing pragma. If
qt_sync_suspend_processing
is not followed by
qt_sync_resume_processing
the behavior of
qt_sync_suspend_processing
is the same as the behavior of qt_sync_stop_processing.
Pragma qt_class
Syntax
#pragma qt_class(<symbol>)
Description
The pragma requests generating of the header file alias with the symbol name. For example, use the following code in qassert.h:
#pragma qt_class(QtAssert)
syncqt generates the QtAssert header file with the inclusion of qassert.h.
Note: syncqt doesn't detect the file name collisions at the moment when this topic is written, so conflicting files will be overwritten in undefined order.
Pragma qt_no_master_include
Syntax
#pragma qt_no_master_include
Description
The pragma indicates to syncqt that the header file shouldn't be included in the module's master header file.
CMake integration
syncqt is part of the Qt build system and it runs implicitly for all Qt modules that are created using the
qt_internal_add_module
command and other
qt_internal_
command that imply the
qt_internal_add_module
call. There are not too many arguments of the
qt_internal_add_module
command that controls the syncqt behavior.
NO_SYNC_QT
Skips syncqt processing of the module header files.
<PRIVATE|QPA|RHI>_HEADER_FILTERS
Indicates accepts the CMake regular expression as an argument and indicates how header files of the corresponding type should be filtered from others.
HEADER_SYNC_SOURCE_DIRECTORY
The source directory for the header sync procedure. Header files outside this directory will be ignored by syncqt.