qt 6.6.0 clean

This commit is contained in:
kleuter 2023-11-01 22:23:55 +01:00
parent 7b5ada15e7
commit 5d8194efa7
1449 changed files with 134276 additions and 31391 deletions

View File

@ -5,10 +5,9 @@
# (directly by qtbase) we actually add the extra definitions
if (NOT DEFINED QT_SUPERBUILD OR DEFINED QT_REPO_MODULE_VERSION)
set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_LEAN_HEADERS=1")
list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1")
endif()
set(QT_REPO_MODULE_VERSION "6.5.3")
set(QT_REPO_MODULE_VERSION "6.6.0")
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
set(QT_COPYRIGHT_YEAR "2023")
@ -17,12 +16,14 @@ set(QT_COPYRIGHT "Copyright (C) ${QT_COPYRIGHT_YEAR} The Qt Company Ltd and othe
# Minimum requirement for building Qt
set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT_SHARED "3.16")
set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT_STATIC "3.21")
set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT_APPLE "3.21")
# Minimum requirement for consuming Qt in a user project.
# This might be different in the future, e.g. be lower than the requirement for
# building Qt.
set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_SHARED "3.16")
set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_STATIC "3.21")
set(QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_APPLE "3.21")
# Policy settings for commands defined by qtbase. These will also be injected
# into the top level policy scope of each Qt module when building Qt so that

View File

@ -1 +1 @@
QT_PACKAGEDATE_STR=2023-09-25
QT_PACKAGEDATE_STR=2023-10-04

2
.tag
View File

@ -1 +1 @@
372eaedc5b8c771c46acc4c96e91bbade4ca3624
33f5e985e480283bb0ca9dea5f82643e825ba87c

View File

@ -1,8 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# special case skip regeneration
# Need an explicit call at the top level. This is the absolute minimum version
# needed to configure the project with any combination of enabled features.
# The call to qt_build_repo_begin() will upgrade policies further.

View File

@ -0,0 +1,18 @@
@echo off
:: The directory of this script is the expanded absolute path of the "$qt_prefix/bin" directory.
set script_dir_path=%~dp0
:: Try to use original cmake, otherwise to make it relocatable, use any cmake found in PATH.
set cmake_path=@CMAKE_COMMAND@
if not exist "%cmake_path%" set cmake_path=cmake
if NOT "%~2" == "" goto :showhelp
if NOT "%~1" == "" (set PROJECT_DIR=%~1) else (set PROJECT_DIR=%cd%)
"%cmake_path%" -DPROJECT_DIR="%PROJECT_DIR%" -P "%script_dir_path%\@__GlobalConfig_relative_path_from_bin_dir_to_cmake_config_dir@\QtInitProject.cmake"
exit /b %errorlevel%
:showhelp
echo Usage
echo. qt-cmake-create <path/to/project>
exit /b 1

29
bin/qt-cmake-create.in Normal file
View File

@ -0,0 +1,29 @@
#!/bin/sh
HELP_MESSAGE="Usage
qt-cmake-create <path/to/project>"
# The directory of this script is the expanded absolute path of the "$qt_prefix/bin" directory.
script_dir_path=`dirname $0`
script_dir_path=`(cd "$script_dir_path"; /bin/pwd)`
# Try to use original cmake, otherwise to make it relocatable, use any cmake found in PATH.
original_cmake_path="@CMAKE_COMMAND@"
cmake_path=$original_cmake_path
if ! test -f "$cmake_path"; then
cmake_path="cmake"
fi
if [ "$#" -gt 1 ]; then
echo "Invalid number of arguments"
echo "$HELP_MESSAGE"
exit 1
fi
if [ "$#" -gt 0 ]; then
PROJECT_DIR=$1
else
PROJECT_DIR=$PWD
fi
exec "$cmake_path" -DPROJECT_DIR="$PROJECT_DIR" -P \
"$script_dir_path/@__GlobalConfig_relative_path_from_bin_dir_to_cmake_config_dir@/QtInitProject.cmake"

98
cmake/FindMimer.cmake Normal file
View File

@ -0,0 +1,98 @@
# Copyright (C) 2022 The Qt Company Ltd.
# Copyright (C) 2022 Mimer Information Technology
# SPDX-License-Identifier: BSD-3-Clause
# FindMimer
# ---------
# Try to locate the Mimer SQL client library
if(NOT DEFINED MimerSQL_ROOT)
if(DEFINED ENV{MIMERSQL_DEV_ROOT})
set(MimerSQL_ROOT "$ENV{MIMERSQL_DEV_ROOT}")
endif()
endif()
if(NOT DEFINED MimerSQL_ROOT)
find_package(PkgConfig QUIET)
endif()
if(PkgConfig_FOUND AND NOT DEFINED MimerSQL_ROOT)
pkg_check_modules(PC_Mimer QUIET mimcontrol)
set(MimerSQL_include_dir_hints "${PC_MimerSQL_INCLUDEDIR}")
set(MimerSQL_library_hints "${PC_MimerSQL_LIBDIR}")
else()
if(DEFINED MimerSQL_ROOT)
if(WIN32)
set(MimerSQL_include_dir_hints "${MimerSQL_ROOT}\\include")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|X86)$")
set(MimerSQL_library_hints "${MimerSQL_ROOT}\\lib\\x86")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(amd64|AMD64)$")
set(MimerSQL_library_hints "${MimerSQL_ROOT}\\lib\\amd64")
else()
set(MimerSQL_library_hints "")
endif()
else()
set(MimerSQL_include_dir_hints "${MimerSQL_ROOT}/include")
set(MimerSQL_library_hints "${MimerSQL_ROOT}/lib")
endif()
else()
if(WIN32)
set(MimerSQL_include_dir_hints "C:\\MimerSQLDev\\include")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|X86)$")
set(MimerSQL_library_hints "C:\\MimerSQLDev\\lib\\x86")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(amd64|AMD64)$")
set(MimerSQL_library_hints "C:\\MimerSQLDev\\lib\\amd64")
else()
set(MimerSQL_library_hints "")
endif()
elseif(APPLE AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(MimerSQL_library_hints "/usr/local/lib")
set(MimerSQL_include_dir_hints "/usr/local/include")
else()
set(MimerSQL_include_dir_hints "")
set(MimerSQL_library_hints "")
endif()
endif()
endif()
find_path(Mimer_INCLUDE_DIR
NAMES mimerapi.h
HINTS ${MimerSQL_include_dir_hints})
if(WIN32)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|X86)$")
set(MIMER_LIBS_NAMES mimapi32)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(amd64|AMD64)$")
set(MIMER_LIBS_NAMES mimapi64)
endif()
else()
set(MIMER_LIBS_NAMES mimerapi)
endif()
find_library(Mimer_LIBRARIES
NAMES ${MIMER_LIBS_NAMES}
HINTS ${MimerSQL_library_hints})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Mimer
REQUIRED_VARS Mimer_LIBRARIES Mimer_INCLUDE_DIR)
# Now try to get the include and library path.
if(Mimer_FOUND)
set(Mimer_INCLUDE_DIRS ${Mimer_INCLUDE_DIR})
set(Mimer_LIBRARY_DIRS ${Mimer_LIBRARIES})
if (NOT TARGET MimerSQL::MimerSQL)
add_library(MimerSQL::MimerSQL UNKNOWN IMPORTED)
set_target_properties(MimerSQL::MimerSQL PROPERTIES
IMPORTED_LOCATION "${Mimer_LIBRARY_DIRS}"
INTERFACE_INCLUDE_DIRECTORIES "${Mimer_INCLUDE_DIRS}")
endif ()
endif()
mark_as_advanced(Mimer_INCLUDE_DIR Mimer_LIBRARIES)
include(FeatureSummary)
set_package_properties(MimerSQL PROPERTIES
URL "https://www.mimer.com"
DESCRIPTION "Mimer client library")

View File

@ -0,0 +1,53 @@
# Copyright (C) 2022 The Qt Company Ltd.
# Copyright (C) 2023 Intel Corpotation.
# SPDX-License-Identifier: BSD-3-Clause
# We can't create the same interface imported target multiple times, CMake will complain if we do
# that. This can happen if the find_package call is done in multiple different subdirectories.
if(TARGET WrapResolv::WrapResolv)
set(WrapResolv_FOUND ON)
return()
endif()
set(WrapResolv_FOUND OFF)
include(CheckCXXSourceCompiles)
include(CMakePushCheckState)
if(QNX)
find_library(LIBRESOLV socket)
else()
find_library(LIBRESOLV resolv)
endif()
cmake_push_check_state()
if(LIBRESOLV)
list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBRESOLV}")
endif()
check_cxx_source_compiles("
#include <netinet/in.h>
#include <resolv.h>
int main(int, char **argv)
{
res_state statep;
int n = res_nmkquery(statep, 0, argv[1], 0, 0, NULL, 0, NULL, NULL, 0);
n = res_nsend(statep, NULL, 0, NULL, 0);
n = dn_expand(NULL, NULL, NULL, NULL, 0);
return n;
}
" HAVE_LIBRESOLV_FUNCTIONS)
cmake_pop_check_state()
if(HAVE_LIBRESOLV_FUNCTIONS)
set(WrapResolv_FOUND ON)
add_library(WrapResolv::WrapResolv INTERFACE IMPORTED)
if(LIBRESOLV)
target_link_libraries(WrapResolv::WrapResolv INTERFACE "${LIBRESOLV}")
endif()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WrapResolv DEFAULT_MSG WrapResolv_FOUND)

View File

@ -21,17 +21,31 @@ if(LIBRT)
endif()
check_cxx_source_compiles("
#include <unistd.h>
#include <time.h>
#include <unistd.h>
int main(int, char **) {
timespec ts; clock_gettime(CLOCK_REALTIME, &ts);
}" HAVE_GETTIME)
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return 0;
}
" HAVE_GETTIME)
check_cxx_source_compiles("
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
int main(int, char **) {
shm_open(\"test\", O_RDWR | O_CREAT | O_EXCL, 0666);
shm_unlink(\"test\");
return 0;
}
" HAVE_SHM_OPEN_SHM_UNLINK)
cmake_pop_check_state()
if(HAVE_GETTIME)
if(HAVE_GETTIME OR HAVE_SHM_OPEN_SHM_UNLINK)
set(WrapRt_FOUND ON)
add_library(WrapRt::WrapRt INTERFACE IMPORTED)
if (LIBRT)

View File

@ -48,6 +48,26 @@ if(Vulkan_INCLUDE_DIR)
target_include_directories(WrapVulkanHeaders::WrapVulkanHeaders INTERFACE
${__qt_molten_vk_homebrew_include_path})
endif()
# Check for homebrew vulkan-headers folder structure
# If instead of molten-vk folder, CMAKE_PREFIX_PATH points to Homebrew's
# vulkan-headers installation, then we will not be able to find molten-vk
# headers. If we assume that user has installed the molten-vk formula as
# well, then we might have a chance to pick it up like this.
if(Vulkan_INCLUDE_DIR MATCHES "/homebrew/Cellar/")
set(__qt_standalone_molten_vk_homebrew_include_path
"${Vulkan_INCLUDE_DIR}/../../../../opt/molten-vk/include")
else()
set(__qt_standalone_molten_vk_homebrew_include_path
"${Vulkan_INCLUDE_DIR}/../../molten-vk/include")
endif()
get_filename_component(
__qt_standalone_molten_vk_homebrew_include_path
"${__qt_standalone_molten_vk_homebrew_include_path}" ABSOLUTE)
if(EXISTS "${__qt_standalone_molten_vk_homebrew_include_path}")
target_include_directories(WrapVulkanHeaders::WrapVulkanHeaders INTERFACE
${__qt_standalone_molten_vk_homebrew_include_path})
endif()
endif()
endif()

View File

@ -28,10 +28,10 @@ include(FindPackageHandleStandardArgs)
if(TARGET zstd::libzstd_static OR TARGET zstd::libzstd_shared)
find_package_handle_standard_args(WrapZSTD
REQUIRED_VARS zstd_VERSION VERSION_VAR zstd_VERSION)
if(TARGET zstd::libzstd_static)
set(zstdtargetsuffix "_static")
else()
if(TARGET zstd::libzstd_shared)
set(zstdtargetsuffix "_shared")
else()
set(zstdtargetsuffix "_static")
endif()
if(NOT TARGET WrapZSTD::WrapZSTD)
add_library(WrapZSTD::WrapZSTD INTERFACE IMPORTED)

View File

@ -7,6 +7,7 @@
"compiler_target": "${CMAKE_CXX_COMPILER_TARGET}",
"compiler_version": "${CMAKE_CXX_COMPILER_VERSION}",
"cross_compiled": ${cross_compilation},
"target_system": "${CMAKE_SYSTEM_NAME}"
"target_system": "${CMAKE_SYSTEM_NAME}",
"architecture": "${TEST_architecture_arch}"
}
}

View File

@ -8,6 +8,9 @@
# Make sure to not run detection when building standalone tests, because the detection was already
# done when initially configuring qtbase.
# This needs to be here because QtAutoDetect loads before any other modules
option(QT_USE_VCPKG "Enable the use of vcpkg" ON)
function(qt_internal_ensure_static_qt_config)
if(NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build Qt statically or dynamically" FORCE)
@ -161,7 +164,7 @@ function(qt_auto_detect_android)
endfunction()
function(qt_auto_detect_vcpkg)
if(DEFINED ENV{VCPKG_ROOT})
if(QT_USE_VCPKG AND DEFINED ENV{VCPKG_ROOT})
set(vcpkg_toolchain_file "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
get_filename_component(vcpkg_toolchain_file "${vcpkg_toolchain_file}" ABSOLUTE)
@ -174,8 +177,8 @@ function(qt_auto_detect_vcpkg)
endif()
set(CMAKE_TOOLCHAIN_FILE "${vcpkg_toolchain_file}" CACHE STRING "" FORCE)
message(STATUS "Using vcpkg from $ENV{VCPKG_ROOT}")
if(DEFINED ENV{VCPKG_DEFAULT_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET)
set(VCPKG_TARGET_TRIPLET "$ENV{VCPKG_DEFAULT_TRIPLET}" CACHE STRING "")
if(DEFINED ENV{QT_VCPKG_TARGET_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET)
set(VCPKG_TARGET_TRIPLET "$ENV{QT_VCPKG_TARGET_TRIPLET}" CACHE STRING "")
message(STATUS "Using vcpkg triplet ${VCPKG_TARGET_TRIPLET}")
endif()
unset(vcpkg_toolchain_file)
@ -229,7 +232,9 @@ function(qt_auto_detect_ios)
endif()
set(CMAKE_OSX_ARCHITECTURES "${osx_architectures}" CACHE STRING "")
qt_internal_ensure_static_qt_config()
if(NOT DEFINED BUILD_SHARED_LIBS)
qt_internal_ensure_static_qt_config()
endif()
# Disable qt rpaths for iOS, just like mkspecs/common/uikit.conf does, due to those
# bundles not being able to use paths outside the app bundle. Not sure this is strictly
@ -239,7 +244,15 @@ function(qt_auto_detect_ios)
endfunction()
function(qt_auto_detect_cmake_config)
if(CMAKE_CONFIGURATION_TYPES)
# If CMAKE_CONFIGURATION_TYPES are not set for the multi-config generator use Release and
# Debug configurations by default, instead of those are proposed by the CMake internal logic.
get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(is_multi)
if(NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Release Debug)
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" PARENT_SCOPE)
endif()
# Allow users to specify this option.
if(NOT QT_MULTI_CONFIG_FIRST_CONFIG)
list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
@ -476,6 +489,12 @@ function(qt_auto_detect_integrity)
endif()
endfunction()
# Save the build type before project() might set one.
# This allows us to determine if the user has set an explicit build type that we should use.
function(qt_auto_detect_cmake_build_type)
set(__qt_auto_detect_cmake_build_type_before_project_call "${CMAKE_BUILD_TYPE}" PARENT_SCOPE)
endfunction()
# Let CMake load our custom platform modules.
# CMake-provided platform modules take precedence.
if(NOT QT_AVOID_CUSTOM_PLATFORM_MODULES)
@ -495,3 +514,4 @@ qt_auto_detect_wasm()
qt_auto_detect_win32_arm()
qt_auto_detect_linux_x86()
qt_auto_detect_integrity()
qt_auto_detect_cmake_build_type()

View File

@ -216,6 +216,7 @@ qt_copy_or_install(FILES
cmake/QtAndroidHelpers.cmake
cmake/QtAppHelpers.cmake
cmake/QtAutogenHelpers.cmake
cmake/QtBaseTopLevelHelpers.cmake
cmake/QtBuild.cmake
cmake/QtBuildInformation.cmake
cmake/QtCMakeHelpers.cmake
@ -332,6 +333,7 @@ set(__public_cmake_helpers
cmake/QtCopyFileIfDifferent.cmake
cmake/QtFeature.cmake
cmake/QtFeatureCommon.cmake
cmake/QtInitProject.cmake
cmake/QtPublicAppleHelpers.cmake
cmake/QtPublicCMakeHelpers.cmake
cmake/QtPublicCMakeVersionHelpers.cmake
@ -395,17 +397,30 @@ if(QT_WILL_INSTALL)
)
endif()
if(MACOS)
qt_copy_or_install(FILES
cmake/macos/MacOSXBundleInfo.plist.in
DESTINATION "${__GlobalConfig_install_dir}/macos"
if(APPLE)
if(MACOS)
set(platform_shortname "macos")
elseif(IOS)
set(platform_shortname "ios")
endif()
qt_copy_or_install(FILES "cmake/${platform_shortname}/Info.plist.app.in"
DESTINATION "${__GlobalConfig_install_dir}/${platform_shortname}"
)
elseif(IOS)
qt_copy_or_install(FILES
cmake/ios/Info.plist.app.in
cmake/ios/LaunchScreen.storyboard
DESTINATION "${__GlobalConfig_install_dir}/ios"
# For examples built as part of prefix build before install
file(COPY "cmake/${platform_shortname}/Info.plist.app.in"
DESTINATION "${__GlobalConfig_build_dir}/${platform_shortname}"
)
if(IOS)
qt_copy_or_install(FILES "cmake/ios/LaunchScreen.storyboard"
DESTINATION "${__GlobalConfig_install_dir}/ios"
)
# For examples built as part of prefix build before install
file(COPY "cmake/ios/LaunchScreen.storyboard"
DESTINATION "${__GlobalConfig_build_dir}/ios"
)
endif()
elseif(WASM)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/util/wasm/wasmtestrunner/qt-wasmtestrunner.py"
"${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-wasmtestrunner.py" @ONLY)

View File

@ -0,0 +1,85 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# Depends on __qt6_qtbase_src_path being set in the top-level dir.
macro(qt_internal_top_level_setup_autodetect)
# Run platform auto-detection /before/ the first project() call and thus
# before the toolchain file is loaded.
# Don't run auto-detection when doing standalone tests. In that case, the detection
# results are taken from either QtBuildInternals or the qt.toolchain.cmake file.
if(NOT QT_BUILD_STANDALONE_TESTS)
set(__qt6_auto_detect_path "${__qt6_qtbase_src_path}/cmake/QtAutoDetect.cmake")
if(NOT EXISTS "${__qt6_auto_detect_path}")
message(FATAL_ERROR "Required file does not exist: '${__qt6_auto_detect_path}'")
endif()
include("${__qt6_auto_detect_path}")
endif()
endmacro()
macro(qt_internal_top_level_setup_after_project)
# TODO: Remove this variable once the top-level calls this function and
# qt_internal_qt_configure_end is not called in qt_print_build_instructions anymore.
set(__qt6_top_level_after_project_called TRUE)
qt_internal_top_level_setup_testing()
endmacro()
macro(qt_internal_top_level_setup_testing)
# Required so we can call ctest from the root build directory
enable_testing()
endmacro()
# Depends on __qt6_qtbase_src_path being set in the top-level dir.
macro(qt_internal_top_level_setup_cmake_module_path)
if (NOT QT_BUILD_STANDALONE_TESTS)
set(__qt6_cmake_module_path "${__qt6_qtbase_src_path}/cmake")
if(NOT EXISTS "${__qt6_cmake_module_path}")
message(FATAL_ERROR "Required directory does not exist: '${__qt6_cmake_module_path}'")
endif()
list(APPEND CMAKE_MODULE_PATH "${__qt6_cmake_module_path}")
list(APPEND CMAKE_MODULE_PATH
"${__qt6_cmake_module_path}/3rdparty/extra-cmake-modules/find-modules")
list(APPEND CMAKE_MODULE_PATH "${__qt6_cmake_module_path}/3rdparty/kwin")
endif()
endmacro()
macro(qt_internal_top_level_before_build_submodules)
qt_internal_top_level_setup_no_create_targets()
endmacro()
macro(qt_internal_top_level_setup_no_create_targets)
# Also make sure the CMake config files do not recreate the already-existing targets
if (NOT QT_BUILD_STANDALONE_TESTS)
set(QT_NO_CREATE_TARGETS TRUE)
endif()
endmacro()
macro(qt_internal_top_level_end)
qt_internal_print_top_level_info()
# Depends on QtBuildInternalsConfig being included, which is the case whenver any repo is
# configured.
qt_internal_qt_configure_end()
endmacro()
function(qt_internal_print_top_level_info)
if(NOT QT_BUILD_STANDALONE_TESTS)
# Display a summary of everything
include(QtBuildInformation)
include(QtPlatformSupport)
qt_print_feature_summary()
qt_print_build_instructions()
endif()
endfunction()
macro(qt_internal_top_level_after_add_subdirectory)
if(module STREQUAL "qtbase")
if (NOT QT_BUILD_STANDALONE_TESTS)
list(APPEND CMAKE_PREFIX_PATH "${QtBase_BINARY_DIR}/${INSTALL_LIBDIR}/cmake")
list(APPEND CMAKE_FIND_ROOT_PATH "${QtBase_BINARY_DIR}")
endif()
endif()
endmacro()

View File

@ -281,7 +281,7 @@ qt_setup_tool_path_command()
# Platform define path, etc.
if(WIN32)
set(QT_DEFAULT_PLATFORM_DEFINITIONS WIN32 _ENABLE_EXTENDED_ALIGNED_STORAGE)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
if(QT_64BIT)
list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64)
endif()
@ -434,7 +434,7 @@ set(QT_TOP_LEVEL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
# Prevent warnings about object files without any symbols. This is a common
# thing in Qt as we tend to build files unconditionally, and then use ifdefs
# to compile out parts that are not relevant.
if(CMAKE_HOST_APPLE AND APPLE)
if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
foreach(lang ASM C CXX)
# We have to tell 'ar' to not run ranlib by itself, by passing the 'S' option
set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qcS <TARGET> <LINK_FLAGS> <OBJECTS>")
@ -577,11 +577,6 @@ endif()
_qt_internal_determine_if_host_info_package_needed(__qt_build_requires_host_info_package)
_qt_internal_find_host_info_package("${__qt_build_requires_host_info_package}")
# Create tool script wrapper if necessary.
# TODO: Remove once all direct usages of QT_TOOL_COMMAND_WRAPPER_PATH are replaced with function
# calls.
_qt_internal_generate_tool_command_wrapper()
# This sets up the poor man's scope finalizer mechanism.
# For newer CMake versions, we use cmake_language(DEFER CALL) instead.
if(CMAKE_VERSION VERSION_LESS "3.19.0")

View File

@ -111,6 +111,13 @@ from the build directory")
if(QT_SUPERBUILD)
qt_internal_save_previously_visited_packages()
endif()
# TODO: Abuse qt_print_build_instructions being called as the last command in a top-level build.
# Instead we should call this explicitly at the end of the top-level project.
# TODO: Remove this once the top-level calls qt_internal_top_level_setup_after_project
if(QT_SUPERBUILD AND NOT __qt6_top_level_after_project_called)
qt_internal_qt_configure_end()
endif()
endfunction()
function(qt_configure_print_summary_helper summary_reports force_show)

View File

@ -105,6 +105,30 @@ endif()
# build.
include(QtPlatformSupport)
# Set FEATURE_${feature} if INPUT_${feature} is set in certain circumstances.
#
# Needs to be in QtBuildInternalsConfig.cmake instead of QtFeature.cmake because it's used in
# qt_build_internals_disable_pkg_config_if_needed.
function(qt_internal_compute_feature_value_from_possible_input feature)
# If FEATURE_ is not defined try to use the INPUT_ variable to enable/disable feature.
# If FEATURE_ is defined and the configure script is being used (so
# QT_INTERNAL_CALLED_FROM_CONFIGURE is TRUE), ignore the FEATURE_ variable, and take into
# account the INPUT_ variable instead, because a command line argument takes priority over
# a pre-cached FEATURE_ variable.
if((NOT DEFINED FEATURE_${feature} OR QT_INTERNAL_CALLED_FROM_CONFIGURE)
AND DEFINED INPUT_${feature}
AND NOT "${INPUT_${feature}}" STREQUAL "undefined"
AND NOT "${INPUT_${feature}}" STREQUAL "")
if(INPUT_${feature})
set(FEATURE_${feature} ON)
else()
set(FEATURE_${feature} OFF)
endif()
set(FEATURE_${feature} "${FEATURE_${feature}}" PARENT_SCOPE)
endif()
endfunction()
function(qt_build_internals_disable_pkg_config_if_needed)
# pkg-config should not be used by default on Darwin and Windows platforms (and QNX), as defined
# in the qtbase/configure.json. Unfortunately by the time the feature is evaluated there are
@ -131,15 +155,7 @@ function(qt_build_internals_disable_pkg_config_if_needed)
endif()
# Features won't have been evaluated yet if this is the first run, have to evaluate this here
if ((NOT DEFINED "FEATURE_pkg_config") AND (DEFINED "INPUT_pkg_config")
AND (NOT "${INPUT_pkg_config}" STREQUAL "undefined")
AND (NOT "${INPUT_pkg_config}" STREQUAL ""))
if(INPUT_pkg_config)
set(FEATURE_pkg_config ON)
else()
set(FEATURE_pkg_config OFF)
endif()
endif()
qt_internal_compute_feature_value_from_possible_input(pkg_config)
# If user explicitly specified a value for the feature, honor it, even if it might break
# the build.
@ -296,7 +312,27 @@ function(qt_build_internals_add_toplevel_targets)
COMMENT "Building everything in ${qt_repo_targets_name}/${qt_repo_target_basename}")
add_dependencies("${qt_repo_target_name}" ${qt_repo_targets})
list(APPEND qt_repo_target_all "${qt_repo_target_name}")
# Create special dependency target for External Project examples excluding targets
# marked as skipped.
set(qt_repo_target_name
"${qt_repo_targets_name}_${qt_repo_target_basename}_for_examples")
add_custom_target("${qt_repo_target_name}")
set(unskipped_targets "")
foreach(target IN LISTS qt_repo_targets)
if(TARGET "${target}")
qt_internal_is_target_skipped_for_examples("${target}" is_skipped)
if(NOT is_skipped)
list(APPEND unskipped_targets "${target}")
endif()
endif()
endforeach()
if(unskipped_targets)
add_dependencies("${qt_repo_target_name}" ${unskipped_targets})
endif()
endif()
endforeach()
if (qt_repo_target_all)
# Note qt_repo_targets_name is different from qt_repo_target_name that is used above.
@ -570,9 +606,27 @@ macro(qt_build_repo_end)
set(QT_INTERNAL_FRESH_REQUESTED "FALSE" CACHE INTERNAL "")
endif()
if(NOT QT_SUPERBUILD)
qt_internal_qt_configure_end()
endif()
list(POP_BACK CMAKE_MESSAGE_CONTEXT)
endmacro()
# Function called either at the end of per-repo configuration, or at the end of configuration of
# a super build.
# At the moment it is called before examples are configured in a per-repo build. We might want
# to change that at some point if needed.
function(qt_internal_qt_configure_end)
# If Qt is configued via the configure script, remove the marker variable, so that any future
# reconfigurations that are done by calling cmake directly don't trigger configure specific
# logic.
unset(QT_INTERNAL_CALLED_FROM_CONFIGURE CACHE)
# Clean up stale feature input values.
qt_internal_clean_feature_inputs()
endfunction()
macro(qt_build_repo)
qt_build_repo_begin(${ARGN})
@ -856,7 +910,7 @@ macro(qt_examples_build_begin)
set(QT_EXAMPLE_DEPENDENCIES ${qt_repo_plugins_recursive} ${arg_DEPENDS})
if(TARGET ${qt_repo_targets_name}_src)
list(APPEND QT_EXAMPLE_DEPENDENCIES ${qt_repo_targets_name}_src)
list(APPEND QT_EXAMPLE_DEPENDENCIES ${qt_repo_targets_name}_src_for_examples)
endif()
if(TARGET ${qt_repo_targets_name}_tools)
@ -980,19 +1034,118 @@ set(CMAKE_INSTALL_PREFIX \"\${_qt_internal_examples_cmake_install_prefix_backup}
set(CMAKE_UNITY_BUILD ${QT_UNITY_BUILD})
endmacro()
# Allows building an example either as an ExternalProject or in-tree with the Qt build.
# Also allows installing the example sources.
function(qt_internal_add_example subdir)
if(NOT QT_IS_EXTERNAL_EXAMPLES_BUILD)
qt_internal_add_example_in_tree(${ARGV})
else()
qt_internal_add_example_external_project(${ARGV})
# Pre-compute unique example name based on the subdir, in case of target name clashes.
qt_internal_get_example_unique_name(unique_example_name "${subdir}")
# QT_INTERNAL_NO_CONFIGURE_EXAMPLES is not meant to be used by Qt builders, it's here for faster
# testing of the source installation code path for build system engineers.
if(NOT QT_INTERNAL_NO_CONFIGURE_EXAMPLES)
if(NOT QT_IS_EXTERNAL_EXAMPLES_BUILD)
qt_internal_add_example_in_tree("${subdir}")
else()
qt_internal_add_example_external_project("${subdir}"
NAME "${unique_example_name}")
endif()
endif()
if(QT_INSTALL_EXAMPLES_SOURCES)
string(TOLOWER ${PROJECT_NAME} project_name_lower)
qt_internal_install_example_sources("${subdir}"
NAME "${unique_example_name}"
REPO_NAME "${project_name_lower}")
endif()
endfunction()
# Gets the install prefix where an example should be installed.
# Used for computing the final installation path.
function(qt_internal_get_example_install_prefix out_var)
# Allow customizing the installation path of the examples. Will be used in CI.
if(QT_INTERNAL_EXAMPLES_INSTALL_PREFIX)
set(qt_example_install_prefix "${QT_INTERNAL_EXAMPLES_INSTALL_PREFIX}")
else()
set(qt_example_install_prefix "${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLESDIR}")
endif()
file(TO_CMAKE_PATH "${qt_example_install_prefix}" qt_example_install_prefix)
set(${out_var} "${qt_example_install_prefix}" PARENT_SCOPE)
endfunction()
# Gets the install prefix where an example's sources should be installed.
# Used for computing the final installation path.
function(qt_internal_get_examples_sources_install_prefix out_var)
# Allow customizing the installation path of the examples source specifically.
if(QT_INTERNAL_EXAMPLES_SOURCES_INSTALL_PREFIX)
set(qt_example_install_prefix "${QT_INTERNAL_EXAMPLES_SOURCES_INSTALL_PREFIX}")
else()
qt_internal_get_example_install_prefix(qt_example_install_prefix)
endif()
file(TO_CMAKE_PATH "${qt_example_install_prefix}" qt_example_install_prefix)
set(${out_var} "${qt_example_install_prefix}" PARENT_SCOPE)
endfunction()
# Gets the relative path of an example, relative to the current repo's examples source dir.
# QT_EXAMPLE_BASE_DIR is meant to be already set in a parent scope.
function(qt_internal_get_example_rel_path out_var subdir)
file(RELATIVE_PATH example_rel_path
"${QT_EXAMPLE_BASE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
set(${out_var} "${example_rel_path}" PARENT_SCOPE)
endfunction()
# Gets the install path where an example should be installed.
function(qt_internal_get_example_install_path out_var subdir)
qt_internal_get_example_install_prefix(qt_example_install_prefix)
qt_internal_get_example_rel_path(example_rel_path "${subdir}")
set(example_install_path "${qt_example_install_prefix}/${example_rel_path}")
set(${out_var} "${example_install_path}" PARENT_SCOPE)
endfunction()
# Gets the install path where an example's sources should be installed.
function(qt_internal_get_examples_sources_install_path out_var subdir)
qt_internal_get_examples_sources_install_prefix(qt_example_install_prefix)
qt_internal_get_example_rel_path(example_rel_path "${subdir}")
set(example_install_path "${qt_example_install_prefix}/${example_rel_path}")
set(${out_var} "${example_install_path}" PARENT_SCOPE)
endfunction()
# Get the unique name of an example project based on its subdir or explicitly given name.
# Makes the name unique by appending a short sha1 hash of the relative path of the example
# if a target of the same name already exist.
function(qt_internal_get_example_unique_name out_var subdir)
qt_internal_get_example_rel_path(example_rel_path "${subdir}")
set(name "${subdir}")
# qtdeclarative has calls like qt_internal_add_example(imagine/automotive)
# so passing a nested subdirectory. Custom targets (and thus ExternalProjects) can't contain
# slashes, so extract the last part of the path to be used as a name.
if(name MATCHES "/")
string(REPLACE "/" ";" exploded_path "${name}")
list(POP_BACK exploded_path last_dir)
if(NOT last_dir)
message(FATAL_ERROR "Example subdirectory must have a name.")
else()
set(name "${last_dir}")
endif()
endif()
# Likely a clash with an example subdir ExternalProject custom target of the same name in a
# top-level build.
if(TARGET "${name}")
string(SHA1 rel_path_hash "${example_rel_path}")
string(SUBSTRING "${rel_path_hash}" 0 4 short_hash)
set(name "${name}-${short_hash}")
endif()
set(${out_var} "${name}" PARENT_SCOPE)
endfunction()
# Use old non-ExternalProject approach, aka build in-tree with the Qt build.
function(qt_internal_add_example_in_tree subdir)
file(RELATIVE_PATH example_rel_path
"${QT_EXAMPLE_BASE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
# Unset the default CMAKE_INSTALL_PREFIX that's generated in
# ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
# so we can override it with a different value in
@ -1006,15 +1159,8 @@ unset(CMAKE_INSTALL_PREFIX)
# Override the install prefix in the subdir cmake_install.cmake, so that
# relative install(TARGETS DESTINATION) calls in example projects install where we tell them to.
# Allow customizing the installation path of the examples. Will be used in CI.
if(QT_INTERNAL_EXAMPLES_INSTALL_PREFIX)
set(qt_example_install_prefix "${QT_INTERNAL_EXAMPLES_INSTALL_PREFIX}")
else()
set(qt_example_install_prefix "${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLESDIR}")
endif()
file(TO_CMAKE_PATH "${qt_example_install_prefix}" qt_example_install_prefix)
set(CMAKE_INSTALL_PREFIX "${qt_example_install_prefix}/${example_rel_path}")
qt_internal_get_example_install_path(example_install_path "${subdir}")
set(CMAKE_INSTALL_PREFIX "${example_install_path}")
# Make sure unclean example projects have their INSTALL_EXAMPLEDIR set to "."
# Won't have any effect on example projects that don't use INSTALL_EXAMPLEDIR.
@ -1024,7 +1170,7 @@ unset(CMAKE_INSTALL_PREFIX)
# TODO: Remove once all repositories use qt_internal_add_example instead of add_subdirectory.
set(QT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT ON)
add_subdirectory(${subdir} ${ARGN})
add_subdirectory(${subdir})
endfunction()
function(qt_internal_add_example_external_project subdir)
@ -1034,33 +1180,6 @@ function(qt_internal_add_example_external_project subdir)
cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${singleOpts}" "${multiOpts}")
file(RELATIVE_PATH example_rel_path
"${QT_EXAMPLE_BASE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}")
if(NOT arg_NAME)
set(arg_NAME "${subdir}")
# qtdeclarative has calls like qt_internal_add_example(imagine/automotive)
# so passing a nested subdirectory. Custom targets (and thus ExternalProjects) can't contain
# slashes, so extract the last part of the path to be used as a name.
if(arg_NAME MATCHES "/")
string(REPLACE "/" ";" exploded_path "${arg_NAME}")
list(POP_BACK exploded_path last_dir)
if(NOT last_dir)
message(FATAL_ERROR "Example subdirectory must have a name.")
else()
set(arg_NAME "${last_dir}")
endif()
endif()
endif()
# Likely a clash with an example subdir ExternalProject custom target of the same name.
if(TARGET "${arg_NAME}")
string(SHA1 rel_path_hash "${example_rel_path}")
string(SUBSTRING "${rel_path_hash}" 0 4 short_hash)
set(arg_NAME "${arg_NAME}-${short_hash}")
endif()
# TODO: Fix example builds when using Conan / install prefixes are different for each repo.
if(QT_SUPERBUILD OR QtBase_BINARY_DIR)
# When doing a top-level build or when building qtbase,
@ -1281,15 +1400,7 @@ function(qt_internal_add_example_external_project subdir)
# example_source_dir, use _qt_internal_override_example_install_dir_to_dot to ensure
# INSTALL_EXAMPLEDIR does not interfere.
# Allow customizing the installation path of the examples. Will be used in CI.
if(QT_INTERNAL_EXAMPLES_INSTALL_PREFIX)
set(qt_example_install_prefix "${QT_INTERNAL_EXAMPLES_INSTALL_PREFIX}")
else()
set(qt_example_install_prefix "${CMAKE_INSTALL_PREFIX}/${INSTALL_EXAMPLESDIR}")
endif()
file(TO_CMAKE_PATH "${qt_example_install_prefix}" qt_example_install_prefix)
set(example_install_prefix "${qt_example_install_prefix}/${example_rel_path}")
qt_internal_get_example_install_path(example_install_path "${subdir}")
set(ep_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}")
@ -1304,7 +1415,7 @@ function(qt_internal_add_example_external_project subdir)
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/${subdir}-ep"
STAMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/${subdir}-ep/stamp"
BINARY_DIR "${ep_binary_dir}"
INSTALL_DIR "${example_install_prefix}"
INSTALL_DIR "${example_install_path}"
INSTALL_COMMAND ""
${build_command}
TEST_COMMAND ""
@ -1358,6 +1469,54 @@ execute_process(
endfunction()
function(qt_internal_install_example_sources subdir)
set(options "")
set(single_args NAME REPO_NAME)
set(multi_args "")
cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${single_args}" "${multi_args}")
qt_internal_get_examples_sources_install_path(example_install_path "${subdir}")
# The trailing slash is important to avoid duplicate nested directory names.
set(example_source_dir "${subdir}/")
# Allow controlling whether sources should be part of the default install target.
if(QT_INSTALL_EXAMPLES_SOURCES_BY_DEFAULT)
set(exclude_from_all "")
else()
set(exclude_from_all "EXCLUDE_FROM_ALL")
endif()
# Create an install component for all example sources. Can also be part of the default
# install target if EXCLUDE_FROM_ALL is not passed.
install(
DIRECTORY "${example_source_dir}"
DESTINATION "${example_install_path}"
COMPONENT "examples_sources"
USE_SOURCE_PERMISSIONS
${exclude_from_all}
)
# Also create a specific install component just for this repo's examples.
install(
DIRECTORY "${example_source_dir}"
DESTINATION "${example_install_path}"
COMPONENT "examples_sources_${arg_REPO_NAME}"
USE_SOURCE_PERMISSIONS
EXCLUDE_FROM_ALL
)
# Also create a specific install component just for the current example's sources.
install(
DIRECTORY "${example_source_dir}"
DESTINATION "${example_install_path}"
COMPONENT "examples_sources_${arg_NAME}"
USE_SOURCE_PERMISSIONS
EXCLUDE_FROM_ALL
)
endfunction()
if ("STANDALONE_TEST" IN_LIST Qt6BuildInternals_FIND_COMPONENTS)
include(${CMAKE_CURRENT_LIST_DIR}/QtStandaloneTestTemplateProject/Main.cmake)
if (NOT PROJECT_VERSION_MAJOR)

View File

@ -103,6 +103,9 @@ set(QT_BUILD_EXAMPLES_AS_EXTERNAL "@QT_BUILD_EXAMPLES_AS_EXTERNAL@" CACHE BOOL
# Propagate usage of ccache.
set(QT_USE_CCACHE @QT_USE_CCACHE@ CACHE BOOL "Enable the use of ccache")
# Propagate usage of vcpkg, ON by default.
set(QT_USE_VCPKG @QT_USE_VCPKG@ CACHE BOOL "Enable the use of vcpkg")
# Propagate usage of unity build.
set(QT_UNITY_BUILD @QT_UNITY_BUILD@ CACHE BOOL "Enable unity (jumbo) build")
set(QT_UNITY_BUILD_BATCH_SIZE "@QT_UNITY_BUILD_BATCH_SIZE@" CACHE STRING "Unity build batch size")
@ -163,6 +166,7 @@ function(qt_internal_force_set_cmake_build_type_conditionally value)
AND NOT QT_NO_FORCE_SET_CMAKE_BUILD_TYPE
AND NOT __qt_internal_extras_is_multi_config)
set(CMAKE_BUILD_TYPE "${value}" CACHE STRING "Choose the type of build." FORCE)
set(__qt_build_internals_cmake_build_type "${value}" PARENT_SCOPE)
endif()
endfunction()

View File

@ -14,6 +14,8 @@ function(qt_internal_get_supported_min_cmake_version_for_building_qt out_var)
set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT}")
# We're building qtbase so the values come from .cmake.conf.
elseif(APPLE)
set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT_APPLE}")
elseif(BUILD_SHARED_LIBS)
set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_BUILDING_QT_SHARED}")
else()
@ -30,7 +32,9 @@ function(qt_internal_get_supported_min_cmake_version_for_using_qt out_var)
"It should have been set by this point.")
endif()
if(BUILD_SHARED_LIBS)
if(APPLE)
set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_APPLE}")
elseif(BUILD_SHARED_LIBS)
set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_SHARED}")
else()
set(supported_version "${QT_SUPPORTED_MIN_CMAKE_VERSION_FOR_USING_QT_STATIC}")

View File

@ -92,10 +92,10 @@ endif()
# Windows MSVC
if(MSVC)
set(QT_CFLAGS_OPTIMIZE "-O2")
set(QT_CFLAGS_OPTIMIZE "-O2 -Ob3") # -Ob3 was introduced in Visual Studio 2019 version 16.0
set(QT_CFLAGS_OPTIMIZE_DEBUG "-Od")
set(QT_CFLAGS_OPTIMIZE_SIZE "-O1")
set(QT_CFLAGS_OPTIMIZE_VALID_VALUES "/O2" "/O1" "/Od" "/Ob0" "/Ob1" "/Ob2" "/O0" "-O0")
set(QT_CFLAGS_OPTIMIZE_VALID_VALUES "/O2" "/O1" "/Od" "/Ob0" "/Ob1" "/Ob2" "/Ob3" "/O0" "-O0")
if(CLANG)
set(QT_CFLAGS_OPTIMIZE_FULL "/clang:-O3")

View File

@ -29,13 +29,12 @@ list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}")
list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/3rdparty/extra-cmake-modules/find-modules")
list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/3rdparty/kwin")
if(APPLE AND (NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin"))
# Add module directory to pick up custom Info.plist template for macOS
list(APPEND CMAKE_MODULE_PATH "${_qt_import_prefix}/macos")
elseif(APPLE AND CMAKE_SYSTEM_NAME STREQUAL "iOS")
# Add module directory to pick up custom Info.plist template for iOS
set(__qt_internal_cmake_ios_support_files_path "${_qt_import_prefix}/ios")
list(APPEND CMAKE_MODULE_PATH "${__qt_internal_cmake_ios_support_files_path}")
if(APPLE)
if(NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(__qt_internal_cmake_apple_support_files_path "${_qt_import_prefix}/macos")
elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS")
set(__qt_internal_cmake_apple_support_files_path "${_qt_import_prefix}/ios")
endif()
endif()
# Public helpers available to all Qt packages.

View File

@ -148,7 +148,7 @@ function(qt_internal_add_executable name)
if(WASM)
# WASM unconditionally sets DISABLE_EXCEPTION_CATCHING=1
qt_internal_set_exceptions_flags("${name}" NO_EXCEPTIONS)
qt_internal_set_exceptions_flags("${name}" FALSE)
else()
qt_internal_set_exceptions_flags("${name}" ${arg_EXCEPTIONS})
endif()
@ -422,7 +422,7 @@ function(qt_internal_add_configure_time_executable target)
)
set(should_build_at_configure_time TRUE)
if(EXISTS "${target_binary_path}")
if(EXISTS "${target_binary_path}" AND EXISTS "${timestamp_file}")
set(last_ts 0)
foreach(source IN LISTS sources)
file(TIMESTAMP "${source}" ts "%s")

View File

@ -177,15 +177,20 @@ function(qt_evaluate_config_expression resultVar)
set(${resultVar} ${result} PARENT_SCOPE)
endfunction()
function(_qt_internal_get_feature_condition_keywords out_var)
set(keywords "EQUAL" "LESS" "LESS_EQUAL" "GREATER" "GREATER_EQUAL" "STREQUAL" "STRLESS"
"STRLESS_EQUAL" "STRGREATER" "STRGREATER_EQUAL" "VERSION_EQUAL" "VERSION_LESS"
"VERSION_LESS_EQUAL" "VERSION_GREATER" "VERSION_GREATER_EQUAL" "MATCHES"
"EXISTS" "COMMAND" "DEFINED" "NOT" "AND" "OR" "TARGET" "EXISTS" "IN_LIST" "(" ")")
set(${out_var} "${keywords}" PARENT_SCOPE)
endfunction()
function(_qt_internal_dump_expression_values expression_dump expression)
set(dump "")
set(skipNext FALSE)
set(isTargetExpression FALSE)
set(keywords "EQUAL" "LESS" "LESS_EQUAL" "GREATER" "GREATER_EQUAL" "STREQUAL" "STRLESS"
"STRLESS_EQUAL" "STRGREATER" "STRGREATER_EQUAL" "VERSION_EQUAL" "VERSION_LESS"
"VERSION_LESS_EQUAL" "VERSION_GREATER" "VERSION_GREATER_EQUAL" "MATCHES"
"EXISTS" "COMMAND" "DEFINED" "NOT" "AND" "OR" "TARGET" "EXISTS" "IN_LIST" "(" ")")
_qt_internal_get_feature_condition_keywords(keywords)
list(LENGTH expression length)
math(EXPR length "${length}-1")
@ -239,19 +244,44 @@ endfunction()
# ${computed} is also stored when reconfiguring and the condition does not align with the user
# provided value.
#
function(qt_feature_check_and_save_user_provided_value resultVar feature condition computed label)
function(qt_feature_check_and_save_user_provided_value
resultVar feature condition condition_expression computed label)
if (DEFINED "FEATURE_${feature}")
# Revisit new user provided value
set(user_value "${FEATURE_${feature}}")
string(TOUPPER "${user_value}" result)
string(TOUPPER "${user_value}" user_value_upper)
set(result "${user_value_upper}")
# If the build is marked as dirty and the user_value doesn't meet the new condition,
# reset it to the computed one.
# If ${feature} depends on another dirty feature, reset the ${feature} value to
# ${computed}.
get_property(dirty_build GLOBAL PROPERTY _qt_dirty_build)
if(NOT condition AND result AND dirty_build)
set(result "${computed}")
message(WARNING "Reset FEATURE_${feature} value to ${result}, because it doesn't \
meet its condition after reconfiguration.")
if(dirty_build)
_qt_internal_feature_compute_feature_dependencies(deps "${feature}")
if(deps)
get_property(dirty_features GLOBAL PROPERTY _qt_dirty_features)
foreach(dirty_feature ${dirty_features})
if(dirty_feature IN_LIST deps AND NOT "${result}" STREQUAL "${computed}")
set(result "${computed}")
message(WARNING
"Auto-resetting 'FEATURE_${feature}' from '${user_value_upper}' to "
"'${computed}', "
"because the dependent feature '${dirty_feature}' was marked dirty.")
# Append ${feature} as a new dirty feature.
set_property(GLOBAL APPEND PROPERTY _qt_dirty_features "${feature}")
break()
endif()
endforeach()
endif()
# If the build is marked as dirty and the feature doesn't meet its condition,
# reset its value to the computed one, which is likely OFF.
if(NOT condition AND result)
set(result "${computed}")
message(WARNING "Resetting 'FEATURE_${feature}' from '${user_value_upper}' to "
"'${computed}' because it doesn't meet its condition after reconfiguration. "
"Condition expression is: '${condition_expression}'")
endif()
endif()
set(bool_values OFF NO FALSE N ON YES TRUE Y)
@ -299,6 +329,14 @@ condition:\n ${conditionString}\nCondition values dump:\n ${conditionDump}
set(QT_KNOWN_FEATURES "${QT_KNOWN_FEATURES}" CACHE INTERNAL "" FORCE)
endmacro()
macro(_qt_internal_parse_feature_definition feature)
cmake_parse_arguments(arg
"PRIVATE;PUBLIC"
"LABEL;PURPOSE;SECTION;"
"AUTODETECT;CONDITION;ENABLE;DISABLE;EMIT_IF"
${_QT_FEATURE_DEFINITION_${feature}})
endmacro()
# The build system stores 2 CMake cache variables for each feature, to allow detecting value changes
# during subsequent reconfigurations.
@ -334,9 +372,7 @@ function(qt_evaluate_feature feature)
message(FATAL_ERROR "Attempting to evaluate feature ${feature} but its definition is missing. Either the feature does not exist or a dependency to the module that defines it is missing")
endif()
cmake_parse_arguments(arg
"PRIVATE;PUBLIC"
"LABEL;PURPOSE;SECTION;" "AUTODETECT;CONDITION;ENABLE;DISABLE;EMIT_IF" ${_QT_FEATURE_DEFINITION_${feature}})
_qt_internal_parse_feature_definition("${feature}")
if("${arg_ENABLE}" STREQUAL "")
set(arg_ENABLE OFF)
@ -374,16 +410,7 @@ function(qt_evaluate_feature feature)
qt_evaluate_config_expression(emit_if ${arg_EMIT_IF})
endif()
# If FEATURE_ is not defined trying to use INPUT_ variable to enable/disable feature.
if ((NOT DEFINED "FEATURE_${feature}") AND (DEFINED "INPUT_${feature}")
AND (NOT "${INPUT_${feature}}" STREQUAL "undefined")
AND (NOT "${INPUT_${feature}}" STREQUAL ""))
if(INPUT_${feature})
set(FEATURE_${feature} ON)
else()
set(FEATURE_${feature} OFF)
endif()
endif()
qt_internal_compute_feature_value_from_possible_input("${feature}")
# Warn about a feature which is not emitted, but the user explicitly provided a value for it.
if(NOT emit_if AND DEFINED FEATURE_${feature})
@ -401,7 +428,8 @@ function(qt_evaluate_feature feature)
# Only save the user provided value if the feature was emitted.
if(emit_if)
qt_feature_check_and_save_user_provided_value(
saved_user_value "${feature}" "${condition}" "${computed}" "${arg_LABEL}")
saved_user_value
"${feature}" "${condition}" "${arg_CONDITION}" "${computed}" "${arg_LABEL}")
else()
# Make sure the feature internal value is OFF if not emitted.
set(saved_user_value OFF)
@ -414,6 +442,60 @@ function(qt_evaluate_feature feature)
set(QT_FEATURE_LABEL_${feature} "${arg_LABEL}" CACHE INTERNAL "")
endfunction()
# Collect feature names that ${feature} depends on, by inspecting the given expression.
function(_qt_internal_feature_extract_feature_dependencies_from_expression out_var expression)
list(LENGTH expression length)
math(EXPR length "${length}-1")
if(length LESS 0)
set(${out_var} "" PARENT_SCOPE)
return()
endif()
set(deps "")
foreach(memberIdx RANGE ${length})
list(GET expression ${memberIdx} member)
if(member MATCHES "^QT_FEATURE_(.+)")
list(APPEND deps "${CMAKE_MATCH_1}")
endif()
endforeach()
set(${out_var} "${deps}" PARENT_SCOPE)
endfunction()
# Collect feature names that ${feature} depends on, based on feature names that appear
# in the ${feature}'s condition expressions.
function(_qt_internal_feature_compute_feature_dependencies out_var feature)
# Only compute the deps once per feature.
get_property(deps_computed GLOBAL PROPERTY _qt_feature_deps_computed_${feature})
if(deps_computed)
get_property(deps GLOBAL PROPERTY _qt_feature_deps_${feature})
set(${out_var} "${deps}" PARENT_SCOPE)
return()
endif()
_qt_internal_parse_feature_definition("${feature}")
set(options_to_check AUTODETECT CONDITION ENABLE DISABLE EMIT_IF)
set(deps "")
# Go through each option that takes condition expressions and collect the feature names.
foreach(option ${options_to_check})
set(option_value "${arg_${option}}")
if(option_value)
_qt_internal_feature_extract_feature_dependencies_from_expression(
option_deps "${option_value}")
if(option_deps)
list(APPEND deps ${option_deps})
endif()
endif()
endforeach()
set_property(GLOBAL PROPERTY _qt_feature_deps_computed_${feature} TRUE)
set_property(GLOBAL PROPERTY _qt_feature_deps_${feature} "${deps}")
set(${out_var} "${deps}" PARENT_SCOPE)
endfunction()
function(qt_feature_config feature config_var_name)
qt_feature_normalize_name("${feature}" feature)
cmake_parse_arguments(PARSE_ARGV 2 arg
@ -786,6 +868,49 @@ function(qt_feature_copy_global_config_features_to_core target)
endif()
endfunction()
function(qt_internal_detect_dirty_features)
# We need to clean up QT_FEATURE_*, but only once per configuration cycle
get_property(qt_feature_clean GLOBAL PROPERTY _qt_feature_clean)
if(NOT qt_feature_clean AND NOT QT_NO_FEATURE_AUTO_RESET)
message(STATUS "Checking for feature set changes")
set_property(GLOBAL PROPERTY _qt_feature_clean TRUE)
foreach(feature ${QT_KNOWN_FEATURES})
qt_internal_compute_feature_value_from_possible_input("${feature}")
if(DEFINED "FEATURE_${feature}" AND
NOT "${QT_FEATURE_${feature}}" STREQUAL "${FEATURE_${feature}}")
message(" '${feature}' was changed from ${QT_FEATURE_${feature}} "
"to ${FEATURE_${feature}}")
set(dirty_build TRUE)
set_property(GLOBAL APPEND PROPERTY _qt_dirty_features "${feature}")
endif()
unset("QT_FEATURE_${feature}" CACHE)
endforeach()
set(QT_KNOWN_FEATURES "" CACHE INTERNAL "" FORCE)
if(dirty_build)
set_property(GLOBAL PROPERTY _qt_dirty_build TRUE)
message(WARNING
"Due to detected feature set changes, dependent features "
"will be re-computed automatically. This might cause a lot of files to be rebuilt. "
"To disable this behavior, configure with -DQT_NO_FEATURE_AUTO_RESET=ON")
endif()
endif()
endfunction()
function(qt_internal_clean_feature_inputs)
foreach(feature IN LISTS QT_KNOWN_FEATURES)
# Unset the INPUT_foo cache variables after they were used in feature evaluation, to
# ensure stale values don't influence features upon reconfiguration when
# QT_INTERNAL_CALLED_FROM_CONFIGURE is TRUE and the INPUT_foo variable is not passed.
# e.g. first configure -no-gui, then manually toggle FEATURE_gui to ON in
# CMakeCache.txt, then reconfigure (with the configure script) without -no-gui.
# Without this unset(), we'd have switched FEATURE_gui to OFF again.
unset(INPUT_${feature} CACHE)
endforeach()
endfunction()
function(qt_config_compile_test name)
if(DEFINED "TEST_${name}")
return()
@ -924,6 +1049,7 @@ function(qt_config_compile_test name)
# fail instead of cmake abort later via CMAKE_REQUIRED_LIBRARIES.
string(FIND "${library}" "::" cmake_target_namespace_separator)
if(NOT cmake_target_namespace_separator EQUAL -1)
message(STATUS "Performing Test ${arg_LABEL} - Failed because ${library} not found")
set(HAVE_${name} FALSE)
break()
endif()

View File

@ -16,6 +16,15 @@ function(qt_find_package_promote_targets_to_global_scope target)
"qt_find_package_targets_dict" "promote_global")
endfunction()
# As an optimization when using -developer-build, qt_find_package records which
# packages were found during the initial configuration. Then on subsequent
# reconfigurations it skips looking for packages that were not found on the
# initial run.
# For the build system to pick up a newly added qt_find_package call, you need to:
# - Start with a clean build dir
# - Or remove the <builddir>/CMakeCache.txt file and configure from scratch
# - Or remove the QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES cache variable (by
# editing CMakeCache.txt) and reconfigure.
macro(qt_find_package)
# Get the target names we expect to be provided by the package.
set(find_package_options CONFIG NO_MODULE MODULE REQUIRED)

View File

@ -4,6 +4,7 @@
macro(qt_find_apple_system_frameworks)
if(APPLE)
qt_internal_find_apple_system_framework(FWAppKit AppKit)
qt_internal_find_apple_system_framework(FWCFNetwork CFNetwork)
qt_internal_find_apple_system_framework(FWAssetsLibrary AssetsLibrary)
qt_internal_find_apple_system_framework(FWPhotos Photos)
qt_internal_find_apple_system_framework(FWAudioToolbox AudioToolbox)
@ -58,7 +59,7 @@ function(qt_internal_find_apple_system_framework out_var framework_name)
endif()
endfunction()
# Copy header files to QtXYZ.framework/Versions/A/Headers/
# Copy header files to the framework's Headers directory
# Use this function for header files that
# - are not added as source files to the target
# - are not marked as PUBLIC_HEADER
@ -71,7 +72,7 @@ function(qt_copy_framework_headers target)
set(options)
set(oneValueArgs)
set(multiValueArgs PUBLIC PRIVATE QPA)
set(multiValueArgs PUBLIC PRIVATE QPA RHI)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
qt_internal_get_framework_info(fw ${target})
@ -79,10 +80,11 @@ function(qt_copy_framework_headers target)
set(output_dir_PUBLIC "${output_dir}/${fw_versioned_header_dir}")
set(output_dir_PRIVATE "${output_dir}/${fw_private_module_header_dir}/private")
set(output_dir_QPA "${output_dir}/${fw_private_module_header_dir}/qpa")
set(output_dir_RHI "${output_dir}/${fw_private_module_header_dir}/rhi")
set(out_files)
foreach(type IN ITEMS PUBLIC PRIVATE QPA)
foreach(type IN ITEMS PUBLIC PRIVATE QPA RHI)
set(fw_output_header_dir "${output_dir_${type}}")
foreach(hdr IN LISTS arg_${type})
get_filename_component(in_file_path ${hdr} ABSOLUTE)
@ -164,8 +166,13 @@ function(qt_internal_get_framework_info out_var target)
set(${out_var}_name "${module}")
set(${out_var}_dir "${${out_var}_name}.framework")
set(${out_var}_header_dir "${${out_var}_dir}/Headers")
set(${out_var}_versioned_header_dir "${${out_var}_dir}/Versions/${${out_var}_version}/Headers")
set(${out_var}_private_header_dir "${${out_var}_header_dir}/${${out_var}_bundle_version}")
if(UIKIT)
# iOS frameworks do not version their headers
set(${out_var}_versioned_header_dir "${${out_var}_header_dir}")
else()
set(${out_var}_versioned_header_dir "${${out_var}_dir}/Versions/${${out_var}_version}/Headers")
endif()
set(${out_var}_private_header_dir "${${out_var}_versioned_header_dir}/${${out_var}_bundle_version}")
set(${out_var}_private_module_header_dir "${${out_var}_private_header_dir}/${module}")
set(${out_var}_name "${${out_var}_name}" PARENT_SCOPE)

View File

@ -104,6 +104,7 @@ function(qt_internal_add_headersclean_target module_target module_headers)
set(hcleanFLAGS -Wall -Wextra -Werror -Woverloaded-virtual -Wshadow -Wundef -Wfloat-equal
-Wnon-virtual-dtor -Wpointer-arith -Wformat-security -Wno-long-long -Wno-variadic-macros
-fno-operator-names
-pedantic-errors)
if(QT_FEATURE_reduce_relocations AND UNIX)
@ -181,9 +182,7 @@ function(qt_internal_add_headersclean_target module_target module_headers)
)
set(input_header_path_type ABSOLUTE)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# -Za would enable strict standards behavior, but we can't add it because
# <windows.h> and <GL.h> violate the standards.
set(hcleanFLAGS -std:c++latest -Zc:__cplusplus -WX -W3)
set(hcleanFLAGS -std:c++latest -Zc:__cplusplus -WX -W3 -EHsc)
# Because we now add `-DNOMINMAX` to `PlatformCommonInternal`.
set(hcleanUDEFS -UNOMINMAX)

214
cmake/QtInitProject.cmake Normal file
View File

@ -0,0 +1,214 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
if(NOT PROJECT_DIR)
set(PROJECT_DIR "${CMAKE_SOURCE_DIR}")
endif()
get_filename_component(project_name "${PROJECT_DIR}" NAME)
get_filename_component(project_abs_dir "${PROJECT_DIR}" ABSOLUTE)
if(NOT IS_DIRECTORY "${project_abs_dir}")
message(FATAL_ERROR "Unable to scan ${project_abs_dir}. The directory doesn't exist.")
endif()
set(known_extensions "")
set(types "")
# The function allows extending the capabilities of this script and establishes simple relation
# chains between the file types.
# Option Arguments:
# EXPERIMENTAL
# Marks that the support of the following files is experimental and the required Qt modules
# are in Technical preview state.
# DEPRECATED
# Marks that the support of the following files will be discontinued soon and the required
# Qt modules are deprecated.
# One-value Arguments:
# TEMPLATE
# The CMake code template. Use the '@files@' string for the files substitution.
# Multi-value Arguments:
# EXTENSIONS
# List of the file extensions treated as this source 'type'.
# MODULES
# List of Qt modules required for these file types.
# DEPENDS
# The prerequisite source 'type' needed by this source 'type'
macro(handle_type type)
cmake_parse_arguments(arg
"EXPERIMENTAL;DEPRECATED"
"TEMPLATE"
"EXTENSIONS;MODULES;DEPENDS"
${ARGN}
)
if(NOT arg_EXTENSIONS)
message(FATAL_ERROR "Unexpected call handle_type of with no EXTENSIONS specified."
" This is the Qt issue, please report a bug at https://bugreports.qt.io.")
endif()
set(unique_extensions_subset "${known_extensions}")
list(REMOVE_ITEM unique_extensions_subset ${arg_EXTENSIONS})
if(NOT "${known_extensions}" STREQUAL "${unique_extensions_subset}")
message(FATAL_ERROR "${type} contains duplicated extensions, this is not supported."
" This is the Qt issue, please report a bug at https://bugreports.qt.io.")
endif()
set(${type}_file_extensions "${arg_EXTENSIONS}")
if(NOT arg_TEMPLATE)
message(FATAL_ERROR "Unexpected call handle_type of with no TEMPLATE specified."
" This is the Qt issue, please report a bug at https://bugreports.qt.io.")
endif()
set(${type}_template "${arg_TEMPLATE}")
if(arg_MODULES)
set(${type}_required_modules "${arg_MODULES}")
endif()
list(APPEND types ${type})
if(arg_EXPERIMENTAL)
set(${type}_is_experimental TRUE)
else()
set(${type}_is_experimental FALSE)
endif()
if(arg_DEPRECATED)
set(${type}_is_deprecated TRUE)
else()
set(${type}_is_deprecated FALSE)
endif()
if(arg_DEPENDS)
set(${type}_dependencies ${arg_DEPENDS})
endif()
endmacro()
handle_type(cpp EXTENSIONS .c .cc .cpp .cxx .h .hh .hxx .hpp MODULES Core TEMPLATE
"\n\nqt_add_executable(${project_name}
@files@
)"
)
handle_type(qml EXTENSIONS .qml .js .mjs MODULES Gui Qml Quick TEMPLATE
"\n\nqt_add_qml_module(${project_name}
URI ${project_name}
OUTPUT_DIRECTORY qml
VERSION 1.0
RESOURCE_PREFIX /qt/qml
QML_FILES
@files@
)"
)
handle_type(ui EXTENSIONS .ui MODULES Gui Widgets DEPENDS cpp TEMPLATE
"\n\ntarget_sources(${project_name}
PRIVATE
@files@
)"
)
handle_type(qrc EXTENSIONS .qrc DEPENDS cpp TEMPLATE
"\n\nqt_add_resources(${project_name}_resources @files@)
target_sources(${project_name}
PRIVATE
\\\${${project_name}_resources}
)"
)
handle_type(protobuf EXPERIMENTAL EXTENSIONS .proto MODULES Protobuf Grpc TEMPLATE
"\n\nqt_add_protobuf(${project_name}
GENERATE_PACKAGE_SUBFOLDERS
PROTO_FILES
@files@
)"
)
set(extra_packages "")
file(GLOB_RECURSE files RELATIVE "${project_abs_dir}" "${project_abs_dir}/*")
foreach(f IN LISTS files)
get_filename_component(file_extension "${f}" LAST_EXT)
string(TOLOWER "${file_extension}" file_extension)
foreach(type IN LISTS types)
if(file_extension IN_LIST ${type}_file_extensions)
list(APPEND ${type}_sources "${f}")
list(APPEND packages ${${type}_required_modules})
if(${type}_is_experimental)
message("We found files with the following extensions in your directory:"
" ${${type}_file_extensions}\n"
"Note that the modules ${${type}_required_modules} are"
" in the technical preview state.")
endif()
if(${type}_is_deprecated)
message("We found files with the following extensions in your directory:"
" ${${type}_file_extensions}\n"
"Note that the modules ${${type}_required_modules} are deprecated.")
endif()
break()
endif()
endforeach()
endforeach()
if(packages)
list(REMOVE_DUPLICATES packages)
list(JOIN packages " " packages_string)
list(JOIN packages "\n Qt::" deps_string)
set(deps_string "Qt::${deps_string}")
endif()
set(content
"cmake_minimum_required(VERSION 3.16)
project(${project_name} LANGUAGES CXX)
find_package(Qt6 REQUIRED COMPONENTS ${packages_string})
qt_standard_project_setup()"
)
set(has_useful_sources FALSE)
foreach(type IN LISTS types)
if(${type}_sources)
set(skip FALSE)
foreach(dep IN LISTS ${type}_dependencies)
if(NOT ${dep}_sources)
set(skip TRUE)
message("Sources of type ${${type}_file_extensions} cannot live in the project"
" without ${${dep}_file_extensions} files. Skipping.")
break()
endif()
endforeach()
if(skip)
continue()
endif()
set(has_useful_sources TRUE)
string(REGEX MATCH "( +)@files@" unused "${${type}_template}")
list(JOIN ${type}_sources "\n${CMAKE_MATCH_1}" ${type}_sources)
string(REPLACE "@files@" "${${type}_sources}" ${type}_content
"${${type}_template}")
string(APPEND content "${${type}_content}")
endif()
endforeach()
string(APPEND content "\n\ntarget_link_libraries(${project_name}
PRIVATE
${deps_string}
)\n"
)
if(EXISTS "${project_abs_dir}/CMakeLists.txt")
message(FATAL_ERROR "Project is already initialized in current directory."
" Please remove CMakeLists.txt if you want to regenerate the project.")
endif()
if(NOT has_useful_sources)
message(FATAL_ERROR "Could not find any files to generate the project.")
endif()
file(WRITE "${project_abs_dir}/CMakeLists.txt" "${content}")
message("The project file is successfully generated. To build the project run:"
"\nmkdir build"
"\ncd build"
"\nqt-cmake ${project_abs_dir}"
"\ncmake --build ${project_abs_dir}"
)

View File

@ -156,6 +156,8 @@ qt_internal_add_target_aliases(PlatformToolInternal)
target_link_libraries(PlatformToolInternal INTERFACE PlatformAppInternal)
qt_internal_add_global_definition(QT_NO_JAVA_STYLE_ITERATORS)
qt_internal_add_global_definition(QT_NO_AS_CONST)
qt_internal_add_global_definition(QT_NO_QEXCHANGE)
qt_internal_add_global_definition(QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
qt_internal_add_global_definition(QT_EXPLICIT_QFILE_CONSTRUCTION_FROM_PATH)

View File

@ -35,6 +35,15 @@ function(qt_process_qlalr consuming_target input_file_list flags)
return()
endif()
qt_internal_is_skipped_test(skipped ${consuming_target})
if(skipped)
return()
endif()
qt_internal_is_in_test_batch(in_batch ${consuming_target})
if(in_batch)
_qt_internal_test_batch_target_name(consuming_target)
endif()
foreach(input_file ${input_file_list})
file(STRINGS ${input_file} input_file_lines)
qt_qlalr_find_option_in_list("${input_file_lines}" "^%parser(.+)" "parser")

View File

@ -27,6 +27,8 @@ endif()
if (NOT QT_NO_CREATE_TARGETS AND @INSTALL_CMAKE_NAMESPACE@@target@_FOUND)
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@AdditionalTargetInfo.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@ExtraProperties.cmake"
OPTIONAL)
if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS)
include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake")
endif()

View File

@ -30,6 +30,7 @@ macro(qt_internal_get_internal_add_module_keywords option_args single_args multi
EXTERNAL_HEADERS_DIR
PRIVATE_HEADER_FILTERS
QPA_HEADER_FILTERS
RHI_HEADER_FILTERS
HEADER_SYNC_SOURCE_DIRECTORY
${__default_target_info_args}
)
@ -114,6 +115,10 @@ endfunction()
# The regular expressions that filter QPA header files out of target sources.
# The value must use the following format 'regex1|regex2|regex3'.
#
# RHI_HEADER_FILTERS
# The regular expressions that filter RHI header files out of target sources.
# The value must use the following format 'regex1|regex2|regex3'.
#
# HEADER_SYNC_SOURCE_DIRECTORY
# The source directory for header sync procedure. Header files outside this directory will be
# ignored by syncqt. The specifying this directory allows to skip the parsing of the whole
@ -326,14 +331,24 @@ function(qt_internal_add_module target)
EXPORT_PROPERTIES "${export_properties}")
endif()
# FIXME: This workaround is needed because the deployment logic
# for iOS and WASM just copies/embeds the directly linked library,
# which will just be a versioned symlink to the actual library.
if((UIKIT OR WASM) AND BUILD_SHARED_LIBS)
set(version_args "")
else()
set(version_args
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR})
endif()
if(NOT arg_HEADER_MODULE)
set_target_properties(${target} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}"
ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
${version_args}
)
qt_set_target_info_properties(${target} ${ARGN})
qt_handle_multi_config_output_dirs("${target}")
@ -436,6 +451,13 @@ function(qt_internal_add_module target)
set_target_properties(${target}
PROPERTIES _qt_module_qpa_headers_filter_regex "${qpa_filter_regex}")
set(rhi_filter_regex "")
if(arg_RHI_HEADER_FILTERS)
set(rhi_filter_regex "${arg_RHI_HEADER_FILTERS}")
endif()
set_target_properties(${target}
PROPERTIES _qt_module_rhi_headers_filter_regex "${rhi_filter_regex}")
set(private_filter_regex ".+_p(ch)?\\.h")
if(arg_PRIVATE_HEADER_FILTERS)
set(private_filter_regex "${private_filter_regex}|${arg_PRIVATE_HEADER_FILTERS}")
@ -793,6 +815,11 @@ set(QT_ALLOW_MISSING_TOOLS_PACKAGES TRUE)")
EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
CONFIG_INSTALL_DIR "${config_install_dir}")
qt_internal_export_genex_properties(TARGETS ${target}
EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target}
CONFIG_INSTALL_DIR "${config_install_dir}"
)
### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins
# that belong to Qt.
if(NOT arg_HEADER_MODULE)
@ -878,6 +905,7 @@ function(qt_finalize_module target)
PUBLIC ${module_headers_public} "${module_depends_header}"
PRIVATE ${module_headers_private}
QPA ${module_headers_qpa}
RHI ${module_headers_rhi}
)
qt_finalize_framework_headers_copy(${target})
@ -910,6 +938,7 @@ endfunction()
# * foo_versioned_inner_include_dir with the value "QtCore/6.2.0/QtCore"
# * foo_private_include_dir with the value "QtCore/6.2.0/QtCore/private"
# * foo_qpa_include_dir with the value "QtCore/6.2.0/QtCore/qpa"
# * foo_rhi_include_dir with the value "QtCore/6.2.0/QtCore/rhi"
# * foo_interface_name the interface name of the module stored in _qt_module_interface_name
# property, e.g. Core.
#
@ -932,6 +961,9 @@ endfunction()
# * foo_<build|install>_qpa_include_dir with
# qtbase_build_dir/include/QtCore/6.2.0/QtCore/qpa for build interface and
# include/QtCore/6.2.0/QtCore/qpa for install interface.
# * foo_<build|install>_rhi_include_dir with
# qtbase_build_dir/include/QtCore/6.2.0/QtCore/rhi for build interface and
# include/QtCore/6.2.0/QtCore/rhi for install interface.
# The following values are set by the function and might be useful in caller's scope:
# * repo_install_interface_include_dir contains path to the top-level repository include directory,
# e.g. qtbase_build_dir/include
@ -966,6 +998,8 @@ the different base name for the module info variables.")
"${${result}_versioned_inner_include_dir}/private")
set("${result}_qpa_include_dir"
"${${result}_versioned_inner_include_dir}/qpa")
set("${result}_rhi_include_dir"
"${${result}_versioned_inner_include_dir}/rhi")
# Module build interface directories
set(repo_build_interface_include_dir "${QT_BUILD_DIR}/include")
@ -979,6 +1013,8 @@ the different base name for the module info variables.")
"${repo_build_interface_include_dir}/${${result}_private_include_dir}")
set("${result}_build_interface_qpa_include_dir"
"${repo_build_interface_include_dir}/${${result}_qpa_include_dir}")
set("${result}_build_interface_rhi_include_dir"
"${repo_build_interface_include_dir}/${${result}_rhi_include_dir}")
# Module install interface directories
set(repo_install_interface_include_dir "${INSTALL_INCLUDEDIR}")
@ -992,6 +1028,8 @@ the different base name for the module info variables.")
"${repo_install_interface_include_dir}/${${result}_private_include_dir}")
set("${result}_install_interface_qpa_include_dir"
"${repo_install_interface_include_dir}/${${result}_qpa_include_dir}")
set("${result}_install_interface_rhi_include_dir"
"${repo_install_interface_include_dir}/${${result}_rhi_include_dir}")
set("${result}" "${module}" PARENT_SCOPE)
set("${result}_versioned" "${module_versioned}" PARENT_SCOPE)
@ -1005,6 +1043,7 @@ the different base name for the module info variables.")
"${${result}_versioned_inner_include_dir}" PARENT_SCOPE)
set("${result}_private_include_dir" "${${result}_private_include_dir}" PARENT_SCOPE)
set("${result}_qpa_include_dir" "${${result}_qpa_include_dir}" PARENT_SCOPE)
set("${result}_rhi_include_dir" "${${result}_rhi_include_dir}" PARENT_SCOPE)
set("${result}_interface_name" "${module_interface_name}" PARENT_SCOPE)
# Setting module build interface directories in parent scope
@ -1019,6 +1058,8 @@ the different base name for the module info variables.")
"${${result}_build_interface_private_include_dir}" PARENT_SCOPE)
set("${result}_build_interface_qpa_include_dir"
"${${result}_build_interface_qpa_include_dir}" PARENT_SCOPE)
set("${result}_build_interface_rhi_include_dir"
"${${result}_build_interface_rhi_include_dir}" PARENT_SCOPE)
# Setting module install interface directories in parent scope
set(repo_install_interface_include_dir "${repo_install_interface_include_dir}" PARENT_SCOPE)
@ -1032,6 +1073,8 @@ the different base name for the module info variables.")
"${${result}_install_interface_private_include_dir}" PARENT_SCOPE)
set("${result}_install_interface_qpa_include_dir"
"${${result}_install_interface_qpa_include_dir}" PARENT_SCOPE)
set("${result}_install_interface_rhi_include_dir"
"${${result}_install_interface_rhi_include_dir}" PARENT_SCOPE)
endfunction()
function(qt_internal_list_to_json_array out_var list_var)
@ -1075,6 +1118,10 @@ function(qt_describe_module target)
endif()
set(extra_build_information "")
if(NOT QT_NAMESPACE STREQUAL "")
string(APPEND extra_build_information "
\"namespace\": \"${QT_NAMESPACE}\",")
endif()
if(ANDROID)
string(APPEND extra_build_information "
\"android\": {
@ -1135,7 +1182,7 @@ endfunction()
function(qt_internal_install_module_headers target)
set(options)
set(one_value_args)
set(multi_value_args PUBLIC PRIVATE QPA)
set(multi_value_args PUBLIC PRIVATE QPA RHI)
cmake_parse_arguments(arg "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
qt_internal_module_info(module ${target})
@ -1160,6 +1207,7 @@ function(qt_internal_install_module_headers target)
PUBLIC ${arg_PUBLIC}
PRIVATE ${arg_PRIVATE}
QPA ${arg_QPA}
RHI ${arg_RHI}
)
else()
if(arg_PUBLIC)
@ -1173,6 +1221,9 @@ function(qt_internal_install_module_headers target)
if(arg_QPA)
qt_install(FILES ${arg_QPA} DESTINATION "${module_install_interface_qpa_include_dir}")
endif()
if(arg_RHI)
qt_install(FILES ${arg_RHI} DESTINATION "${module_install_interface_rhi_include_dir}")
endif()
endif()
endfunction()
@ -1180,6 +1231,7 @@ function(qt_internal_collect_module_headers out_var target)
set(${out_var}_public "")
set(${out_var}_private "")
set(${out_var}_qpa "")
set(${out_var}_rhi "")
set(${out_var}_all "")
qt_internal_get_target_sources(sources ${target})
@ -1200,6 +1252,7 @@ function(qt_internal_collect_module_headers out_var target)
get_target_property(public_filter ${target} _qt_module_public_headers_filter_regex)
get_target_property(private_filter ${target} _qt_module_private_headers_filter_regex)
get_target_property(qpa_filter ${target} _qt_module_qpa_headers_filter_regex)
get_target_property(rhi_filter ${target} _qt_module_rhi_headers_filter_regex)
set(condition_independent_headers_warning "")
foreach(file_path IN LISTS sources)
@ -1251,6 +1304,8 @@ function(qt_internal_collect_module_headers out_var target)
list(APPEND ${out_var}_all "${file_path}")
if(qpa_filter AND file_name MATCHES "${qpa_filter}")
list(APPEND ${out_var}_qpa "${file_path}")
elseif(rhi_filter AND file_name MATCHES "${rhi_filter}")
list(APPEND ${out_var}_rhi "${file_path}")
elseif(private_filter AND file_name MATCHES "${private_filter}")
list(APPEND ${out_var}_private "${file_path}")
elseif((NOT public_filter OR file_name MATCHES "${public_filter}")
@ -1274,7 +1329,7 @@ function(qt_internal_collect_module_headers out_var target)
endif()
set(header_types public private qpa)
set(header_types public private qpa rhi)
set(has_header_types_properties "")
foreach(header_type IN LISTS header_types)
get_target_property(current_propety_value ${target} _qt_module_has_${header_type}_headers)
@ -1296,5 +1351,6 @@ function(qt_internal_collect_module_headers out_var target)
_qt_module_has_public_headers
_qt_module_has_private_headers
_qt_module_has_qpa_headers
_qt_module_has_rhi_headers
)
endfunction()

View File

@ -148,6 +148,41 @@ while(NOT "${configure_args}" STREQUAL "")
endif()
endwhile()
# Read the specified manually generator value from CMake command line.
# The '-cmake-generator' argument has higher priority than CMake command line.
if(NOT generator)
set(is_next_arg_generator_name FALSE)
foreach(arg IN LISTS cmake_args)
if(is_next_arg_generator_name)
set(is_next_arg_generator_name FALSE)
if(NOT arg MATCHES "^-.*")
set(generator "${arg}")
set(auto_detect_generator FALSE)
endif()
elseif(arg MATCHES "^-G(.*)")
set(generator "${CMAKE_MATCH_1}")
if(generator)
set(auto_detect_generator FALSE)
else()
set(is_next_arg_generator_name TRUE)
endif()
endif()
endforeach()
endif()
# Attempt to detect the generator type, either single or multi-config
if("${generator}" STREQUAL "Xcode"
OR "${generator}" STREQUAL "Ninja Multi-Config"
OR "${generator}" MATCHES "^Visual Studio")
set(multi_config ON)
else()
set(multi_config OFF)
endif()
# Tell the build system we are configuring via the configure script so we can act on that.
# The cache variable is unset at the end of configuration.
push("-DQT_INTERNAL_CALLED_FROM_CONFIGURE:BOOL=TRUE")
if(FRESH_REQUESTED)
push("-DQT_INTERNAL_FRESH_REQUESTED:BOOL=TRUE")
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
@ -826,6 +861,7 @@ translate_boolean_input(precompile_header BUILD_WITH_PCH)
translate_boolean_input(unity_build QT_UNITY_BUILD)
translate_string_input(unity_build_batch_size QT_UNITY_BUILD_BATCH_SIZE)
translate_boolean_input(ccache QT_USE_CCACHE)
translate_boolean_input(vcpkg QT_USE_VCPKG)
translate_boolean_input(shared BUILD_SHARED_LIBS)
translate_boolean_input(warnings_are_errors WARNINGS_ARE_ERRORS)
translate_string_input(qt_namespace QT_NAMESPACE)
@ -875,6 +911,7 @@ endif()
drop_input(make)
drop_input(nomake)
translate_boolean_input(install-examples-sources QT_INSTALL_EXAMPLES_SOURCES)
check_qt_build_parts(nomake)
check_qt_build_parts(make)
@ -896,9 +933,9 @@ if(INPUT_force_debug_info)
endif()
list(LENGTH build_configs nr_of_build_configs)
if(nr_of_build_configs EQUAL 1)
if(nr_of_build_configs EQUAL 1 AND NOT multi_config)
push("-DCMAKE_BUILD_TYPE=${build_configs}")
elseif(nr_of_build_configs GREATER 1)
elseif(nr_of_build_configs GREATER 1 OR multi_config)
set(multi_config ON)
string(REPLACE ";" "[[;]]" escaped_build_configs "${build_configs}")
# We must not use the push macro here to avoid variable expansion.
@ -983,6 +1020,14 @@ endforeach()
push("${MODULE_ROOT}")
if(INPUT_sysroot)
qtConfAddWarning("The -sysroot option is deprecated and no longer has any effect. "
"It is recommended to use a toolchain file instead, i.e., "
"-DCMAKE_TOOLCHAIN_FILE=<filename>. "
"Alternatively, you may use -DCMAKE_SYSROOT option "
"to pass the sysroot to CMake.\n")
endif()
# Restore the escaped semicolons in arguments that are lists
list(TRANSFORM cmake_args REPLACE "\\[\\[;\\]\\]" "\\\\;")

View File

@ -27,7 +27,7 @@ function(_qt_internal_handle_ios_launch_screen target)
if(NOT launch_screen AND NOT QT_NO_SET_DEFAULT_IOS_LAUNCH_SCREEN)
set(is_default_launch_screen TRUE)
set(launch_screen
"${__qt_internal_cmake_ios_support_files_path}/LaunchScreen.storyboard")
"${__qt_internal_cmake_apple_support_files_path}/LaunchScreen.storyboard")
endif()
# Check that the launch screen exists.
@ -554,15 +554,13 @@ function(_qt_internal_set_xcode_bitcode_enablement target)
"NO")
endfunction()
function(_qt_internal_generate_ios_info_plist target)
function(_qt_internal_copy_info_plist target)
# If the project already specifies a custom file, we don't override it.
get_target_property(existing_plist "${target}" MACOSX_BUNDLE_INFO_PLIST)
if(existing_plist)
return()
get_target_property(info_plist_in "${target}" MACOSX_BUNDLE_INFO_PLIST)
if(NOT info_plist_in)
set(info_plist_in "${__qt_internal_cmake_apple_support_files_path}/Info.plist.app.in")
endif()
set(info_plist_in "${__qt_internal_cmake_ios_support_files_path}/Info.plist.app.in")
string(MAKE_C_IDENTIFIER "${target}" target_identifier)
set(info_plist_out_dir
"${CMAKE_CURRENT_BINARY_DIR}/.qt/info_plist/${target_identifier}")
@ -592,6 +590,62 @@ function(_qt_internal_generate_ios_info_plist target)
set_target_properties("${target}" PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${info_plist_out}")
endfunction()
function(_qt_internal_plist_buddy plist_file)
cmake_parse_arguments(PARSE_ARGV 1 arg
"" "OUTPUT_VARIABLE;ERROR_VARIABLE" "COMMANDS")
foreach(command ${arg_COMMANDS})
execute_process(COMMAND "/usr/libexec/PlistBuddy"
-c "${command}" "${plist_file}"
OUTPUT_VARIABLE plist_buddy_output
ERROR_VARIABLE plist_buddy_error)
string(STRIP "${plist_buddy_output}" plist_buddy_output)
if(arg_OUTPUT_VARIABLE)
list(APPEND ${arg_OUTPUT_VARIABLE} ${plist_buddy_output})
set(${arg_OUTPUT_VARIABLE} ${${arg_OUTPUT_VARIABLE}} PARENT_SCOPE)
endif()
if(arg_ERROR_VARIABLE)
list(APPEND ${arg_ERROR_VARIABLE} ${plist_buddy_error})
set(${arg_ERROR_VARIABLE} ${${arg_ERROR_VARIABLE}} PARENT_SCOPE)
endif()
if(plist_buddy_error)
return()
endif()
endforeach()
endfunction()
function(_qt_internal_set_apple_localizations target)
if(QT_NO_SET_PLIST_LOCALIZATIONS)
return()
endif()
get_target_property(supported_languages "${target}" _qt_apple_supported_languages)
if("${supported_languages}" STREQUAL "supported_languages-NOTFOUND")
return()
endif()
get_target_property(plist_file "${target}" MACOSX_BUNDLE_INFO_PLIST)
if (NOT plist_file)
return()
endif()
_qt_internal_plist_buddy("${plist_file}"
COMMANDS "print CFBundleLocalizations"
OUTPUT_VARIABLE existing_localizations
)
if(existing_localizations)
return()
endif()
list(TRANSFORM supported_languages PREPEND
"Add CFBundleLocalizations: string ")
_qt_internal_plist_buddy("${plist_file}"
COMMANDS
"Add CFBundleLocalizations array"
${supported_languages}
"Delete CFBundleAllowMixedLocalizations"
)
endfunction()
function(_qt_internal_set_ios_simulator_arch target)
if(CMAKE_XCODE_ATTRIBUTE_ARCHS
OR QT_NO_SET_XCODE_ARCHS)
@ -621,6 +675,9 @@ endfunction()
function(_qt_internal_finalize_apple_app target)
# Shared between macOS and iOS apps
_qt_internal_copy_info_plist("${target}")
_qt_internal_set_apple_localizations("${target}")
# Only set the various properties if targeting the Xcode generator, otherwise the various
# Xcode tokens are embedded as-is instead of being dynamically evaluated.
# This affects things like the version number or application name as reported by Qt API.
@ -637,12 +694,12 @@ function(_qt_internal_finalize_apple_app target)
endfunction()
function(_qt_internal_finalize_ios_app target)
_qt_internal_finalize_apple_app("${target}")
# Must be called before we generate the Info.plist
_qt_internal_handle_ios_launch_screen("${target}")
_qt_internal_finalize_apple_app("${target}")
_qt_internal_set_xcode_targeted_device_family("${target}")
_qt_internal_set_xcode_bitcode_enablement("${target}")
_qt_internal_handle_ios_launch_screen("${target}")
_qt_internal_generate_ios_info_plist("${target}")
_qt_internal_set_ios_simulator_arch("${target}")
endfunction()

View File

@ -53,7 +53,7 @@ endfunction()
function(__qt_internal_get_emcc_recommended_version out_var)
# This version of Qt needs this version of emscripten.
set(QT_EMCC_RECOMMENDED_VERSION "3.1.25")
set(QT_EMCC_RECOMMENDED_VERSION "3.1.37")
set(${out_var} "${QT_EMCC_RECOMMENDED_VERSION}" PARENT_SCOPE)
endfunction()
@ -81,12 +81,16 @@ function(__qt_internal_get_qt_build_emsdk_version out_var)
endif()
if(EXISTS "${WASM_BUILD_DIR}/src/corelib/global/qconfig.h")
file(READ "${WASM_BUILD_DIR}/src/corelib/global/qconfig.h" ver)
else()
elseif(EXISTS "${WASM_BUILD_DIR}/include/QtCore/qconfig.h")
file(READ "${WASM_BUILD_DIR}/include/QtCore/qconfig.h" ver)
else()
message("qconfig.h not found, unable to determine Qt build Emscripten version")
endif()
if (ver)
string(REGEX MATCH "#define QT_EMCC_VERSION.\"[0-9]+\\.[0-9]+\\.[0-9]+\"" emOutput ${ver})
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" build_emcc_version "${emOutput}")
set(${out_var} "${build_emcc_version}" PARENT_SCOPE)
endif()
string(REGEX MATCH "#define QT_EMCC_VERSION.\"[0-9]+\\.[0-9]+\\.[0-9]+\"" emOutput ${ver})
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" build_emcc_version "${emOutput}")
set(${out_var} "${build_emcc_version}" PARENT_SCOPE)
endfunction()
function(_qt_test_emscripten_version)

View File

@ -37,8 +37,6 @@ function(qt_generate_qconfig_cpp in_file out_file)
set(QT_SYS_CONF_DIR "${INSTALL_SYSCONFDIR}")
# Compute and set relocation prefixes.
# TODO: Clean this up, there's a bunch of unrealistic assumptions here.
# See qtConfOutput_preparePaths in qtbase/configure.pri.
if(WIN32)
set(lib_location_absolute_path
"${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}")
@ -213,6 +211,7 @@ function(qt_get_qmake_module_name result module)
string(REGEX REPLACE "^Qt6" "" module "${module}")
string(REGEX REPLACE "Private$" "_private" module "${module}")
string(REGEX REPLACE "Qpa$" "_qpa_lib_private" module "${module}")
string(REGEX REPLACE "Rhi$" "_rhi_lib_private" module "${module}")
string(TOLOWER "${module}" module)
set(${result} ${module} PARENT_SCOPE)
endfunction()

View File

@ -3,10 +3,14 @@
function(qt_internal_add_resource target resourceName)
if(NOT TARGET "${target}")
qt_internal_is_in_test_batch(in_batch ${target})
if(NOT in_batch)
message(FATAL_ERROR "Trying to add resource to a non-existing target \"${target}\".")
endif()
message(FATAL_ERROR "${target} is not a target.")
endif()
qt_internal_is_skipped_test(skipped ${target})
if(skipped)
return()
endif()
qt_internal_is_in_test_batch(in_batch ${target})
if(in_batch)
_qt_internal_test_batch_target_name(target)
endif()

View File

@ -8,18 +8,14 @@
set(QT_BUILDING_QT TRUE CACHE BOOL
"When this is present and set to true, it signals that we are building Qt from source.")
# Pre-calculate the developer_build feature if it's set by the user via INPUT_developer_build
if(NOT FEATURE_developer_build AND INPUT_developer_build
AND NOT "${INPUT_developer_build}" STREQUAL "undefined")
set(FEATURE_developer_build ON)
endif()
# Pre-calculate the developer_build feature if it's set by the user via the INPUT_developer_build
# variable when using the configure script. When not using configure, don't take the INPUT variable
# into account, so that users can toggle the feature directly in the cache or via IDE.
qt_internal_compute_feature_value_from_possible_input(developer_build)
# Pre-calculate the no_prefix feature if it's set by configure via INPUT_no_prefix.
# This needs to be done before qtbase/configure.cmake is processed.
if(NOT FEATURE_no_prefix AND INPUT_no_prefix
AND NOT "${INPUT_no_prefix}" STREQUAL "undefined")
set(FEATURE_no_prefix ON)
endif()
qt_internal_compute_feature_value_from_possible_input(no_prefix)
set(_default_build_type "Release")
if(FEATURE_developer_build)
@ -49,7 +45,20 @@ unset(QT_EXTRA_BUILD_INTERNALS_VARS)
# Save the global property in a variable to make it available to feature conditions.
get_property(QT_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
# Try to detect if an explicit CMAKE_BUILD_TYPE was set by the user.
# CMake sets CMAKE_BUILD_TYPE_INIT to Debug on most Windows platforms and doesn't set
# anything for UNIXes. CMake assigns CMAKE_BUILD_TYPE_INIT to CMAKE_BUILD_TYPE during
# first project() if CMAKE_BUILD_TYPE has no previous value.
# We use extra information about the state of CMAKE_BUILD_TYPE before the first
# project() call that's set in QtAutodetect.
# STREQUAL check needs to have expanded variables because an undefined var is not equal
# to an empty defined var.
# See also qt_internal_force_set_cmake_build_type_conditionally which is used
# to set the build type when building other repos or tests.
if("${CMAKE_BUILD_TYPE}" STREQUAL "${CMAKE_BUILD_TYPE_INIT}"
AND NOT __qt_auto_detect_cmake_build_type_before_project_call
AND NOT __qt_build_internals_cmake_build_type
AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${_default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${_default_build_type}" CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE
@ -193,6 +202,8 @@ else()
set(QT_INTERNAL_CONFIGURE_FROM_IDE FALSE CACHE INTERNAL "Configuring Qt Project from IDE")
endif()
set(_qt_sync_headers_at_configure_time_default ${QT_INTERNAL_CONFIGURE_FROM_IDE})
if(FEATURE_developer_build)
if(DEFINED QT_CMAKE_EXPORT_COMPILE_COMMANDS)
set(CMAKE_EXPORT_COMPILE_COMMANDS ${QT_CMAKE_EXPORT_COMPILE_COMMANDS})
@ -213,11 +224,26 @@ if(FEATURE_developer_build)
if (CMAKE_BUILD_TYPE AND CMAKE_BUILD_TYPE STREQUAL Debug)
set(__build_benchmarks OFF)
endif()
# Sync headers during the initial configuration of a -developer-build to facilitate code
# navigation for code editors that use an LSP-based code model.
set(_qt_sync_headers_at_configure_time_default TRUE)
else()
set(_qt_build_tests_default OFF)
set(__build_benchmarks OFF)
endif()
# Sync Qt header files at configure time
option(QT_SYNC_HEADERS_AT_CONFIGURE_TIME "Run syncqt at configure time already"
${_qt_sync_headers_at_configure_time_default})
unset(_qt_sync_headers_at_configure_time_default)
# In static Ninja Multi-Config builds the sync_headers dependencies(and other autogen dependencies
# are not added to '_autogen/timestamp' targets. See QTBUG-113974.
if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND NOT QT_BUILD_SHARED_LIBS)
set(QT_SYNC_HEADERS_AT_CONFIGURE_TIME TRUE CACHE BOOL "" FORCE)
endif()
# Build Benchmarks
option(QT_BUILD_BENCHMARKS "Build Qt Benchmarks" ${__build_benchmarks})
if(QT_BUILD_BENCHMARKS)
@ -255,10 +281,10 @@ endif()
option(QT_BUILD_TESTS_BATCHED "Link all tests into a single binary." ${_qt_batch_tests})
if(QT_BUILD_TESTS AND QT_BUILD_TESTS_BATCHED AND CMAKE_VERSION VERSION_LESS "3.18")
if(QT_BUILD_TESTS AND QT_BUILD_TESTS_BATCHED AND CMAKE_VERSION VERSION_LESS "3.19")
message(FATAL_ERROR
"Test batching requires at least CMake 3.18, due to requiring per-source "
"TARGET_DIRECTORY assignments.")
"Test batching requires at least CMake 3.19, due to requiring per-source "
"TARGET_DIRECTORY assignments and DEFER calls.")
endif()
# QT_BUILD_TOOLS_WHEN_CROSSCOMPILING -> QT_FORCE_BUILD_TOOLS
@ -285,6 +311,9 @@ enable_testing()
option(QT_BUILD_EXAMPLES "Build Qt examples" OFF)
option(QT_BUILD_EXAMPLES_BY_DEFAULT "Should examples be built as part of the default 'all' target." ON)
option(QT_INSTALL_EXAMPLES_SOURCES "Install example sources" OFF)
option(QT_INSTALL_EXAMPLES_SOURCES_BY_DEFAULT
"Install example sources as part of the default 'install' target" ON)
# FIXME: Support prefix builds as well QTBUG-96232
if(QT_WILL_INSTALL)
@ -354,31 +383,11 @@ endif()
option(QT_ALLOW_SYMLINK_IN_PATHS "Allows symlinks in paths." OFF)
# We need to clean up QT_FEATURE_*, but only once per configuration cycle
get_property(qt_feature_clean GLOBAL PROPERTY _qt_feature_clean)
if(NOT qt_feature_clean)
message(STATUS "Check for feature set changes")
set_property(GLOBAL PROPERTY _qt_feature_clean TRUE)
foreach(feature ${QT_KNOWN_FEATURES})
if(DEFINED "FEATURE_${feature}" AND
NOT "${QT_FEATURE_${feature}}" STREQUAL "${FEATURE_${feature}}")
message(" '${feature}' is changed from ${QT_FEATURE_${feature}} \
to ${FEATURE_${feature}}")
set(dirty_build TRUE)
endif()
unset("QT_FEATURE_${feature}" CACHE)
endforeach()
set(QT_KNOWN_FEATURES "" CACHE INTERNAL "" FORCE)
if(dirty_build)
set_property(GLOBAL PROPERTY _qt_dirty_build TRUE)
message(WARNING "Re-configuring in existing build folder. \
Some features will be re-evaluated automatically.")
endif()
endif()
qt_internal_detect_dirty_features()
if(NOT QT_BUILD_EXAMPLES)
# Disable deployment setup to avoid warnings about missing patchelf with CMake < 3.21.
set(QT_SKIP_SETUP_DEPLOYMENT ON)
endif()
option(QT_ALLOW_DOWNLOAD "Allows files to be downloaded when building Qt." OFF)

View File

@ -79,6 +79,7 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
endif()
get_target_property(qpa_filter_regex ${target} _qt_module_qpa_headers_filter_regex)
get_target_property(rhi_filter_regex ${target} _qt_module_rhi_headers_filter_regex)
get_target_property(private_filter_regex ${target} _qt_module_private_headers_filter_regex)
# We need to use the real paths since otherwise it may lead to the invalid work of the
@ -96,6 +97,12 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
)
endif()
if(rhi_filter_regex)
set(rhi_filter_argument
-rhiHeadersFilter "${rhi_filter_regex}"
)
endif()
set(common_syncqt_arguments
-module "${module}"
-sourceDir "${source_dir_real}"
@ -104,8 +111,10 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
-includeDir "${module_build_interface_include_dir}"
-privateIncludeDir "${module_build_interface_private_include_dir}"
-qpaIncludeDir "${module_build_interface_qpa_include_dir}"
-rhiIncludeDir "${module_build_interface_rhi_include_dir}"
-generatedHeaders ${module_headers_generated}
${qpa_filter_argument}
${rhi_filter_argument}
${public_namespaces_filter}
${non_qt_module_argument}
${internal_module_argument}
@ -178,6 +187,7 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
${syncqt_args_rsp}
${module_headers}
${QT_CMAKE_EXPORT_NAMESPACE}::syncqt
"$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_internal_sync_headers_deps>>"
COMMENT
"Running syncqt.cpp for module: ${module}"
VERBATIM
@ -194,6 +204,8 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
${syncqt_outputs}
)
add_dependencies(sync_headers ${target}_sync_headers)
set_target_properties(${target}
PROPERTIES _qt_internal_sync_headers_target ${target}_sync_headers)
if(is_3rd_party_library)
add_dependencies(thirdparty_sync_headers ${target}_sync_headers)
@ -224,7 +236,7 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
endif()
add_dependencies(sync_all_public_headers ${target}_sync_all_public_headers)
if(NOT is_3rd_party_library AND NOT is_framework)
if(NOT is_3rd_party_library AND NOT is_framework AND module_headers)
# Install all the CaMeL style aliases of header files from the staging directory in one rule
qt_install(DIRECTORY "${syncqt_staging_dir}/"
DESTINATION "${module_install_interface_include_dir}"
@ -246,7 +258,7 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
# Run sync Qt first time at configure step to make all header files available for the code model
# of IDEs.
get_property(synced_modules GLOBAL PROPERTY _qt_synced_modules)
if(NOT "${module}" IN_LIST synced_modules)
if(NOT "${module}" IN_LIST synced_modules AND QT_SYNC_HEADERS_AT_CONFIGURE_TIME)
message(STATUS "Running syncqt.cpp for module: ${module}")
get_target_property(syncqt_location ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt LOCATION)
execute_process(

View File

@ -20,10 +20,14 @@
# Skip the specified source files by PRECOMPILE_HEADERS feature.
function(qt_internal_extend_target target)
if(NOT TARGET "${target}")
qt_internal_is_in_test_batch(in_batch ${target})
if(NOT in_batch)
message(FATAL_ERROR "Trying to extend a non-existing target \"${target}\".")
endif()
message(FATAL_ERROR "${target} is not a target.")
endif()
qt_internal_is_skipped_test(skipped ${target})
if(skipped)
return()
endif()
qt_internal_is_in_test_batch(in_batch ${target})
if(in_batch)
_qt_internal_test_batch_target_name(target)
endif()
@ -109,6 +113,19 @@ function(qt_internal_extend_target target)
if(NOT base_lib STREQUAL lib)
qt_create_nolink_target("${base_lib}" ${target})
endif()
# Collect _sync_headers targets from libraries that the target depends on. This is
# heuristic way of building the dependency tree between the _sync_headers targets of
# different Qt modules.
if(TARGET "${lib}")
get_target_property(is_private ${lib} _qt_is_private_module)
if(is_private)
get_target_property(lib ${lib} _qt_public_module_target_name)
endif()
set(out_genex "$<TARGET_PROPERTY:${lib},_qt_internal_sync_headers_target>")
set_property(TARGET ${target}
APPEND PROPERTY _qt_internal_sync_headers_deps "${out_genex}")
endif()
endforeach()
# Set-up the target
@ -1018,6 +1035,24 @@ function(qt_internal_mark_as_internal_target target)
set_target_properties(${target} PROPERTIES _qt_is_internal_target TRUE)
endfunction()
# Marks a target with a property to skip it adding it as a dependency when building examples as
# ExternalProjects.
# Needed to create a ${repo}_src global target that examples can depend on in multi-config builds
# due to a bug in AUTOUIC.
#
# See QTBUG-110369.
function(qt_internal_skip_dependency_for_examples target)
set_target_properties(${target} PROPERTIES _qt_skip_dependency_for_examples TRUE)
endfunction()
function(qt_internal_is_target_skipped_for_examples target out_var)
get_property(is_skipped TARGET ${target} PROPERTY _qt_skip_dependency_for_examples)
if(NOT is_skipped)
set(is_skipped FALSE)
endif()
set(${out_var} "${is_skipped}" PARENT_SCOPE)
endfunction()
function(qt_internal_link_internal_platform_for_object_library target)
# We need to apply iOS bitcode flags to object libraries that are associated with internal
# modules or plugins (e.g. object libraries added by qt_internal_add_resource,
@ -1080,11 +1115,15 @@ endfunction()
# The function disables one or multiple internal global definitions that are defined by the
# qt_internal_add_global_definition function for a specific 'target'.
function(qt_internal_undefine_global_definition target)
if(NOT TARGET ${target})
qt_internal_is_in_test_batch(in_batch ${target})
if(NOT ${in_batch})
message(FATAL_ERROR "${target} is not a target.")
endif()
if(NOT TARGET "${target}")
message(FATAL_ERROR "${target} is not a target.")
endif()
qt_internal_is_skipped_test(skipped ${target})
if(skipped)
return()
endif()
qt_internal_is_in_test_batch(in_batch ${target})
if(in_batch)
_qt_internal_test_batch_target_name(target)
endif()
@ -1135,3 +1174,157 @@ function(qt_internal_get_target_sources_property out_var)
endif()
set(${out_var} "${${out_var}}" PARENT_SCOPE)
endfunction()
# This function collects target properties that contain generator expressions and needs to be
# exported. This function is needed since the CMake EXPORT_PROPERTIES property doesn't support
# properties that contain generator expressions.
# Usage: qt_internal_add_genex_properties_export(target properties...)
function(qt_internal_add_genex_properties_export target)
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
set(config_check_begin "")
set(config_check_end "")
if(is_multi_config)
list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
# The genex snippet is evaluated to '$<NOT:$<BOOL:$<CONFIG>>>' in the generated cmake file.
# The check is only applicable to the 'main' configuration. If user project doesn't use
# multi-config generator, then the check supposed to return true and the value from the
# 'main' configuration supposed to be used.
string(JOIN "" check_if_config_empty
"$<1:$><NOT:"
"$<1:$><BOOL:"
"$<1:$><CONFIG$<ANGLE-R>"
"$<ANGLE-R>"
"$<ANGLE-R>"
)
# The genex snippet is evaluated to '$<CONFIG:'Qt config type'>' in the generated cmake
# file and checks if the config that user uses matches the generated cmake file config.
string(JOIN "" check_user_config
"$<1:$><CONFIG:$<CONFIG>$<ANGLE-R>"
)
# The genex snippet is evaluated to '$<$<OR:$<CONFIG:'Qt config type'>>:'Property content'>
# for non-main Qt configs and to
# $<$<OR:$<CONFIG:'Qt config type'>,$<NOT:$<BOOL:$<CONFIG>>>>:'Property content'> for the
# main Qt config. This guard is required to choose the correct value of the property for the
# user project according to the user config type.
# All genexes need to be escaped properly to protect them from evaluation by the
# file(GENERATE call in the qt_internal_export_genex_properties function.
string(JOIN "" config_check_begin
"$<1:$><"
"$<1:$><OR:"
"${check_user_config}"
"$<$<CONFIG:${first_config_type}>:$<COMMA>${check_if_config_empty}>"
"$<ANGLE-R>:"
)
set(config_check_end "$<ANGLE-R>")
endif()
set(target_name "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
foreach(property IN LISTS ARGN)
set(target_property_genex "$<TARGET_PROPERTY:${target_name},${property}>")
# All properties that contain lists need to be protected of processing by JOIN genex calls.
# So this escapes the semicolons for these list.
set(target_property_list_escape
"$<JOIN:$<GENEX_EVAL:${target_property_genex}>,\;>")
set(property_value
"\"${config_check_begin}${target_property_list_escape}${config_check_end}\"")
set_property(TARGET ${target} APPEND PROPERTY _qt_export_genex_properties_content
"${property} ${property_value}")
endforeach()
endfunction()
# This function executes generator expressions for the properties that are added by the
# qt_internal_add_genex_properties_export function and sets the calculated values to the
# corresponding properties in the generated ExtraProperties.cmake file. The file then needs to be
# included after the target creation routines in Config.cmake files. It also supports Multi-Config
# builds.
# Arguments:
# EXPORT_NAME_PREFIX:
# The portion of the file name before ExtraProperties.cmake
# CONFIG_INSTALL_DIR:
# Installation location for the file.
# TARGETS:
# The internal target names.
function(qt_internal_export_genex_properties)
set(option_args "")
set(single_args
EXPORT_NAME_PREFIX
CONFIG_INSTALL_DIR
)
set(multi_args TARGETS)
cmake_parse_arguments(arg "${option_args}" "${single_args}" "${multi_args}" ${ARGN})
if(NOT arg_EXPORT_NAME_PREFIX)
message(FATAL_ERROR "qt_internal_export_genex_properties: "
"Missing EXPORT_NAME_PREFIX argument.")
endif()
if(NOT arg_TARGETS)
message(FATAL_ERROR "qt_internal_export_genex_properties: "
"TARGETS argument must contain at least one target")
endif()
foreach(target IN LISTS arg_TARGETS)
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
set(output_file_base_name "${arg_EXPORT_NAME_PREFIX}ExtraProperties")
set(should_append "")
set(config_suffix "")
if(is_multi_config)
list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type)
set(config_suffix "$<$<NOT:$<CONFIG:${first_config_type}>>:-$<CONFIG>>")
# If the generated file belongs to the 'main' config type, we should set property
# but not append it.
string(JOIN "" should_append
"$<$<NOT:$<CONFIG:${first_config_type}>>: APPEND>")
endif()
set(file_name "${output_file_base_name}${config_suffix}.cmake")
qt_path_join(output_file "${arg_CONFIG_INSTALL_DIR}"
"${file_name}")
if(NOT IS_ABSOLUTE "${output_file}")
qt_path_join(output_file "${QT_BUILD_DIR}" "${output_file}")
endif()
set(target_name "${QT_CMAKE_EXPORT_NAMESPACE}::${target}")
string(JOIN "" set_property_begin "set_property(TARGET "
"${target_name}${should_append} PROPERTY "
)
set(set_property_end ")")
set(set_property_glue "${set_property_end}\n${set_property_begin}")
set(property_list
"$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_export_genex_properties_content>>")
string(JOIN "" set_property_content "${set_property_begin}"
"$<JOIN:${property_list},${set_property_glue}>"
"${set_property_end}")
if(is_multi_config)
set(config_includes "")
foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES)
if(NOT first_config_type STREQUAL config)
set(include_file_name
"${output_file_base_name}-${config}.cmake")
list(APPEND config_includes
"include(\"\${CMAKE_CURRENT_LIST_DIR}/${include_file_name}\")")
endif()
endforeach()
list(JOIN config_includes "\n" config_includes_string)
set(config_includes_string
"\n$<$<CONFIG:${first_config_type}>:${config_includes_string}>")
endif()
file(GENERATE OUTPUT "${output_file}"
CONTENT "$<$<BOOL:${property_list}>:${set_property_content}${config_includes_string}>"
CONDITION "$<BOOL:${property_list}>"
)
endforeach()
qt_install(FILES "$<$<BOOL:${property_list}>:${output_file}>"
DESTINATION "${arg_CONFIG_INSTALL_DIR}"
COMPONENT Devel
)
endfunction()

View File

@ -247,6 +247,7 @@ function(qt_internal_add_test_to_batch batch_name name)
# Lazy-init the test batch
if(NOT TARGET ${target})
qt_internal_library_deprecation_level(deprecation_define)
qt_internal_add_executable(${target}
${exceptions_text}
${gui_text}
@ -254,11 +255,16 @@ function(qt_internal_add_test_to_batch batch_name name)
NO_INSTALL
OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/build_dir"
SOURCES "${QT_CMAKE_DIR}/qbatchedtestrunner.in.cpp"
DEFINES QTEST_BATCH_TESTS
DEFINES QTEST_BATCH_TESTS ${deprecation_define}
INCLUDE_DIRECTORIES ${private_includes}
LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core
${QT_CMAKE_EXPORT_NAMESPACE}::Test
${QT_CMAKE_EXPORT_NAMESPACE}::TestPrivate
# Add GUI by default so that the plugins link properly with non-standalone
# build of tests. Plugin handling is currently only done in
# qt_internal_add_executable if Gui is present. This should be reevaluated with
# multiple batches.
${QT_CMAKE_EXPORT_NAMESPACE}::Gui
)
set_property(TARGET ${target} PROPERTY _qt_has_exceptions ${arg_EXCEPTIONS})
@ -309,17 +315,12 @@ function(qt_internal_add_test_to_batch batch_name name)
list(PREPEND batched_test_list ${name})
set_property(GLOBAL PROPERTY _qt_batched_test_list_property ${batched_test_list})
qt_internal_library_deprecation_level(deprecation_define)
# Merge the current test with the rest of the batch
qt_internal_extend_target(${target}
INCLUDE_DIRECTORIES ${arg_INCLUDE_DIRECTORIES}
PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES}
LIBRARIES ${arg_LIBRARIES}
SOURCES ${arg_SOURCES}
DEFINES
${arg_DEFINES}
${deprecation_define}
COMPILE_OPTIONS ${arg_COMPILE_OPTIONS}
COMPILE_FLAGS ${arg_COMPILE_FLAGS}
LINK_OPTIONS ${arg_LINK_OPTIONS}
@ -336,7 +337,7 @@ function(qt_internal_add_test_to_batch batch_name name)
set_source_files_properties(${source}
TARGET_DIRECTORY ${target}
PROPERTIES COMPILE_DEFINITIONS
"BATCHED_TEST_NAME=\"${name}\"")
"BATCHED_TEST_NAME=\"${name}\";${arg_DEFINES}" )
endforeach()
set(${batch_name} ${target} PARENT_SCOPE)
@ -363,6 +364,34 @@ function(qt_internal_is_in_test_batch out name)
endif()
endfunction()
function(qt_internal_is_skipped_test out name)
get_target_property(is_skipped_test ${name} _qt_is_skipped_test)
set(${out} ${is_skipped_test} PARENT_SCOPE)
endfunction()
function(qt_internal_set_skipped_test name)
set_target_properties(${name} PROPERTIES _qt_is_skipped_test TRUE)
endfunction()
function(qt_internal_is_qtbase_test out)
get_filename_component(dir "${CMAKE_CURRENT_BINARY_DIR}" ABSOLUTE)
set(${out} FALSE PARENT_SCOPE)
while(TRUE)
get_filename_component(filename "${dir}" NAME)
if("${filename}" STREQUAL "qtbase")
set(${out} TRUE PARENT_SCOPE)
break()
endif()
set(prev_dir "${dir}")
get_filename_component(dir "${dir}" DIRECTORY)
if("${dir}" STREQUAL "${prev_dir}")
break()
endif()
endwhile()
endfunction()
function(qt_internal_get_batched_test_arguments out testname)
if(WASM)
# Add a query string to the runner document, so that the script therein
@ -403,6 +432,32 @@ function(qt_internal_add_test name)
_qt_internal_validate_all_args_are_parsed(arg)
_qt_internal_validate_no_unity_build(arg)
set(batch_current_test FALSE)
if(QT_BUILD_TESTS_BATCHED AND NOT arg_NO_BATCH AND NOT arg_QMLTEST AND NOT arg_MANUAL
AND ("${QT_STANDALONE_TEST_PATH}" STREQUAL ""
OR DEFINED ENV{QT_BATCH_STANDALONE_TESTS}))
set(batch_current_test TRUE)
endif()
if(batch_current_test OR (QT_BUILD_TESTS_BATCHED AND arg_QMLTEST))
if (QT_SUPERBUILD OR DEFINED ENV{TESTED_MODULE_COIN})
set(is_qtbase_test FALSE)
if(QT_SUPERBUILD)
qt_internal_is_qtbase_test(is_qtbase_test)
elseif($ENV{TESTED_MODULE_COIN} STREQUAL "qtbase")
set(is_qtbase_test TRUE)
endif()
if(NOT is_qtbase_test)
file(GENERATE OUTPUT "dummy${name}.cpp" CONTENT "int main() { return 0; }")
# Add a dummy target to tackle some potential problems
qt_internal_add_executable(${name} SOURCES "dummy${name}.cpp")
# Batched tests outside of qtbase are unsupported and skipped
qt_internal_set_skipped_test(${name})
return()
endif()
endif()
endif()
if (NOT arg_OUTPUT_DIRECTORY)
set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
@ -421,9 +476,8 @@ function(qt_internal_add_test name)
"removed in a future Qt version. Use the LIBRARIES option instead.")
endif()
if(NOT arg_NO_BATCH AND QT_BUILD_TESTS_BATCHED AND NOT arg_QMLTEST AND NOT arg_MANUAL)
if(batch_current_test)
qt_internal_add_test_to_batch(name ${name} ${ARGN})
set(setting_up_batched_test TRUE)
elseif(arg_SOURCES)
if(QT_BUILD_TESTS_BATCHED AND arg_QMLTEST)
message(WARNING "QML tests won't be batched - unsupported (yet)")
@ -499,7 +553,6 @@ function(qt_internal_add_test name)
qt_internal_extend_target("${name}" CONDITION ANDROID
LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Gui
)
set(setting_up_batched_test FALSE)
set_target_properties(${name} PROPERTIES _qt_is_test_executable TRUE)
set_target_properties(${name} PROPERTIES _qt_is_manual_test ${arg_MANUAL})
endif()
@ -550,7 +603,7 @@ function(qt_internal_add_test name)
elseif(WASM)
# The test script expects an html file. In case of batched tests, the
# version specialized for running batches has to be supplied.
if(setting_up_batched_test)
if(batch_current_test)
get_target_property(batch_output_dir ${name} RUNTIME_OUTPUT_DIRECTORY)
set(test_executable "${batch_output_dir}/${name}.html")
else()
@ -562,11 +615,16 @@ function(qt_internal_add_test name)
list(APPEND extra_test_args "--silence_timeout=60")
# TODO: Add functionality to specify browser
list(APPEND extra_test_args "--browser=chrome")
list(APPEND extra_test_args "--browser_args=\"--password-store=basic\"")
list(APPEND extra_test_args "--kill_exit")
# We always want to enable asyncify for tests, as some of them use exec
# Tests may require asyncify if they use exec(). Enable asyncify for
# batched tests since this is the configuration used on the CI system.
# Optimize for size (-Os), since asyncify tends to make the resulting
# binary very large
target_link_options("${name}" PRIVATE "SHELL:-s ASYNCIFY" "-Os")
if(batch_current_test)
target_link_options("${name}" PRIVATE "SHELL:-s ASYNCIFY" "-Os")
endif()
# This tells cmake to run the tests with this script, since wasm files can't be
# executed directly
@ -588,9 +646,11 @@ function(qt_internal_add_test name)
endif()
if(NOT arg_MANUAL)
if(setting_up_batched_test)
if(batch_current_test)
qt_internal_get_batched_test_arguments(batched_test_args ${testname})
list(PREPEND extra_test_args ${batched_test_args})
elseif(WASM AND CMAKE_BUILD_TYPE STREQUAL "Debug")
list(PREPEND extra_test_args "qvisualoutput")
endif()
qt_internal_collect_command_environment(test_env_path test_env_plugin_path)
@ -661,10 +721,29 @@ function(qt_internal_add_test name)
foreach(testdata IN LISTS arg_TESTDATA)
list(APPEND builtin_files ${testdata})
endforeach()
foreach(file IN LISTS builtin_files)
set_source_files_properties(${file}
PROPERTIES QT_SKIP_QUICKCOMPILER TRUE
)
endforeach()
set(blacklist_path "BLACKLIST")
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
list(APPEND builtin_files ${blacklist_path})
if(batch_current_test)
set(blacklist_path "BLACKLIST")
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
get_target_property(blacklist_files ${name} _qt_blacklist_files)
if(NOT blacklist_files)
set_target_properties(${name} PROPERTIES _qt_blacklist_files "")
set(blacklist_files "")
cmake_language(EVAL CODE "cmake_language(DEFER DIRECTORY \"${CMAKE_SOURCE_DIR}\" CALL \"_qt_internal_finalize_batch\" \"${name}\") ")
endif()
list(PREPEND blacklist_files "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
set_target_properties(${name} PROPERTIES _qt_blacklist_files "${blacklist_files}")
endif()
else()
set(blacklist_path "BLACKLIST")
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}")
list(APPEND builtin_files ${blacklist_path})
endif()
endif()
list(REMOVE_DUPLICATES builtin_files)
@ -762,7 +841,8 @@ for this function. Will be ignored")
endif()
set(executable_name ${arg_NAME})
if(QT_BUILD_TESTS_BATCHED)
qt_internal_is_in_test_batch(is_in_batch ${executable_name})
if(is_in_batch)
_qt_internal_test_batch_target_name(executable_name)
endif()
add_test(NAME "${arg_NAME}" COMMAND "${CMAKE_COMMAND}" "-P" "${arg_OUTPUT_FILE}"
@ -828,8 +908,8 @@ function(qt_internal_add_test_helper name)
set(extra_args_to_pass)
if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY)
if(QT_BUILD_TESTS_BATCHED)
_qt_internal_test_batch_target_name(test_batch_target_name)
_qt_internal_test_batch_target_name(test_batch_target_name)
if(QT_BUILD_TESTS_BATCHED AND TARGET ${test_batch_target_name})
get_target_property(
test_batch_output_dir ${test_batch_target_name} RUNTIME_OUTPUT_DIRECTORY)
set(extra_args_to_pass OUTPUT_DIRECTORY "${test_batch_output_dir}")

View File

@ -8,7 +8,8 @@ function (qt_internal_setup_wasm_target_properties wasmTarget)
target_link_options("${wasmTarget}" INTERFACE
"SHELL:-s MAX_WEBGL_VERSION=2"
"SHELL:-s FETCH=1"
"SHELL:-s WASM_BIGINT=1")
"SHELL:-s WASM_BIGINT=1"
"SHELL:-s STACK_SIZE=5MB")
target_link_libraries("${wasmTarget}" INTERFACE embind)
@ -93,17 +94,25 @@ function (qt_internal_setup_wasm_target_properties wasmTarget)
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
# plugins are SIDE_MODULE
target_compile_options("${wasmTarget}" INTERFACE
"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,MODULE_LIBRARY>:" -s SIDE_MODULE=1>)
target_link_options("${wasmTarget}" INTERFACE
"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,MODULE_LIBRARY>:" -s SIDE_MODULE=1>)
set(side_modules
MODULE_LIBRARY SHARED_LIBRARY)
set(enable_side_module_if_needed
"$<$<IN_LIST:$<TARGET_PROPERTY:TYPE>,${side_modules}>:SHELL:-s SIDE_MODULE=1>")
set(enable_main_module_if_needed
"$<$<IN_LIST:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:SHELL:-s MAIN_MODULE=1>")
set(set_shared_module_type_if_needed
"${enable_side_module_if_needed}"
"${enable_main_module_if_needed}"
)
# shared libs are SIDE_MODULE
target_compile_options("${wasmTarget}" INTERFACE
"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>:" -s SIDE_MODULE=1>)
# Add Qt libdir to linker library paths
set(qt_lib_location
"${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
target_link_options("${wasmTarget}" INTERFACE
"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>:" -s SIDE_MODULE=1>)
"$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:SHELL:" -L${qt_lib_location}/>)
target_compile_options("${wasmTarget}" INTERFACE "${set_shared_module_type_if_needed}")
target_link_options("${wasmTarget}" INTERFACE "${set_shared_module_type_if_needed}")
else()
target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ERROR_ON_UNDEFINED_SYMBOLS=1")

View File

@ -39,6 +39,20 @@ function(qt_internal_create_wrapper_scripts)
DESTINATION "${INSTALL_BINDIR}")
endif()
if(generate_unix)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-create.in"
"${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create" @ONLY
NEWLINE_STYLE LF)
qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create"
DESTINATION "${INSTALL_BINDIR}")
endif()
if(generate_non_unix)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake-create.bat.in"
"${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create.bat" @ONLY
NEWLINE_STYLE CRLF)
qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-create.bat"
DESTINATION "${INSTALL_BINDIR}")
endif()
# Provide a private convenience wrapper with options which should not be propagated via the
# public qt-cmake wrapper e.g. CMAKE_GENERATOR.
# These options can not be set in a toolchain file, but only on the command line.

View File

@ -313,3 +313,16 @@ $ cd some/empty/directory
$ ~/Qt/6.0.0/bin/qt-cmake-standalone-test ~/source/of/qtbase/test/auto/corelib/io/qprocess
$ cmake --build .
```
## qt-cmake-create
Generates a simple CMakeLists.txt based on source files in specified project directory.
Example:
```
$ cd some/source/directory/
$ qt-cmake-create
$ qt-cmake -S . -B /build/directory
$ cmake --build /build/directory
```

View File

@ -17,7 +17,6 @@ The following table describes the mapping of configure options to CMake argument
| -no-feature-foo | -DFEATURE_foo=OFF | |
| -list-features | | At the moment: configure with cmake once, |
| | | then use ccmake or cmake-gui to inspect the features. |
| -list-libraries | | |
| -opensource | n/a | |
| -commercial | n/a | |
| -confirm-license | n/a | |
@ -60,6 +59,7 @@ The following table describes the mapping of configure options to CMake argument
| -R <string> | -DQT_EXTRA_RPATHS=path1;path2 | |
| -rpath | negative CMAKE_SKIP_BUILD_RPATH | |
| | negative CMAKE_SKIP_INSTALL_RPATH | |
| | negative CMAKE_MACOSX_RPATH | |
| -reduce-exports | -DFEATURE_reduce_exports=ON | |
| -reduce-relocations | -DFEATURE_reduce_relocations=ON | |
| -plugin-manifests | | |
@ -75,16 +75,9 @@ The following table describes the mapping of configure options to CMake argument
| -ccache | -DQT_USE_CCACHE=ON | |
| -unity-build | -DQT_UNITY_BUILD=ON | |
| -unity-build-batch-size <int> | -DQT_UNITY_BUILD_BATCH_SIZE=<int> | |
| -make-tool <tool> | n/a | |
| -mp | n/a | |
| -warnings-are-errors | -DWARNINGS_ARE_ERRORS=ON | |
| -silent | n/a | |
| -sysroot <dir> | -DCMAKE_SYSROOT=<dir> | Should be provided by a toolchain file that's |
| | | passed via -DCMAKE_TOOLCHAIN_FILE=<filename> |
| -no-gcc-sysroot | n/a | The corresponding CMake variables are CMAKE_SYSROOT_LINK |
| | | and CMAKE_SYSROOT_COMPILE. |
| | | They are usually set in a toolchain file. |
| -no-pkg-config | -DFEATURE_pkg_config=OFF | |
| -no-vcpkg | -DQT_USE_VCPKG=OFF | |
| -D <string> | -DQT_EXTRA_DEFINES=<string1>;<string2> | |
| -I <string> | -DQT_EXTRA_INCLUDEPATHS=<string1>;<string2> | |
| -L <string> | -DQT_EXTRA_LIBDIRS=<string1>;<string2> | |
@ -110,6 +103,7 @@ The following table describes the mapping of configure options to CMake argument
| | | build them separately, after configuration. |
| -nomake <part> | -DQT_BUILD_TESTS=OFF | A way to turn off tools explicitly is missing. |
| | -DQT_BUILD_EXAMPLES=OFF | |
| -install-examples-sources | -DQT_INSTALL_EXAMPLES_SOURCES=ON | |
| -no-gui | -DFEATURE_gui=OFF | |
| -no-widgets | -DFEATURE_widgets=OFF | |
| -no-dbus | -DFEATURE_dbus=OFF | |

View File

@ -1,11 +1,13 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qglobal.h>
#ifndef @header_base_name_upper@_H
#define @header_base_name_upper@_H
#include <QtCore/qcompilerdetection.h>
#include <QtCore/qtconfigmacros.h> // Q_@module_define_infix@_EXPORT
#include <QtCore/qtdeprecationmarkers.h> // QT_IF_DEPRECATED_SINCE
#if defined(QT_SHARED) || !defined(QT_STATIC)
# if defined(QT_BUILD_@module_define_infix@_LIB)
# define Q_@module_define_infix@_EXPORT Q_DECL_EXPORT

View File

@ -4,6 +4,8 @@
#ifndef @header_base_name_upper@_P_H
#define @header_base_name_upper@_P_H
// This file is autogenerated. Changes will be overwritten.
//
// W A R N I N G
// -------------

View File

@ -0,0 +1,65 @@
{
"Project": {
"Git": {
"_active": true,
"sourceserver_gitdir": "/data/axivion/databases/$(env:TESTED_MODULE_COIN).git"
},
"BuildSystemIntegration": {
"child_order": [
"GCCSetup",
"CMake",
"LinkLibraries"
]
},
"CMake": {
"_active": true,
"_copy_from": "CMakeIntegration",
"build_environment": {},
"build_options": "-j4",
"generate_options": "--fresh",
"generator": "Ninja"
},
"GCCSetup": {
"_active": true,
"_copy_from": "Command",
"build_command": "gccsetup --cc gcc --cxx g++ --config ../../../axivion/"
},
"LinkLibraries": {
"_active": true,
"_copy_from": "AxivionLinker",
"input_files": [
"build/lib/lib*.so*.ir"
],
"ir": "build/$(env:TESTED_MODULE_COIN).ir",
"plugin_files": [
"build/plugins/*/lib*.so*.ir"
]
},
"Project-GlobalOptions": {
"ci_mode": {
"clean_before": false
},
"directory": "../work/qt/$(env:TESTED_MODULE_COIN)",
"ir": "build/$(env:TESTED_MODULE_COIN).ir",
"name": "qt_$(env:TESTED_MODULE_COIN)_dev_$(env:TARGET_OS_COIN)"
}
},
"Results": {
"Dashboard": {
"dashboard_url": "https://axivion-srv.ci.qt.io/axivion/"
},
"Database": {
"ci_mode": {
"directory": "/data/axivion/databases"
}
}
},
"_Format": "1.0",
"_Version": "trunk-9e0ef9c5818",
"_VersionNum": [
7,
6,
9999,
11489
]
}

View File

@ -76,9 +76,14 @@ instructions:
- !include "{{qt/qtbase}}/call_host_install.yaml"
- type: SignPackage
enable_if:
condition: property
property: host.os
equals_value: Windows
condition: and
conditions:
- condition: property
property: host.os
equals_value: Windows
- condition: property
property: features
contains_value: Packaging
directory: "{{.InstallRoot}}/{{.AgentWorkingDir}}"
maxTimeInSeconds: 1200
maxTimeBetweenOutput: 1200

View File

@ -73,9 +73,14 @@ instructions:
- !include "{{qt/qtbase}}/call_host_install.yaml"
- type: SignPackage
enable_if:
condition: property
property: host.os
equals_value: Windows
condition: and
conditions:
- condition: property
property: host.os
equals_value: Windows
- condition: property
property: features
contains_value: Packaging
directory: "{{.InstallRoot}}/{{.AgentWorkingDir}}"
maxTimeInSeconds: 1200
maxTimeBetweenOutput: 1200

View File

@ -0,0 +1,98 @@
analysis_instructions_axivion: &analysis_instructions_axivion
type: Group
instructions:
- type: Group
instructions:
- type: EnvironmentVariable
variableName: AXIVION_CHAINLOAD_TOOLCHAIN_FILE
variableValue: "{{.AgentWorkingDir}}/install/lib/cmake/Qt6/qt.toolchain.cmake"
- type: EnvironmentVariable
variableName: CMAKE_PREFIX_PATH
variableValue: "{{.AgentWorkingDir}}/install/lib/cmake"
enable_if:
condition: runtime
env_var: TESTED_MODULE_COIN
not_equals_value: "qtbase"
- type: Group
instructions:
- type: Rename
sourcePath: "{{.SourceDir}}/coin/axivion/ci_config_{{.Env.TARGET_OS_COIN}}.json"
targetPath: "{{.Env.HOME}}/axivion/ci_config.json"
userMessageOnFailure: "Moving ci_config.json failed. Make sure you have included the file in coin/axivion/ -folder"
- type: SetBuildDirectory
directory: "{{.SourceDir}}"
- type: ChangeDirectory
directory: "{{.BuildDir}}"
- type: ExecuteCommand
command: ["../../../axivion/start_analysis.sh"]
maxTimeInSeconds: 28800
maxTimeBetweenOutput: 28800
userMessageOnFailure: "Failed to run analysis"
build_environment_axivion: &build_environment_axivion
type: Group
instructions:
- type: ExecuteCommand
command: ["sudo", "mkdir", "-p","/data/axivion"]
maxTimeInSeconds: 100
maxTimeBetweenOutput: 100
userMessageOnFailure: "Create mount point for results failed"
- type: ExecuteCommand
command: ["sudo", "mount", "-o", "rw", "10.212.0.93:/data/axivion", "/data/axivion"]
maxTimeInSeconds: 100
maxTimeBetweenOutput: 100
userMessageOnFailure: "Mount failed"
- type: ExecuteCommand
command: ["rm","-rf","{{.SourceDir}}"]
maxTimeInSeconds: 100
maxTimeBetweenOutput: 100
userMessageOnFailure: "Failed to remove source directory"
- type: MakeDirectory
directory: "{{.SourceDir}}"
- type: ChangeDirectory
directory: "{{.SourceDir}}"
- type: ExecuteCommand
command: ["git", "clone", "--jobs={{.NumCPU}}", "-n","--depth=50", "git://{{.Env.QT_COIN_GIT_DAEMON}}/qt-project/qt/{{.Env.TESTED_MODULE_COIN}}","."]
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed to clone repository"
- type: ExecuteCommand
command: ["git", "fetch", "--recurse-submodules", "origin", "{{.Env.TESTED_MODULE_REVISION_COIN}}"]
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed to fetch sources"
- type: ExecuteCommand
command: ["git", "checkout", "--force", "{{.Env.TESTED_MODULE_REVISION_COIN}}"]
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed to checkout sources"
- type: ExecuteCommand
command: ["git", "submodule", "update", "--init", "--recursive"]
maxTimeInSeconds: 1800
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed to initialize git submodules"
- type: Group
instructions:
- !include "{{qt/qtbase}}/cmake_module_build_instructions.yaml"
enable_if:
condition: runtime
env_var: TESTED_MODULE_COIN
not_equals_value: "qtbase"
- type: Group
instructions:
- !include "{{qt/qtbase}}/cmake_qtbase_build_instructions.yaml"
enable_if:
condition: runtime
env_var: TESTED_MODULE_COIN
equals_value: "qtbase"
type: Group
instructions:
- !include "{{qt/qtbase}}/prepare_building_env.yaml"
- *build_environment_axivion
- *analysis_instructions_axivion
enable_if:
condition: property
property: features
contains_value: Axivion

View File

@ -24,6 +24,33 @@ instructions:
- condition: property
property: features
not_contains_value: "TargetBuildOnly"
- condition: property
property: features
not_contains_value: "DebianPackaging"
- condition: property
property: features
not_contains_value: Axivion
- type: Group
instructions:
- !include "{{qt/qtbase}}/coin_module_axivion_template_v2.yaml"
enable_if:
condition: and
conditions:
- condition: property
property: features
contains_value: Axivion
- condition: runtime
env_var: TESTED_MODULE_COIN
not_equals_value: "qtdoc"
- condition: runtime
env_var: TESTED_MODULE_COIN
not_equals_value: "qtquickeffectmaker"
- condition: runtime
env_var: TESTED_MODULE_COIN
not_equals_value: "qttranslations"
- condition: runtime
env_var: TESTED_MODULE_COIN
not_equals_value: "qtwebengine"
- type: Group
instructions:
- !include "{{qt/qtbase}}/cmake_cross_compilation_module_build_instructions.yaml"
@ -48,3 +75,15 @@ instructions:
- condition: property
property: target.arch
equals_value: ARM64
- condition: property
property: features
not_contains_value: "DebianPackaging"
- type: Group
instructions:
- type: Group
instructions:
- !include "{{qt/qtbase}}/debian/debian_build_module.yaml"
enable_if:
condition: property
property: features
contains_value: "DebianPackaging"

View File

@ -17,6 +17,19 @@ instructions:
- condition: property
property: features
not_contains_value: "TargetBuildOnly"
- condition: property
property: features
not_contains_value: "DebianPackaging"
- condition: property
property: features
not_contains_value: Axivion
- type: Group
instructions:
- !include "{{qt/qtbase}}/coin_module_axivion_template_v2.yaml"
enable_if:
condition: property
property: features
contains_value: Axivion
- type: Group
instructions:
- type: Group
@ -53,3 +66,15 @@ instructions:
- condition: property
property: target.arch
equals_value: ARM64
- condition: property
property: features
not_contains_value: "DebianPackaging"
- type: Group
instructions:
- type: Group
instructions:
- !include "{{qt/qtbase}}/debian/debian_build_module.yaml"
enable_if:
condition: property
property: features
contains_value: "DebianPackaging"

View File

@ -0,0 +1,125 @@
type: Group
enable_if:
condition: property
property: features
contains_value: DebianPackaging
instructions:
- !include "{{qt/qtbase}}/debian/prepare_debian_env.yaml"
- type: EnvironmentVariable
variableName: GIT_SSH_COMMAND
variableValue: "ssh -o StrictHostKeyChecking=no"
- type: ChangeDirectory
directory: "{{.AgentWorkingDir}}"
- type: MakeDirectory
directory: output/debian_packages
- type: MakeDirectory
directory: debian_packages
- type: ExecuteCommand
command: "git clone git@git.qt.io:tqtc-debian/package_generator.git"
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed to clone package generator repo"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: ExecuteCommand
command: "git clone -b 6.6 git@git.qt.io:tqtc-debian/qt6-{{.Env.TESTED_MODULE_PLAIN_COIN}}.git"
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed to clone debian packaging repo"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: ChangeDirectory
directory: "qt6-{{.Env.TESTED_MODULE_PLAIN_COIN}}"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: ExecuteCommand
command: "git checkout {{.Env.DEBIAN_RULES_REF}}"
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed to checkout debian rules branch"
disable_if:
condition: or
conditions:
- condition: runtime
env_var: DEBIAN_RULES_REF
equals_value: null
- condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: ChangeDirectory
directory: "{{.AgentWorkingDir}}"
- type: ExecuteCommand
command: "wget -q {{.CoinDownloadURL}}/{{.Env.MODULE_SOURCES_RELATIVE_STORAGE_PATH}}"
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed get sources"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: ExecuteCommand
command: "mv sources_unix.tar.gz qt-{{.Env.QT_REPO_MODULE_VERSION}}-{{.Env.TESTED_MODULE_PLAIN_COIN}}-src_{{.Env.QT_REPO_MODULE_VERSION}}.orig.tar.gz"
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed rename src pkg"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: ChangeDirectory
directory: "{{.AgentWorkingDir}}/qt6-{{.Env.TESTED_MODULE_PLAIN_COIN}}"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
# rc is required currently by the script
- type: ExecuteCommand
command: "../package_generator/generate_packaging.sh --qt-version {{.Env.QT_REPO_MODULE_VERSION}} --deb-rev 1 --release tqtc-focal"
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed to generate pkg"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: ChangeDirectory
directory: "{{.AgentWorkingDir}}"
- type: ExecuteCommand
command: "dpkg-source -b qt6-{{.Env.TESTED_MODULE_PLAIN_COIN}}"
maxTimeInSeconds: 900
maxTimeBetweenOutput: 900
userMessageOnFailure: "Failed dpkg-source"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: ExecuteCommand
command: ["sbuild",
"--build-dep-resolver=apt",
"-sAd", "tqtc-focal",
"-c", "{{.Env.COIN_SBUILD_CHROOT}}",
"--build-dir", "output/debian_packages",
"--extra-repository={{.Env.COIN_EXTRA_DEBIAN_REPO}}",
"--extra-package={{.Env.COIN_EXTRA_DEBIAN_PACKAGES}}",
"--extra-package={{.AgentWorkingDir}}/debian_packages/",
"qt-{{.Env.QT_REPO_MODULE_VERSION}}-{{.Env.TESTED_MODULE_PLAIN_COIN}}-src_{{.Env.QT_REPO_MODULE_VERSION}}-1.dsc"]
maxTimeInSeconds: 18000
maxTimeBetweenOutput: 18000
userMessageOnFailure: "Failed build debian packages"
disable_if:
condition: runtime
env_var: COIN_SKIP_DEBIAN
contains_value: "MISSING_DEBIAN_INST"
- type: UploadArtifact
archiveDirectory: "{{.AgentWorkingDir}}/output"
transferType: UploadModuleBuildArtifact
maxTimeInSeconds: 1200
maxTimeBetweenOutput: 1200

View File

@ -0,0 +1,85 @@
type: Group
enable_if:
condition: property
property: features
contains_value: DebianPackaging
instructions:
- type: EnvironmentVariable
variableName: COIN_SBUILD_CHROOT
variableValue: "stable-arm64-sbuild"
enable_if:
condition: and
conditions:
- condition: runtime
env_var: COIN_SBUILD_CHROOT
equals_value: null
- condition: property
property: target.arch
equals_value: AARCH64
- type: EnvironmentVariable
variableName: COIN_SBUILD_CHROOT
variableValue: "stable-amd64-sbuild"
enable_if:
condition: and
conditions:
- condition: runtime
env_var: COIN_SBUILD_CHROOT
equals_value: null
- condition: property
property: target.arch
equals_value: X86_64
- type: EnvironmentVariable
variableName: COIN_SBUILD_DISTRO
variableValue: "arm64-focal"
enable_if:
condition: property
property: target.arch
equals_value: AARCH64
- type: EnvironmentVariable
variableName: COIN_SBUILD_DISTRO
variableValue: "amd64-focal"
disable_if:
condition: property
property: target.arch
equals_value: AARCH64
- type: EnvironmentVariable
variableName: COIN_SKIP_DEBIAN
variableValue: "MISSING_DEBIAN_INST"
enable_if:
condition: or
conditions:
- condition: runtime
env_var: TESTED_MODULE_COIN
equals_value: "qtactiveqt"
- condition: runtime
env_var: TESTED_MODULE_COIN
equals_value: "qtqa"
- condition: runtime
env_var: TESTED_MODULE_COIN
equals_value: "qtdoc"
- condition: runtime
env_var: TESTED_MODULE_COIN
equals_value: "qt5"
# Set version info to environment
- type: ParseEnvironmentVariableFromFile
regex: "QT_REPO_MODULE_VERSION \"(?P<QT_REPO_MODULE_VERSION>.*)\""
filename: "{{.SourceDir}}/.cmake.conf"
maxTimeInSeconds: 300
maxTimeBetweenOutput: 300
userMessageOnFailure: "Failed to parse version information from .cmake.conf"
disable_if:
condition: runtime
env_var: TESTED_MODULE_COIN
equals_value: "qt5"
- type: ParseEnvironmentVariableFromFile
regex: "QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT \"(?P<QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT>.*)\""
filename: "{{.SourceDir}}/.cmake.conf"
maxTimeInSeconds: 300
maxTimeBetweenOutput: 300
userMessageOnFailure: "Failed to parse status information from .cmake.conf"
disable_if:
condition: runtime
env_var: TESTED_MODULE_COIN
equals_value: "qt5"

View File

@ -4,9 +4,17 @@ accept_configuration:
property: features
not_contains_value: Disable
downstream_check:
mode: build
modules:
../qtdeclarative:
ref: dev
configurations:
- rhel-8.4
machine_type:
Build:
cores: 4
cores: 8
Test:
cores: 4

View File

@ -141,7 +141,7 @@ const char msg2[] = "==Qt=magic=Qt== Sub-architecture:"
// Leading-Zero bit count, Intel Core 4th Generation ("Haswell")
" lzcnt"
#endif
#ifdef __MMX__
#if defined(__MMX__) && defined(__i386__)
// Multimedia Extensions, Pentium MMX, AMD K6-2
" mmx"
#endif
@ -198,11 +198,11 @@ const char msg2[] = "==Qt=magic=Qt== Sub-architecture:"
// Shadow stack, Intel processor TBA
" shstk"
#endif
#if defined(__SSE__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1) || defined(_M_X64)
#if (defined(__SSE__) && defined(__i386__)) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1 && defined(_M_IX86))
// Streaming SIMD Extensions, Intel Pentium III, AMD Athlon
" sse"
#endif
#if defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) || defined(_M_X64)
#if (defined(__SSE2__) && defined(__i386__)) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2 && defined(_M_IX86))
// SSE2, Intel Pentium-M, Intel Pentium 4, AMD Opteron and Athlon 64
" sse2"
#endif

View File

@ -1,7 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# special case skip regeneration
cmake_minimum_required(VERSION 3.16)
project(objcopytest LANGUAGES CXX)
add_executable(objcopytest main.cpp)

View File

@ -64,10 +64,13 @@ Build options:
-cmake-file-api ...... Let CMake store build metadata for loading the build
into an IDE. [no; yes if -developer-build]
-no-guess-compiler ... Do not guess the compiler from the target mkspec.
-release ............. Build Qt with debugging turned off [yes]
-debug ............... Build Qt with debugging turned on [no]
-debug-and-release ... Build two versions of Qt, with and without
debugging turned on [yes] (Apple and Windows only)
-release ............. Build Qt with optimizations and without debug
symbols [yes]
Note that -developer-build implies -debug unless
-release is also explicitly specified
-debug ............... Build Qt without optimizations and with debug symbols
[no]
-debug-and-release ... Build two versions of Qt in one build tree [no]
-optimize-debug ...... Enable debug-friendly optimizations in debug builds
[auto] (Not supported with MSVC or Clang toolchains)
-optimize-size ....... Optimize release builds for size instead of speed [no]
@ -80,7 +83,8 @@ Build options:
sections. [auto for static builds, otherwise no]
-force-asserts ....... Enable Q_ASSERT even in release builds [no]
-developer-build ..... Compile and link Qt for developing Qt itself
(exports for auto-tests, extra checks, etc.) [no]
(exports for auto-tests, extra checks, implies
-no-prefix, etc.) [no]
-shared .............. Build shared Qt libraries [yes] (no for UIKit)
-static .............. Build static Qt libraries [no] (yes for UIKit)
@ -157,10 +161,10 @@ Build options:
Build environment:
-sysroot <dir> ....... Set <dir> as the target sysroot
-pkg-config .......... Use pkg-config [auto] (Unix only)
-vcpkg ............... Use vcpkg [yes]
-D <string> .......... Pass additional preprocessor define
-I <string> .......... Pass additional include path
-L <string> .......... Pass additional library path
@ -198,6 +202,9 @@ Component selection:
[default: libs and examples, also tools if not
cross-building, also tests if -developer-build]
-nomake <part> ....... Exclude <part> from the list of parts to be built.
-install-examples-sources Installs examples source code into the Qt prefix
Only possible when -make examples is also passed
[no]
-gui ................. Build the Qt GUI module and dependencies [yes]
-widgets ............. Build the Qt Widgets module and dependencies [yes]
-no-dbus ............. Do not build the Qt D-Bus module
@ -289,6 +296,6 @@ Gui, printing, widget options:
Database options:
-sql-<driver> ........ Enable SQL <driver> plugin. Supported drivers:
db2 ibase mysql oci odbc psql sqlite
db2 ibase mysql oci odbc psql sqlite mimer
[all auto]
-sqlite .............. Select used sqlite [system/qt]

View File

@ -109,7 +109,6 @@ SSL_free(SSL_new(0));
}
")
# special case end
qt_find_package(WrapZSTD 1.3 PROVIDED_TARGETS WrapZSTD::WrapZSTD MODULE_NAME global QMAKE_LIB zstd)
qt_find_package(WrapDBus1 1.2 PROVIDED_TARGETS dbus-1 MODULE_NAME global QMAKE_LIB dbus)
qt_find_package(Libudev PROVIDED_TARGETS PkgConfig::Libudev MODULE_NAME global QMAKE_LIB libudev)
@ -208,51 +207,6 @@ endif()
# machineTuple
qt_config_compile_test_machine_tuple("machine tuple")
# cxx14
qt_config_compile_test(cxx14
LABEL "C++14 support"
CODE
"#if __cplusplus > 201103L
// Compiler claims to support C++14, trust it
#else
# error __cplusplus must be > 201103L (the value of C++11)
#endif
int main(void)
{
/* BEGIN TEST: */
/* END TEST: */
return 0;
}
"
CXX_STANDARD 14
)
# cxx17
qt_config_compile_test(cxx17
LABEL "C++17 support"
CODE
"#if __cplusplus > 201402L
// Compiler claims to support C++17, trust it
#else
# error __cplusplus must be > 201402L (the value for C++14)
#endif
#include <map> // https://bugs.llvm.org//show_bug.cgi?id=33117
#include <variant>
int main(void)
{
/* BEGIN TEST: */
std::variant<int> v(42);
int i = std::get<int>(v);
std::visit([](const auto &) { return 1; }, v);
/* END TEST: */
return 0;
}
"
CXX_STANDARD 17
)
# cxx20
qt_config_compile_test(cxx20
LABEL "C++20 support"
@ -485,7 +439,6 @@ qt_feature("android-style-assets" PRIVATE
)
qt_feature("shared" PUBLIC
LABEL "Building shared libraries"
AUTODETECT NOT UIKIT
CONDITION BUILD_SHARED_LIBS
)
qt_feature_definition("shared" "QT_STATIC" NEGATE PREREQUISITE "!defined(QT_SHARED) && !defined(QT_STATIC)")
@ -517,7 +470,6 @@ qt_feature("optimize_size"
CONDITION NOT QT_FEATURE_debug OR QT_FEATURE_debug_and_release
)
qt_feature_config("optimize_size" QMAKE_PRIVATE_CONFIG)
# special case begin
qt_feature("optimize_full"
LABEL "Fully optimize release builds (-O3)"
AUTODETECT OFF
@ -526,10 +478,10 @@ qt_feature_config("optimize_full" QMAKE_PRIVATE_CONFIG)
qt_feature("msvc_obj_debug_info"
LABEL "Embed debug info in object files (MSVC)"
CONDITION MSVC
ENABLE QT_USE_CCACHE
AUTODETECT OFF
)
qt_feature_config("msvc_obj_debug_info" QMAKE_PRIVATE_CONFIG)
# special case end
qt_feature("pkg-config" PUBLIC
LABEL "Using pkg-config"
AUTODETECT NOT APPLE AND NOT WIN32 AND NOT ANDROID
@ -667,29 +619,10 @@ qt_feature_config("plugin-manifests" QMAKE_PUBLIC_CONFIG
NEGATE
NAME "no_plugin_manifest"
)
qt_feature("c++11" PUBLIC
LABEL "C++11"
)
qt_feature_config("c++11" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("c++14" PUBLIC
LABEL "C++14"
CONDITION QT_FEATURE_cxx11 AND TEST_cxx14
)
qt_feature_config("c++14" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("c++17" PUBLIC
LABEL "C++17"
CONDITION QT_FEATURE_cxx14 AND TEST_cxx17
)
qt_feature_config("c++17" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("c++1z" PUBLIC
LABEL "C++17"
CONDITION QT_FEATURE_cxx17
)
qt_feature_config("c++1z" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("c++20" PUBLIC
LABEL "C++20"
AUTODETECT OFF
CONDITION QT_FEATURE_cxx17 AND TEST_cxx20
CONDITION TEST_cxx20
)
qt_feature_config("c++20" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("c++2a" PUBLIC
@ -707,17 +640,6 @@ qt_feature("c++2b" PUBLIC
AUTODETECT FALSE
CONDITION QT_FEATURE_cxx20 AND (CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") AND TEST_cxx2b
)
qt_feature("c89"
LABEL "C89"
)
qt_feature("c99" PUBLIC
LABEL "C99"
CONDITION c_std_99 IN_LIST CMAKE_C_COMPILE_FEATURES
)
qt_feature("c11" PUBLIC
LABEL "C11"
CONDITION QT_FEATURE_c99 AND c_std_11 IN_LIST CMAKE_C_COMPILE_FEATURES
)
qt_feature("precompile_header"
LABEL "Using precompiled headers"
CONDITION BUILD_WITH_PCH AND TEST_precompile_header
@ -920,7 +842,9 @@ qt_feature_definition("mips_dspr2" "QT_COMPILER_SUPPORTS_MIPS_DSPR2" VALUE "1")
qt_feature_config("mips_dspr2" QMAKE_PRIVATE_CONFIG)
qt_feature("neon" PRIVATE
LABEL "NEON"
CONDITION ( ( ( TEST_architecture_arch STREQUAL arm ) OR ( TEST_architecture_arch STREQUAL arm64 ) ) AND TEST_arch_${TEST_architecture_arch}_subarch_neon ) OR QT_FORCE_FEATURE_neon # special case
CONDITION ( ( ( TEST_architecture_arch STREQUAL arm ) OR
( TEST_architecture_arch STREQUAL arm64 ) ) AND
TEST_arch_${TEST_architecture_arch}_subarch_neon ) OR QT_FORCE_FEATURE_neon
)
qt_feature_definition("neon" "QT_COMPILER_SUPPORTS_NEON" VALUE "1")
qt_feature_config("neon" QMAKE_PRIVATE_CONFIG)
@ -986,7 +910,6 @@ qt_feature("stdlib-libcpp" PRIVATE
AUTODETECT OFF
CONDITION LINUX AND NOT ANDROID
)
# special case begin
# Check whether CMake was built with zstd support.
# See https://gitlab.kitware.com/cmake/cmake/-/issues/21552
if(NOT DEFINED CACHE{QT_CMAKE_ZSTD_SUPPORT})
@ -1003,7 +926,6 @@ if(NOT DEFINED CACHE{QT_CMAKE_ZSTD_SUPPORT})
unset(qt_check_zstd_exit_code)
endif()
endif()
# special case end
qt_feature("thread" PUBLIC
SECTION "Kernel"
LABEL "Thread support"
@ -1143,22 +1065,10 @@ qt_configure_add_summary_entry(
ARGS "optimize_size"
CONDITION NOT QT_FEATURE_debug OR QT_FEATURE_debug_and_release
)
# special case begin
qt_configure_add_summary_entry(
ARGS "optimize_full"
)
# special case end
qt_configure_add_summary_entry(ARGS "shared")
qt_configure_add_summary_entry(
TYPE "firstAvailableFeature"
ARGS "c11 c99 c89"
MESSAGE "Using C standard"
)
qt_configure_add_summary_entry(
TYPE "firstAvailableFeature"
ARGS "c++2b c++20 c++17 c++14 c++11"
MESSAGE "Using C++ standard"
)
qt_configure_add_summary_entry(
ARGS "ccache"
CONDITION UNIX
@ -1232,6 +1142,13 @@ qt_configure_add_summary_entry(ARGS "sanitize_fuzzer_no_link")
qt_configure_add_summary_entry(ARGS "sanitize_undefined")
qt_configure_end_summary_section() # end of "Sanitizers" section
qt_configure_add_summary_build_parts("Build parts")
if(QT_INSTALL_EXAMPLES_SOURCES)
set(_examples_sources_entry_message "yes")
else()
set(_examples_sources_entry_message "no")
endif()
qt_configure_add_summary_entry(ARGS "Install examples sources" TYPE "message"
MESSAGE "${_examples_sources_entry_message}")
qt_configure_add_summary_entry(
ARGS "appstore-compliant"
CONDITION APPLE OR ANDROID OR WIN32
@ -1251,6 +1168,14 @@ qt_configure_add_summary_entry(ARGS "xml")
qt_configure_end_summary_section() # end of "Qt modules and options" section
qt_configure_add_summary_section(NAME "Support enabled for")
qt_configure_add_summary_entry(ARGS "pkg-config")
if(QT_USE_VCPKG AND (DEFINED ENV{VCPKG_ROOT} OR VCPKG_TARGET_TRIPLET))
set(_vcpkg_entry_message "yes")
else()
set(_vcpkg_entry_message "no")
endif()
qt_configure_add_summary_entry(ARGS "Using vcpkg" TYPE "message" MESSAGE "${_vcpkg_entry_message}")
qt_configure_add_summary_entry(ARGS "libudev")
qt_configure_add_summary_entry(ARGS "openssl")
qt_configure_add_summary_entry(ARGS "openssl-linked")
@ -1265,13 +1190,6 @@ qt_configure_add_report_entry(
MESSAGE "Using static linking will disable the use of dynamically loaded plugins. Make sure to import all needed static plugins, or compile needed modules into the library."
CONDITION NOT QT_FEATURE_shared
)
# special case begin
# qt_configure_add_report_entry(
# TYPE ERROR
# MESSAGE "Debug build without Release build is not currently supported on ios see QTBUG-71990. Use -debug-and-release."
# CONDITION IOS AND QT_FEATURE_debug AND NOT QT_FEATURE_debug_and_release
# )
# special case end
qt_configure_add_report_entry(
TYPE WARNING
MESSAGE "-debug-and-release is only supported on Darwin and Windows platforms. Qt can be built in release mode with separate debug information, so -debug-and-release is no longer necessary."
@ -1301,6 +1219,16 @@ if (TEST_architecture_arch STREQUAL x86_64 OR TEST_architecture_arch STREQUAL i3
MESSAGE [=[
All x86 intrinsics and SIMD support were disabled. If this was in error, check
the result of the build in config.tests/x86intrin and report at https://bugreports.qt.io.
]=]
)
elseif (MSVC AND CLANG)
# Warn only
qt_configure_add_report_entry(
TYPE WARNING
CONDITION (NOT QT_FEATURE_x86intrin)
MESSAGE [=[
x86 intrinsics support is disabled for clang-cl build. This might be necessary due to
https://github.com/llvm/llvm-project/issues/53520
]=]
)
else()
@ -1317,7 +1245,6 @@ ${TEST_x86intrin_OUTPUT}
)
endif()
endif()
# special case begin
qt_configure_add_report_entry(
TYPE ERROR
MESSAGE "Setting a library infix is not supported for framework builds."
@ -1336,7 +1263,6 @@ qt_configure_add_report_entry(
if(WASM)
qt_extra_definition("QT_EMCC_VERSION" "\"${EMCC_VERSION}\"" PUBLIC)
endif()
# special case end
qt_extra_definition("QT_VERSION_STR" "\"${PROJECT_VERSION}\"" PUBLIC)
qt_extra_definition("QT_VERSION_MAJOR" ${PROJECT_VERSION_MAJOR} PUBLIC)
qt_extra_definition("QT_VERSION_MINOR" ${PROJECT_VERSION_MINOR} PUBLIC)

View File

@ -1,7 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# special case skip regeneration
#
# Copy/Install doc configuration files to the build/install directory
#

View File

@ -125,6 +125,7 @@ macro.cmakepropertywebassemblyonly = "\\note This property is used only if targe
macro.cmakepropertyiosonly = "\\note This property is used only if targeting iOS."
macro.cmakevariableiosonly = "\\note This variable is used only if targeting iOS."
macro.qtpolicydeprecatedbehavior = "\\note The \\c{OLD} behavior of a policy is deprecated, and may be removed in the future."
#Appends the tech preview link to the brief sentence and adds to tech_preview
#group.
#Must be placed directly under a \brief command

View File

@ -35,7 +35,7 @@ manifestmeta.highlighted.attributes = isHighlighted:true
manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \
"Qt3D/Qt 3D: Planets QML Example" \
"Qt3D/Qt 3D: Simple Custom Material QML Example" \
"QtAndroidExtras/Qt Notifier" \
"QtCore/Qt Android Notifier" \
"QtBluetooth/Bluetooth Low Energy Scanner Example" \
"QtBluetooth/Bluetooth Scanner Example" \
"QtBluetooth/QML Bluetooth Scanner Example" \
@ -51,15 +51,12 @@ manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \
"QtLocation/Places Map (QML)" \
"QtLocation/Plane Spotter (QML)" \
"QtMultimedia/AudioEngine Example" \
"QtMultimedia/Camera Example" \
"QtMultimedia/QML Camera Example" \
"QtMultimedia/QML Video Example" \
"QtMultimedia/QML Video Shader Effects Example" \
"QtNFC/Annotated URL Example" \
"QtNFC/QML Poster Example" \
"QtOpenGL/2D Painting Example" \
"QtOpenGL/Hello GLES3 Example" \
"QtOpenGL/Textures Example" \
"QtPositioning/SatelliteInfo (C++/QML)" \
"QtPositioning/Weather Info (C++/QML)" \
"QtPurchasing/Qt Purchasing Examples - QtHangman" \
@ -94,8 +91,6 @@ manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \
"QtQuickControls/Qt Quick Controls - Flat Style" \
"QtQuickControls/Qt Quick Controls - Gallery" \
"QtQuickControls/Qt Quick Controls - Imagine Style Example: Automotive" \
"QtQuickControls/Qt Quick Controls - Side Panel" \
"QtQuickControls/Qt Quick Controls - Swipe to Remove" \
"QtQuickControls/Qt Quick Controls - Text Editor" \
"QtQuickControls/Qt Quick Controls - Wearable Demo" \
"QtQuickDialogs/*" \
@ -107,47 +102,7 @@ manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \
"QtSQL/Master Detail Example" \
"QtSVG/Text Object Example" \
"QtUiTools/Text Finder Example" \
"QtWebView/Qt WebView Examples - Minibrowser" \
"QtWidgets/Address Book Example" \
"QtWidgets/Affine Transformations" \
"QtWidgets/Analog Clock Example" \
"QtWidgets/Animated Tiles Example" \
"QtWidgets/Application Chooser Example" \
"QtWidgets/Basic Layouts Example" \
"QtWidgets/Border Layout Example" \
"QtWidgets/Code Editor Example" \
"QtWidgets/Colliding Mice Example" \
"QtWidgets/Concentric Circles Example" \
"QtWidgets/Digital Clock Example" \
"QtWidgets/Dynamic Layouts Example" \
"QtWidgets/Easing Curves Example" \
"QtWidgets/Editable Tree Model Example" \
"QtWidgets/Elided Label Example" \
"QtWidgets/Fade Message Effect Example" \
"QtWidgets/Flow Layout Example" \
"QtWidgets/Font Sampler Example" \
"QtWidgets/Frozen Column Example" \
"QtWidgets/Gradients" \
"QtWidgets/Group Box Example" \
"QtWidgets/Image Composition Example" \
"QtWidgets/Line Edits Example" \
"QtWidgets/Mouse Button Tester" \
"QtWidgets/Move Blocks Example" \
"QtWidgets/Painter Paths Example" \
"QtWidgets/Painter Paths Example" \
"QtWidgets/Path Stroking" \
"QtWidgets/Pixelator Example" \
"QtWidgets/Recent Files Example" \
"QtWidgets/SDI Example" \
"QtWidgets/Scribble Example" \
"QtWidgets/Simple Tree Model Example" \
"QtWidgets/Sliders Example" \
"QtWidgets/Spreadsheet" \
"QtWidgets/Touch Dials Example" \
"QtWidgets/Transformations Example" \
"QtWidgets/Undo Framework" \
"QtWidgets/Vector Deformation" \
"QtWidgets/Wiggly Example"
"QtWebView/Qt WebView Examples - Minibrowser"
manifestmeta.android.tags = android

View File

@ -1,2 +1,25 @@
qt_internal_add_example(bindablesubscription)
qt_internal_add_example(subscription)
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(bindableproperties LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/bindableproperties")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
add_subdirectory(shared)
add_subdirectory(subscription)
add_subdirectory(bindablesubscription)
install(TARGETS subscription bindablesubscription
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -1,50 +1,15 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(bindablesubscription LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/bindableproperties/bindablesubscription")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(bindablesubscription
../shared/subscriptionwindow.cpp ../shared/subscriptionwindow.h ../shared/subscriptionwindow.ui
main.cpp
bindablesubscription.cpp bindablesubscription.h
bindableuser.cpp bindableuser.h
bindablesubscription.cpp
bindablesubscription.h
bindableuser.cpp
bindableuser.h
)
target_link_libraries(bindablesubscription PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
bindableproperties_shared
)
# Resources:
set(countries_resource_files
"../shared/finland.png"
"../shared/germany.png"
"../shared/norway.png"
)
qt_add_resources(bindablesubscription "countries"
PREFIX
"/"
BASE
"../shared"
FILES
${countries_resource_files}
)
install(TARGETS bindablesubscription
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,23 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_library(bindableproperties_shared STATIC
subscriptionwindow.cpp
subscriptionwindow.h
subscriptionwindow.ui
)
target_link_libraries(bindableproperties_shared PUBLIC
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
qt_add_resources(bindableproperties_shared "countries"
PREFIX
"/"
FILES
"finland.png"
"germany.png"
"norway.png"
)

View File

@ -1,50 +1,12 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(subscription LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/bindableproperties/subscription")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()
qt_add_executable(subscription
../shared/subscriptionwindow.cpp ../shared/subscriptionwindow.h ../shared/subscriptionwindow.ui
main.cpp
subscription.cpp subscription.h
user.cpp user.h
)
target_link_libraries(subscription PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
# Resources:
set(countries_resource_files
"../shared/finland.png"
"../shared/germany.png"
"../shared/norway.png"
)
qt_add_resources(subscription "countries"
PREFIX
"/"
BASE
"../shared"
FILES
${countries_resource_files}
)
install(TARGETS subscription
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
bindableproperties_shared
)

View File

@ -23,6 +23,8 @@ qt_add_executable(androidnotifier
main.cpp
notificationclient.cpp
notificationclient.h
android/src/org/qtproject/example/androidnotifier/NotificationClient.java
android/AndroidManifest.xml
)
target_link_libraries(androidnotifier PRIVATE

View File

@ -6,6 +6,7 @@
\example platform/androidnotifier
\examplecategory {Mobile}
\brief Demonstrates calling Java code from Qt in an Android application.
\ingroup androidplatform
\image androidnotifier.png
@ -48,7 +49,7 @@
The call to the Java meethod use \l QJniObject which relies on the Java Native
Interface (JNI) APIs to communicate with Java. Also, in the previous snippet,
we are passing the app's context object which the the static Java code can use
we are passing the app's context object, which the static Java code can use
to tap into the app's specific properties and APIs.
To make sure our smiley buttons do what they are supposed to, we add the

View File

@ -0,0 +1,188 @@
#!/bin/env python3
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
"""Digest cbor-tags.xml file into code for insertion into main.cpp
See main.cpp's comment on how to regenerate its GENERATED CODE.
See ./cbortag.py --help for further details on how to invoke.
You can import this is a module without invoking the script.
"""
def firstChild(parent, tag):
"""Return parent's first child element with the given tag."""
return next(node for node in parent.childNodes
if node.nodeType == parent.ELEMENT_NODE and node.nodeName == tag)
def nodeAttrIs(node, attr, seek):
"""Checks whether the node has a given value for an attribute
Takes the node to check, the name of the attribute and the value
to check against. Returns true if the node does have that value
for the named attribute."""
if node.nodeType != node.ELEMENT_NODE:
return False
if node.attributes is None or attr not in node.attributes:
return False
return node.attributes[attr].value == seek
def getRfcValue(node):
"""Extract RFC reference from an <xref type="rfc" ...> element
Some of these have a reference including section details as the
body of the element, otherwise the data attribute should identify
the RFC. If neither is found, an empty string is returned."""
if node.childNodes:
return node.childNodes[0].nodeValue # Maybe accumulate several children ?
if node.attributes is None or 'data' not in node.attributes:
return ''
return node.attributes['data'].value
def readRegistry(filename):
"""Handles the XML parsing and returns the relevant parts.
Single argument is the path to the cbor-tags.xml file; returns a
twople of the title element's text and an interator over the
record nodes. Checks some things are as expected while doing so."""
from xml.dom.minidom import parse
doc = parse(filename).documentElement
assert nodeAttrIs(doc, 'id', 'cbor-tags')
title = firstChild(doc, 'title').childNodes[0].nodeValue
registry = firstChild(doc, 'registry')
assert nodeAttrIs(registry, 'id', 'tags')
records = (node for node in registry.childNodes if node.nodeName == 'record')
return title, records
def digest(record):
"""Digest a single record from cbor-tags.xml
If the record is not of interest, returns the twople (None, None).
For records of interest, returns (n, t) where n is the numeric tag
code of the record and t is a text describing it. If the record,
or its semantics field, has an xref child with type="rfc", the RFC
mentioned there is included with the text of the semantics; such a
record is of interest, provided it has a semantics field and no
dash in its value. Records with a value field containing a dash
(indicating a range) are not of interest. Records with a value of
256 or above are only of interest if they include an RFC."""
data = {}
for kid in record.childNodes:
if kid.nodeName == 'xref':
if not nodeAttrIs(kid, 'type', 'rfc'):
continue
rfc = getRfcValue(kid)
if rfc:
# Potentially stomping one taken from semantics
data['rfc'] = rfc
elif kid.nodeName == 'semantics':
text = rfc = ''
for part in kid.childNodes:
if part.nodeType == kid.TEXT_NODE:
text += part.nodeValue
elif part.nodeType == kid.ELEMENT_NODE:
if part.nodeName != 'xref' or not nodeAttrIs(part, 'type', 'rfc'):
continue # potentially append content to text
assert not rfc, ('Duplicate RFC ?', rfc, part)
rfc = getRfcValue(part)
if rfc:
if text.endswith('()'):
text = text[:-2].rstrip()
if 'rfc' not in data:
data['rfc'] = rfc
data['semantics'] = ' '.join(text.split())
elif kid.nodeName == 'value':
data['value'] = kid.childNodes[0].nodeValue
text = data.get('semantics')
if not text or 'value' not in data or '-' in data['value']:
return None, None
value = int(data['value'])
if 'rfc' in data:
rfc = data["rfc"].replace('rfc', 'RFC')
text = f'{text} [{rfc}]'
elif value >= 256:
return None, None
return value, text
def entries(records):
"""Digest each record of interest into a value and text.
The value and text form the raw material of the tagDescriptions
array in main.cpp; see digest for which records are retained."""
for record in records:
value, text = digest(record)
if value is not None:
yield value, text
def marginBound(text, prior, left, right):
"""Split up a string literal for tidy display.
The first parameter, text, is the content of the string literal;
quotes shall be added. It may be split into several fragments,
each quoted, so as to abide by line length constraints.
The remaining parameters are integers: prior is the text already
present on the line before text is to be added; left is the width
of the left margin for all subsequent lines; and right is the
right margin to stay within, where possible. The returned string
is either a space with the whole quoted text following, to fit on
the line already started to length prior, or a sequence of quoted
strings, each preceded by a newline and indent of width left."""
if prior + 3 + len(text) < right: # 1 for space, 2 for quotes
return f' "{text}"'
width = right - left - 2 # 2 for the quotes
words = iter(text.split(' '))
lines, current = [''], [next(words)]
for word in words:
if len(word) + sum(len(w) + 1 for w in current) > width:
line = ' '.join(current)
lines.append(f'"{line}"')
current = ['', word]
else:
current.append(word)
line = ' '.join(current)
lines.append(f'"{line}"')
return ('\n' + ' ' * left).join(lines)
def main(argv, speak):
"""Takes care of driving the process.
Takes the command-line argument list (whose first entry is the
name of this script) and standard output (or compatible stream of
your choosing) to which to write data. If the --out option is
specified in the arguments, the file it names is used in place of
this output stream."""
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
parser = ArgumentParser(
description='Digest cbor-tags.xml into code to insert in main.cpp',
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('path', help='path of the cbor-tags.xml file',
default='cbor-tags.xml')
parser.add_argument('--out', help='file to write instead of standard output')
args = parser.parse_args(argv[1:])
emit = (open(args.out) if args.out else speak).write
title, records = readRegistry(args.path)
emit(f"""\
struct CborTagDescription
{{
QCborTag tag;
const char *description; // with space and parentheses
}};
// {title}
static const CborTagDescription tagDescriptions[] = {{
// from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
""")
for value, text in sorted(entries(records)):
prior = f' {{ QCborTag({value}),'
body = marginBound(f' ({text})', len(prior), 6, 96)
emit(f"{prior}{body} }},\n")
emit("""\
{ QCborTag(-1), nullptr }
};
""")
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv, sys.stdout))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

@ -19,18 +19,12 @@ using namespace Qt::StringLiterals;
/*
* To regenerate:
* curl -O https://www.iana.org/assignments/cbor-tags/cbor-tags.xml
* xsltproc tag-transform.xslt cbor-tags.xml
* ./cbortag.py cbor-tags.xml
*
* The XHTML URL mentioned in the comment below is a human-readable version of
* the same resource.
*/
/* TODO (if possible): fix XSLT to replace each newline and surrounding space in
a semantics entry with a single space, instead of using a raw string to wrap
each, propagating the spacing from the XML to the output of cbordump. Also
auto-purge dangling spaces from the ends of generated lines.
*/
// GENERATED CODE
struct CborTagDescription
{
@ -38,180 +32,101 @@ struct CborTagDescription
const char *description; // with space and parentheses
};
// CBOR Tags
// Concise Binary Object Representation (CBOR) Tags
static const CborTagDescription tagDescriptions[] = {
// from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
{ QCborTag(0),
R"r( (Standard date/time string; see Section 3.4.1 [RFC8949]))r" },
{ QCborTag(1),
R"r( (Epoch-based date/time; see Section 3.4.2 [RFC8949]))r" },
{ QCborTag(2),
R"r( (Positive bignum; see Section 3.4.3 [RFC8949]))r" },
{ QCborTag(3),
R"r( (Negative bignum; see Section 3.4.3 [RFC8949]))r" },
{ QCborTag(4),
R"r( (Decimal fraction; see Section 3.4.4 [RFC8949]))r" },
{ QCborTag(5),
R"r( (Bigfloat; see Section 3.4.4 [RFC8949]))r" },
{ QCborTag(16),
R"r( (COSE Single Recipient Encrypted Data Object [RFC9052]))r" },
{ QCborTag(17),
R"r( (COSE Mac w/o Recipients Object [RFC9052]))r" },
{ QCborTag(18),
R"r( (COSE Single Signer Data Object [RFC9052]))r" },
{ QCborTag(19),
R"r( (COSE standalone V2 countersignature [RFC9338]))r" },
{ QCborTag(0), " (Standard date/time string; see Section 3.4.1 [RFC8949])" },
{ QCborTag(1), " (Epoch-based date/time; see Section 3.4.2 [RFC8949])" },
{ QCborTag(2), " (Positive bignum; see Section 3.4.3 [RFC8949])" },
{ QCborTag(3), " (Negative bignum; see Section 3.4.3 [RFC8949])" },
{ QCborTag(4), " (Decimal fraction; see Section 3.4.4 [RFC8949])" },
{ QCborTag(5), " (Bigfloat; see Section 3.4.4 [RFC8949])" },
{ QCborTag(16), " (COSE Single Recipient Encrypted Data Object [RFC9052])" },
{ QCborTag(17), " (COSE Mac w/o Recipients Object [RFC9052])" },
{ QCborTag(18), " (COSE Single Signer Data Object [RFC9052])" },
{ QCborTag(19), " (COSE standalone V2 countersignature [RFC9338])" },
{ QCborTag(21),
R"r( (Expected conversion to base64url encoding; see Section 3.4.5.2 [RFC8949]))r" },
{ QCborTag(22),
R"r( (Expected conversion to base64 encoding; see Section 3.4.5.2 [RFC8949]))r" },
{ QCborTag(23),
R"r( (Expected conversion to base16 encoding; see Section 3.4.5.2 [RFC8949]))r" },
{ QCborTag(24),
R"r( (Encoded CBOR data item; see Section 3.4.5.1 [RFC8949]))r" },
{ QCborTag(25),
R"r( (reference the nth previously seen string))r" },
{ QCborTag(26),
R"r( (Serialised Perl object with classname and constructor arguments))r" },
" (Expected conversion to base64url encoding; see Section 3.4.5.2 [RFC8949])" },
{ QCborTag(22), " (Expected conversion to base64 encoding; see Section 3.4.5.2 [RFC8949])" },
{ QCborTag(23), " (Expected conversion to base16 encoding; see Section 3.4.5.2 [RFC8949])" },
{ QCborTag(24), " (Encoded CBOR data item; see Section 3.4.5.1 [RFC8949])" },
{ QCborTag(25), " (reference the nth previously seen string)" },
{ QCborTag(26), " (Serialised Perl object with classname and constructor arguments)" },
{ QCborTag(27),
R"r( (Serialised language-independent object with type name and constructor arguments))r" },
{ QCborTag(28),
R"r( (mark value as (potentially) shared))r" },
{ QCborTag(29),
R"r( (reference nth marked value))r" },
{ QCborTag(30),
R"r( (Rational number))r" },
{ QCborTag(31),
R"r( (Absent value in a CBOR Array))r" },
{ QCborTag(32),
R"r( (URI; see Section 3.4.5.3 [RFC8949]))r" },
{ QCborTag(33),
R"r( (base64url; see Section 3.4.5.3 [RFC8949]))r" },
{ QCborTag(34),
R"r( (base64; see Section 3.4.5.3 [RFC8949]))r" },
{ QCborTag(35),
R"r( (Regular expression; see Section 2.4.4.3 [RFC7049]))r" },
{ QCborTag(36),
R"r( (MIME message; see Section 3.4.5.3 [RFC8949]))r" },
{ QCborTag(37),
R"r( (Binary UUID (RFC4122, Section 4.1.2)))r" },
{ QCborTag(38),
R"r( (Language-tagged string [RFC9290]))r" },
{ QCborTag(39),
R"r( (Identifier))r" },
{ QCborTag(40),
R"r( (Multi-dimensional Array, row-major order [RFC8746]))r" },
{ QCborTag(41),
R"r( (Homogeneous Array [RFC8746]))r" },
{ QCborTag(42),
R"r( (IPLD content identifier))r" },
{ QCborTag(43),
R"r( (YANG bits datatype; see Section 6.7. [RFC9254]))r" },
{ QCborTag(44),
R"r( (YANG enumeration datatype; see Section 6.6. [RFC9254]))r" },
{ QCborTag(45),
R"r( (YANG identityref datatype; see Section 6.10. [RFC9254]))r" },
{ QCborTag(46),
R"r( (YANG instance-identifier datatype; see Section 6.13. [RFC9254]))r" },
{ QCborTag(47),
R"r( (YANG Schema Item iDentifier (sid); see Section 3.2. [RFC9254]))r" },
{ QCborTag(52),
R"r( (IPv4, [prefixlen,IPv4], [IPv4,prefixpart] [RFC9164]))r" },
{ QCborTag(54),
R"r( (IPv6, [prefixlen,IPv6], [IPv6,prefixpart] [RFC9164]))r" },
{ QCborTag(61),
R"r( (CBOR Web Token (CWT) [RFC8392]))r" },
{ QCborTag(63),
R"r( (Encoded CBOR Sequence ))r" },
{ QCborTag(64),
R"r( (uint8 Typed Array [RFC8746]))r" },
{ QCborTag(65),
R"r( (uint16, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(66),
R"r( (uint32, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(67),
R"r( (uint64, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(68),
R"r( (uint8 Typed Array, clamped arithmetic [RFC8746]))r" },
{ QCborTag(69),
R"r( (uint16, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(70),
R"r( (uint32, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(71),
R"r( (uint64, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(72),
R"r( (sint8 Typed Array [RFC8746]))r" },
{ QCborTag(73),
R"r( (sint16, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(74),
R"r( (sint32, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(75),
R"r( (sint64, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(76),
R"r( ((reserved) [RFC8746]))r" },
{ QCborTag(77),
R"r( (sint16, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(78),
R"r( (sint32, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(79),
R"r( (sint64, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(80),
R"r( (IEEE 754 binary16, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(81),
R"r( (IEEE 754 binary32, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(82),
R"r( (IEEE 754 binary64, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(83),
R"r( (IEEE 754 binary128, big endian, Typed Array [RFC8746]))r" },
{ QCborTag(84),
R"r( (IEEE 754 binary16, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(85),
R"r( (IEEE 754 binary32, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(86),
R"r( (IEEE 754 binary64, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(87),
R"r( (IEEE 754 binary128, little endian, Typed Array [RFC8746]))r" },
{ QCborTag(96),
R"r( (COSE Encrypted Data Object [RFC9052]))r" },
{ QCborTag(97),
R"r( (COSE MACed Data Object [RFC9052]))r" },
{ QCborTag(98),
R"r( (COSE Signed Data Object [RFC9052]))r" },
{ QCborTag(100),
R"r( (Number of days since the epoch date 1970-01-01 [RFC8943]))r" },
{ QCborTag(101),
R"r( (alternatives as given by the uint + 128; see Section 9.1))r" },
{ QCborTag(103),
R"r( (Geographic Coordinates))r" },
{ QCborTag(104),
R"r( (Geographic Coordinate Reference System WKT or EPSG number))r" },
{ QCborTag(110),
R"r( (relative object identifier (BER encoding); SDNV sequence [RFC9090]))r" },
{ QCborTag(111),
R"r( (object identifier (BER encoding) [RFC9090]))r" },
{ QCborTag(112),
R"r( (object identifier (BER encoding), relative to 1.3.6.1.4.1 [RFC9090]))r" },
{ QCborTag(120),
R"r( (Internet of Things Data Point))r" },
" (Serialised language-independent object with type name and constructor arguments)" },
{ QCborTag(28), " (mark value as (potentially) shared)" },
{ QCborTag(29), " (reference nth marked value)" },
{ QCborTag(30), " (Rational number)" },
{ QCborTag(31), " (Absent value in a CBOR Array)" },
{ QCborTag(32), " (URI; see Section 3.4.5.3 [RFC8949])" },
{ QCborTag(33), " (base64url; see Section 3.4.5.3 [RFC8949])" },
{ QCborTag(34), " (base64; see Section 3.4.5.3 [RFC8949])" },
{ QCborTag(35), " (Regular expression; see Section 2.4.4.3 [RFC7049])" },
{ QCborTag(36), " (MIME message; see Section 3.4.5.3 [RFC8949])" },
{ QCborTag(37), " (Binary UUID [RFC4122, Section 4.1.2])" },
{ QCborTag(38), " (Language-tagged string [RFC9290, Appendix A])" },
{ QCborTag(39), " (Identifier)" },
{ QCborTag(40), " (Multi-dimensional Array, row-major order [RFC8746])" },
{ QCborTag(41), " (Homogeneous Array [RFC8746])" },
{ QCborTag(42), " (IPLD content identifier)" },
{ QCborTag(43), " (YANG bits datatype; see Section 6.7. [RFC9254])" },
{ QCborTag(44), " (YANG enumeration datatype; see Section 6.6. [RFC9254])" },
{ QCborTag(45), " (YANG identityref datatype; see Section 6.10. [RFC9254])" },
{ QCborTag(46), " (YANG instance-identifier datatype; see Section 6.13. [RFC9254])" },
{ QCborTag(47), " (YANG Schema Item iDentifier (sid); see Section 3.2. [RFC9254])" },
{ QCborTag(52), " (IPv4, [prefixlen,IPv4], [IPv4,prefixpart] [RFC9164])" },
{ QCborTag(54), " (IPv6, [prefixlen,IPv6], [IPv6,prefixpart] [RFC9164])" },
{ QCborTag(61), " (CBOR Web Token (CWT) [RFC8392])" },
{ QCborTag(63), " (Encoded CBOR Sequence [RFC8742])" },
{ QCborTag(64), " (uint8 Typed Array [RFC8746])" },
{ QCborTag(65), " (uint16, big endian, Typed Array [RFC8746])" },
{ QCborTag(66), " (uint32, big endian, Typed Array [RFC8746])" },
{ QCborTag(67), " (uint64, big endian, Typed Array [RFC8746])" },
{ QCborTag(68), " (uint8 Typed Array, clamped arithmetic [RFC8746])" },
{ QCborTag(69), " (uint16, little endian, Typed Array [RFC8746])" },
{ QCborTag(70), " (uint32, little endian, Typed Array [RFC8746])" },
{ QCborTag(71), " (uint64, little endian, Typed Array [RFC8746])" },
{ QCborTag(72), " (sint8 Typed Array [RFC8746])" },
{ QCborTag(73), " (sint16, big endian, Typed Array [RFC8746])" },
{ QCborTag(74), " (sint32, big endian, Typed Array [RFC8746])" },
{ QCborTag(75), " (sint64, big endian, Typed Array [RFC8746])" },
{ QCborTag(76), " ((reserved) [RFC8746])" },
{ QCborTag(77), " (sint16, little endian, Typed Array [RFC8746])" },
{ QCborTag(78), " (sint32, little endian, Typed Array [RFC8746])" },
{ QCborTag(79), " (sint64, little endian, Typed Array [RFC8746])" },
{ QCborTag(80), " (IEEE 754 binary16, big endian, Typed Array [RFC8746])" },
{ QCborTag(81), " (IEEE 754 binary32, big endian, Typed Array [RFC8746])" },
{ QCborTag(82), " (IEEE 754 binary64, big endian, Typed Array [RFC8746])" },
{ QCborTag(83), " (IEEE 754 binary128, big endian, Typed Array [RFC8746])" },
{ QCborTag(84), " (IEEE 754 binary16, little endian, Typed Array [RFC8746])" },
{ QCborTag(85), " (IEEE 754 binary32, little endian, Typed Array [RFC8746])" },
{ QCborTag(86), " (IEEE 754 binary64, little endian, Typed Array [RFC8746])" },
{ QCborTag(87), " (IEEE 754 binary128, little endian, Typed Array [RFC8746])" },
{ QCborTag(96), " (COSE Encrypted Data Object [RFC9052])" },
{ QCborTag(97), " (COSE MACed Data Object [RFC9052])" },
{ QCborTag(98), " (COSE Signed Data Object [RFC9052])" },
{ QCborTag(100), " (Number of days since the epoch date 1970-01-01 [RFC8943])" },
{ QCborTag(101), " (alternatives as given by the uint + 128; see Section 9.1)" },
{ QCborTag(103), " (Geographic Coordinates)" },
{ QCborTag(104), " (Geographic Coordinate Reference System WKT or EPSG number)" },
{ QCborTag(110), " (relative object identifier (BER encoding); SDNV sequence [RFC9090])" },
{ QCborTag(111), " (object identifier (BER encoding) [RFC9090])" },
{ QCborTag(112), " (object identifier (BER encoding), relative to 1.3.6.1.4.1 [RFC9090])" },
{ QCborTag(120), " (Internet of Things Data Point)" },
{ QCborTag(260),
R"r( (Network Address (IPv4 or IPv6 or MAC Address) (DEPRECATED in favor of 52 and 54
for IP addresses) [http://www.employees.oRg/~RaviR/CboR-netwoRk.txt]))r" },
" (Network Address (IPv4 or IPv6 or MAC Address) (DEPRECATED in favor of 52 and 54 for IP"
" addresses) [RFC9164])" },
{ QCborTag(261),
R"r( (Network Address Prefix (IPv4 or IPv6 Address + Mask Length) (DEPRECATED in favor of 52 and 54
for IP addresses) [https://github.Com/toRaviR/CBOR-Tag-SpeCs/blob/masteR/netwoRkPReFix.md]))r" },
" (Network Address Prefix (IPv4 or IPv6 Address + Mask Length) (DEPRECATED in favor of 52"
" and 54 for IP addresses) [RFC9164])" },
{ QCborTag(271),
R"r( (DDoS Open Threat Signaling (DOTS) signal channel object,
as defined in [RFC9132]))r" },
{ QCborTag(1004),
R"r( ( full-date string [RFC8943]))r" },
{ QCborTag(1040),
R"r( (Multi-dimensional Array, column-major order [RFC8746]))r" },
{ QCborTag(55799),
R"r( (Self-described CBOR; see Section 3.4.6 [RFC8949]))r" },
{ QCborTag(55800),
R"r( (indicates that the file contains CBOR Sequences [RFC9277]))r" },
" (DDoS Open Threat Signaling (DOTS) signal channel object, as defined in [RFC9132])" },
{ QCborTag(1004), " (full-date string [RFC8943])" },
{ QCborTag(1040), " (Multi-dimensional Array, column-major order [RFC8746])" },
{ QCborTag(55799), " (Self-described CBOR; see Section 3.4.6 [RFC8949])" },
{ QCborTag(55800), " (indicates that the file contains CBOR Sequences [RFC9277])" },
{ QCborTag(55801),
R"r( (indicates that the file starts with a CBOR-Labeled Non-CBOR Data label. [RFC9277]))r" },
" (indicates that the file starts with a CBOR-Labeled Non-CBOR Data label. [RFC9277])" },
{ QCborTag(-1), nullptr }
};
// END GENERATED CODE

View File

@ -1,27 +0,0 @@
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="http://www.iana.org/assignments" xmlns="http://www.iana.org/assignments" xmlns:_="http://www.iana.org/assignments" xmlns:DEFAULT="http://www.iana.org/assignments" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="no" method="text"/>
<xsl:template match="/a:registry[@id='cbor-tags']">struct CborTagDescription
{
QCborTag tag;
const char *description; // with space and parentheses
};
// <xsl:value-of select="a:registry/a:title"/>
static const CborTagDescription tagDescriptions[] = {
// from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
<xsl:for-each select="a:registry/a:record">
<xsl:sort select="a:value" data-type="number"/>
<xsl:if test="a:semantics != ''">
<xsl:call-template name="row"/>
</xsl:if>
</xsl:for-each> { QCborTag(-1), nullptr }
};
</xsl:template>
<xsl:template name="row"> { QCborTag(<xsl:value-of select="a:value"/>),
R"r( (<xsl:value-of select="a:semantics"/> <xsl:call-template name="xref"/>))r" },
</xsl:template><!-- fn:replace(a:semantics, '\s+', ' ') -->
<xsl:template name="xref"><xsl:if test="a:xref/@type = 'rfc'"> [<xsl:value-of
select="translate(a:xref/@data,'rfc','RFC')"/>]</xsl:if>
</xsl:template>
</xsl:stylesheet>

View File

@ -35,8 +35,8 @@
serializing to another format — for example XML or QDataStream, which require passing
a document-like object — or when the object identity is important (QObject
subclasses, for example), other patterns may be more suitable. See the
\l{xml/dombookmarks} and \l{xml/streambookmarks} examples for XML, and the
implementation of \l QListWidgetItem::read() and \l QListWidgetItem::write()
\l{dombookmarks} example for XML, and the implementation of
\l QListWidgetItem::read() and \l QListWidgetItem::write()
for idiomatic QDataStream serialization. The \c{print()} functions in this example
are good examples of QTextStream serialization, even though they, of course, lack
the deserialization side.

View File

@ -7,9 +7,9 @@
#include <stdlib.h>
//! [0]
constexpr int DataSize = 100000;
const int DataSize = 100000;
constexpr int BufferSize = 8192;
const int BufferSize = 8192;
char buffer[BufferSize];
QSemaphore freeBytes(BufferSize);

View File

@ -23,7 +23,8 @@ public:
{
setAttribute(Qt::WA_OpaquePaintEvent, true);
setAttribute(Qt::WA_NoSystemBackground, true);
connect(&m_animator, SIGNAL(frameChanged(int)), SLOT(update()));
connect(&m_animator, &QTimeLine::frameChanged,
this, qOverload<>(&Digits::update));
m_animator.setFrameRange(0, 100);
m_animator.setDuration(600);
m_animator.setEasingCurve(QEasingCurve::InOutSine);
@ -272,9 +273,9 @@ public:
QAction *slideAction = new QAction("&Slide", this);
QAction *flipAction = new QAction("&Flip", this);
QAction *rotateAction = new QAction("&Rotate", this);
connect(slideAction, SIGNAL(triggered()), SLOT(chooseSlide()));
connect(flipAction, SIGNAL(triggered()), SLOT(chooseFlip()));
connect(rotateAction, SIGNAL(triggered()), SLOT(chooseRotate()));
connect(slideAction, &QAction::triggered, this, &DigiFlip::chooseSlide);
connect(flipAction, &QAction::triggered, this, &DigiFlip::chooseFlip);
connect(rotateAction, &QAction::triggered, this, &DigiFlip::chooseRotate);
addAction(slideAction);
addAction(flipAction);
addAction(rotateAction);

View File

@ -71,8 +71,8 @@ public:
ui.searchBar->hide();
ui.infoBox->hide();
connect(ui.searchButton, SIGNAL(clicked()), SLOT(startSearch()));
connect(ui.flightEdit, SIGNAL(returnPressed()), SLOT(startSearch()));
connect(ui.searchButton, &QPushButton::clicked, this, &FlightInfo::startSearch);
connect(ui.flightEdit, &QLineEdit::returnPressed, this, &FlightInfo::startSearch);
setWindowTitle("Flight Info");
@ -83,11 +83,11 @@ public:
QAction *searchTodayAction = new QAction("Today's Flight", this);
QAction *searchYesterdayAction = new QAction("Yesterday's Flight", this);
QAction *randomAction = new QAction("Random Flight", this);
connect(searchTodayAction, SIGNAL(triggered()), SLOT(today()));
connect(searchYesterdayAction, SIGNAL(triggered()), SLOT(yesterday()));
connect(randomAction, SIGNAL(triggered()), SLOT(randomFlight()));
connect(&m_manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(handleNetworkData(QNetworkReply*)));
connect(searchTodayAction, &QAction::triggered, this, &FlightInfo::today);
connect(searchYesterdayAction, &QAction::triggered, this, &FlightInfo::yesterday);
connect(randomAction, &QAction::triggered, this, &FlightInfo::randomFlight);
connect(&m_manager, &QNetworkAccessManager::finished,
this, &FlightInfo::handleNetworkData);
addAction(searchTodayAction);
addAction(searchYesterdayAction);
addAction(randomAction);

View File

@ -24,8 +24,8 @@ LightMaps::LightMaps(QWidget *parent)
{
m_normalMap = new SlippyMap(this);
m_largeMap = new SlippyMap(this);
connect(m_normalMap, SIGNAL(updated(QRect)), SLOT(updateMap(QRect)));
connect(m_largeMap, SIGNAL(updated(QRect)), SLOT(update()));
connect(m_normalMap, &SlippyMap::updated, this, &LightMaps::updateMap);
connect(m_largeMap, &SlippyMap::updated, this, &LightMaps::updateMap);
}
void LightMaps::setCenter(qreal lat, qreal lng)

View File

@ -5,3 +5,4 @@ if(NOT TARGET Qt6::Gui)
return()
endif()
qt_internal_add_example(rasterwindow)
qt_internal_add_example(rhiwindow)

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -0,0 +1,440 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example rhiwindow
\title RHI Window Example
\examplecategory {Graphics & Multimedia}
\brief This example shows how to create a minimal QWindow-based
application using QRhi.
\image rhiwindow_example.jpg
Qt 6.6 starts offering its accelerated 3D API and shader abstraction layer
for application use as well. Applications can now use the same 3D graphics
classes Qt itself uses to implement the Qt Quick scenegraph or the Qt Quick
3D engine. In earlier Qt versions QRhi and the related classes were all
private APIs. From 6.6 on these classes are in a similar category as QPA
family of classes: neither fully public nor private, but something
in-between, with a more limited compatibility promise compared to public
APIs. On the other hand, QRhi and the related classes now come with full
documentation similarly to public APIs.
There are multiple ways to use QRhi, the example here shows the most
low-level approach: targeting a QWindow, while not using Qt Quick, Qt Quick
3D, or Widgets in any form, and setting up all the rendering and windowing
infrastructure in the application.
In contrast, when writing a QML application with Qt Quick or Qt Quick 3D,
and wanting to add QRhi-based rendering to it, such an application is going
to rely on the window and rendering infrastructure Qt Quick has already
initialized, and it is likely going to query an existing QRhi instance from
the QQuickWindow. There dealing with QRhi::create(), platform/API specifics
such as \l{QVulkanInstance}{Vulkan instances}, or correctly handling
\l{QExposeEvent}{expose} and resize events for the window are all managed
by Qt Quick. Whereas in this example, all that is managed and taken care
of by the application itself.
\note For QWidget-based applications in particular, it should be noted that
QWidget::createWindowContainer() allows embedding a QWindow (backed by a
native window) into the widget-based user interface. Therefore, the \c
HelloWindow class from this example is reusable in QWidget-based
applications, assuming the necessary initialization from \c main() is in
place as well.
\section1 3D API Support
The application supports all the current \l{QRhi::Implementation}{QRhi
backends}. When no command-line arguments are specified, platform-specific
defaults are used: Direct 3D 11 on Windows, OpenGL on Linux, Metal on
macOS/iOS.
Running with \c{--help} shows the available command-line options:
\list
\li -d or --d3d11 for Direct 3D 11
\li -D or --d3d12 for Direct 3D 12
\li -m or --metal for Metal
\li -v or --vulkan for Vulkan
\li -g or --opengl for OpenGL or OpenGL ES
\li -n or --null for the \l{QRhi::Null}{Null backend}
\endlist
\section1 Build System Notes
This application relies solely on the Qt GUI module. It does not use Qt
Widgets or Qt Quick.
In order to access the RHI APIs, which are available to all Qt applications
but come with a limited compatibility promise, the \c target_link_libraries
CMake command lists \c{Qt6::GuiPrivate}. This is what enables the
\c{#include <rhi/qrhi.h>} include statement to compile successfully.
\section1 Features
The application features:
\list
\li A resizable QWindow,
\li a swapchain and depth-stencil buffer that properly follows the size of
the window,
\li logic to initialize, render, and tear down at the appropriate time
based on events such as \l QExposeEvent and \l QPlatformSurfaceEvent,
\li rendering a fullscreen textured quad, using a texture the contents of
which is generated in a QImage via QPainter (using the raster paint engine,
i.e. the generating of the image's pixel data is all CPU-based, that data
is then uploaded into a GPU texture),
\li rendering a triangle with blending and depth testing enabled, using a
perspective projection, while applying a model transform that changes on
every frame,
\li an efficient, cross-platform render loop using
\l{QWindow::requestUpdate()}{requestUpdate()}.
\endlist
\section1 Shaders
The application uses two sets of vertex and fragment shader pairs:
\list
\li one for the fullscreen quad, which uses no vertex inputs and the
fragment shader samples a texture (\c quad.vert, \c quad.frag),
\li and another pair for the triangle, where vertex positions and colors
are provided in a vertex buffer and a modelview-projection matrix is
provided in a uniform buffer (\c color.vert, \c color.frag).
\endlist
The shaders are written as Vulkan-compatible GLSL source code.
Due to being a Qt GUI module example, this example cannot have a dependency
on the \l{Qt Shader Tools} module. This means that CMake helper functions
such as \c{qt_add_shaders} are not available for use. Therefore, the
example has the pre-processed \c{.qsb} files included in the
\c{shaders/prebuilt} folder, and they are simply included within the
executable via \c{qt_add_resources}. This approach is not generally
recommended for applications, consider rather using \l{Qt Shader Tools
Build System Integration}{qt_add_shaders}, which avoids the need to
manually generate and manage the \c{.qsb} files.
To generate the \c{.qsb} files for this example, the command \c{qsb --qt6
color.vert -o prebuilt/color.vert.qsb} etc. was used. This leads to
compiling to \l{https://www.khronos.org/spir/}{SPIR-V} and than transpiling
into GLSL (\c{100 es} and \c 120), HLSL (5.0), and MSL (1.2). All the
shader versions are then packed together into a QShader and serialized to
disk.
\section1 API-specific Initialization
For some of the 3D APIs the main() function has to perform the appropriate
API-specific initialiation, e.g. to create a QVulkanInstance when using
Vulkan. For OpenGL we have to ensure a depth buffer is available, this is
done via QSurfaceFormat. These steps are not in the scope of QRhi since
QRhi backends for OpenGL or Vulkan build on the existing Qt facilities such
as QOpenGLContext or QVulkanInstance.
\snippet rhiwindow/main.cpp api-setup
\note For Vulkan, note how
QRhiVulkanInitParams::preferredInstanceExtensions() is taken into account
to ensure the appropriate extensions are enabled.
\c HelloWindow is a subclass of \c RhiWindow, which in turn is a QWindow.
\c RhiWindow contains everything needed to manage a resizable window with
a\ swapchain (and depth-stencil buffer), and is potentially reusable in
other applications as well. \c HelloWindow contains the rendering logic
specific to this particular example application.
In the QWindow subclass constructor the surface type is set based on the
selected 3D API.
\snippet rhiwindow/rhiwindow.cpp rhiwindow-ctor
Creating and initializing a QRhi object is implemented in
RhiWindow::init(). Note that this is invoked only when the window is
\c renderable, which is indicated by an \l{QExposeEvent}{expose event}.
Depending on which 3D API we use, the appropriate InitParams struct needs
to be passed to QRhi::create(). With OpenGL for example, a
QOffscreenSurface (or some other QSurface) must be created by the
application and provided for use to the QRhi. With Vulkan, a successfully
initialized QVulkanInstance is required. Others, such as Direct 3D or Metal
need no additional information to be able to initialize.
\snippet rhiwindow/rhiwindow.cpp rhi-init
Apart from this, everything else, all the rendering code, is fully
cross-platform and has no branching or conditions specific to any of the 3D
API.
\section1 Expose Events
What \c renderable exactly means is platform-specific. For example, on
macOS a window that is fully obscured (fully behind some other window) is
not renderable, whereas on Windows obscuring has no significance.
Fortunately, the application needs no special knowledge about this: Qt's
platform plugins abstract the differences behind the expose event. However,
the \l{QWindow::exposeEvent()}{exposeEvent()} reimplementation also needs
to be aware that an empty output size (e.g. width and height of 0) is also
something that should be treated as a non-renderable situation. On Windows
for example, this is what is going to happen when minimizing the window.
Hence the check based on QRhiSwapChain::surfacePixelSize().
This implementation of expose event handling attempts to be robust, safe,
and portable. Qt Quick itself also implements a very similar logic in its
render loops.
\snippet rhiwindow/rhiwindow.cpp expose
In RhiWindow::render(), which is invoked in response to the
\l{QEvent::UpdateRequest}{UpdateRequest} event generated by
\l{QWindow::requestUpdate()}{requestUpdate()}, the following check is in
place, to prevent attempting to render when the swapchain initialization
failed, or when the window became non-renderable.
\snippet rhiwindow/rhiwindow.cpp render-precheck
\section1 Swapchain, Depth-Stencil buffer, and Resizing
To render to the QWindow, a QRhiSwapChain is needed. In addition, a
QRhiRenderBuffer acting as the depth-stencil buffer is created as well
since the application demonstrates how depth testing can be enabled in a
graphics pipeline. With some legacy 3D APIs managing the depth/stencil
buffer for a window is part of the corresponding windowing system interface
API (EGL, WGL, GLX, etc., meaning the depth/stencil buffer is implicitly
managed together with the \c{window surface}), whereas with modern APIs
managing the depth-stencil buffer for a window-based render target is no
different from offscreen render targets. QRhi abstracts this, but for best
performance it still needs to be indicated that the QRhiRenderBuffer is
\l{QRhiRenderBuffer::UsedWithSwapChainOnly}{used with together with a
QRhiSwapChain}.
The QRhiSwapChain is associated with the QWindow and the depth/stencil
buffer.
\snippet rhiwindow/rhiwindow.h swapchain-data
\codeline
\snippet rhiwindow/rhiwindow.cpp swapchain-init
When the window size changes, the swapchain needs to be resized as well.
This is implemented in resizeSwapChain().
\snippet rhiwindow/rhiwindow.cpp swapchain-resize
Unlike other QRhiResource subclasses, QRhiSwapChain features slightly
different semantics when it comes to its create-function. As the name,
\l{QRhiSwapChain::createOrResize()}{createOrResize()}, suggests, this needs
to be called whenever it is known that the output window size may be out of
sync with what the swapchain was last initialized. The associated
QRhiRenderBuffer for depth-stencil gets its
\l{QRhiRenderBuffer::pixelSize()}{size} set automatically, and
\l{QRhiRenderBuffer::create()}{create()} is called on it implicitly from the
swapchain's createOrResize().
This is also a convenient place to (re)calculate the projection and view
matrices since the perspective projection we set up depends on the output
aspect ratio.
\note To eliminate coordinate system differences, the
\l{QRhi::clipSpaceCorrMatrix()}{a backend/API-specific "correction" matrix}
is queried from QRhi and baked in to the projection matrix. This is what
allows the application to work with OpenGL-style vertex data, assuming a
coordinate system with the origin at the bottom-left.
The resizeSwapChain() function is called from RhiWindow::render() when it
is discovered that the currently reported size is not the same anymore as
what the swapchain was last initialized with.
See QRhiSwapChain::currentPixelSize() and QRhiSwapChain::surfacePixelSize()
for further details.
High DPI support is built-in: the sizes, as the naming indicates, are
always in pixels, taking the window-specific
\l{QWindow::devicePixelRatio()}{scale factor} into account. On the QRhi
(and 3D API) level there is no concept of high DPI scaling, everything is
always in pixels. This means that a QWindow with a size() of 1280x720 and
a devicePixelRatio() of 2 is a render target (swapchain) with a (pixel) size
of 2560x1440.
\snippet rhiwindow/rhiwindow.cpp render-resize
\section1 Render Loop
The application renders continuously, throttled by the presentation rate
(vsync). This is ensured by calling
\l{QWindow::requestUpdate()}{requestUpdate()} from RhiWindow::render() when
the currently recorded frame has been submitted.
\snippet rhiwindow/rhiwindow.cpp request-update
This eventually leads to getting a \l{QEvent::UpdateRequest}{UpdateRequest}
event. This is handled in the reimplementation of event().
\snippet rhiwindow/rhiwindow.cpp event
\section1 Resource and Pipeline Setup
The application records a single render pass that issues two draw calls,
with two different graphics pipelines. One is the "background", with the
texture containing the QPainter-generated image, then a single triangle is
rendered on top with blending enabled.
The vertex and uniform buffer used with the triangle is created like this.
The size of the uniform buffer is 68 bytes since the shader specific a \c
mat4 and a \c float member in the uniform block. Watch out for the
\l{https://registry.khronos.org/OpenGL/specs/gl/glspec45.core.pdf#page=159}{std140
layout rules}. This presents no surprises in this example since the \c
float member that follows the \c mat4 has the correct alignment without any
additional padding, but it may become relevant in other applications,
especially when working with types such as \c vec2 or \c vec3. When in
doubt, consider checking the QShaderDescription for the
\l{QShader::description()}{QShader}, or, what is often more convenient, run
the \c qsb tool on the \c{.qsb} file with the \c{-d} argument to inspect
the metadata in human-readable form. The printed information includes,
among other things, the uniform block member offsets, sizes, and the total
size in bytes of each uniform block.
\snippet rhiwindow/rhiwindow.cpp render-init-1
The vertex and fragment shaders both need a uniform buffer at binding point
0. This is ensured by the QRhiShaderResourceBindings object. The graphics
pipeline is then setup with the shaders and a number of additional
information. The example also relies on a number of convenient defaults,
e.g. the primitive topology is
\l{QRhiGraphicsPipeline::Triangles}{Triangles}, but that is the default,
and therefore it is not explicitly set. See QRhiGraphicsPipeline for
further details.
In addition to specifying the topology and various state, the pipeline must
also be associated with:
\list
\li The vertex input layout in form of a QRhiVertexInputLayout. This
specifies the type and component count for each vertex input location, the
total stride in bytes per vertex, and other related data.
QRhiVertexInputLayout only holds data, not actual native resources, and is
copiable.
\li A valid and successfully initialized QRhiShaderResourceBindings object.
This describes the layout of the resource bindings (uniform buffers,
textures, samplers) the shaders expect. This must either by the
QRhiShaderResourceBindings used when recording the draw calls, or another
that is
\l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible with it}.
This simple application takes the former approach.
\li A valid QRhiRenderPassDescriptor object. This must be retrieved from,
or \l{QRhiRenderPassDescriptor::isCompatible()}{be compatible with} the
render target. The example uses the former, by creating a
QRhiRenderPassDescriptor object via
QRhiSwapChain::newCompatibleRenderPassDescriptor().
\endlist
\snippet rhiwindow/rhiwindow.cpp render-init-2
getShader() is a helper function that loads a \c{.qsb} file and
deserializes a QShader from it.
\snippet rhiwindow/rhiwindow.cpp getshader
The \c{color.vert} shader specifies the following as the vertex inputs:
\badcode
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;
\endcode
The C++ code however provides vertex data as 2 floats for position, with 3
floats for the color interleaved. (\c x, \c y, \c r, \c g, \c b for each
vertex) This is why the stride is \c{5 * sizeof(float)} and the inputs for
locations 0 and 1 are specified as \c Float2 and \c Float3, respectively.
This is valid, and the \c z and \c w of the \c vec4 position will get set
automatically.
\section1 Rendering
Recording a frame is started by calling \l{QRhi::beginFrame()} and finished
by calling \l{QRhi::endFrame()}.
\snippet rhiwindow/rhiwindow.cpp beginframe
Some of the resources (buffers, textures) have static data in the
application, meaning the content never changes. The vertex buffer's content
is provided in the initialization step for example, and is not changed
afterwards. These data update operations are recorded in \c
m_initialUpdates. When not yet done, the commands on this resource update
batch are merged into the per-frame batch.
\snippet rhiwindow/rhiwindow.cpp render-1
Having a per-frame resource update batch is necessary since the uniform
buffer contents with the modelview-projection matrix and the opacity
changes on every frame.
\snippet rhiwindow/rhiwindow.cpp render-rotation
\snippet rhiwindow/rhiwindow.cpp render-opacity
To begin recording the render pass, a QRhiCommandBuffer is queried, and the
output size is determined, which will be useful for setting up the viewport
and resizing our fullscreen texture, if needed.
\snippet rhiwindow/rhiwindow.cpp render-cb
Starting a render pass implies clearing the render target's color and
depth-stencil buffers (unless the render target flags indicate otherwise,
but that is only an option for texture-based render targets). Here we
specify black for color, 1.0f for depth, and 0 for stencil (unused). The
last argument, \c resourceUpdates, is what ensures that the data update
commands recorded on the batch get committed. Alternatively, we could have
used QRhiCommandBuffer::resourceUpdate() instead. The render pass targets a
swapchain, hence calling
\l{QRhiSwapChain::currentFrameRenderTarget()}{currentFrameRenderTarget()}
to get a valid QRhiRenderTarget.
\snippet rhiwindow/rhiwindow.cpp render-pass
Recording the draw call for the triangle is straightforward: set the
pipeline, set the shader resources, set the vertex/index buffer(s), and
record the draw call. Here we use a non-indexed draw with just 3 vertices.
\snippet rhiwindow/rhiwindow.cpp render-pass-record
The \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} call
has no arguments given, which implies using \c m_colorTriSrb since that was
associated with the active QRhiGraphicsPipeline (\c m_colorPipeline).
We will not dive into the details of the rendering of the fullscreen
background image. See the example source code for that. It is however worth
noting a common pattern for "resizing" a texture or buffer resource. There
is no such thing as changing the size of an existing native resource, so
changing a texture or buffer size must be followed by a call to create(),
to release and recreate the underlying native resources. To ensure that the
QRhiTexture always has the required size, the application implements the
following logic. Note that \c m_texture stays valid for the entire lifetime
of the window, which means object references to it, e.g. in a
QRhiShaderResourceBindings, continue to be valid all the time. It is only
the underlying native resources that come and go over time.
\snippet rhiwindow/rhiwindow.cpp ensure-texture
Once a QImage is generated and the QPainter-based drawing into it has
finished, we use
\l{QRhiResourceUpdateBatch::uploadTexture()}{uploadTexture()} to record a
texture upload on the resource update batch:
\snippet rhiwindow/rhiwindow.cpp ensure-texture-2
\sa QRhi, QRhiSwapChain, QWindow, QRhiCommandBuffer, QRhiResourceUpdateBatch, QRhiBuffer, QRhiTexture
*/

View File

@ -4,4 +4,5 @@ TEMPLATE = subdirs
QT_FOR_CONFIG += gui
CONFIG += no_docs_target
SUBDIRS += rasterwindow
SUBDIRS += rasterwindow \
rhiwindow

View File

@ -0,0 +1,59 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(rhiwindow LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/gui/rhiwindow")
find_package(Qt6 REQUIRED COMPONENTS Core Gui)
qt_standard_project_setup()
qt_add_executable(rhiwindow
main.cpp
rhiwindow.cpp rhiwindow.h
)
set_target_properties(rhiwindow PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(rhiwindow PRIVATE
Qt6::Core
Qt6::Gui
Qt6::GuiPrivate
)
set_source_files_properties("shaders/prebuilt/color.vert.qsb"
PROPERTIES QT_RESOURCE_ALIAS "color.vert.qsb"
)
set_source_files_properties("shaders/prebuilt/color.frag.qsb"
PROPERTIES QT_RESOURCE_ALIAS "color.frag.qsb"
)
set_source_files_properties("shaders/prebuilt/quad.vert.qsb"
PROPERTIES QT_RESOURCE_ALIAS "quad.vert.qsb"
)
set_source_files_properties("shaders/prebuilt/quad.frag.qsb"
PROPERTIES QT_RESOURCE_ALIAS "quad.frag.qsb"
)
qt_add_resources(rhiwindow "rhiwindow"
PREFIX
"/"
FILES
"shaders/prebuilt/color.vert.qsb"
"shaders/prebuilt/color.frag.qsb"
"shaders/prebuilt/quad.vert.qsb"
"shaders/prebuilt/quad.frag.qsb"
)
install(TARGETS rhiwindow
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,110 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QCommandLineParser>
#include "rhiwindow.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QRhi::Implementation graphicsApi;
// Use platform-specific defaults when no command-line arguments given.
#if defined(Q_OS_WIN)
graphicsApi = QRhi::D3D11;
#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
graphicsApi = QRhi::Metal;
#elif QT_CONFIG(vulkan)
graphicsApi = QRhi::Vulkan;
#else
graphicsApi = QRhi::OpenGLES2;
#endif
QCommandLineParser cmdLineParser;
cmdLineParser.addHelpOption();
QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null"));
cmdLineParser.addOption(nullOption);
QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL"));
cmdLineParser.addOption(glOption);
QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan"));
cmdLineParser.addOption(vkOption);
QCommandLineOption d3d11Option({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
cmdLineParser.addOption(d3d11Option);
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
cmdLineParser.addOption(d3d12Option);
QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
cmdLineParser.addOption(mtlOption);
cmdLineParser.process(app);
if (cmdLineParser.isSet(nullOption))
graphicsApi = QRhi::Null;
if (cmdLineParser.isSet(glOption))
graphicsApi = QRhi::OpenGLES2;
if (cmdLineParser.isSet(vkOption))
graphicsApi = QRhi::Vulkan;
if (cmdLineParser.isSet(d3d11Option))
graphicsApi = QRhi::D3D11;
if (cmdLineParser.isSet(d3d12Option))
graphicsApi = QRhi::D3D12;
if (cmdLineParser.isSet(mtlOption))
graphicsApi = QRhi::Metal;
//! [api-setup]
// For OpenGL, to ensure there is a depth/stencil buffer for the window.
// With other APIs this is under the application's control (QRhiRenderBuffer etc.)
// and so no special setup is needed for those.
QSurfaceFormat fmt;
fmt.setDepthBufferSize(24);
fmt.setStencilBufferSize(8);
// Special case macOS to allow using OpenGL there.
// (the default Metal is the recommended approach, though)
// gl_VertexID is a GLSL 130 feature, and so the default OpenGL 2.1 context
// we get on macOS is not sufficient.
#ifdef Q_OS_MACOS
fmt.setVersion(4, 1);
fmt.setProfile(QSurfaceFormat::CoreProfile);
#endif
QSurfaceFormat::setDefaultFormat(fmt);
// For Vulkan.
#if QT_CONFIG(vulkan)
QVulkanInstance inst;
if (graphicsApi == QRhi::Vulkan) {
// Request validation, if available. This is completely optional
// and has a performance impact, and should be avoided in production use.
inst.setLayers({ "VK_LAYER_KHRONOS_validation" });
// Play nice with QRhi.
inst.setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
if (!inst.create()) {
qWarning("Failed to create Vulkan instance, switching to OpenGL");
graphicsApi = QRhi::OpenGLES2;
}
}
#endif
//! [api-setup]
HelloWindow window(graphicsApi);
#if QT_CONFIG(vulkan)
if (graphicsApi == QRhi::Vulkan)
window.setVulkanInstance(&inst);
#endif
window.resize(1280, 720);
window.setTitle(QCoreApplication::applicationName() + QLatin1String(" - ") + window.graphicsApiName());
window.show();
int ret = app.exec();
// RhiWindow::event() will not get invoked when the
// PlatformSurfaceAboutToBeDestroyed event is sent during the QWindow
// destruction. That happens only when exiting via app::quit() instead of
// the more common QWindow::close(). Take care of it: if the QPlatformWindow
// is still around (there was no close() yet), get rid of the swapchain
// while it's not too late.
if (window.handle())
window.releaseSwapChain();
return ret;
}

View File

@ -0,0 +1,435 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "rhiwindow.h"
#include <QPlatformSurfaceEvent>
#include <QPainter>
#include <QFile>
#include <rhi/qshader.h>
//! [rhiwindow-ctor]
RhiWindow::RhiWindow(QRhi::Implementation graphicsApi)
: m_graphicsApi(graphicsApi)
{
switch (graphicsApi) {
case QRhi::OpenGLES2:
setSurfaceType(OpenGLSurface);
break;
case QRhi::Vulkan:
setSurfaceType(VulkanSurface);
break;
case QRhi::D3D11:
case QRhi::D3D12:
setSurfaceType(Direct3DSurface);
break;
case QRhi::Metal:
setSurfaceType(MetalSurface);
break;
case QRhi::Null:
break; // RasterSurface
}
}
//! [rhiwindow-ctor]
QString RhiWindow::graphicsApiName() const
{
switch (m_graphicsApi) {
case QRhi::Null:
return QLatin1String("Null (no output)");
case QRhi::OpenGLES2:
return QLatin1String("OpenGL");
case QRhi::Vulkan:
return QLatin1String("Vulkan");
case QRhi::D3D11:
return QLatin1String("Direct3D 11");
case QRhi::D3D12:
return QLatin1String("Direct3D 12");
case QRhi::Metal:
return QLatin1String("Metal");
}
return QString();
}
//! [expose]
void RhiWindow::exposeEvent(QExposeEvent *)
{
// initialize and start rendering when the window becomes usable for graphics purposes
if (isExposed() && !m_initialized) {
init();
resizeSwapChain();
m_initialized = true;
}
const QSize surfaceSize = m_hasSwapChain ? m_sc->surfacePixelSize() : QSize();
// stop pushing frames when not exposed (or size is 0)
if ((!isExposed() || (m_hasSwapChain && surfaceSize.isEmpty())) && m_initialized && !m_notExposed)
m_notExposed = true;
// Continue when exposed again and the surface has a valid size. Note that
// surfaceSize can be (0, 0) even though size() reports a valid one, hence
// trusting surfacePixelSize() and not QWindow.
if (isExposed() && m_initialized && m_notExposed && !surfaceSize.isEmpty()) {
m_notExposed = false;
m_newlyExposed = true;
}
// always render a frame on exposeEvent() (when exposed) in order to update
// immediately on window resize.
if (isExposed() && !surfaceSize.isEmpty())
render();
}
//! [expose]
//! [event]
bool RhiWindow::event(QEvent *e)
{
switch (e->type()) {
case QEvent::UpdateRequest:
render();
break;
case QEvent::PlatformSurface:
// this is the proper time to tear down the swapchain (while the native window and surface are still around)
if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
releaseSwapChain();
break;
default:
break;
}
return QWindow::event(e);
}
//! [event]
//! [rhi-init]
void RhiWindow::init()
{
if (m_graphicsApi == QRhi::Null) {
QRhiNullInitParams params;
m_rhi.reset(QRhi::create(QRhi::Null, &params));
}
#if QT_CONFIG(opengl)
if (m_graphicsApi == QRhi::OpenGLES2) {
m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
QRhiGles2InitParams params;
params.fallbackSurface = m_fallbackSurface.get();
params.window = this;
m_rhi.reset(QRhi::create(QRhi::OpenGLES2, &params));
}
#endif
#if QT_CONFIG(vulkan)
if (m_graphicsApi == QRhi::Vulkan) {
QRhiVulkanInitParams params;
params.inst = vulkanInstance();
params.window = this;
m_rhi.reset(QRhi::create(QRhi::Vulkan, &params));
}
#endif
#ifdef Q_OS_WIN
if (m_graphicsApi == QRhi::D3D11) {
QRhiD3D11InitParams params;
// Enable the debug layer, if available. This is optional
// and should be avoided in production builds.
params.enableDebugLayer = true;
m_rhi.reset(QRhi::create(QRhi::D3D11, &params));
} else if (m_graphicsApi == QRhi::D3D12) {
QRhiD3D12InitParams params;
// Enable the debug layer, if available. This is optional
// and should be avoided in production builds.
params.enableDebugLayer = true;
m_rhi.reset(QRhi::create(QRhi::D3D12, &params));
}
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (m_graphicsApi == QRhi::Metal) {
QRhiMetalInitParams params;
m_rhi.reset(QRhi::create(QRhi::Metal, &params));
}
#endif
if (!m_rhi)
qFatal("Failed to create RHI backend");
//! [rhi-init]
//! [swapchain-init]
m_sc.reset(m_rhi->newSwapChain());
m_ds.reset(m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
QSize(), // no need to set the size here, due to UsedWithSwapChainOnly
1,
QRhiRenderBuffer::UsedWithSwapChainOnly));
m_sc->setWindow(this);
m_sc->setDepthStencil(m_ds.get());
m_rp.reset(m_sc->newCompatibleRenderPassDescriptor());
m_sc->setRenderPassDescriptor(m_rp.get());
//! [swapchain-init]
customInit();
}
//! [swapchain-resize]
void RhiWindow::resizeSwapChain()
{
m_hasSwapChain = m_sc->createOrResize(); // also handles m_ds
const QSize outputSize = m_sc->currentPixelSize();
m_viewProjection = m_rhi->clipSpaceCorrMatrix();
m_viewProjection.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
m_viewProjection.translate(0, 0, -4);
}
//! [swapchain-resize]
void RhiWindow::releaseSwapChain()
{
if (m_hasSwapChain) {
m_hasSwapChain = false;
m_sc->destroy();
}
}
//! [render-precheck]
void RhiWindow::render()
{
if (!m_hasSwapChain || m_notExposed)
return;
//! [render-precheck]
//! [render-resize]
// If the window got resized or newly exposed, resize the swapchain. (the
// newly-exposed case is not actually required by some platforms, but is
// here for robustness and portability)
//
// This (exposeEvent + the logic here) is the only safe way to perform
// resize handling. Note the usage of the RHI's surfacePixelSize(), and
// never QWindow::size(). (the two may or may not be the same under the hood,
// depending on the backend and platform)
//
if (m_sc->currentPixelSize() != m_sc->surfacePixelSize() || m_newlyExposed) {
resizeSwapChain();
if (!m_hasSwapChain)
return;
m_newlyExposed = false;
}
//! [render-resize]
//! [beginframe]
QRhi::FrameOpResult result = m_rhi->beginFrame(m_sc.get());
if (result == QRhi::FrameOpSwapChainOutOfDate) {
resizeSwapChain();
if (!m_hasSwapChain)
return;
result = m_rhi->beginFrame(m_sc.get());
}
if (result != QRhi::FrameOpSuccess) {
qWarning("beginFrame failed with %d, will retry", result);
requestUpdate();
return;
}
customRender();
//! [beginframe]
//! [request-update]
m_rhi->endFrame(m_sc.get());
// Always request the next frame via requestUpdate(). On some platforms this is backed
// by a platform-specific solution, e.g. CVDisplayLink on macOS, which is potentially
// more efficient than a timer, queued metacalls, etc.
requestUpdate();
}
//! [request-update]
static float vertexData[] = {
// Y up (note clipSpaceCorrMatrix in m_viewProjection), CCW
0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
};
//! [getshader]
static QShader getShader(const QString &name)
{
QFile f(name);
if (f.open(QIODevice::ReadOnly))
return QShader::fromSerialized(f.readAll());
return QShader();
}
//! [getshader]
HelloWindow::HelloWindow(QRhi::Implementation graphicsApi)
: RhiWindow(graphicsApi)
{
}
//! [ensure-texture]
void HelloWindow::ensureFullscreenTexture(const QSize &pixelSize, QRhiResourceUpdateBatch *u)
{
if (m_texture && m_texture->pixelSize() == pixelSize)
return;
if (!m_texture)
m_texture.reset(m_rhi->newTexture(QRhiTexture::RGBA8, pixelSize));
else
m_texture->setPixelSize(pixelSize);
m_texture->create();
QImage image(pixelSize, QImage::Format_RGBA8888_Premultiplied);
//! [ensure-texture]
QPainter painter(&image);
painter.fillRect(QRectF(QPointF(0, 0), pixelSize), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f));
painter.setPen(Qt::transparent);
painter.setBrush({ QGradient(QGradient::DeepBlue) });
painter.drawRoundedRect(QRectF(QPointF(20, 20), pixelSize - QSize(40, 40)), 16, 16);
painter.setPen(Qt::black);
QFont font;
font.setPixelSize(0.05 * qMin(pixelSize.width(), pixelSize.height()));
painter.setFont(font);
painter.drawText(QRectF(QPointF(60, 60), pixelSize - QSize(120, 120)), 0,
QLatin1String("Rendering with QRhi to a resizable QWindow.\nThe 3D API is %1.\nUse the command-line options to choose a different API.")
.arg(graphicsApiName()));
painter.end();
if (m_rhi->isYUpInNDC())
image = image.mirrored();
//! [ensure-texture-2]
u->uploadTexture(m_texture.get(), image);
//! [ensure-texture-2]
}
//! [render-init-1]
void HelloWindow::customInit()
{
m_initialUpdates = m_rhi->nextResourceUpdateBatch();
m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
m_vbuf->create();
m_initialUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
static const quint32 UBUF_SIZE = 68;
m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE));
m_ubuf->create();
//! [render-init-1]
ensureFullscreenTexture(m_sc->surfacePixelSize(), m_initialUpdates);
m_sampler.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
m_sampler->create();
//! [render-init-2]
m_colorTriSrb.reset(m_rhi->newShaderResourceBindings());
static const QRhiShaderResourceBinding::StageFlags visibility =
QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage;
m_colorTriSrb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, visibility, m_ubuf.get())
});
m_colorTriSrb->create();
m_colorPipeline.reset(m_rhi->newGraphicsPipeline());
// Enable depth testing; not quite needed for a simple triangle, but we
// have a depth-stencil buffer so why not.
m_colorPipeline->setDepthTest(true);
m_colorPipeline->setDepthWrite(true);
// Blend factors default to One, OneOneMinusSrcAlpha, which is convenient.
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend;
premulAlphaBlend.enable = true;
m_colorPipeline->setTargetBlends({ premulAlphaBlend });
m_colorPipeline->setShaderStages({
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) }
});
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 5 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
{ 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
});
m_colorPipeline->setVertexInputLayout(inputLayout);
m_colorPipeline->setShaderResourceBindings(m_colorTriSrb.get());
m_colorPipeline->setRenderPassDescriptor(m_rp.get());
m_colorPipeline->create();
//! [render-init-2]
m_fullscreenQuadSrb.reset(m_rhi->newShaderResourceBindings());
m_fullscreenQuadSrb->setBindings({
QRhiShaderResourceBinding::sampledTexture(0, QRhiShaderResourceBinding::FragmentStage,
m_texture.get(), m_sampler.get())
});
m_fullscreenQuadSrb->create();
m_fullscreenQuadPipeline.reset(m_rhi->newGraphicsPipeline());
m_fullscreenQuadPipeline->setShaderStages({
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/quad.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/quad.frag.qsb")) }
});
m_fullscreenQuadPipeline->setVertexInputLayout({});
m_fullscreenQuadPipeline->setShaderResourceBindings(m_fullscreenQuadSrb.get());
m_fullscreenQuadPipeline->setRenderPassDescriptor(m_rp.get());
m_fullscreenQuadPipeline->create();
}
//! [render-1]
void HelloWindow::customRender()
{
QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
if (m_initialUpdates) {
resourceUpdates->merge(m_initialUpdates);
m_initialUpdates->release();
m_initialUpdates = nullptr;
}
//! [render-1]
//! [render-rotation]
m_rotation += 1.0f;
QMatrix4x4 modelViewProjection = m_viewProjection;
modelViewProjection.rotate(m_rotation, 0, 1, 0);
resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData());
//! [render-rotation]
//! [render-opacity]
m_opacity += m_opacityDir * 0.005f;
if (m_opacity < 0.0f || m_opacity > 1.0f) {
m_opacityDir *= -1;
m_opacity = qBound(0.0f, m_opacity, 1.0f);
}
resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 64, 4, &m_opacity);
//! [render-opacity]
//! [render-cb]
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
const QSize outputSizeInPixels = m_sc->currentPixelSize();
//! [render-cb]
// (re)create the texture with a size matching the output surface size, when necessary.
ensureFullscreenTexture(outputSizeInPixels, resourceUpdates);
//! [render-pass]
cb->beginPass(m_sc->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, resourceUpdates);
//! [render-pass]
cb->setGraphicsPipeline(m_fullscreenQuadPipeline.get());
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->draw(3);
//! [render-pass-record]
cb->setGraphicsPipeline(m_colorPipeline.get());
cb->setShaderResources();
const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(3);
cb->endPass();
//! [render-pass-record]
}

View File

@ -0,0 +1,78 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef WINDOW_H
#define WINDOW_H
#include <QWindow>
#include <QOffscreenSurface>
#include <rhi/qrhi.h>
class RhiWindow : public QWindow
{
public:
RhiWindow(QRhi::Implementation graphicsApi);
QString graphicsApiName() const;
void releaseSwapChain();
protected:
virtual void customInit() = 0;
virtual void customRender() = 0;
// destruction order matters to a certain degree: the fallbackSurface must
// outlive the rhi, the rhi must outlive all other resources. The resources
// need no special order when destroying.
#if QT_CONFIG(opengl)
std::unique_ptr<QOffscreenSurface> m_fallbackSurface;
#endif
std::unique_ptr<QRhi> m_rhi;
//! [swapchain-data]
std::unique_ptr<QRhiSwapChain> m_sc;
std::unique_ptr<QRhiRenderBuffer> m_ds;
std::unique_ptr<QRhiRenderPassDescriptor> m_rp;
//! [swapchain-data]
bool m_hasSwapChain = false;
QMatrix4x4 m_viewProjection;
private:
void init();
void resizeSwapChain();
void render();
void exposeEvent(QExposeEvent *) override;
bool event(QEvent *) override;
QRhi::Implementation m_graphicsApi;
bool m_initialized = false;
bool m_notExposed = false;
bool m_newlyExposed = false;
};
class HelloWindow : public RhiWindow
{
public:
HelloWindow(QRhi::Implementation graphicsApi);
void customInit() override;
void customRender() override;
private:
void ensureFullscreenTexture(const QSize &pixelSize, QRhiResourceUpdateBatch *u);
std::unique_ptr<QRhiBuffer> m_vbuf;
std::unique_ptr<QRhiBuffer> m_ubuf;
std::unique_ptr<QRhiTexture> m_texture;
std::unique_ptr<QRhiSampler> m_sampler;
std::unique_ptr<QRhiShaderResourceBindings> m_colorTriSrb;
std::unique_ptr<QRhiGraphicsPipeline> m_colorPipeline;
std::unique_ptr<QRhiShaderResourceBindings> m_fullscreenQuadSrb;
std::unique_ptr<QRhiGraphicsPipeline> m_fullscreenQuadPipeline;
QRhiResourceUpdateBatch *m_initialUpdates = nullptr;
float m_rotation = 0;
float m_opacity = 1;
int m_opacityDir = -1;
};
#endif

View File

@ -0,0 +1,4 @@
INCLUDEPATH += $$PWD
SOURCES += $$PWD/rhiwindow.cpp
HEADERS += $$PWD/rhiwindow.h
RESOURCES += $$PWD/rhiwindow.qrc

View File

@ -0,0 +1,9 @@
include(rhiwindow.pri)
QT += gui-private
SOURCES += \
main.cpp
target.path = $$[QT_INSTALL_EXAMPLES]/gui/rhiwindow
INSTALLS += target

View File

@ -0,0 +1,8 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="color.vert.qsb">shaders/prebuilt/color.vert.qsb</file>
<file alias="color.frag.qsb">shaders/prebuilt/color.frag.qsb</file>
<file alias="quad.vert.qsb">shaders/prebuilt/quad.vert.qsb</file>
<file alias="quad.frag.qsb">shaders/prebuilt/quad.frag.qsb</file>
</qresource>
</RCC>

View File

@ -0,0 +1,15 @@
#version 440
layout(location = 0) in vec3 v_color;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
float opacity;
};
void main()
{
fragColor = vec4(v_color * opacity, opacity);
}

View File

@ -0,0 +1,17 @@
#version 440
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;
layout(location = 0) out vec3 v_color;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
float opacity;
};
void main()
{
v_color = color;
gl_Position = mvp * position;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,11 @@
#version 440
layout(location = 0) in vec2 v_uv;
layout(location = 0) out vec4 fragColor;
layout(binding = 0) uniform sampler2D tex;
void main()
{
vec4 c = texture(tex, v_uv);
fragColor = vec4(c.rgb * c.a, c.a);
}

View File

@ -0,0 +1,10 @@
#version 440
layout (location = 0) out vec2 v_uv;
void main()
{
// https://www.saschawillems.de/blog/2016/08/13/vulkan-tutorial-on-rendering-a-fullscreen-quad-without-buffers/
v_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(v_uv * 2.0 - 1.0, 0.0, 1.0);
}

View File

@ -14,6 +14,7 @@
#include <cstdio>
using namespace Qt::StringLiterals;
static std::optional<QDnsLookup::Type> typeFromParameter(QStringView type)
{
if (type.compare(u"a", Qt::CaseInsensitive) == 0)
@ -218,7 +219,7 @@ int main(int argc, char *argv[])
DnsManager manager;
manager.setQuery(query);
QTimer::singleShot(0, &manager, SLOT(execute()));
QTimer::singleShot(0, &manager, &DnsManager::execute);
return app.exec();
}

View File

@ -3,8 +3,10 @@
/*!
\example network-chat
\title Network Chat Example
\title Network Chat
\ingroup examples-network
\examplecategory {Networking}
\meta tag {network,serialization}
\brief Demonstrates a stateful peer-to-peer Chat client.
This example uses broadcasting with QUdpSocket and QNetworkInterface to

Some files were not shown because too many files have changed in this diff Show More