Syncqt
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. #include <QtCore/QCoreApplication> because QCoreApplication is a public symbol / class
- Header file that contains the module version information, and named as <module>Version, e.g. 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 QT_<BEGIN|END>NAMESPACE 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:
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 #include <QtCore/QObject> but not #include <QObject> in public header files. syncqt detects include directives that don't follow this convention and throws the error:
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 Qt<Module> name. The file contains the includes of all public header files provided by the module. syncqt also checks if the public header contains QT_REQUIRE_CONFIG macros call and guards the header file including directive with corresponding QT_CONFIG 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.
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.