Skip to content
Snippets Groups Projects
Commit f34d5f7d authored by Alexandru Croitor's avatar Alexandru Croitor
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
# Discussion topics
* [API review](api.md)
* Naming of `add_qt_gui_executable`
* Naming of internal functions in public Macros files
* Current code is mixed, some uses `_qt` some uses `_qt_internal`, some might not be prefixed
* Proposal: use `_qt_internal_foo()` aka an underscore followed by `qt_internal`
* Scope finalizer behavior
* `cmake_language(DEFER CALL)` aka qmake's `CONFIG += foo` and `foo.prf`
* Best way to leverage it for our API
* Should we consider using `find_package(Qt)` magic to call finalizers
* https://cmake.org/cmake/help/git-master/command/cmake_language.html#defer
* https://bugreports.qt.io/browse/QTBUG-77377
* Should new CMake Public APIs be declared Technical Preview for Qt 6.0?
* (Spoiler - Alexandru thinks yes)
* Most of the new public APIs are not tested at all
* Especially `qt_add_plugin()` and `qt_add_qml_module()` are complex and thus might not work (due to not being tested)
## Gerrit review changes
* qtbase
* https://codereview.qt-project.org/c/qt/qtbase/+/317353
* qtdeclarative
* https://codereview.qt-project.org/c/qt/qtdeclarative/+/317354
* qtshadertools
* https://codereview.qt-project.org/c/qt/qtshadertools/+/317356
* qtquick3d
* https://codereview.qt-project.org/c/qt/qtquick3d/+/317355
* qtremoteobjects
* https://codereview.qt-project.org/c/qt/qtremoteobjects/+/317358
api.md 0 → 100644
# New public API
A bunch of new CMake public API functions or renamed functions from `qt5_` to `qt6_`.
<br>
# qtbase
https://github.com/qt/qtbase/blob/dev/src/corelib/Qt6CoreMacros.cmake
<br>
`qt6_make_output_file` - marked deprecated in qt5, should be internal?
<br>
`qt6_get_moc_flags` - marked deprecated in qt5, should be internal?
<br>
`qt6_create_moc_command` - marked deprecated in qt5, should be internal?
<br>
`qt6_generate_moc` - renamed from qt5_, has versionless
<br>
`add_qt_gui_executable` - maybe rename to `add_qt_executable`, or `qt_add_executable`?
```cmake
function(add_qt_gui_executable target)
add_executable("${target}" WIN32 MACOSX_BUNDLE ${ARGN})
add_library("${target}" MODULE ${ARGN}) # android
target_link_libraries("${target}" PRIVATE Qt::Core)
if(TARGET Qt::Gui)
target_link_libraries("${target}" PRIVATE Qt::Gui)
endif()
endfunction()
```
<br>
`qt6_generate_meta_types_json_file` - new, has versionless
```cmake
# Generate Qt metatypes.json for a target.
#
# INSTALL_DIR: Location where to install the metatypes file. For public consumption defaults to a ${CMAKE_INSTALL_PREFIX}/lib/metatypes directory.
#
# COPY_OVER_INSTALL: (Qt Internal) When present will install the file via a post build step copy rather than using install.
#
# MANUAL_MOC_JSON_FILES: list of manually generated json files
function(qt6_generate_meta_types_json_file target)
```
<br>
`qt6_generate_win32_rc_file` - new, has versionless
```cmake
# Generate Win32 RC files for a target.
# All entries in the RC file are generated
# from target properties:
# QT_TARGET_COMPANY_NAME, QT_TARGET_DESCRIPTION, etc.
# The QT_TARGET_WINDOWS_RC_FILE prop can be used to specify a custom RC file instead of autogenerating one
function(qt6_generate_win32_rc_file target)
```
<br>
`qt6_add_plugin` - new, has versionless
```cmake
# Build a Qt plugin.
# No installation behavior.
# Might be missing some implementation details that are handled by the internal counterpart.
# Arguments:
# STATIC: Make it a static plugin
# OUTPUT_NAME: name of the plugin file
# CLASS_NAME
# TYPE: imageformats, etc
function(qt6_add_plugin target)
```
<br>
`qt6_disable_utf8_sources` - new, has versionless
```cmake
# By default Qt6 forces usage of utf8 sources for consumers of Qt.
# Users can opt out of utf8 sources by calling this function with the target name of their application or library.
function(qt6_disable_utf8_sources target)
```
<br>
`qt6_add_resources` - old, has versionless, new `TARGET` behavior instead of outfiles var.
```cmake
# When using this command with static libraries, one or more special targets
# will be generated. Should you wish to perform additional processing on these targets pass a value to the OUTPUT_TARGETS parameter.
function(qt6_add_resources outfiles )
if (TARGET ${outfiles})
```
<br>
https://github.com/qt/qtbase/blob/dev/src/corelib/Qt6AndroidMacros.cmake
`qt6_android_generate_deployment_settings` - new, has versionless, should be internal?
```cmake
# Generate the deployment settings json file for a cmake target.
# Uses global vars
# ANDROID_NDK
# ANDROID_SDK_ROOT
# ANDROID_NDK_HOST_SYSTEM_NAME
# CMAKE_ANDROID_ARCH_ABI
# QT_ANDROID_APPLICATION_ARGUMENTS
# QT_HOST_PATH
# CMAKE_SYSROOT
# Uses target properties:
# QT_ANDROID_DEPLOYMENT_DEPENDENCIES
# QT_ANDROID_EXTRA_PLUGINS
# QT_ANDROID_EXTRA_LIBS
# QT_ANDROID_PACKAGE_SOURCE_DIR
# QT_QML_IMPORT_PATH
# QT_QML_ROOT_PATH
# Sets target property:
# QT_ANDROID_DEPLOYMENT_SETTINGS_FILE
#
function(qt6_android_generate_deployment_settings target)
```
<br>
`qt6_android_apply_arch_suffix` - new, has versionless, should be internal?
```cmake
function(qt6_android_apply_arch_suffix target)
get_target_property(target_type ${target} TYPE)
if (target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY")
set_property(TARGET "${target}" PROPERTY SUFFIX "_${CMAKE_ANDROID_ARCH_ABI}.so")
endif()
endfunction()
```
<br>
`qt6_android_add_apk_target` - new, has versionless, should be internal?
```cmake
# Add custom target to package the APK
# Uses global vars:
# QT_HOST_PATH
# CMAKE_ANDROID_ARCH_ABI
# QT_NO_GLOBAL_APK_TARGET - allow opt out of global target add_dependencies
# Uses target properties:
# QT_ANDROID_DEPLOYMENT_SETTINGS_FILE
function(qt6_android_add_apk_target target)
```
<br>
`qt6_android_get_sdk_build_tools_revision` - new, has versionless, should be internal?
```cmake
# Locate newest Android sdk build tools revision
# Uses global vars:
# ANDROID_SDK_ROOT
function(qt6_android_get_sdk_build_tools_revision out_var)
```
# qtdeclarative
https://github.com/qt/qtdeclarative/blob/dev/src/qml/Qt6QmlMacros.cmake
`qt6_import_qml_plugins` - old, has versionless
```cmake
# For static builds only.
# Calls qmlimportscanner, links in used qml plugins, generates and compiles a cpp file with relevant Q_IMPORT_PLUGIN() macro calls.
#
# Arguments:
# PATH_TO_SCAN: Path to pass to qmlimportscanner to scan .qml files for the modules they use.
function(qt6_import_qml_plugins target)
```
<br>
`qt6_add_qml_module` - new, has versionless
```cmake
# Creates a QML module.
# Arguments:
# URI: Declares the module identifier of the module (REQUIRED)
# VERSION: The module's version. (REQUIRED)
# TARGET_PATH: Overwrite the generated target path. (OPTIONAL)
# RESOURCE_PREFIX: Resource Prefix to be used when generating a static library. (OPTIONAL)
# OUTPUT_DIRECTORY: If the module is not to be built under ${CMAKE_CURRENT_BINARY_DIR}. This ensures the qmldir file is copied to the right location. (OPTIONAL)
# INSTALL_LOCATION: Intended installation directory for this module. Default installation path will be ${INSTALL_QMLDIR}. (OPTIONAL).
# DO_NOT_INSTALL_METADATA: Will not install supporting files.
# INSTALL_QML_FILES: Will install the qml files along side the plugin.
# SOURCES: List of C++ sources. (OPTIONAL)
# DEPENDENCIES: List of QML Module dependencies and their versions. The module and its version must be separated via a slash(/). E.g. QtQuick/2.0
# QML_FILES: List of Qml files.
# CLASSNAME: Provides the class name of the C++ plugin used by the module. (REQUIRED for static targets)
# DESIGNER_SUPPORTED: Specify this argument if the plugin is supported by Qt Designer (OPTIONAL)
# TYPEINFO: Path to a file which declares a type description file for the module that can be read by QML tools such as Qt Creator to access information about the types defined by the module's plugins. (OPTIONAL)
# IMPORTS: List of other Qml Modules that this module imports. (OPTIONAL)
# OPTIONAL_IMPORTS: List of other Qml Modules that this module may import at
# run-time. Those are not automatically imported by the QML engine when
# importing the current module, but rather serve as hints to tools like
# qmllint. (OPTIONAL)
# RESOURCE_EXPORT: In static builds, processed QML files are compiled into a static lib, this names the target.
# SKIP_TYPE_REGISTRATION: When present will cause the generated qmldir file
# to not list any qml types. These are expected to be registered by the
# c++ plugin code instead.
# PLUGIN_OPTIONAL: The plugin is marked as optional in the qmldir file.
function(qt6_add_qml_module target)
```
`qt6_target_qml_files` - new, has versionless
```cmake
# Add Qml files (.qml,.js,.mjs) to a Qml module. This will also append the
# qml files to the qmldir file of the module. Source file properties can
# be used to control the generated qmldir entry.
# QT_QML_SOURCE_VERSION: Version(s) for this qml file.
# QT_QML_SOURCE_TYPENAME: Override the file's type name.
# QT_QML_SINGLETON_TYPE: The qml file contains a singleton type.
# QT_QML_INTERNAL_TYPE: When set to true, the type specified by
# QT_QML_SOURCE_TYPENAME will not be available to users of this module.
# QT_QML_SKIP_QMLDIR_ENTRY: No qmldir entry will be created for the source file. Useful if a file needs to be installed (like a private JS file) but does not expose a public type.
function(qt6_target_qml_files target)
```
<br>
`qt6_qml_type_registration` - new, has versionless, should be internal?
```cmake
# Creates a .qmltypes file and compiles an auto-generated "${target}_qmltyperegistrations.cpp" file.
# Target properties used:
# QT_QMLTYPES_FILENAME: Used for the name of the generated file.
# QT_QML_MODULE_URI: Module URI of target
# QT_QML_MODULE_VERSION: Module version
# QT_QML_MODULE_INSTALL_DIR: Install location for .qmltypes file
# QT_QML_MODULE_INSTALL_QMLTYPES: Whether to install the .qmltypes file
# Sets properties:
# QT_QML_MODULE_PLUGIN_TYPES_FILE - path to the generated .qmltypes file
function(qt6_qml_type_registration target)
```
# qtquick3d
https://github.com/qt/qtquick3d/blob/dev/src/quick3d/Qt6Quick3DMacros.cmake
`qt6_quick3d_build_shaders` - new, has versionless
```cmake
# Generates shaders from the given files and links the compiled resource files into ${target}.
#
# Arguments used:
# resource_name: creates .qrc file based on value of the argument
# FILES: list of shader file paths
function(qt6_quick3d_build_shaders target resource_name)
```
# qtshadertools
https://github.com/qt/qtshadertools/blob/dev/src/shadertools/Qt6ShaderToolsMacros.cmake
`qt6_add_shaders` - new, has versionless
```cmake
# Invokes qsb on each file in FILES. Extensions must be .vert, .frag, or .comp.
# The resulting .qsb files are added as resources under PREFIX.
# target and resourcename are like for qt6_add_resources.
# Uses qt6_add_resources.
#
# Arguments used:
#
# FILES: list of file paths, e.g. color.vert
# DEFINES: list of custom macros for glslang
# PREFIX: Qt resource prefix to use, e.g "/shaders"
#
# BATCHABLE: enable generating batchable vertex shader variants
# PRECOMPILE: invoke native tools where applicable
# PERTARGETCOMPILE: compile to SPIR-V and translate separately per output language version
# NOGLSL: skip generating the language
# NOHLSL: skip generating the language
# NOMSL: skip generating the language
# DEBUGINFO: generate full debug
# OPTIMIZED: optimize for performance
# GLSL: override the version to generate
# HLSL: override the version to generate
# MSL: override the version to generate
function(qt6_add_shaders target resourcename)
```
# qtremoteobjects
https://github.com/qt/qtremoteobjects/blob/dev/src/remoteobjects/Qt5RemoteObjectsMacros.cmake
https://github.com/qt/qtremoteobjects/blob/dev/src/remoteobjects/Qt6RemoteObjectsMacros.cmake
All the functions below seem to implement what `qt5_generate_repc` does, but with completely new names and arguments. `qt5_generate_repc` is not ported to `qt6_` atm.
<br>
`qt6_add_repc_files` - new, no versionless yet
```cmake
# Calls `repc` on list of FILES and adds them as `target` sources.
#
# Arguments:
# type: one of 'source', 'replica', 'merged'
# FILES: list of files to call repc on
function(qt6_add_repc_files type target)
```
<br>
`qt6_add_repc_source` - new, no versionless yet
Calls `qt6_add_repc_files` with `type` set to `source`.
<br>
`qt6_add_repc_replica` - new, no versionless yet
Calls `qt6_add_repc_files` with `type` set to `replica`.
<br>
`qt6_add_repc_merged` - new, no versionless yet
Calls `qt6_add_repc_files` with `type` set to `merged`.
<br>
`qt6_rep_from_header` - new, no versionless yet
```cmake
# Creates a .rep interface file from a QObject header
#
# Arguments:
# ${ARGN}: list of files to run `repc -o rep` on.
function(qt6_rep_from_header target)
```
\ No newline at end of file
CMake 3.19 brings in a feature similar to qmake's `CONFIG += foo` loading `foo.prf` after parsing a `project.pro` file.
In CMake, instead of loading a file, we can call a function after processing a CMakeLists.txt file.
We could leverage this new feature to make CMake Qt APIs nicer,
by not forcing the user to call various functions at the end of each of their projects.
Consider the projects in finalizers0.cmake
# Approach 1: Straightforward
cmake_minimum_required(VERSION 3.18)
project(proj LANGUAGES CXX)
function(qt_add_qml_module target)
add_executable(${target})
# ....
# Register finalizers to run after the CMakeLists.txt file is processed.
cmake_language(DEFER CALL DIRECTORY "${CMAKE_SOURCE_DIR}" qt_run_qml_compiler "${target}")
cmake_language(DEFER CALL DIRECTORY "${CMAKE_SOURCE_DIR}" qt_auto_set_bundle_info_list "${target}")
cmake_language(DEFER CALL DIRECTORY "${CMAKE_SOURCE_DIR}" qt_import_qml_plugins "${target}")
endfunction()
function(qt_run_qml_compiler target)
# Make the function no-op, so that once a user upgrades to CMake 3.19+, existing projects
# that explicitly call qt_run_qml_compiler() don't break.
get_target_property(processed "${target}" _qt_run_qml_compiler_processed)
if(processed)
return()
endif()
set_target_properies("${target}" PROPERTIES _qt_run_qml_compiler_processed TRUE)
get_target_property(qml_files "${target}" QT_QML_MODULE_FILES)
# ... process
endfunction()
find_package(Qt6Qml)
qt_add_qml_module(Foo)
qt_target_qml_files(Foo a.qml)
if(APPLE)
qt_target_qml_files(Foo apple.qml)
endif()
qt_run_qml_compiler(target)
# Once user upgrades to CMake 3.19+, no need to call
# qt_run_qml_compiler manually anymore.
# Approach2: Alternative approach with crazy magic, resembling qmake's behavior more closely
# $ cat Qt6Config.cmake
# ....
function(qt_add_qml_module target)
add_executable(${target}) # No finalizer
endfunction()
add_library(Qt6::Core IMPORTED)
cmake_language(DEFER CALL DIRECTORY "${CMAKE_SOURCE_DIR}" qt_finalizer_magic) # run after processing ALL CMakeLists.txt
# Perhaps only CMakeLists.txt under the scope of the current directory's find_package(Qt6Core) call.
# This function gets all targets below this directory
function(get_all_targets _result _dir)
get_property(_subdirs DIRECTORY "${_dir}" PROPERTY SUBDIRECTORIES)
foreach(_subdir IN LISTS _subdirs)
get_all_targets(${_result} "${_subdir}")
endforeach()
get_property(_sub_targets DIRECTORY "${_dir}" PROPERTY BUILDSYSTEM_TARGETS)
set(${_result} ${${_result}} ${_sub_targets} PARENT_SCOPE)
endfunction()
# Iterate over all targets in all projects, and run magic qt code for any target linking against a Qt6:: lib.
function(qt_finalizer_magic)
get_all_targets(targets "${CMAKE_CURRENT_SOURCE_DIR}")
foreach(target ${targets})
get_target_property(libs ${target} LINK_LIBRARIES)
foreach(lib ${libs})
if(lib MATCHES "^Qt6::")
qt_finalize_target(${target})
endif()
endforeach()
endforeach()
endfunction()
function(qt_finalize_target target)
qt_run_qml_compiler("${target}")
qt_auto_set_bundle_info_list("${target}")
qt_import_qml_plugins("${target}")
# .... other finalizers
endfunction()
# Possible problems with approach 2
# Doing finalization things outside of the directory scope where the target is defined can lead to problems.
# * Automatic Qt linkage detection might not work in all cases
# * add_custom_command doesn't work properly
# * GENERATED files don't work properly
# * Might be fixed in 3.20 via https://gitlab.kitware.com/cmake/cmake/-/merge_requests/5308
# * Can partially be worked around using set_source_files_properties() + DIRECTORY option
# * other issues i'm not aware of yet
# * no PoC implemented yet :(
# Use case 1: Running qml compiler
function(qt_add_qml_module target)
add_executable(${target})
# ....
# Register finalizer to run after all CMakeLists.txt files are processed.
cmake_language(DEFER CALL DIRECTORY "${CMAKE_SOURCE_DIR}" qt_run_qml_compiler "${target}" more args here)
endfunction()
# Generate and compile cpp files.
function(qt_run_qml_compiler target)
get_target_property(qml_files "${target}" _qt_qml_files)
foreach(qml_file ${qml_files})
add_custom_command(OUTPUT "compiled_${qml_file}.cpp" COMMAND qml_cpp_generator ...)
target_sources("${target}" "compiled_${qml_file}.cpp")
endforeach()
endfunction()
# Mini project
cmake_minimum_required(VERSION 3.14.0)
project(proj LANGUAGES CXX)
add_subdirectory(a1)
add_subdirectory(a2)
# a1/CMakeLists.txt
qt_add_qml_module(Foo)
qt_target_qml_files(Foo a.qml)
if(APPLE)
qt_target_qml_files(Foo b.qml)
endif()
# once all CMakeLists.txt files are processed (just before configuration ends)
# run deferred qt_run_qml_compiler()
# Use case 2: Provide a custom Info.plist default
function(qt_add_executable target)
add_executable(${target} ${ARGN})
# ....
# Register finalizer to set MACOSX_BUNDLE_INFO_PLIST
# if it's not set already set.
cmake_language(DEFER CALL qt_auto_set_bundle_info_list "${target}")
endfunction()
function(qt_auto_set_bundle_info_list target)
get_target_property(info_plist "${target}" MACOSX_BUNDLE_INFO_PLIST)
if(NOT info_plist)
set(info_plist "${Qt6_DIR}/Info.plist")
set_target_properties("${target}" PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${info_plist}")
endif()
endfunction()
# Mini project
cmake_minimum_required(VERSION 3.15)
project(app)
qt_add_executable(app main.cpp)
# Use case 3: static plugins auto linking
function(qt_add_executable target)
add_executable(${target} ${ARGN})
# ....
# Register finalizer to link in static plugins depending
# on which libraries are in LINK_LIBRAIRES and extra information
# set by qt_import_plugins.
cmake_language(DEFER CALL qt_auto_import_plugins "${target}")
endfunction()
function(qt_auto_import_plugins target)
get_target_property(plugins "${target}" QT_PLUGINS)
foreach(plugin ${plugins})
target_link_libraries("${target}" "${plugin}")
endforeach()
endfunction()
function(qt_import_plugins target)
# ....
set_property(TARGET "${target}" APPEND PROPERTY QT_PLUGINS "${plugin}")
# ....
endfunction()
cmake_minimum_required(VERSION 3.15)
project(proj LANGUAGES CXX)
qt_add_executable(app main.cpp)
target_link_libraries(app PRIVATE Qt::Gui Qt::OpenGL)
qt_import_plugins(app INCLUDE Qt::QXcbIntegrationPlugin)
# General notes
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment