6.5.3 clean

This commit is contained in:
kleuter 2023-11-01 18:02:52 +01:00
parent bbe896803b
commit 7018d9e6c8
2170 changed files with 57471 additions and 43550 deletions

View File

@ -8,7 +8,7 @@ if (NOT DEFINED QT_SUPERBUILD OR DEFINED QT_REPO_MODULE_VERSION)
list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1") list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1")
endif() endif()
set(QT_REPO_MODULE_VERSION "6.5.1") set(QT_REPO_MODULE_VERSION "6.5.3")
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
set(QT_COPYRIGHT_YEAR "2023") set(QT_COPYRIGHT_YEAR "2023")

2
.gitattributes vendored
View File

@ -1,2 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@ -1 +1 @@
QT_PACKAGEDATE_STR=2023-05-22 QT_PACKAGEDATE_STR=2023-09-25

2
.tag
View File

@ -1 +1 @@
55aee8697512af105dfefabc1e2ec41d4df1e45e 372eaedc5b8c771c46acc4c96e91bbade4ca3624

View File

@ -40,11 +40,26 @@ function(qt_internal_check_if_path_has_symlinks path)
endwhile() endwhile()
endif() endif()
if(is_symlink) if(is_symlink)
message(FATAL_ERROR "The path \"${path}\" contains symlinks. \ set(possible_solutions_for_resolving_symlink [[
This is not supported. Possible solutions: - Map directories using a transparent mechanism such as mount --bind
- map directories using a transparent mechanism such as mount --bind - Pass the real path of the build directory to CMake, e.g. using
- pass the real path of the build directory to CMake, e.g. using \ cd $(realpath <path>) before invoking cmake <source_dir>.
cd $(realpath <path>) before invoking cmake <source_dir>.") ]])
if(QT_ALLOW_SYMLINK_IN_PATHS)
# In some cases, e.g., Homebrew, it is beneficial to skip this check.
# Before this, Homebrew had to patch this out to be able to get their build.
message(WARNING
"The path \"${path}\" contains symlinks. "
"This is not recommended, and it may lead to unexpected issues. If you do "
"not have a good reason for enabling 'QT_ALLOW_SYMLINK_IN_PATHS', disable "
"it, and follow one of the following solutions: \n"
"${possible_solutions_for_resolving_symlink} ")
else()
message(FATAL_ERROR
"The path \"${path}\" contains symlinks. "
"This is not supported. Possible solutions: \n"
"${possible_solutions_for_resolving_symlink} ")
endif()
endif() endif()
endfunction() endfunction()
qt_internal_check_if_path_has_symlinks("${CMAKE_BINARY_DIR}") qt_internal_check_if_path_has_symlinks("${CMAKE_BINARY_DIR}")

View File

@ -128,7 +128,8 @@ check_cxx_source_compiles("
#include <EGL/egl.h> #include <EGL/egl.h>
int main(int, char **) { int main(int, char **) {
EGLint x = 0; EGLDisplay dpy = 0; EGLContext ctx = 0; [[maybe_unused]] EGLint x = 0;
EGLDisplay dpy = 0; EGLContext ctx = 0;
eglDestroyContext(dpy, ctx); eglDestroyContext(dpy, ctx);
}" HAVE_EGL) }" HAVE_EGL)

View File

@ -12,12 +12,24 @@ find_path(GSSAPI_INCLUDE_DIRS
HINTS ${PC_GSSAPI_INCLUDEDIR} HINTS ${PC_GSSAPI_INCLUDEDIR}
) )
# On macOS, vcpkg opts for finding frameworks LAST. This is generally fine;
# however, in the case of GSSAPI, `usr/lib/libgssapi_krb5.tbd` which is a
# symlink to `Kerberos.framework` misses a few symols, e.g.,
# `___gss_c_nt_hostbased_service_oid_desc`, and it causes build failure.
# So, we need to make sure that we find `GSS.framework`.
set(gssapi_library_names
GSS # framework
gss # solaris
gssapi # FreeBSD
gssapi_krb5
)
if(APPLE)
list(REMOVE_ITEM gssapi_library_names "gssapi_krb5")
endif()
find_library(GSSAPI_LIBRARIES find_library(GSSAPI_LIBRARIES
NAMES NAMES
GSS # framework ${gssapi_library_names}
gss # solaris
gssapi # FreeBSD
gssapi_krb5
HINTS ${PC_GSSAPI_LIBDIR} HINTS ${PC_GSSAPI_LIBDIR}
) )
@ -44,4 +56,3 @@ mark_as_advanced(GSSAPI_INCLUDE_DIRS GSSAPI_LIBRARIES)
include(FeatureSummary) include(FeatureSummary)
set_package_properties(GSSAPI PROPERTIES set_package_properties(GSSAPI PROPERTIES
DESCRIPTION "Generic Security Services Application Program Interface") DESCRIPTION "Generic Security Services Application Program Interface")

View File

@ -18,9 +18,7 @@ find_package_handle_standard_args(PPS DEFAULT_MSG PPS_INCLUDE_DIR PPS_LIBRARY)
mark_as_advanced(PPS_INCLUDE_DIR PPS_LIBRARY) mark_as_advanced(PPS_INCLUDE_DIR PPS_LIBRARY)
if(PPS_FOUND) if(PPS_FOUND)
add_library(__PPS INTERFACE IMPORTED) add_library(PPS::PPS INTERFACE IMPORTED)
target_link_libraries(__PPS INTERFACE "${PPS_LIBRARY}") target_link_libraries(PPS::PPS INTERFACE "${PPS_LIBRARY}")
target_include_directories(__PPS INTERFACE "${PPS_INCLUDE_DIR}") target_include_directories(PPS::PPS INTERFACE "${PPS_INCLUDE_DIR}")
add_library(PPS::PPS ALIAS __PPS)
endif() endif()

View File

@ -17,14 +17,18 @@ if (OpenGL_FOUND)
add_library(WrapOpenGL::WrapOpenGL INTERFACE IMPORTED) add_library(WrapOpenGL::WrapOpenGL INTERFACE IMPORTED)
if(APPLE) if(APPLE)
# CMake 3.27 and older:
# On Darwin platforms FindOpenGL sets IMPORTED_LOCATION to the absolute path of the library # On Darwin platforms FindOpenGL sets IMPORTED_LOCATION to the absolute path of the library
# within the framework. This ends up as an absolute path link flag, which we don't want, # within the framework. This ends up as an absolute path link flag, which we don't want,
# because that makes our .prl files un-relocatable. # because that makes our .prl files un-relocatable.
# Extract the framework path instead, and use that in INTERFACE_LINK_LIBRARIES, # Extract the framework path instead, and use that in INTERFACE_LINK_LIBRARIES,
# which CMake ends up transforming into a reloctable -framework flag. # which CMake ends up transforming into a relocatable -framework flag.
# See https://gitlab.kitware.com/cmake/cmake/-/issues/20871 for details. # See https://gitlab.kitware.com/cmake/cmake/-/issues/20871 for details.
#
# CMake 3.28 and above:
# IMPORTED_LOCATION is the absolute path the the OpenGL.framework folder.
get_target_property(__opengl_fw_lib_path OpenGL::GL IMPORTED_LOCATION) get_target_property(__opengl_fw_lib_path OpenGL::GL IMPORTED_LOCATION)
if(__opengl_fw_lib_path) if(__opengl_fw_lib_path AND NOT __opengl_fw_lib_path MATCHES "/([^/]+)\\.framework$")
get_filename_component(__opengl_fw_path "${__opengl_fw_lib_path}" DIRECTORY) get_filename_component(__opengl_fw_path "${__opengl_fw_lib_path}" DIRECTORY)
endif() endif()

View File

@ -53,6 +53,7 @@ function(qt_internal_add_app target)
${arg_NO_UNITY_BUILD} ${arg_NO_UNITY_BUILD}
${forward_install_dir} ${forward_install_dir}
SOURCES ${arg_SOURCES} SOURCES ${arg_SOURCES}
NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES} NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES}
INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES
${arg_INCLUDE_DIRECTORIES} ${arg_INCLUDE_DIRECTORIES}

View File

@ -115,43 +115,38 @@ endfunction()
function(qt_run_linker_version_script_support) function(qt_run_linker_version_script_support)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/version_flag.map" "VERS_1 { global: sym; };
VERS_2 { global: sym; }
VERS_1;
")
if(DEFINED CMAKE_REQUIRED_FLAGS)
set(CMAKE_REQUIRED_FLAGS_SAVE ${CMAKE_REQUIRED_FLAGS})
else()
set(CMAKE_REQUIRED_FLAGS "")
endif()
set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "-Wl,--version-script=\"${CMAKE_CURRENT_BINARY_DIR}/version_flag.map\"")
# Pass the linker that the main project uses to the version script compile test.
qt_internal_get_active_linker_flags(linker_flags)
if(linker_flags)
set(CMAKE_REQUIRED_LINK_OPTIONS ${linker_flags})
endif()
check_cxx_source_compiles("int main(void){return 0;}" HAVE_LD_VERSION_SCRIPT)
if(DEFINED CMAKE_REQUIRED_FLAGS_SAVE)
set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE})
endif()
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map")
# For some reason the linker command line written by the XCode generator, which is # For some reason the linker command line written by the XCode generator, which is
# subsequently executed by xcodebuild, ignores the linker flag, and thus the test # subsequently executed by xcodebuild, ignores the linker flag, and thus the test
# seemingly succeeds. Explicitly disable the version script test on darwin platforms. # seemingly succeeds. Explicitly disable the version script test on darwin platforms.
if(APPLE)
set(HAVE_LD_VERSION_SCRIPT OFF)
endif()
# Also makes no sense with MSVC-style command-line # Also makes no sense with MSVC-style command-line
if(MSVC) if(NOT APPLE AND NOT MSVC)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/version_flag.map" [=[
VERS_1 { global: sym1; };
VERS_2 { global: sym2; } VERS_1;
]=])
set(CMAKE_REQUIRED_LINK_OPTIONS "")
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS
"-Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/version_flag.map")
# Pass the linker that the main project uses to the version script compile test.
qt_internal_get_active_linker_flags(linker_flags)
if(linker_flags)
list(APPEND CMAKE_REQUIRED_LINK_OPTIONS ${linker_flags})
endif()
check_cxx_source_compiles([=[
int sym1;
int sym2;
int main(void) { return 0; }
]=] HAVE_LD_VERSION_SCRIPT)
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/version_flag.map")
else()
set(HAVE_LD_VERSION_SCRIPT OFF) set(HAVE_LD_VERSION_SCRIPT OFF)
endif() endif()
set(TEST_ld_version_script "${HAVE_LD_VERSION_SCRIPT}" CACHE INTERNAL "linker version script support") set(TEST_ld_version_script "${HAVE_LD_VERSION_SCRIPT}"
CACHE INTERNAL "linker version script support")
list(APPEND QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT TEST_ld_version_script) list(APPEND QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT TEST_ld_version_script)
set(QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT ${QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT} CACHE INTERNAL "Test variables that should be exported") set(QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT ${QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT}
CACHE INTERNAL "Test variables that should be exported")
endfunction() endfunction()
function(qt_internal_ensure_latest_win_nt_api) function(qt_internal_ensure_latest_win_nt_api)

View File

@ -101,7 +101,8 @@ if(MACOS AND QT_IS_MACOS_UNIVERSAL
QT_FEATURE_x86intrin) QT_FEATURE_x86intrin)
endif() endif()
if(MACOS AND QT_IS_MACOS_UNIVERSAL AND __qt_osx_first_arch STREQUAL "x86_64") if(MACOS AND QT_IS_MACOS_UNIVERSAL AND
(__qt_osx_first_arch STREQUAL "x86_64" OR __qt_osx_first_arch STREQUAL "x86_64h"))
set(QT_FORCE_FEATURE_neon ON CACHE INTERNAL "Force enable neon due to platform requirements.") set(QT_FORCE_FEATURE_neon ON CACHE INTERNAL "Force enable neon due to platform requirements.")
set(__QtFeature_custom_enabled_cache_variables set(__QtFeature_custom_enabled_cache_variables
TEST_subarch_neon TEST_subarch_neon
@ -373,6 +374,10 @@ qt_copy_or_install(DIRECTORY cmake/
FILES_MATCHING PATTERN "Find*.cmake" FILES_MATCHING PATTERN "Find*.cmake"
PATTERN "tests" EXCLUDE PATTERN "tests" EXCLUDE
PATTERN "3rdparty" EXCLUDE PATTERN "3rdparty" EXCLUDE
PATTERN "macos" EXCLUDE
PATTERN "ios" EXCLUDE
PATTERN "platforms" EXCLUDE
PATTERN "QtBuildInternals" EXCLUDE
) )
# In prefix builds we also need to copy the files into the build config directory, so that the # In prefix builds we also need to copy the files into the build config directory, so that the
@ -383,6 +388,10 @@ if(QT_WILL_INSTALL)
FILES_MATCHING PATTERN "Find*.cmake" FILES_MATCHING PATTERN "Find*.cmake"
PATTERN "tests" EXCLUDE PATTERN "tests" EXCLUDE
PATTERN "3rdparty" EXCLUDE PATTERN "3rdparty" EXCLUDE
PATTERN "macos" EXCLUDE
PATTERN "ios" EXCLUDE
PATTERN "platforms" EXCLUDE
PATTERN "QtBuildInternals" EXCLUDE
) )
endif() endif()

View File

@ -284,21 +284,21 @@ if(WIN32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8) if(CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64) list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS WIN64 _WIN64)
endif() endif()
if(MSVC)
if (CLANG) if(CLANG)
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC" OR MSVC)
set(QT_DEFAULT_MKSPEC win32-clang-msvc) set(QT_DEFAULT_MKSPEC win32-clang-msvc)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") elseif(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU" OR MINGW)
set(QT_DEFAULT_MKSPEC win32-clang-g++)
endif()
elseif(MSVC)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(QT_DEFAULT_MKSPEC win32-arm64-msvc) set(QT_DEFAULT_MKSPEC win32-arm64-msvc)
else() else()
set(QT_DEFAULT_MKSPEC win32-msvc) set(QT_DEFAULT_MKSPEC win32-msvc)
endif() endif()
elseif(CLANG AND MINGW)
set(QT_DEFAULT_MKSPEC win32-clang-g++)
elseif(MINGW) elseif(MINGW)
set(QT_DEFAULT_MKSPEC win32-g++) set(QT_DEFAULT_MKSPEC win32-g++)
endif()
if (MINGW)
list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS MINGW_HAS_SECURE_API=1) list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS MINGW_HAS_SECURE_API=1)
endif() endif()
elseif(LINUX) elseif(LINUX)
@ -376,15 +376,23 @@ else()
set(QT_QMAKE_HOST_MKSPEC "${QT_QMAKE_TARGET_MKSPEC}") set(QT_QMAKE_HOST_MKSPEC "${QT_QMAKE_TARGET_MKSPEC}")
endif() endif()
if(NOT EXISTS "${QT_MKSPECS_DIR}/${QT_QMAKE_TARGET_MKSPEC}") if(NOT QT_QMAKE_TARGET_MKSPEC OR NOT EXISTS "${QT_MKSPECS_DIR}/${QT_QMAKE_TARGET_MKSPEC}")
if(NOT QT_QMAKE_TARGET_MKSPEC)
set(reason "Platform is not detected. Please make sure your build environment is configured"
" properly or specify it manually using QT_QMAKE_TARGET_MKSPEC variable and one of the"
" known platforms.")
else()
set(reason "Unknown platform ${QT_QMAKE_TARGET_MKSPEC}")
endif()
file(GLOB known_platforms file(GLOB known_platforms
LIST_DIRECTORIES true LIST_DIRECTORIES true
RELATIVE "${QT_MKSPECS_DIR}" RELATIVE "${QT_MKSPECS_DIR}"
"${QT_MKSPECS_DIR}/*" "${QT_MKSPECS_DIR}/*"
) )
list(JOIN known_platforms "\n " known_platforms) list(JOIN known_platforms "\n " known_platforms)
message(FATAL_ERROR "Unknown platform ${QT_QMAKE_TARGET_MKSPEC}\n\ message(FATAL_ERROR "${reason}\n"
Known platforms:\n ${known_platforms}") "Known platforms:\n ${known_platforms}")
endif() endif()
if(NOT DEFINED QT_DEFAULT_PLATFORM_DEFINITIONS) if(NOT DEFINED QT_DEFAULT_PLATFORM_DEFINITIONS)
@ -459,6 +467,7 @@ set(__default_private_args
DISABLE_AUTOGEN_TOOLS DISABLE_AUTOGEN_TOOLS
ENABLE_AUTOGEN_TOOLS ENABLE_AUTOGEN_TOOLS
PLUGIN_TYPES PLUGIN_TYPES
NO_PCH_SOURCES
NO_UNITY_BUILD_SOURCES NO_UNITY_BUILD_SOURCES
) )
set(__default_public_args set(__default_public_args

View File

@ -109,7 +109,7 @@ from the build directory")
set(QT_INTERNAL_BUILD_INSTRUCTIONS_SHOWN "TRUE" CACHE STRING "" FORCE) set(QT_INTERNAL_BUILD_INSTRUCTIONS_SHOWN "TRUE" CACHE STRING "" FORCE)
if(QT_SUPERBUILD) if(QT_SUPERBUILD)
qt_internal_save_previously_found_packages() qt_internal_save_previously_visited_packages()
endif() endif()
endfunction() endfunction()

View File

@ -308,24 +308,19 @@ function(qt_build_internals_add_toplevel_targets)
endfunction() endfunction()
macro(qt_enable_cmake_languages) macro(qt_enable_cmake_languages)
include(CheckLanguage)
set(__qt_required_language_list C CXX) set(__qt_required_language_list C CXX)
set(__qt_optional_language_list ) set(__qt_platform_required_language_list )
# https://gitlab.kitware.com/cmake/cmake/-/issues/20545
if(APPLE) if(APPLE)
list(APPEND __qt_optional_language_list OBJC OBJCXX) list(APPEND __qt_platform_required_language_list OBJC OBJCXX)
endif() endif()
foreach(__qt_lang ${__qt_required_language_list}) foreach(__qt_lang ${__qt_required_language_list})
enable_language(${__qt_lang}) enable_language(${__qt_lang})
endforeach() endforeach()
foreach(__qt_lang ${__qt_optional_language_list}) foreach(__qt_lang ${__qt_platform_required_language_list})
check_language(${__qt_lang}) enable_language(${__qt_lang})
if(CMAKE_${__qt_lang}_COMPILER)
enable_language(${__qt_lang})
endif()
endforeach() endforeach()
# The qtbase call is handled in qtbase/CMakeLists.txt. # The qtbase call is handled in qtbase/CMakeLists.txt.
@ -434,6 +429,12 @@ macro(qt_build_repo_begin)
add_custom_target(sync_headers) add_custom_target(sync_headers)
endif() endif()
# The special target that we use to sync 3rd-party headers before the gn run when building
# qtwebengine in top-level builds.
if(NOT TARGET thirdparty_sync_headers)
add_custom_target(thirdparty_sync_headers)
endif()
# Add global qt_plugins, qpa_plugins and qpa_default_plugins convenience custom targets. # Add global qt_plugins, qpa_plugins and qpa_default_plugins convenience custom targets.
# Internal executables will add a dependency on the qpa_default_plugins target, # Internal executables will add a dependency on the qpa_default_plugins target,
# so that building and running a test ensures it won't fail at runtime due to a missing qpa # so that building and running a test ensures it won't fail at runtime due to a missing qpa
@ -562,7 +563,7 @@ macro(qt_build_repo_end)
endif() endif()
if(NOT QT_SUPERBUILD) if(NOT QT_SUPERBUILD)
qt_internal_save_previously_found_packages() qt_internal_save_previously_visited_packages()
endif() endif()
if(QT_INTERNAL_FRESH_REQUESTED) if(QT_INTERNAL_FRESH_REQUESTED)
@ -1415,3 +1416,13 @@ function(qt_internal_run_common_config_tests)
qt_internal_check_cmp0099_available() qt_internal_check_cmp0099_available()
qt_configure_end_summary_section() qt_configure_end_summary_section()
endfunction() endfunction()
# It is used in QtWebEngine to replace the REALPATH with ABSOLUTE path, which is
# useful for building Qt in Homebrew.
function(qt_internal_get_filename_path_mode out_var)
set(mode REALPATH)
if(APPLE AND QT_ALLOW_SYMLINK_IN_PATHS)
set(mode ABSOLUTE)
endif()
set(${out_var} ${mode} PARENT_SCOPE)
endfunction()

View File

@ -124,5 +124,5 @@ endif()
# Emscripten Clang # Emscripten Clang
if(WASM) if(WASM)
set(QT_CFLAGS_OPTIMIZE_DEBUG "-O2 -g") # -Og is not supported set(QT_CFLAGS_OPTIMIZE_DEBUG "-O2 -g") # -Og is not supported
set(QT_CFLAGS_SSE2 -O2 -msimd128 -msse -msse2) set(QT_CFLAGS_SSE2 "-O2 -msimd128 -msse -msse2")
endif() endif()

View File

@ -30,6 +30,7 @@ function(qt_internal_add_executable name)
endif() endif()
_qt_internal_create_executable(${name}) _qt_internal_create_executable(${name})
qt_internal_mark_as_internal_target(${name})
if(ANDROID) if(ANDROID)
_qt_internal_android_executable_finalizer(${name}) _qt_internal_android_executable_finalizer(${name})
endif() endif()
@ -119,6 +120,7 @@ function(qt_internal_add_executable name)
qt_internal_extend_target("${name}" qt_internal_extend_target("${name}"
${arg_NO_UNITY_BUILD} ${arg_NO_UNITY_BUILD}
SOURCES ${arg_SOURCES} SOURCES ${arg_SOURCES}
NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES} NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES}
INCLUDE_DIRECTORIES ${private_includes} INCLUDE_DIRECTORIES ${private_includes}
DEFINES ${arg_DEFINES} DEFINES ${arg_DEFINES}
@ -369,6 +371,7 @@ function(qt_internal_add_configure_time_executable target)
set(target_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/configure_time_bins") set(target_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/configure_time_bins")
if(arg_CONFIG) if(arg_CONFIG)
set(CMAKE_TRY_COMPILE_CONFIGURATION "${arg_CONFIG}") set(CMAKE_TRY_COMPILE_CONFIGURATION "${arg_CONFIG}")
string(TOUPPER "_${arg_CONFIG}" config_suffix)
endif() endif()
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
@ -462,6 +465,29 @@ function(qt_internal_add_configure_time_executable target)
set(cmake_flags_arg CMAKE_FLAGS "${arg_CMAKE_FLAGS}") set(cmake_flags_arg CMAKE_FLAGS "${arg_CMAKE_FLAGS}")
endif() endif()
configure_file("${template}" "${target_binary_dir}/CMakeLists.txt" @ONLY) configure_file("${template}" "${target_binary_dir}/CMakeLists.txt" @ONLY)
qt_internal_get_enabled_languages_for_flag_manipulation(enabled_languages)
foreach(lang IN LISTS enabled_languages)
set(compiler_flags_var "CMAKE_${lang}_FLAGS")
list(APPEND cmake_flags_arg "-D${compiler_flags_var}:STRING=${${compiler_flags_var}}")
if(arg_CONFIG)
set(compiler_flags_var_config "${compiler_flags_var}${config_suffix}")
list(APPEND cmake_flags_arg
"-D${compiler_flags_var_config}:STRING=${${compiler_flags_var_config}}")
endif()
endforeach()
qt_internal_get_target_link_types_for_flag_manipulation(target_link_types)
foreach(linker_type IN LISTS target_link_types)
set(linker_flags_var "CMAKE_${linker_type}_LINKER_FLAGS")
list(APPEND cmake_flags_arg "-D${linker_flags_var}:STRING=${${linker_flags_var}}")
if(arg_CONFIG)
set(linker_flags_var_config "${linker_flags_var}${config_suffix}")
list(APPEND cmake_flags_arg
"-D${linker_flags_var_config}:STRING=${${linker_flags_var_config}}")
endif()
endforeach()
try_compile(result try_compile(result
"${target_binary_dir}" "${target_binary_dir}"
"${target_binary_dir}" "${target_binary_dir}"

View File

@ -41,10 +41,13 @@ macro(qt_find_package)
# Due to this behavior being different from what general CMake projects expect, it is only # Due to this behavior being different from what general CMake projects expect, it is only
# done for -developer-builds. # done for -developer-builds.
if(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES AND if(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES AND
NOT "${ARGV0}" IN_LIST QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES) NOT "${ARGV0}" IN_LIST QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES
AND "${ARGV0}" IN_LIST QT_INTERNAL_PREVIOUSLY_SEARCHED_PACKAGES)
set(_qt_find_package_skip_find_package TRUE) set(_qt_find_package_skip_find_package TRUE)
endif() endif()
set_property(GLOBAL APPEND PROPERTY _qt_previously_searched_packages "${ARGV0}")
if(QT_DEBUG_QT_FIND_PACKAGE AND ${ARGV0}_FOUND AND arg_PROVIDED_TARGETS) if(QT_DEBUG_QT_FIND_PACKAGE AND ${ARGV0}_FOUND AND arg_PROVIDED_TARGETS)
set(_qt_find_package_skip_find_package TRUE) set(_qt_find_package_skip_find_package TRUE)
foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS}) foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS})
@ -221,7 +224,7 @@ endmacro()
# Only applies to -developer-builds by default. # Only applies to -developer-builds by default.
# Can also be opted in or opted out via QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES. # Can also be opted in or opted out via QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES.
# Opting out will need two reconfigurations to take effect. # Opting out will need two reconfigurations to take effect.
function(qt_internal_save_previously_found_packages) function(qt_internal_save_previously_visited_packages)
if(DEFINED QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES) if(DEFINED QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES)
set(should_save "${QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES}") set(should_save "${QT_INTERNAL_SAVE_PREVIOUSLY_FOUND_PACKAGES}")
else() else()
@ -235,6 +238,7 @@ function(qt_internal_save_previously_found_packages)
if(NOT should_save) if(NOT should_save)
# When the value is flipped to OFF, remove any previously saved packages. # When the value is flipped to OFF, remove any previously saved packages.
unset(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES CACHE) unset(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES CACHE)
unset(QT_INTERNAL_PREVIOUSLY_SEARCHED_PACKAGES CACHE)
return() return()
endif() endif()
@ -244,6 +248,15 @@ function(qt_internal_save_previously_found_packages)
set(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES "${_qt_previously_found_packages}" CACHE INTERNAL set(QT_INTERNAL_PREVIOUSLY_FOUND_PACKAGES "${_qt_previously_found_packages}" CACHE INTERNAL
"List of CMake packages found during configuration using qt_find_package.") "List of CMake packages found during configuration using qt_find_package.")
endif() endif()
get_property(_qt_previously_searched_packages GLOBAL PROPERTY _qt_previously_searched_packages)
if(_qt_previously_searched_packages)
list(REMOVE_DUPLICATES _qt_previously_searched_packages)
set(QT_INTERNAL_PREVIOUSLY_SEARCHED_PACKAGES
"${_qt_previously_searched_packages}" CACHE INTERNAL
"List of CMake packages searched during configuration using qt_find_package."
)
endif()
endfunction() endfunction()
# Return qmake library name for the given target, e.g. return "vulkan" for "Vulkan::Vulkan". # Return qmake library name for the given target, e.g. return "vulkan" for "Vulkan::Vulkan".

View File

@ -33,22 +33,15 @@ function(qt_internal_add_linker_version_script target)
endif() endif()
string(APPEND contents "};\n") string(APPEND contents "};\n")
set(current "Qt_${PROJECT_VERSION_MAJOR}") set(current "Qt_${PROJECT_VERSION_MAJOR}")
if (QT_NAMESPACE STREQUAL "")
set(tag_symbol "qt_version_tag")
else()
set(tag_symbol "qt_version_tag_${QT_NAMESPACE}")
endif()
string(APPEND contents "${current} { *; };\n") string(APPEND contents "${current} { *; };\n")
foreach(minor_version RANGE ${PROJECT_VERSION_MINOR}) get_target_property(type ${target} TYPE)
set(previous "${current}") if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}") set(property_genex "$<TARGET_PROPERTY:${target},_qt_extra_linker_script_content>")
if (minor_version EQUAL ${PROJECT_VERSION_MINOR}) set(check_genex "$<BOOL:${property_genex}>")
string(APPEND contents "${current} { ${tag_symbol}; } ${previous};\n") string(APPEND contents
else() "$<${check_genex}:${property_genex}>")
string(APPEND contents "${current} {} ${previous};\n") endif()
endif()
endforeach()
set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in") set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in")
set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version") set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version")
@ -87,6 +80,11 @@ function(qt_internal_add_link_flags_no_undefined target)
if (NOT QT_BUILD_SHARED_LIBS OR WASM) if (NOT QT_BUILD_SHARED_LIBS OR WASM)
return() return()
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# ld64 defaults to -undefined,error, and in Xcode 15
# passing this option is deprecated, causing a warning.
return()
endif()
if ((GCC OR CLANG) AND NOT MSVC) if ((GCC OR CLANG) AND NOT MSVC)
if(CLANG AND QT_FEATURE_sanitizer) if(CLANG AND QT_FEATURE_sanitizer)
return() return()
@ -124,11 +122,20 @@ endfunction()
function(qt_internal_apply_gc_binaries target visibility) function(qt_internal_apply_gc_binaries target visibility)
set(possible_visibilities PRIVATE INTERFACE PUBLIC) set(possible_visibilities PRIVATE INTERFACE PUBLIC)
list(FIND possible_visibilities "${visibility}" known_visibility) if(NOT visibility IN_LIST possible_visibilities)
if (known_visibility EQUAL "-1")
message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.") message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
endif() endif()
string(JOIN "" clang_or_gcc_begin
"$<$<OR:"
"$<CXX_COMPILER_ID:GNU>,"
"$<CXX_COMPILER_ID:Clang>,"
"$<CXX_COMPILER_ID:AppleClang>,"
"$<CXX_COMPILER_ID:IntelLLVM>"
">:"
)
set(clang_or_gcc_end ">")
if ((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC) if ((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC)
if(APPLE) if(APPLE)
set(gc_sections_flag "-Wl,-dead_strip") set(gc_sections_flag "-Wl,-dead_strip")
@ -137,16 +144,26 @@ function(qt_internal_apply_gc_binaries target visibility)
elseif(LINUX OR BSD OR WIN32 OR ANDROID) elseif(LINUX OR BSD OR WIN32 OR ANDROID)
set(gc_sections_flag "-Wl,--gc-sections") set(gc_sections_flag "-Wl,--gc-sections")
endif() endif()
# Save the flag value with and without genex wrapping, so we can remove the wrapping
# when generating .pc pkgconfig files.
set_property(GLOBAL PROPERTY _qt_internal_gc_sections_without_genex "${gc_sections_flag}")
set(gc_sections_flag
"${clang_or_gcc_begin}${gc_sections_flag}${clang_or_gcc_end}")
set_property(GLOBAL PROPERTY _qt_internal_gc_sections_with_genex "${gc_sections_flag}")
endif() endif()
if(gc_sections_flag) if(gc_sections_flag)
target_link_options("${target}" ${visibility} "${gc_sections_flag}") target_link_options("${target}" ${visibility} "${gc_sections_flag}")
endif() endif()
if((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC) if((GCC OR CLANG) AND NOT WASM AND NOT UIKIT AND NOT MSVC)
set(split_sections_flags "-ffunction-sections" "-fdata-sections") set(split_sections_flags
"${clang_or_gcc_begin}-ffunction-sections;-fdata-sections${clang_or_gcc_end}")
endif() endif()
if(split_sections_flags) if(split_sections_flags)
target_compile_options("${target}" ${visibility} ${split_sections_flags}) target_compile_options("${target}" ${visibility} "${split_sections_flags}")
endif() endif()
endfunction() endfunction()
@ -156,13 +173,17 @@ function(qt_internal_apply_intel_cet target visibility)
endif() endif()
set(possible_visibilities PRIVATE INTERFACE PUBLIC) set(possible_visibilities PRIVATE INTERFACE PUBLIC)
list(FIND possible_visibilities "${visibility}" known_visibility) if(NOT visibility IN_LIST possible_visibilities)
if (known_visibility EQUAL "-1")
message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.") message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.")
endif() endif()
if(GCC) if(GCC)
set(flags "-mshstk") string(JOIN "" flags
"$<$<OR:"
"$<CXX_COMPILER_ID:GNU>,"
"$<CXX_COMPILER_ID:Clang>,"
"$<CXX_COMPILER_ID:AppleClang>"
">:-mshstk>")
endif() endif()
if(flags) if(flags)
target_compile_options("${target}" ${visibility} "${flags}") target_compile_options("${target}" ${visibility} "${flags}")
@ -287,14 +308,15 @@ function(qt_set_msvc_cplusplus_options target visibility)
# Check qt_config_compile_test for more info. # Check qt_config_compile_test for more info.
if(MSVC AND MSVC_VERSION GREATER_EQUAL 1913) if(MSVC AND MSVC_VERSION GREATER_EQUAL 1913)
set(flags "-Zc:__cplusplus" "-permissive-") set(flags "-Zc:__cplusplus" "-permissive-")
target_compile_options("${target}" ${visibility} "$<$<COMPILE_LANGUAGE:CXX>:${flags}>") target_compile_options("${target}" ${visibility}
"$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<COMPILE_LANGUAGE:CXX>>:${flags}>")
endif() endif()
endfunction() endfunction()
function(qt_enable_utf8_sources target) function(qt_enable_utf8_sources target)
set(utf8_flags "") set(utf8_flags "")
if(MSVC) if(MSVC)
list(APPEND utf8_flags "-utf-8") list(APPEND utf8_flags "$<$<CXX_COMPILER_ID:MSVC>:-utf-8>")
endif() endif()
if(utf8_flags) if(utf8_flags)
@ -557,12 +579,20 @@ endfunction()
# Removes specified flags from CMAKE_<LANGUAGES>_FLAGS[_CONFIGS] variables # Removes specified flags from CMAKE_<LANGUAGES>_FLAGS[_CONFIGS] variables
# #
# IN_CACHE enables flags removal from CACHE # Option Arguments:
# CONFIGS list of configurations that need to clear flags. Clears all configs by default if not # IN_CACHE
# specified. # Enables flags removal from CACHE
# LANGUAGES list of LANGUAGES that need clear flags. Clears all languages by default if not # REGEX
# specified. # Enables the flag processing as a regular expression.
# REGEX enables the flag processing as a regular expression. #
# Multi-value Arguments:
# CONFIGS
# List of configurations that need to clear flags. Clears all configs by default if not
# specified.
#
# LANGUAGES
# List of LANGUAGES that need clear flags. Clears all languages by default if not
# specified.
function(qt_internal_remove_compiler_flags flags) function(qt_internal_remove_compiler_flags flags)
cmake_parse_arguments(PARSE_ARGV 1 arg cmake_parse_arguments(PARSE_ARGV 1 arg
"IN_CACHE;REGEX" "IN_CACHE;REGEX"
@ -585,8 +615,7 @@ function(qt_internal_remove_compiler_flags flags)
if(arg_CONFIGS) if(arg_CONFIGS)
set(configs "${arg_CONFIGS}") set(configs "${arg_CONFIGS}")
else() else()
message(FATAL_ERROR qt_internal_get_configs_for_flag_manipulation(configs)
"You must specify at least one configuration for which to remove the flags.")
endif() endif()
if(arg_REGEX) if(arg_REGEX)
@ -992,14 +1021,42 @@ function(qt_internal_set_up_config_optimizations_like_in_qmake)
IN_CACHE) IN_CACHE)
endif() endif()
# Legacy Android toolchain file adds the `-g` flag to CMAKE_<LANG>_FLAGS, as a
# result, our release build ends up containing debug symbols. To avoid that, we
# remove the flag from CMAKE_<LANGL>_FLAGS and add
# it to CMAKE_<LANG>_FLAGS_DEBUG.
#
# Note:
# The new `android.toolchain.cmake` file does not have this problem, but
# it has other issues, eg., https://github.com/android/ndk/issues/1693, so we
# cannot force it. While we do load the new toolchain, it automatically falls
# back to the legacy toolchain, ie., `android-legacy.toolchain.cmake` which
# has the problem described above.
#
# Todo:
# When the new toolchain is fixed, and it doesn't fall back to the legacy
# anymore by default, then we should be able to remove this workaround.
if(ANDROID AND ANDROID_COMPILER_FLAGS MATCHES "(^| )-g")
qt_internal_remove_compiler_flags("-g")
qt_internal_add_compiler_flags(FLAGS "-g" CONFIGS DEBUG RELWITHDEBINFO)
endif()
# Update all relevant flags in the calling scope # Update all relevant flags in the calling scope
foreach(config ${configs}) foreach(lang ${enabled_languages})
foreach(lang ${enabled_languages}) set(flag_var_name "CMAKE_${lang}_FLAGS")
set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
foreach(config ${configs})
set(flag_var_name "CMAKE_${lang}_FLAGS_${config}") set(flag_var_name "CMAKE_${lang}_FLAGS_${config}")
set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE) set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
endforeach() endforeach()
endforeach()
foreach(t ${target_link_types}) foreach(t ${target_link_types})
set(flag_var_name "CMAKE_${t}_LINKER_FLAGS")
set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
foreach(config ${configs})
set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}") set(flag_var_name "CMAKE_${t}_LINKER_FLAGS_${config}")
set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE) set(${flag_var_name} "${${flag_var_name}}" PARENT_SCOPE)
endforeach() endforeach()

View File

@ -185,6 +185,9 @@ function(qt_internal_add_headersclean_target module_target module_headers)
# <windows.h> and <GL.h> violate the standards. # <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)
# Because we now add `-DNOMINMAX` to `PlatformCommonInternal`.
set(hcleanUDEFS -UNOMINMAX)
# cl.exe needs a source path # cl.exe needs a source path
get_filename_component(source_path "${QT_MKSPECS_DIR}/features/data/dummy.cpp" REALPATH) get_filename_component(source_path "${QT_MKSPECS_DIR}/features/data/dummy.cpp" REALPATH)
@ -195,6 +198,7 @@ function(qt_internal_add_headersclean_target module_target module_headers)
"${hcleanFLAGS}" "${hcleanFLAGS}"
"${target_includes_joined_genex}" "${target_includes_joined_genex}"
"${hcleanDEFS}" "${hcleanDEFS}"
"${hcleanUDEFS}"
) )
string(JOIN " " compiler_command_line_variables string(JOIN " " compiler_command_line_variables
"-FI" "-FI"
@ -227,7 +231,7 @@ function(qt_internal_add_headersclean_target module_target module_headers)
file(GENERATE OUTPUT "${headers_check_parameters}" file(GENERATE OUTPUT "${headers_check_parameters}"
CONTENT "${headers_check_parameters_content}") CONTENT "${headers_check_parameters_content}")
set(sync_headers_dep "sync_headers") set(sync_headers_dep "${module_target}_sync_headers")
foreach(header ${hclean_headers}) foreach(header ${hclean_headers})
# We need realpath here to make sure path starts with drive letter # We need realpath here to make sure path starts with drive letter

View File

@ -102,7 +102,7 @@ function(qt_internal_add_global_definition definition)
set(optional_args) set(optional_args)
set(single_value_args VALUE) set(single_value_args VALUE)
set(multi_value_args SCOPE) set(multi_value_args SCOPE)
cmake_parse_arguments(args cmake_parse_arguments(arg
"${optional_args}" "${optional_args}"
"${single_value_args}" "${single_value_args}"
"${multi_value_args}" "${multi_value_args}"
@ -168,6 +168,8 @@ if(WIN32)
# Needed for M_PI define. Same as mkspecs/features/qt_module.prf. # Needed for M_PI define. Same as mkspecs/features/qt_module.prf.
# It's set for every module being built, but it's not propagated to user apps. # It's set for every module being built, but it's not propagated to user apps.
target_compile_definitions(PlatformModuleInternal INTERFACE _USE_MATH_DEFINES) target_compile_definitions(PlatformModuleInternal INTERFACE _USE_MATH_DEFINES)
# Not disabling min/max macros may result in unintended substitutions of std::min/max
target_compile_definitions(PlatformCommonInternal INTERFACE NOMINMAX)
endif() endif()
if(FEATURE_largefile AND UNIX) if(FEATURE_largefile AND UNIX)
target_compile_definitions(PlatformCommonInternal target_compile_definitions(PlatformCommonInternal
@ -205,6 +207,14 @@ function(qt_internal_apply_bitcode_flags target)
target_compile_options("${target}" INTERFACE ${bitcode_flags}) target_compile_options("${target}" INTERFACE ${bitcode_flags})
endfunction() endfunction()
# Function guards linker options that are applicable for internal Qt targets only from propagating
# them to user projects.
function(qt_internal_platform_link_options target scope)
set(options ${ARGN})
set(is_internal_target_genex "$<BOOL:$<TARGET_PROPERTY:_qt_is_internal_target>>")
target_link_options(${target} ${scope} "$<${is_internal_target_genex}:${options}>")
endfunction()
# Apple deprecated the entire OpenGL API in favor of Metal, which # Apple deprecated the entire OpenGL API in favor of Metal, which
# we are aware of, so silence the deprecation warnings in code. # we are aware of, so silence the deprecation warnings in code.
# This does not apply to user-code, which will need to silence # This does not apply to user-code, which will need to silence
@ -283,7 +293,7 @@ if (MSVC)
$<$<NOT:$<CONFIG:Debug>>:-guard:cf -Gw> $<$<NOT:$<CONFIG:Debug>>:-guard:cf -Gw>
) )
target_link_options(PlatformCommonInternal INTERFACE qt_internal_platform_link_options(PlatformCommonInternal INTERFACE
-DYNAMICBASE -NXCOMPAT -LARGEADDRESSAWARE -DYNAMICBASE -NXCOMPAT -LARGEADDRESSAWARE
$<$<NOT:$<CONFIG:Debug>>:-OPT:REF -OPT:ICF -GUARD:CF> $<$<NOT:$<CONFIG:Debug>>:-OPT:REF -OPT:ICF -GUARD:CF>
) )
@ -299,7 +309,7 @@ endif()
if(QT_FEATURE_intelcet) if(QT_FEATURE_intelcet)
if(MSVC) if(MSVC)
target_link_options(PlatformCommonInternal INTERFACE qt_internal_platform_link_options(PlatformCommonInternal INTERFACE
-CETCOMPAT -CETCOMPAT
) )
else() else()
@ -328,30 +338,31 @@ endif()
if(DEFINED QT_EXTRA_FRAMEWORKPATHS AND APPLE) if(DEFINED QT_EXTRA_FRAMEWORKPATHS AND APPLE)
list(TRANSFORM QT_EXTRA_FRAMEWORKPATHS PREPEND "-F" OUTPUT_VARIABLE __qt_fw_flags) list(TRANSFORM QT_EXTRA_FRAMEWORKPATHS PREPEND "-F" OUTPUT_VARIABLE __qt_fw_flags)
target_compile_options(PlatformCommonInternal INTERFACE ${__qt_fw_flags}) target_compile_options(PlatformCommonInternal INTERFACE ${__qt_fw_flags})
target_link_options(PlatformCommonInternal INTERFACE ${__qt_fw_flags}) qt_internal_platform_link_options(PlatformCommonInternal INTERFACE ${__qt_fw_flags})
unset(__qt_fw_flags) unset(__qt_fw_flags)
endif() endif()
qt_internal_get_active_linker_flags(__qt_internal_active_linker_flags) qt_internal_get_active_linker_flags(__qt_internal_active_linker_flags)
if(__qt_internal_active_linker_flags) if(__qt_internal_active_linker_flags)
target_link_options(PlatformCommonInternal INTERFACE "${__qt_internal_active_linker_flags}") qt_internal_platform_link_options(PlatformCommonInternal INTERFACE
"${__qt_internal_active_linker_flags}")
endif() endif()
unset(__qt_internal_active_linker_flags) unset(__qt_internal_active_linker_flags)
if(QT_FEATURE_enable_gdb_index) if(QT_FEATURE_enable_gdb_index)
target_link_options(PlatformCommonInternal INTERFACE "-Wl,--gdb-index") qt_internal_platform_link_options(PlatformCommonInternal INTERFACE "-Wl,--gdb-index")
endif() endif()
if(QT_FEATURE_enable_new_dtags) if(QT_FEATURE_enable_new_dtags)
target_link_options(PlatformCommonInternal INTERFACE "-Wl,--enable-new-dtags") qt_internal_platform_link_options(PlatformCommonInternal INTERFACE "-Wl,--enable-new-dtags")
endif() endif()
function(qt_get_implicit_sse2_genex_condition out_var) function(qt_get_implicit_sse2_genex_condition out_var)
set(is_shared_lib "$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>") set(is_shared_lib "$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>")
set(is_static_lib "$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>") set(is_static_lib "$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>")
set(is_static_qt_build "$<NOT:$<BOOL:${QT_BUILD_SHARED_LIBS}>>") set(is_static_qt_build "$<NOT:$<BOOL:${QT_BUILD_SHARED_LIBS}>>")
set(is_staitc_lib_during_static_qt_build "$<AND:${is_static_qt_build},${is_static_lib}>") set(is_static_lib_during_static_qt_build "$<AND:${is_static_qt_build},${is_static_lib}>")
set(enable_sse2_condition "$<OR:${is_shared_lib},${is_staitc_lib_during_static_qt_build}>") set(enable_sse2_condition "$<OR:${is_shared_lib},${is_static_lib_during_static_qt_build}>")
set(${out_var} "${enable_sse2_condition}" PARENT_SCOPE) set(${out_var} "${enable_sse2_condition}" PARENT_SCOPE)
endfunction() endfunction()

View File

@ -4,6 +4,10 @@
# This function can be used to compile java sources into a jar package. # This function can be used to compile java sources into a jar package.
function(qt_internal_add_jar target) function(qt_internal_add_jar target)
set(options)
set(oneValueArgs OUTPUT_DIR)
set(multiValueArgs INCLUDE_JARS SOURCES)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(javac_target_version "${QT_ANDROID_JAVAC_TARGET}") set(javac_target_version "${QT_ANDROID_JAVAC_TARGET}")
if (NOT javac_target_version) if (NOT javac_target_version)
@ -18,4 +22,8 @@ function(qt_internal_add_jar target)
set(CMAKE_JAVA_COMPILE_FLAGS -source "${javac_source_version}" -target "${javac_target_version}" -Xlint:unchecked -bootclasspath "${QT_ANDROID_JAR}") set(CMAKE_JAVA_COMPILE_FLAGS -source "${javac_source_version}" -target "${javac_target_version}" -Xlint:unchecked -bootclasspath "${QT_ANDROID_JAR}")
add_jar(${ARGV}) add_jar(${ARGV})
foreach(f IN LISTS arg_SOURCES)
_qt_internal_expose_source_file_to_ide(${target} "${f}")
endforeach()
endfunction() endfunction()

View File

@ -37,7 +37,6 @@ macro(qt_internal_get_internal_add_module_keywords option_args single_args multi
QMAKE_MODULE_CONFIG QMAKE_MODULE_CONFIG
EXTRA_CMAKE_FILES EXTRA_CMAKE_FILES
EXTRA_CMAKE_INCLUDES EXTRA_CMAKE_INCLUDES
NO_PCH_SOURCES
EXTERNAL_HEADERS EXTERNAL_HEADERS
POLICIES POLICIES
${__default_private_args} ${__default_private_args}
@ -447,6 +446,8 @@ function(qt_internal_add_module target)
# If EXTERNAL_HEADERS_DIR is set we install the specified directory and keep the structure # If EXTERNAL_HEADERS_DIR is set we install the specified directory and keep the structure
# without taking into the account the CMake source tree and syncqt outputs. # without taking into the account the CMake source tree and syncqt outputs.
if(arg_EXTERNAL_HEADERS_DIR) if(arg_EXTERNAL_HEADERS_DIR)
set_property(TARGET ${target}
PROPERTY _qt_external_headers_dir "${arg_EXTERNAL_HEADERS_DIR}")
qt_install(DIRECTORY "${arg_EXTERNAL_HEADERS_DIR}/" qt_install(DIRECTORY "${arg_EXTERNAL_HEADERS_DIR}/"
DESTINATION "${module_install_interface_include_dir}" DESTINATION "${module_install_interface_include_dir}"
) )
@ -1186,10 +1187,13 @@ function(qt_internal_collect_module_headers out_var target)
get_target_property(target_type ${target} TYPE) get_target_property(target_type ${target} TYPE)
if(target_type STREQUAL "INTERFACE_LIBRARY") if(target_type STREQUAL "INTERFACE_LIBRARY")
set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}") set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}")
set(binary_dir "${CMAKE_CURRENT_BINARY_DIR}")
else() else()
get_target_property(source_dir ${target} SOURCE_DIR) get_target_property(source_dir ${target} SOURCE_DIR)
get_target_property(binary_dir ${target} BINARY_DIR)
endif() endif()
get_filename_component(source_dir "${source_dir}" ABSOLUTE) get_filename_component(source_dir "${source_dir}" ABSOLUTE)
get_filename_component(binary_dir "${binary_dir}" ABSOLUTE)
get_target_property(is_3rdparty_library ${target} _qt_module_is_3rdparty_header_library) get_target_property(is_3rdparty_library ${target} _qt_module_is_3rdparty_header_library)
@ -1232,7 +1236,14 @@ function(qt_internal_collect_module_headers out_var target)
"\nCondition:\n ${condition_string}") "\nCondition:\n ${condition_string}")
endif() endif()
if(file_path MATCHES "3rdparty/.+" AND NOT is_3rdparty_library) if(is_outside_module_source_dir)
set(base_dir "${binary_dir}")
else()
set(base_dir "${source_dir}")
endif()
file(RELATIVE_PATH file_path_rel "${base_dir}" "${file_path}")
if(file_path_rel MATCHES "3rdparty/.+" AND NOT is_3rdparty_library)
set(is_3rdparty_header TRUE) set(is_3rdparty_header TRUE)
else() else()
set(is_3rdparty_header FALSE) set(is_3rdparty_header FALSE)

View File

@ -51,6 +51,17 @@ function(qt_internal_generate_pkg_config_file module)
list(TRANSFORM loose_include_dirs REPLACE "${INSTALL_INCLUDEDIR}" "\${includedir}") list(TRANSFORM loose_include_dirs REPLACE "${INSTALL_INCLUDEDIR}" "\${includedir}")
list(TRANSFORM loose_include_dirs REPLACE "${INSTALL_MKSPECSDIR}" "\${mkspecsdir}") list(TRANSFORM loose_include_dirs REPLACE "${INSTALL_MKSPECSDIR}" "\${mkspecsdir}")
# Remove genex wrapping around gc_sections flag because we can't evaluate genexes like
# $<CXX_COMPILER_ID> in file(GENERATE). And given that .pc files don't support dynamic
# evaluation like the $<CXX_COMPILER_ID> genex, distros will be expected to patch the .pc
# files according to which compiler they intend to be used with.
get_property(gc_sections_with_genex GLOBAL PROPERTY _qt_internal_gc_sections_with_genex)
get_property(gc_sections_without_genex GLOBAL PROPERTY _qt_internal_gc_sections_without_genex)
if(loose_link_options AND gc_sections_with_genex AND gc_sections_without_genex)
string(REPLACE "${gc_sections_with_genex}" "${gc_sections_without_genex}"
loose_link_options "${loose_link_options}")
endif()
qt_internal_set_pkg_config_cpp_flags(link_options "${loose_link_options}" "") qt_internal_set_pkg_config_cpp_flags(link_options "${loose_link_options}" "")
qt_internal_set_pkg_config_cpp_flags(compile_defs "${loose_compile_defs}" -D) qt_internal_set_pkg_config_cpp_flags(compile_defs "${loose_compile_defs}" -D)
qt_internal_set_pkg_config_cpp_flags(include_dirs "${loose_include_dirs}" -I) qt_internal_set_pkg_config_cpp_flags(include_dirs "${loose_include_dirs}" -I)

View File

@ -336,6 +336,8 @@ function(qt_internal_add_plugin target)
qt_internal_extend_target("${target}" qt_internal_extend_target("${target}"
${arg_NO_UNITY_BUILD} ${arg_NO_UNITY_BUILD}
SOURCES ${arg_SOURCES} SOURCES ${arg_SOURCES}
NO_PCH_SOURCES
${arg_NO_PCH_SOURCES}
NO_UNITY_BUILD_SOURCES NO_UNITY_BUILD_SOURCES
${arg_NO_UNITY_BUILD_SOURCES} ${arg_NO_UNITY_BUILD_SOURCES}
INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES

View File

@ -26,9 +26,14 @@ function(qt_generate_qmake_libraries_pri_content module_name output_root_dir out
set(lib_incdir "") set(lib_incdir "")
set(lib_libdir "") set(lib_libdir "")
set(lib_libs "") set(lib_libs "")
set(seen_targets "")
while(lib_targets) while(lib_targets)
list(POP_BACK lib_targets lib_target) list(POP_BACK lib_targets lib_target)
if(TARGET ${lib_target}) if(TARGET ${lib_target})
if(${lib_target} IN_LIST seen_targets)
continue()
endif()
list(APPEND seen_targets ${lib_target})
get_target_property(lib_target_type ${lib_target} TYPE) get_target_property(lib_target_type ${lib_target} TYPE)
if(lib_target_type STREQUAL "INTERFACE_LIBRARY") if(lib_target_type STREQUAL "INTERFACE_LIBRARY")
get_target_property(iface_libs ${lib_target} INTERFACE_LINK_LIBRARIES) get_target_property(iface_libs ${lib_target} INTERFACE_LINK_LIBRARIES)

View File

@ -55,7 +55,10 @@ if("${MODULE_ROOT}" STREQUAL "")
set(qtbase_or_top_level_build TRUE) set(qtbase_or_top_level_build TRUE)
else() else()
# If MODULE_ROOT is passed without drive letter, we try to add it to the path. # If MODULE_ROOT is passed without drive letter, we try to add it to the path.
get_filename_component(MODULE_ROOT "." REALPATH BASE_DIR "${MODULE_ROOT}") # The check is necessary; otherwise, `get_filename_component` returns an empty string.
if(NOT MODULE_ROOT STREQUAL ".")
get_filename_component(MODULE_ROOT "." REALPATH BASE_DIR "${MODULE_ROOT}")
endif()
set(qtbase_or_top_level_build FALSE) set(qtbase_or_top_level_build FALSE)
endif() endif()
set(configure_filename "configure.cmake") set(configure_filename "configure.cmake")
@ -136,13 +139,6 @@ while(NOT "${configure_args}" STREQUAL "")
list(POP_FRONT configure_args version) list(POP_FRONT configure_args version)
is_valid_qt_hex_version("${arg}" "${version}") is_valid_qt_hex_version("${arg}" "${version}")
push("-DQT_DISABLE_DEPRECATED_UP_TO=${version}") push("-DQT_DISABLE_DEPRECATED_UP_TO=${version}")
elseif(arg STREQUAL "-unity-build")
push("-DQT_UNITY_BUILD=ON")
# QT_UNITY_BUILD_BATCH_SIZE will be set to 8, CMake's default.
elseif(arg STREQUAL "-unity-build-batch-size")
list(POP_FRONT configure_args unity_build_batch_size)
is_non_empty_valid_arg("${arg}" "${unity_build_batch_size}")
push("-DQT_UNITY_BUILD_BATCH_SIZE=${unity_build_batch_size}")
elseif(arg STREQUAL "--") elseif(arg STREQUAL "--")
# Everything after this argument will be passed to CMake verbatim. # Everything after this argument will be passed to CMake verbatim.
list(APPEND cmake_args "${configure_args}") list(APPEND cmake_args "${configure_args}")
@ -827,6 +823,8 @@ endfunction()
drop_input(commercial) drop_input(commercial)
drop_input(confirm-license) drop_input(confirm-license)
translate_boolean_input(precompile_header BUILD_WITH_PCH) 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(ccache QT_USE_CCACHE)
translate_boolean_input(shared BUILD_SHARED_LIBS) translate_boolean_input(shared BUILD_SHARED_LIBS)
translate_boolean_input(warnings_are_errors WARNINGS_ARE_ERRORS) translate_boolean_input(warnings_are_errors WARNINGS_ARE_ERRORS)

View File

@ -221,7 +221,7 @@ function(_qt_internal_find_ios_development_team_id out_var)
endif() endif()
endfunction() endfunction()
function(_qt_internal_get_ios_bundle_identifier_prefix out_var) function(_qt_internal_get_apple_bundle_identifier_prefix out_var)
get_property(prefix GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix) get_property(prefix GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix)
get_property(prefix_computed GLOBAL PROPERTY get_property(prefix_computed GLOBAL PROPERTY
_qt_internal_ios_bundle_identifier_prefix_computed) _qt_internal_ios_bundle_identifier_prefix_computed)
@ -269,8 +269,8 @@ function(_qt_internal_escape_rfc_1034_identifier value out_var)
set("${out_var}" "${value}" PARENT_SCOPE) set("${out_var}" "${value}" PARENT_SCOPE)
endfunction() endfunction()
function(_qt_internal_get_default_ios_bundle_identifier out_var) function(_qt_internal_get_default_apple_bundle_identifier target out_var)
_qt_internal_get_ios_bundle_identifier_prefix(prefix) _qt_internal_get_apple_bundle_identifier_prefix(prefix)
if(NOT prefix) if(NOT prefix)
set(prefix "com.yourcompany") set(prefix "com.yourcompany")
@ -281,14 +281,16 @@ function(_qt_internal_get_default_ios_bundle_identifier out_var)
string(SHA1 hash "${team_id}") string(SHA1 hash "${team_id}")
string(SUBSTRING "${hash}" 0 8 infix) string(SUBSTRING "${hash}" 0 8 infix)
string(APPEND prefix ".${infix}") string(APPEND prefix ".${infix}")
else() endif()
if(CMAKE_GENERATOR STREQUAL "Xcode")
message(WARNING message(WARNING
"No organization bundle identifier prefix could be retrieved from Xcode " "No organization bundle identifier prefix could be retrieved from Xcode preferences. \
"preferences. This can lead to code signing issues due to a non-unique bundle " This can lead to code signing issues due to a non-unique bundle \
"identifier. Please set up an organization prefix by creating a new project within " identifier. Please set up an organization prefix by creating a new project within \
"Xcode, or consider providing a custom bundle identifier by specifying the " Xcode, or consider providing a custom bundle identifier by specifying the \
"XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER property." MACOSX_BUNDLE_GUI_IDENTIFIER or XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER property."
) )
endif() endif()
endif() endif()
@ -299,7 +301,12 @@ function(_qt_internal_get_default_ios_bundle_identifier out_var)
# that the identifier is invalid. # that the identifier is invalid.
_qt_internal_escape_rfc_1034_identifier("${prefix}" prefix) _qt_internal_escape_rfc_1034_identifier("${prefix}" prefix)
set(identifier "${prefix}.\${PRODUCT_NAME:rfc1034identifier}") if(CMAKE_GENERATOR STREQUAL "Xcode")
set(identifier "${prefix}.$(PRODUCT_NAME:rfc1034identifier)")
else()
set(identifier "${prefix}.${target}")
endif()
set("${out_var}" "${identifier}" PARENT_SCOPE) set("${out_var}" "${identifier}" PARENT_SCOPE)
endfunction() endfunction()
@ -384,56 +391,72 @@ function(_qt_internal_set_xcode_development_team_id target)
endif() endif()
endfunction() endfunction()
function(_qt_internal_set_xcode_bundle_identifier target) function(_qt_internal_set_apple_bundle_identifier target)
# Skip all logic if requested. # Skip all logic if requested.
if(QT_NO_SET_XCODE_BUNDLE_IDENTIFIER) if(QT_NO_SET_XCODE_BUNDLE_IDENTIFIER)
return() return()
endif() endif()
# There are two fields to consider: the CFBundleIdentifier key (CFBI) to be written to # There are two fields to consider: the CFBundleIdentifier key (ie., cmake_bundle_identifier)
# Info.plist # to be written to Info.plist and the PRODUCT_BUNDLE_IDENTIFIER (ie., xcode_bundle_identifier)
# and the PRODUCT_BUNDLE_IDENTIFIER (PBI) property to set in the Xcode project. # property to set in the Xcode project. The `cmake_bundle_identifier` set by
# The following logic enables the best out-of-the-box experience combined with maximum # MACOSX_BUNDLE_GUI_IDENTIFIER applies to both Xcode, and other generators, while
# customization. # `xcode_bundle_identifier` set by XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER is
# 1) If values for both fields are not provided, assign ${PRODUCT_BUNDLE_IDENTIFIER} to CFBI # Xcode specific.
# (which is expanded by xcodebuild at build time and will use the value of PBI) and #
# auto-compute a default PBI from Xcode's ${PRODUCT_NAME}. # If Ninja is the generator, we set the value of `MACOSX_BUNDLE_GUI_IDENTIFIER`
# 2) If CFBI is set and PBI isn't, use given CFBI and keep PBI empty. # and don't touch the `XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER`.
# 3) If PBI is set and CFBI isn't, assign ${PRODUCT_BUNDLE_IDENTIFIER} to CFBI and use # If Xcode is the generator, we set the value of `XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER`,
# the given PBI. # and additionally, to silence a Xcode's warning, we set the `MACOSX_BUNDLE_GUI_IDENTIFIER` to
# 4) If both are set, use both given values. # `${PRODUCT_BUNDLE_IDENTIFIER}` so that Xcode could sort it out.
# TLDR:
# cfbi pbi -> result_cfbi result_pbi
# unset unset computed computed
# set unset given_val unset
# unset set computed given_val
# set set given_val given_val
get_target_property(existing_cfbi "${target}" MACOSX_BUNDLE_GUI_IDENTIFIER) get_target_property(existing_cmake_bundle_identifier "${target}"
if(NOT MACOSX_BUNDLE_GUI_IDENTIFIER AND NOT existing_cfbi) MACOSX_BUNDLE_GUI_IDENTIFIER)
set(is_cfbi_given FALSE) get_target_property(existing_xcode_bundle_identifier "${target}"
else() XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
set(is_cfbi_given TRUE)
set(is_cmake_bundle_identifier_given FALSE)
if(existing_cmake_bundle_identifier)
set(is_cmake_bundle_identifier_given TRUE)
elseif(MACOSX_BUNDLE_GUI_IDENTIFIER)
set(is_cmake_bundle_identifier_given TRUE)
set(existing_cmake_bundle_identifier ${MACOSX_BUNDLE_GUI_IDENTIFIER})
endif() endif()
if(NOT is_cfbi_given) set(is_xcode_bundle_identifier_given FALSE)
if(existing_xcode_bundle_identifier)
set(is_xcode_bundle_identifier_given TRUE)
elseif(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
set(is_xcode_bundle_identifier_given TRUE)
set(existing_xcode_bundle_identifier ${CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER})
endif()
if(is_cmake_bundle_identifier_given
AND is_xcode_bundle_identifier_given
AND NOT existing_cmake_bundle_identifier STREQUAL existing_xcode_bundle_identifier)
message(WARNING
"MACOSX_BUNDLE_GUI_IDENTIFIER and XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "
"are set to different values. You only need to set one of them. ")
endif()
if(NOT is_xcode_bundle_identifier_given
AND NOT is_cmake_bundle_identifier_given)
_qt_internal_get_default_apple_bundle_identifier("${target}" bundle_id)
elseif(is_cmake_bundle_identifier_given)
set(bundle_id ${existing_cmake_bundle_identifier})
elseif(is_xcode_bundle_identifier_given)
set(bundle_id ${existing_xcode_bundle_identifier})
endif()
if(CMAKE_GENERATOR STREQUAL "Xcode")
set_target_properties("${target}" set_target_properties("${target}"
PROPERTIES PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER "\${PRODUCT_BUNDLE_IDENTIFIER}") XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${bundle_id}"
endif() MACOSX_BUNDLE_GUI_IDENTIFIER "$(PRODUCT_BUNDLE_IDENTIFIER)")
get_target_property(existing_pbi "${target}" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
if(NOT CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER AND NOT existing_pbi)
set(is_pbi_given FALSE)
else() else()
set(is_pbi_given TRUE)
endif()
if(NOT is_pbi_given AND NOT is_cfbi_given)
_qt_internal_get_default_ios_bundle_identifier(bundle_id)
set_target_properties("${target}" set_target_properties("${target}"
PROPERTIES PROPERTIES
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${bundle_id}") MACOSX_BUNDLE_GUI_IDENTIFIER "${bundle_id}")
endif() endif()
endfunction() endfunction()
@ -503,7 +526,7 @@ function(_qt_internal_set_xcode_bundle_name target)
if(CMAKE_GENERATOR STREQUAL Xcode) if(CMAKE_GENERATOR STREQUAL Xcode)
set_target_properties("${target}" set_target_properties("${target}"
PROPERTIES PROPERTIES
MACOSX_BUNDLE_BUNDLE_NAME "\${PRODUCT_NAME}") MACOSX_BUNDLE_BUNDLE_NAME "$(PRODUCT_NAME)")
else() else()
set_target_properties("${target}" set_target_properties("${target}"
PROPERTIES PROPERTIES
@ -603,12 +626,13 @@ function(_qt_internal_finalize_apple_app target)
# This affects things like the version number or application name as reported by Qt API. # This affects things like the version number or application name as reported by Qt API.
if(CMAKE_GENERATOR STREQUAL "Xcode") if(CMAKE_GENERATOR STREQUAL "Xcode")
_qt_internal_set_xcode_development_team_id("${target}") _qt_internal_set_xcode_development_team_id("${target}")
_qt_internal_set_xcode_bundle_identifier("${target}")
_qt_internal_set_xcode_code_sign_style("${target}") _qt_internal_set_xcode_code_sign_style("${target}")
_qt_internal_set_xcode_bundle_display_name("${target}") _qt_internal_set_xcode_bundle_display_name("${target}")
_qt_internal_set_xcode_install_path("${target}") _qt_internal_set_xcode_install_path("${target}")
endif() endif()
_qt_internal_set_xcode_bundle_name("${target}") _qt_internal_set_xcode_bundle_name("${target}")
_qt_internal_set_apple_bundle_identifier("${target}")
_qt_internal_set_placeholder_apple_bundle_version("${target}") _qt_internal_set_placeholder_apple_bundle_version("${target}")
endfunction() endfunction()

View File

@ -307,7 +307,17 @@ function(_qt_internal_set_up_static_runtime_library target)
set_property(TARGET ${target} PROPERTY set_property(TARGET ${target} PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
elseif(MINGW) elseif(MINGW)
target_link_options(${target} INTERFACE "LINKER:-Bstatic") get_target_property(target_type ${target} TYPE)
if(target_type STREQUAL "EXECUTABLE")
set(link_option PRIVATE)
else()
set(link_option INTERFACE)
endif()
if(CLANG)
target_link_options(${target} ${link_option} "LINKER:-Bstatic")
else()
target_link_options(${target} ${link_option} "-static")
endif()
endif() endif()
endif() endif()
endfunction() endfunction()

View File

@ -6,7 +6,7 @@
function(qt_internal_get_relative_rpath_base_token out_var) function(qt_internal_get_relative_rpath_base_token out_var)
if(APPLE) if(APPLE)
set(rpath_rel_base "@loader_path") set(rpath_rel_base "@loader_path")
elseif(LINUX OR SOLARIS OR FREEBSD OR HURD) elseif(LINUX OR SOLARIS OR FREEBSD OR HURD OR OPENBSD)
set(rpath_rel_base "$ORIGIN") set(rpath_rel_base "$ORIGIN")
else() else()
set(rpath_rel_base "NO_KNOWN_RPATH_REL_BASE") set(rpath_rel_base "NO_KNOWN_RPATH_REL_BASE")

View File

@ -201,7 +201,11 @@ endfunction()
# Enable separate debug information for the given target # Enable separate debug information for the given target
function(qt_enable_separate_debug_info target installDestination) function(qt_enable_separate_debug_info target installDestination)
set(flags QT_EXECUTABLE) set(flags QT_EXECUTABLE)
set(options) if(APPLE)
set(options DSYM_OUTPUT_DIR)
else()
set(options)
endif()
set(multiopts ADDITIONAL_INSTALL_ARGS) set(multiopts ADDITIONAL_INSTALL_ARGS)
cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN})
@ -248,12 +252,20 @@ function(qt_enable_separate_debug_info target installDestination)
get_target_property(is_framework ${target} FRAMEWORK) get_target_property(is_framework ${target} FRAMEWORK)
if(is_framework) if(is_framework)
qt_internal_get_framework_info(fw ${target}) qt_internal_get_framework_info(fw ${target})
set(debug_info_bundle_dir "$<TARGET_BUNDLE_DIR:${target}>.${debug_info_suffix}")
set(BUNDLE_ID ${fw_name}) set(BUNDLE_ID ${fw_name})
else() else()
set(debug_info_bundle_dir "$<TARGET_FILE:${target}>.${debug_info_suffix}")
set(BUNDLE_ID ${target}) set(BUNDLE_ID ${target})
endif() endif()
if (NOT "x${arg_DSYM_OUTPUT_DIR}" STREQUAL "x")
set(debug_info_bundle_dir "${arg_DSYM_OUTPUT_DIR}/${target}")
elseif(is_framework)
set(debug_info_bundle_dir "$<TARGET_BUNDLE_DIR:${target}>")
else()
set(debug_info_bundle_dir "$<TARGET_FILE:${target}>")
endif()
set(debug_info_bundle_dir "${debug_info_bundle_dir}.${debug_info_suffix}")
set(debug_info_contents_dir "${debug_info_bundle_dir}/Contents") set(debug_info_contents_dir "${debug_info_bundle_dir}/Contents")
set(debug_info_target_dir "${debug_info_contents_dir}/Resources/DWARF") set(debug_info_target_dir "${debug_info_contents_dir}/Resources/DWARF")
configure_file( configure_file(

View File

@ -5,8 +5,8 @@
# Set the QT_IS_BUILDING_QT variable so we can verify whether we are building # Set the QT_IS_BUILDING_QT variable so we can verify whether we are building
# Qt from source # Qt from source
set(QT_BUILDING_QT TRUE CACHE set(QT_BUILDING_QT TRUE CACHE BOOL
TYPE STRING "When this is present and set to true, it signals that we are building Qt from source.") "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 # 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 if(NOT FEATURE_developer_build AND INPUT_developer_build
@ -352,6 +352,8 @@ if(QT_UNITY_BUILD)
set(CMAKE_UNITY_BUILD_BATCH_SIZE "${QT_UNITY_BUILD_BATCH_SIZE}") set(CMAKE_UNITY_BUILD_BATCH_SIZE "${QT_UNITY_BUILD_BATCH_SIZE}")
endif() 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 # We need to clean up QT_FEATURE_*, but only once per configuration cycle
get_property(qt_feature_clean GLOBAL PROPERTY _qt_feature_clean) get_property(qt_feature_clean GLOBAL PROPERTY _qt_feature_clean)
if(NOT qt_feature_clean) if(NOT qt_feature_clean)

View File

@ -139,7 +139,6 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
set(syncqt_args "${common_syncqt_arguments}") set(syncqt_args "${common_syncqt_arguments}")
list(APPEND syncqt_args list(APPEND syncqt_args
${common_syncqt_arguments}
-headers ${module_headers} -headers ${module_headers}
-stagingDir "${syncqt_staging_dir}" -stagingDir "${syncqt_staging_dir}"
-knownModules ${known_modules} -knownModules ${known_modules}
@ -150,6 +149,21 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
set(syncqt_args_rsp "${binary_dir_real}/${target}_syncqt_args") set(syncqt_args_rsp "${binary_dir_real}/${target}_syncqt_args")
qt_configure_file(OUTPUT "${syncqt_args_rsp}" CONTENT "${syncqt_args_string}") qt_configure_file(OUTPUT "${syncqt_args_rsp}" CONTENT "${syncqt_args_string}")
get_target_property(external_headers_dir ${target} _qt_external_headers_dir)
if(external_headers_dir)
if(NOT IS_ABSOLUTE "${external_headers_dir}")
get_filename_component(external_headers_dir "${external_headers_dir}" ABSOLUTE)
endif()
if(EXISTS "${external_headers_dir}")
set(external_headers_dir_copy_cmd
COMMAND
${CMAKE_COMMAND}
-E copy_directory
"${external_headers_dir}"
"${module_build_interface_include_dir}"
)
endif()
endif()
add_custom_command( add_custom_command(
OUTPUT OUTPUT
${syncqt_outputs} ${syncqt_outputs}
@ -157,6 +171,7 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
${QT_CMAKE_EXPORT_NAMESPACE}::syncqt ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt
"@${syncqt_args_rsp}" "@${syncqt_args_rsp}"
${build_time_syncqt_arguments} ${build_time_syncqt_arguments}
${external_headers_dir_copy_cmd}
COMMAND COMMAND
${CMAKE_COMMAND} -E touch "${syncqt_timestamp}" ${CMAKE_COMMAND} -E touch "${syncqt_timestamp}"
DEPENDS DEPENDS
@ -167,12 +182,22 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
"Running syncqt.cpp for module: ${module}" "Running syncqt.cpp for module: ${module}"
VERBATIM VERBATIM
) )
set(add_sync_headers_to_all "")
if(is_interface_lib)
set(add_sync_headers_to_all ALL)
endif()
add_custom_target(${target}_sync_headers add_custom_target(${target}_sync_headers
${add_sync_headers_to_all}
DEPENDS DEPENDS
${syncqt_outputs} ${syncqt_outputs}
) )
add_dependencies(sync_headers ${target}_sync_headers) add_dependencies(sync_headers ${target}_sync_headers)
if(is_3rd_party_library)
add_dependencies(thirdparty_sync_headers ${target}_sync_headers)
endif()
# This target is required when building docs, to make all header files and their aliases # This target is required when building docs, to make all header files and their aliases
# available for qdoc. # available for qdoc.
# ${target}_sync_headers is added as dependency to make sure that # ${target}_sync_headers is added as dependency to make sure that
@ -185,6 +210,7 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
COMMAND COMMAND
${QT_CMAKE_EXPORT_NAMESPACE}::syncqt ${QT_CMAKE_EXPORT_NAMESPACE}::syncqt
"@${syncqt_all_args_rsp}" "@${syncqt_all_args_rsp}"
${external_headers_dir_copy_cmd}
DEPENDS DEPENDS
${module_headers} ${module_headers}
${syncqt_all_args_rsp} ${syncqt_all_args_rsp}

View File

@ -14,6 +14,8 @@
# module, these files will raise a warning at configure time if the condition is not met. # module, these files will raise a warning at configure time if the condition is not met.
# COMPILE_FLAGS # COMPILE_FLAGS
# Custom compilation flags. # Custom compilation flags.
# EXTRA_LINKER_SCRIPT_CONTENT
# Extra content that should be appended to a target linker script. Applicable for ld only.
# NO_PCH_SOURCES # NO_PCH_SOURCES
# Skip the specified source files by PRECOMPILE_HEADERS feature. # Skip the specified source files by PRECOMPILE_HEADERS feature.
function(qt_internal_extend_target target) function(qt_internal_extend_target target)
@ -36,6 +38,7 @@ function(qt_internal_extend_target target)
) )
set(single_args set(single_args
PRECOMPILED_HEADER PRECOMPILED_HEADER
EXTRA_LINKER_SCRIPT_CONTENT
) )
set(multi_args set(multi_args
${__default_public_args} ${__default_public_args}
@ -44,7 +47,6 @@ function(qt_internal_extend_target target)
CONDITION CONDITION
CONDITION_INDEPENDENT_SOURCES CONDITION_INDEPENDENT_SOURCES
COMPILE_FLAGS COMPILE_FLAGS
NO_PCH_SOURCES
) )
cmake_parse_arguments(PARSE_ARGV 1 arg cmake_parse_arguments(PARSE_ARGV 1 arg
@ -237,6 +239,10 @@ function(qt_internal_extend_target target)
${sources_property} "${arg_CONDITION_INDEPENDENT_SOURCES}") ${sources_property} "${arg_CONDITION_INDEPENDENT_SOURCES}")
endif() endif()
if(arg_EXTRA_LINKER_SCRIPT_CONTENT)
set_target_properties(${target} PROPERTIES
_qt_extra_linker_script_content "${arg_EXTRA_LINKER_SCRIPT_CONTENT}")
endif()
endfunction() endfunction()
function(qt_is_imported_target target out_var) function(qt_is_imported_target target out_var)
@ -1001,6 +1007,15 @@ endfunction()
# Needed to allow selectively applying certain flags via PlatformXInternal targets. # Needed to allow selectively applying certain flags via PlatformXInternal targets.
function(qt_internal_mark_as_internal_library target) function(qt_internal_mark_as_internal_library target)
set_target_properties(${target} PROPERTIES _qt_is_internal_library TRUE) set_target_properties(${target} PROPERTIES _qt_is_internal_library TRUE)
qt_internal_mark_as_internal_target(${target})
endfunction()
# Marks a target with a property that it was built using the internal Qt API (qt_internal_*) as
# opposed to it being a user project library or executable(qt_add_*, etc).
#
# Needed to allow selectively applying certain flags via PlatformXInternal targets.
function(qt_internal_mark_as_internal_target target)
set_target_properties(${target} PROPERTIES _qt_is_internal_target TRUE)
endfunction() endfunction()
function(qt_internal_link_internal_platform_for_object_library target) function(qt_internal_link_internal_platform_for_object_library target)

View File

@ -214,6 +214,7 @@ function(qt_internal_get_test_arg_definitions optional_args single_value_args mu
MANUAL MANUAL
NO_BATCH NO_BATCH
NO_INSTALL NO_INSTALL
BUNDLE_ANDROID_OPENSSL_LIBS
PARENT_SCOPE PARENT_SCOPE
) )
set(${single_value_args} set(${single_value_args}
@ -526,6 +527,21 @@ function(qt_internal_add_test name)
endif() endif()
if (ANDROID) if (ANDROID)
if(arg_BUNDLE_ANDROID_OPENSSL_LIBS)
if(NOT OPENSSL_ROOT_DIR)
message(WARNING "The argument BUNDLE_ANDROID_OPENSSL_LIBS is set "
"but OPENSSL_ROOT_DIR parameter is not set.")
else()
if(EXISTS "${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libcrypto_3.so")
set_property(TARGET ${name} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS
"${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libcrypto_3.so"
"${OPENSSL_ROOT_DIR}/${CMAKE_ANDROID_ARCH_ABI}/libssl_3.so")
else()
message(STATUS "Test should bundle OpenSSL libraries but they are not found."
" This is fine if OpenSSL was built statically.")
endif()
endif()
endif()
qt_internal_android_test_arguments("${name}" test_executable extra_test_args) qt_internal_android_test_arguments("${name}" test_executable extra_test_args)
set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}") set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}")
elseif(QNX) elseif(QNX)

View File

@ -15,6 +15,13 @@
# INSTALL_VERSIONED_LINK # INSTALL_VERSIONED_LINK
# Prefix build only. On installation, create a versioned hard-link of the installed file. # Prefix build only. On installation, create a versioned hard-link of the installed file.
# E.g. create a link of "bin/qmake6" to "bin/qmake". # E.g. create a link of "bin/qmake6" to "bin/qmake".
# TRY_RUN
# On Windows, it creates a helper batch script that tests whether the tool can be executed
# successfully or not. If not, build halts and an error will be show, with tips on what
# might be cause, and how to fix it. TRY_RUN is disabled when cross-compiling.
# TRY_RUN_FLAGS
# Command line flags that are going to be passed to the tool for testing its correctness.
# If no flags were given, we default to `-v`.
# #
# One-value Arguments: # One-value Arguments:
# EXTRA_CMAKE_FILES # EXTRA_CMAKE_FILES
@ -42,11 +49,13 @@ function(qt_internal_add_tool target_name)
USER_FACING USER_FACING
INSTALL_VERSIONED_LINK INSTALL_VERSIONED_LINK
EXCEPTIONS EXCEPTIONS
NO_UNITY_BUILD) NO_UNITY_BUILD
TRY_RUN)
set(one_value_keywords set(one_value_keywords
TOOLS_TARGET TOOLS_TARGET
INSTALL_DIR INSTALL_DIR
CORE_LIBRARY CORE_LIBRARY
TRY_RUN_FLAGS
${__default_target_info_args}) ${__default_target_info_args})
set(multi_value_keywords set(multi_value_keywords
EXTRA_CMAKE_FILES EXTRA_CMAKE_FILES
@ -105,6 +114,7 @@ function(qt_internal_add_tool target_name)
NO_INSTALL NO_INSTALL
${arg_NO_UNITY_BUILD} ${arg_NO_UNITY_BUILD}
SOURCES ${arg_SOURCES} SOURCES ${arg_SOURCES}
NO_PCH_SOURCES ${arg_NO_PCH_SOURCES}
NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES} NO_UNITY_BUILD_SOURCES ${arg_NO_UNITY_BUILD_SOURCES}
INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES
${arg_INCLUDE_DIRECTORIES} ${arg_INCLUDE_DIRECTORIES}
@ -224,10 +234,62 @@ function(qt_internal_add_tool target_name)
qt_internal_apply_staging_prefix_build_rpath_workaround() qt_internal_apply_staging_prefix_build_rpath_workaround()
endif() endif()
if(arg_TRY_RUN AND WIN32 AND NOT CMAKE_CROSSCOMPILING)
if(NOT arg_TRY_RUN_FLAGS)
set(arg_TRY_RUN_FLAGS "-v")
endif()
_qt_internal_add_try_run_post_build("${target_name}" "${arg_TRY_RUN_FLAGS}")
endif()
qt_enable_separate_debug_info(${target_name} "${install_dir}" QT_EXECUTABLE) qt_enable_separate_debug_info(${target_name} "${install_dir}" QT_EXECUTABLE)
qt_internal_install_pdb_files(${target_name} "${install_dir}") qt_internal_install_pdb_files(${target_name} "${install_dir}")
endfunction() endfunction()
function(_qt_internal_add_try_run_post_build target try_run_flags)
qt_internal_get_upper_case_main_cmake_configuration(main_cmake_configuration)
get_target_property(target_out_dir ${target}
RUNTIME_OUTPUT_DIRECTORY_${main_cmake_configuration})
get_target_property(target_bin_dir ${target}
BINARY_DIR)
set(try_run_scripts_path "${target_bin_dir}/${target}_try_run.bat")
# The only reason -h is passed is because some of the tools, e.g., moc
# wait for an input without any arguments.
qt_configure_file(OUTPUT "${try_run_scripts_path}"
CONTENT "@echo off
${target_out_dir}/${target}.exe ${try_run_flags} > nul 2>&1
if \"%errorlevel%\" == \"-1073741515\" (
echo
echo '${target}' is built successfully, but some of the libraries
echo necessary for running it are missing. If you are building Qt with
echo 3rdparty libraries, make sure that you add their directory to the
echo PATH environment variable.
echo
exit /b %errorlevel%
)
echo. > ${target_bin_dir}/${target}_try_run_passed"
)
add_custom_command(
OUTPUT
${target_bin_dir}/${target}_try_run_passed
DEPENDS
${target}
COMMAND
${CMAKE_COMMAND} -E env QT_COMMAND_LINE_PARSER_NO_GUI_MESSAGE_BOXES=1
${try_run_scripts_path}
COMMENT
"Testing ${target} by trying to run it."
VERBATIM
)
add_custom_target(${target}_try_run ALL
DEPENDS ${target_bin_dir}/${target}_try_run_passed)
endfunction()
function(qt_export_tools module_name) function(qt_export_tools module_name)
# Bail out when not building tools. # Bail out when not building tools.
if(NOT QT_WILL_BUILD_TOOLS) if(NOT QT_WILL_BUILD_TOOLS)
@ -287,7 +349,7 @@ function(qt_export_tools module_name)
string(REGEX REPLACE "_native$" "" tool_name ${tool_name}) string(REGEX REPLACE "_native$" "" tool_name ${tool_name})
endif() endif()
set(extra_cmake_statements "${extra_cmake_statements} set(extra_cmake_statements "${extra_cmake_statements}
if (NOT QT_NO_CREATE_TARGETS) if(NOT QT_NO_CREATE_TARGETS AND ${INSTALL_CMAKE_NAMESPACE}${target}_FOUND)
__qt_internal_promote_target_to_global(${INSTALL_CMAKE_NAMESPACE}::${tool_name}) __qt_internal_promote_target_to_global(${INSTALL_CMAKE_NAMESPACE}::${tool_name})
endif() endif()
") ")

View File

@ -31,6 +31,14 @@ set(__qt_chainload_toolchain_file \"\${__qt_initially_configured_toolchain_file}
list(APPEND init_platform "set(CMAKE_SYSTEM_PROCESSOR arm64 CACHE STRING \"\")") list(APPEND init_platform "set(CMAKE_SYSTEM_PROCESSOR arm64 CACHE STRING \"\")")
endif() endif()
if(QT_QMAKE_TARGET_MKSPEC)
list(APPEND init_platform
"if(NOT QT_QMAKE_TARGET_MKSPEC)"
" set(QT_QMAKE_TARGET_MKSPEC ${QT_QMAKE_TARGET_MKSPEC} CACHE STRING \"\")"
"endif()"
)
endif()
if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "linux-g++-32" AND NOT QT_NO_AUTO_DETECT_LINUX_X86) if("${QT_QMAKE_TARGET_MKSPEC}" STREQUAL "linux-g++-32" AND NOT QT_NO_AUTO_DETECT_LINUX_X86)
set(__qt_toolchain_common_flags_init "-m32") set(__qt_toolchain_common_flags_init "-m32")
@ -121,14 +129,14 @@ set(__qt_chainload_toolchain_file \"\${__qt_initially_configured_toolchain_file}
endif() endif()
if(__qt_embed_toolchain_compilers) if(__qt_embed_toolchain_compilers)
list(APPEND init_platform " list(APPEND init_platform "
set(__qt_initial_c_compiler \"${CMAKE_C_COMPILER}\") set(__qt_initial_c_compiler \"${CMAKE_C_COMPILER}\")
set(__qt_initial_cxx_compiler \"${CMAKE_CXX_COMPILER}\") set(__qt_initial_cxx_compiler \"${CMAKE_CXX_COMPILER}\")
if(NOT DEFINED CMAKE_C_COMPILER AND EXISTS \"\${__qt_initial_c_compiler}\") if(NOT DEFINED CMAKE_C_COMPILER AND EXISTS \"\${__qt_initial_c_compiler}\")
set(CMAKE_C_COMPILER \"\${__qt_initial_c_compiler}\" CACHE STRING \"\") set(CMAKE_C_COMPILER \"\${__qt_initial_c_compiler}\" CACHE STRING \"\")
endif() endif()
if(NOT DEFINED CMAKE_CXX_COMPILER AND EXISTS \"\${__qt_initial_cxx_compiler}\") if(NOT DEFINED CMAKE_CXX_COMPILER AND EXISTS \"\${__qt_initial_cxx_compiler}\")
set(CMAKE_CXX_COMPILER \"\${__qt_initial_cxx_compiler}\" CACHE STRING \"\") set(CMAKE_CXX_COMPILER \"\${__qt_initial_cxx_compiler}\" CACHE STRING \"\")
endif()") endif()")
endif() endif()
unset(init_additional_used_variables) unset(init_additional_used_variables)

View File

@ -6,17 +6,74 @@
# This is used for writing the config.opt file. # This is used for writing the config.opt file.
# #
# This script takes the following arguments: # This script takes the following arguments:
# IN_FILE: The input file. The whole command line as one string. # IN_FILE: The input file. The whole command line as one string, or one argument per line.
# REDO_FILE: A file containing extra commands to be joined with IN_FILE.
# OUT_FILE: The output file. One argument per line. # OUT_FILE: The output file. One argument per line.
# SKIP_ARGS: Number of arguments to skip from the front of the arguments list. # SKIP_ARGS: Number of arguments to skip from the front of the arguments list.
# IGNORE_ARGS: List of arguments to be ignored, i.e. that are not written. # IGNORE_ARGS: List of arguments to be ignored, i.e. that are not written.
#
# If the REDO_FILE is given, its parameters will be merged with IN_FILE parameters
# and be written into the OUT_FILE.
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
# Read arguments from IN_FILE and separate them. # Read arguments from IN_FILE and separate them.
file(READ "${IN_FILE}" raw_args) file(READ "${IN_FILE}" raw_args)
# To catch cases where the path ends with an `\`, e.g., `-prefix "C:\Path\"`
string(REPLACE "\\\"" "\"" raw_args "${raw_args}")
string(REPLACE ";" "[[;]]" raw_args "${raw_args}")
separate_arguments(args NATIVE_COMMAND "${raw_args}") separate_arguments(args NATIVE_COMMAND "${raw_args}")
string(REPLACE "\;" ";" args "${args}")
string(REPLACE "[[;]]" "\;" args "${args}")
if(DEFINED REDO_FILE)
file(READ "${REDO_FILE}" raw_redo_args)
separate_arguments(redo_args NATIVE_COMMAND "${raw_redo_args}")
if(args)
list(FIND args "--" args_ddash_loc)
list(FIND redo_args "--" redo_ddash_loc)
if("${redo_ddash_loc}" STREQUAL "-1")
if("${args_ddash_loc}" STREQUAL "-1")
list(LENGTH args args_ddash_loc)
endif()
# Avoid adding an empty line for an empty -redo
if(NOT "${redo_args}" STREQUAL "")
list(INSERT args ${args_ddash_loc} "${redo_args}")
endif()
else()
# Handling redo's configure options
list(SUBLIST redo_args 0 ${redo_ddash_loc} redo_config_args)
if(redo_config_args)
if("${args_ddash_loc}" STREQUAL "-1")
list(APPEND args "${redo_config_args}")
else()
list(INSERT args ${args_ddash_loc} "${redo_config_args}")
endif()
endif()
# Handling redo's CMake options
list(LENGTH redo_args redo_args_len)
math(EXPR redo_ddash_loc "${redo_ddash_loc} + 1")
# Catch an unlikely case of -redo being called with an empty --, ie., `-redo --`
if(NOT ${redo_ddash_loc} STREQUAL ${redo_args_len})
list(SUBLIST redo_args ${redo_ddash_loc} -1 redo_cmake_args)
endif()
if(DEFINED redo_cmake_args)
if("${args_ddash_loc}" STREQUAL "-1")
list(APPEND args "--")
endif()
list(APPEND args "${redo_cmake_args}")
endif()
endif()
else()
list(APPEND args "${redo_args}")
endif()
endif()
# Skip arguments if requested # Skip arguments if requested
if(DEFINED SKIP_ARGS) if(DEFINED SKIP_ARGS)
foreach(i RANGE 1 ${SKIP_ARGS}) foreach(i RANGE 1 ${SKIP_ARGS})

View File

@ -17,22 +17,22 @@
#endif #endif
#if !defined(QT_BUILD_@module_define_infix@_LIB) && !defined(QT_STATIC) #if !defined(QT_BUILD_@module_define_infix@_LIB) && !defined(QT_STATIC)
/* outside library inline decl + defi */ /* outside library -> inline decl + defi */
/* static builds treat everything as part of the library, so they never inline */ /* static builds treat everything as part of the library, so they never inline */
# define QT_@module_define_infix@_INLINE_SINCE(major, minor) inline # define QT_@module_define_infix@_INLINE_SINCE(major, minor) inline
# define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) 1 # define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) 1
#elif defined(QT_@module_define_infix@_BUILD_REMOVED_API) #elif defined(QT_@module_define_infix@_BUILD_REMOVED_API)
/* inside library, inside removed_api.cpp: /* inside library, inside removed_api.cpp:
* keep deprecated API non-inline decl; * keep deprecated API -> non-inline decl;
* remove deprecated API inline decl; * remove deprecated API -> inline decl;
* definition is always available */ * definition is always available */
# define QT_@module_define_infix@_INLINE_SINCE(major, minor) \ # define QT_@module_define_infix@_INLINE_SINCE(major, minor) \
QT_IF_DEPRECATED_SINCE(major, minor, inline, /* not inline */) QT_IF_DEPRECATED_SINCE(major, minor, inline, /* not inline */)
# define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) 1 # define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) 1
#else #else
/* inside library, outside removed_api.cpp: /* inside library, outside removed_api.cpp:
* keep deprecated API non-inline decl, no defi; * keep deprecated API -> non-inline decl, no defi;
* remove deprecated API inline decl, defi */ * remove deprecated API -> inline decl, defi */
# define QT_@module_define_infix@_INLINE_SINCE(major, minor) \ # define QT_@module_define_infix@_INLINE_SINCE(major, minor) \
QT_IF_DEPRECATED_SINCE(major, minor, inline, /* not inline */) QT_IF_DEPRECATED_SINCE(major, minor, inline, /* not inline */)
# define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) \ # define QT_@module_define_infix@_INLINE_IMPL_SINCE(major, minor) \

View File

@ -13,6 +13,11 @@ instructions:
variableValue: "{{.Env.COMMON_TEST_CMAKE_ARGS}}" variableValue: "{{.Env.COMMON_TEST_CMAKE_ARGS}}"
- !include "{{qt/qtbase}}/cmake_build_and_upload_test_artifacts.yaml" - !include "{{qt/qtbase}}/cmake_build_and_upload_test_artifacts.yaml"
disable_if: disable_if:
condition: property condition: or
property: features conditions:
contains_value: DisableTests - condition: property
property: features
contains_value: DisableTests
- condition: property
property: features
contains_value: DoNotBuildTests

View File

@ -34,6 +34,11 @@ instructions:
variableValue: "{{.Env.COMMON_TARGET_TEST_CMAKE_ARGS}}" variableValue: "{{.Env.COMMON_TARGET_TEST_CMAKE_ARGS}}"
- !include "{{qt/qtbase}}/cmake_build_and_upload_test_artifacts.yaml" - !include "{{qt/qtbase}}/cmake_build_and_upload_test_artifacts.yaml"
disable_if: disable_if:
condition: property condition: or
property: features conditions:
contains_value: DisableTests - condition: property
property: features
contains_value: DisableTests
- condition: property
property: features
contains_value: DoNotBuildTests

View File

@ -61,9 +61,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: COIN_CMAKE_INSTALL_LIBEXEC_DIR variableName: COIN_CMAKE_INSTALL_LIBEXEC_DIR
variableValue: "{{.InstallDir}}{{.Env.CI_PATH_SEP}}host{{.Env.CI_PATH_SEP}}bin" variableValue: "{{.InstallDir}}{{.Env.CI_PATH_SEP}}host{{.Env.CI_PATH_SEP}}bin"
@ -73,9 +78,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- !include "{{qt/qtbase}}/call_host_install.yaml" - !include "{{qt/qtbase}}/call_host_install.yaml"
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: DESTDIR variableName: DESTDIR
@ -123,9 +133,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: COIN_CMAKE_INSTALL_LIBEXEC_DIR variableName: COIN_CMAKE_INSTALL_LIBEXEC_DIR
variableValue: "{{.InstallDir}}{{.Env.CI_PATH_SEP}}target{{.Env.CI_PATH_SEP}}bin" variableValue: "{{.InstallDir}}{{.Env.CI_PATH_SEP}}target{{.Env.CI_PATH_SEP}}bin"
@ -135,9 +150,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- !include "{{qt/qtbase}}/call_target_install.yaml" - !include "{{qt/qtbase}}/call_target_install.yaml"
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: DESTDIR variableName: DESTDIR

View File

@ -47,9 +47,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: COIN_CMAKE_BUILD_LIBEXEC_DIR variableName: COIN_CMAKE_BUILD_LIBEXEC_DIR
variableValue: "{{.BuildDir}}{{.Env.CI_PATH_SEP}}bin" variableValue: "{{.BuildDir}}{{.Env.CI_PATH_SEP}}bin"
@ -59,9 +64,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- !include "{{qt/qtbase}}/call_host_install.yaml" - !include "{{qt/qtbase}}/call_host_install.yaml"
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: DESTDIR variableName: DESTDIR
@ -124,9 +134,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: COIN_CMAKE_BUILD_LIBEXEC_DIR variableName: COIN_CMAKE_BUILD_LIBEXEC_DIR
variableValue: "{{.Env.COIN_CMAKE_BUILD_DIR}}{{.Env.CI_PATH_SEP}}bin" variableValue: "{{.Env.COIN_CMAKE_BUILD_DIR}}{{.Env.CI_PATH_SEP}}bin"
@ -136,9 +151,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- !include "{{qt/qtbase}}/call_target_install.yaml" - !include "{{qt/qtbase}}/call_target_install.yaml"
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: DESTDIR variableName: DESTDIR

View File

@ -41,9 +41,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: COIN_CMAKE_BUILD_LIBEXEC_DIR variableName: COIN_CMAKE_BUILD_LIBEXEC_DIR
variableValue: "{{.Env.COIN_CMAKE_BUILD_DIR}}{{.Env.CI_PATH_SEP}}bin" variableValue: "{{.Env.COIN_CMAKE_BUILD_DIR}}{{.Env.CI_PATH_SEP}}bin"
@ -53,9 +58,14 @@ instructions:
- condition: property - condition: property
property: host.os property: host.os
equals_value: Windows equals_value: Windows
- condition: property - condition: and
property: target.osVersion conditions:
not_in_values: [WebAssembly, Android_ANY] - condition: property
property: target.os
not_equals_value: QNX
- condition: property
property: target.osVersion
not_in_values: [WebAssembly, Android_ANY]
- !include "{{qt/qtbase}}/call_host_install.yaml" - !include "{{qt/qtbase}}/call_host_install.yaml"
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: DESTDIR variableName: DESTDIR

View File

@ -305,6 +305,14 @@ instructions:
condition: property condition: property
property: target.osVersion property: target.osVersion
in_values: [QEMU] in_values: [QEMU]
# This fixes an issue where binfmts is sometimes disabled on the test VMs
- type: ExecuteCommand
command: sudo update-binfmts --enable
userMessageOnFailure: "Failed to enable binfmts"
enable_if:
condition: property
property: target.osVersion
equals_value: QEMU
# Windows on Arm, cross-compilation with MSVC # Windows on Arm, cross-compilation with MSVC
- type: Group - type: Group

View File

@ -1,300 +0,0 @@
# Copyright (C) 2021 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
from conans import ConanFile, tools
from conans.errors import ConanInvalidConfiguration
import os
import re
import shutil
from functools import lru_cache
from pathlib import Path
from typing import Dict, Union
class QtConanError(Exception):
pass
def add_cmake_prefix_path(conan_file: ConanFile, dep: str) -> None:
if dep not in conan_file.deps_cpp_info.deps:
raise QtConanError("Unable to find dependency: {0}".format(dep))
dep_cpp_info = conan_file.deps_cpp_info[dep]
cmake_args_str = str(conan_file.options.get_safe("cmake_args_qtbase", default=""))
formatted_cmake_args_str = conan_file._shared.append_cmake_arg(
cmake_args_str, "CMAKE_PREFIX_PATH", dep_cpp_info.rootpath
)
print("Adjusted cmake args for qtbase build: {0}".format(formatted_cmake_args_str))
setattr(conan_file.options, "cmake_args_qtbase", formatted_cmake_args_str)
def _build_qtbase(conan_file: ConanFile):
# we call the Qt's configure(.bat) directly
script = Path("configure.bat") if tools.os_info.is_windows else Path("configure")
configure = Path(conan_file.build_folder).joinpath(script).resolve(strict=True)
if conan_file.options.get_safe("icu", default=False):
# we need to tell Qt build system where to find the ICU
add_cmake_prefix_path(conan_file, dep="icu")
# convert the Conan options to Qt configure(.bat) arguments
parser = conan_file._qt_option_parser
qt_configure_options = parser.convert_conan_options_to_qt_options(conan_file.options)
cmd = " ".join(
[str(configure), " ".join(qt_configure_options), "-prefix", conan_file.package_folder]
)
cmake_args = parser.get_cmake_args_for_configure(conan_file.options)
if cmake_args:
cmd += " -- {0}".format(" ".join(cmake_args))
conan_file.output.info("Calling: {0}".format(cmd))
conan_file.run(cmd)
cmd = " ".join(["cmake", "--build", ".", "--parallel"])
conan_file.output.info("Calling: {0}".format(cmd))
conan_file.run(cmd)
@lru_cache(maxsize=8)
def _parse_qt_version_by_key(key: str) -> str:
with open(Path(__file__).parent.resolve() / ".cmake.conf") as f:
m = re.search(fr'{key} .*"(.*)"', f.read())
return m.group(1) if m else ""
def _get_qt_minor_version() -> str:
return ".".join(_parse_qt_version_by_key("QT_REPO_MODULE_VERSION").split(".")[:2])
class QtBase(ConanFile):
name = "qtbase"
license = "LGPL-3.0, GPL-2.0+, Commercial Qt License Agreement"
author = "The Qt Company <https://www.qt.io/contact-us>"
url = "https://code.qt.io/cgit/qt/qtbase.git"
description = "Qt6 core framework libraries and tools."
topics = ("qt", "qt6")
settings = "os", "compiler", "arch", "build_type"
_qt_option_parser = None
options = None
default_options = None
exports_sources = "*", "!conan*.*"
# use commit ID as the RREV (recipe revision)
revision_mode = "scm"
python_requires = "qt-conan-common/{0}@qt/everywhere".format(_get_qt_minor_version())
short_paths = True
_shared = None
def init(self):
self._shared = self.python_requires["qt-conan-common"].module
self._qt_option_parser = self._shared.QtOptionParser(Path(__file__).parent.resolve())
self.options = self._qt_option_parser.get_qt_conan_options()
self.default_options = self._qt_option_parser.get_default_qt_conan_options()
def set_version(self):
# Executed during "conan export" i.e. in source tree
_ver = _parse_qt_version_by_key("QT_REPO_MODULE_VERSION")
_prerelease = _parse_qt_version_by_key("QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT")
self.version = _ver + "-" + _prerelease if _prerelease else _ver
def export(self):
self.copy("configure_options.json")
self.copy("configure_features.txt")
self.copy(".cmake.conf")
conf = self._shared.qt_sw_versions_config_folder() / self._shared.qt_sw_versions_config_name()
if not conf.exists():
# If using "conan export" outside Qt CI provisioned machines
print("Warning: Couldn't find '{0}'. 3rd party dependencies skipped.".format(conf))
else:
shutil.copy2(conf, self.export_folder)
def requirements(self):
# list of tuples, (package_name, fallback version)
optional_requirements = [("icu", "56.1")]
for req_name, req_ver_fallback in optional_requirements:
if self.options.get_safe(req_name, default=False) == True:
# Note! If this conan package is being "conan export"ed outside Qt CI and the
# sw versions .ini file is not present then it will fall-back to default version
ver = self._shared.parse_qt_sw_pkg_dependency(
config_folder=Path(self.recipe_folder),
package_name=req_name,
target_os=str(self.settings.os),
)
if not ver:
print(
"Warning: Using fallback version '{0}' for: {1}".format(
req_name, req_ver_fallback
)
)
ver = req_ver_fallback
requirement = "{0}/{1}@qt/everywhere".format(req_name, ver)
print("Setting 3rd party package requirement: {0}".format(requirement))
self.requires(requirement)
def _resolve_qt_host_path(self) -> Union[str, None]:
"""
Attempt to resolve QT_HOST_PATH.
When cross-building the user needs to pass 'qt_host_path' which is transformed to
QT_HOST_PATH later on. Resolve the exact path if possible.
Returns:
string: The resolved QT_HOST_PATH or None if unable to determine it.
"""
_host_p = self.options.get_safe("qt_host_path")
if _host_p:
return str(Path(os.path.expandvars(str(_host_p))).expanduser().resolve(strict=True))
else:
print("Warning: 'qt_host_path' option was not given in cross-build context")
return None
def configure(self):
if self.settings.compiler == "gcc" and tools.Version(self.settings.compiler.version) < "8":
raise ConanInvalidConfiguration("Qt6 does not support GCC before 8")
def _set_default_if_not_set(option_name: str, option_value: bool) -> None:
# let it fail if option name does not exist, it means the recipe is not up to date
if self.options.get_safe(option_name) in [None, "None"]:
setattr(self.options, option_name, option_value)
def _set_build_type(build_type: str) -> None:
if self.settings.build_type != build_type:
msg = (
"The build_type '{0}' changed to '{1}'. Please check your Settings and "
"Options. The used Qt options enforce '{2}' as a build_type. ".format(
self.settings.build_type, build_type, build_type
)
)
raise QtConanError(msg)
self.settings.build_type = build_type
def _check_mutually_exclusive_options(options: Dict[str, bool]) -> None:
if list(options.values()).count(True) > 1:
raise QtConanError(
"These Qt options are mutually exclusive: {0}"
". Choose only one of them and try again.".format(list(options.keys()))
)
default_options = ["shared", "gui", "widgets", "accessibility", "system_proxies", "ico"]
if self.settings.os == "Macos":
default_options.append("framework")
for item in default_options:
_set_default_if_not_set(item, True)
release = self.options.get_safe("release", default=False)
debug = self.options.get_safe("debug", default=False)
debug_and_release = self.options.get_safe("debug_and_release", default=False)
force_debug_info = self.options.get_safe("force_debug_info", default=False)
optimize_size = self.options.get_safe("optimize_size", default=False)
# these options are mutually exclusive options so do a sanity check
_check_mutually_exclusive_options(
{"release": release, "debug": debug, "debug_and_release": debug_and_release}
)
# Prioritize Qt's configure options over Settings.build_type
if debug_and_release == True:
# Qt build system will build both debug and release binaries
if force_debug_info == True:
_set_build_type("RelWithDebInfo")
else:
_set_build_type("Release")
elif release == True:
_check_mutually_exclusive_options(
{"force_debug_info": force_debug_info, "optimize_size": optimize_size}
)
if force_debug_info == True:
_set_build_type("RelWithDebInfo")
elif optimize_size == True:
_set_build_type("MinSizeRel")
else:
_set_build_type("Release")
elif debug == True:
_set_build_type("Debug")
else:
# As a fallback set the build type for Qt configure based on the 'build_type'
# defined in the conan build settings
build_type = self.settings.get_safe("build_type")
if build_type in [None, "None"]:
# set default that mirror the configure(.bat) default values
self.options.release = True
self.settings.build_type = "Release"
elif build_type == "Release":
self.options.release = True
elif build_type == "Debug":
self.options.debug = True
elif build_type == "RelWithDebInfo":
self.options.release = True
self.options.force_debug_info = True
elif build_type == "MinSizeRel":
self.options.release = True
self.options.optimize_size = True
else:
raise QtConanError("Unknown build_type: {0}".format(self.settings.build_type))
if self.settings.os == "Android":
if self.options.get_safe("android_sdk_version") == None:
cmake_args_qtbase = str(self.options.get_safe("cmake_args_qtbase"))
sdk_ver = self._shared.parse_android_sdk_version(cmake_args_qtbase)
if sdk_ver:
print("'android_sdk_version' not given. Deduced version: {0}".format(sdk_ver))
self.options.android_sdk_version = sdk_ver
else:
# TODO, for now we have no clean means to query the Android SDK version from
# Qt build system so we just exclude the "android_sdk" from the package_id.
print("Can't deduce 'android_sdk_version'. Excluding it from 'package_id'")
delattr(self.info.options, "android_sdk_version")
if self.options.get_safe("android_ndk_version") == None:
ndk_ver = str(self.options.get_safe("android_ndk"))
ndk_ver = self._shared.parse_android_ndk_version(Path(ndk_ver, strict=True))
print("'android_ndk_version' not given. Deduced version: {0}".format(ndk_ver))
self.options.android_ndk_version = ndk_ver
def build(self):
self._shared.build_env_wrap(self, _build_qtbase)
def package(self):
self._shared.call_install(self)
def package_info(self):
self._shared.package_info(self)
if tools.cross_building(conanfile=self):
qt_host_path = self._resolve_qt_host_path()
if qt_host_path:
self.env_info.QT_HOST_PATH.append(qt_host_path)
def package_id(self):
# https://docs.conan.io/en/latest/creating_packages/define_abi_compatibility.html
# The package_revision_mode() is too strict for Qt CI. This mode includes artifacts
# checksum in package_id which is problematic in Qt CI re-runs (re-run flaky
# build) which contain different build timestamps (cmake) which end up in library
# files -> different package_id.
self.info.requires.recipe_revision_mode()
# Enable 'qt-conan-common' updates on client side with $conan install .. --update
self.info.python_requires.recipe_revision_mode()
# Remove those configure(.bat) options which should not affect package_id.
# These point to local file system paths and in order to re-use pre-built
# binaries (by Qt CI) by others these should not affect the 'package_id'
# as those probably differ on each machine
rm_list = [
"sdk",
"qpa",
"translationsdir",
"headersclean",
"qt_host_path",
"android_sdk",
"android_ndk",
]
for item in rm_list:
if item in self.info.options:
delattr(self.info.options, item)
# filter also those cmake options that should not end up in the package_id
if hasattr(self.info.options, "cmake_args_qtbase"):
_filter = self._shared.filter_cmake_args_for_package_id
self.info.options.cmake_args_qtbase = _filter(self.info.options.cmake_args_qtbase)
def deploy(self):
self.copy("*") # copy from current package
self.copy_deps("*") # copy from dependencies

144
configure vendored
View File

@ -8,14 +8,18 @@
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# the directory of this script is the "source tree" # the directory of this script is the "source tree"
relpath=`dirname $0` relpath=`dirname "$0"`
relpath=`(cd "$relpath"; /bin/pwd)` relpath=`(cd "$relpath"; /bin/pwd)`
# the current directory is the "build tree" or "object tree" # the current directory is the "build tree" or "object tree"
outpath=`/bin/pwd` outpath=`/bin/pwd`
outpathPrefix=$outpath
# do this early so we don't store it in config.status # do this early so we don't store it in config.status
CFG_TOPLEVEL= CFG_TOPLEVEL=
outpathPrefix=
SAVED_IFS=$IFS
IFS='
'
checkTopLevelBuild() checkTopLevelBuild()
{ {
@ -23,7 +27,7 @@ checkTopLevelBuild()
if [ x"$1" = x"-top-level" ]; then if [ x"$1" = x"-top-level" ]; then
CFG_TOPLEVEL=yes CFG_TOPLEVEL=yes
relpathMangled=`dirname "$relpath"` relpathMangled=`dirname "$relpath"`
outpathPrefix=../ outpathPrefix="$outpathPrefix/.."
else else
if [ -f ../.qmake.super ]; then if [ -f ../.qmake.super ]; then
echo >&2 "ERROR: You cannot configure qtbase separately within a top-level build." echo >&2 "ERROR: You cannot configure qtbase separately within a top-level build."
@ -35,41 +39,26 @@ checkTopLevelBuild()
OPT_CMDLINE= # expanded version for the script OPT_CMDLINE= # expanded version for the script
determineOptFilePath() determineOptFilePath()
{ {
> "${outpathPrefix}/config.redo.in"
set -f # suppress globbing in for loop set -f # suppress globbing in for loop
SAVED_IFS=$IFS
IFS='
'
for i in "$@"; do for i in "$@"; do
if [ x"$i" = x"-top-level" ]; then if [ x"$i" = x"-top-level" ]; then
continue continue
fi fi
case $i in case $i in
-redo|--redo) -redo|--redo)
optfile=${outpathPrefix}config.opt optfile=${outpathPrefix}/config.opt
if test -n "$CFG_TOPLEVEL" && ! test -f $optfile; then if ! test -f "$optfile"; then
optfile=config.opt
fi
if ! test -f $optfile; then
echo >&2 "No config.opt present - cannot redo configuration." echo >&2 "No config.opt present - cannot redo configuration."
exit 1 exit 1
fi fi
for a in `cat $optfile`; do
OPT_CMDLINE="$OPT_CMDLINE
$a"
done
;; ;;
*) *)
OPT_CMDLINE="$OPT_CMDLINE # If redo-ing, write the rest of parameters into the config.redo.in file
$i" echo \"$i\" >> "${outpathPrefix}/config.redo.in"
;; ;;
esac esac
done done
set --
for i in $OPT_CMDLINE; do
set -- "$@" "$i"
done
set +f
IFS=$SAVED_IFS
} }
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@ -88,80 +77,10 @@ while [ "$#" -gt 0 ]; do
CURRENT_OPT="$1" CURRENT_OPT="$1"
case "$1" in case "$1" in
#Autoconf style options #Autoconf style options
--enable-*)
VAR=`echo $1 | sed 's,^--enable-\(.*\),\1,'`
VAL=yes
;;
--disable-*)
VAR=`echo $1 | sed 's,^--disable-\(.*\),\1,'`
VAL=no
;;
--*=*)
VAR=`echo $1 | sed 's,^--\(.*\)=.*,\1,'`
VAL=`echo $1 | sed 's,^--.*=\(.*\),\1,'`
;;
--no-*)
VAR=`echo $1 | sed 's,^--no-\(.*\),\1,'`
VAL=no
;;
--*) --*)
VAR=`echo $1 | sed 's,^--\(.*\),\1,'` VAR=`echo $1 | sed 's,^--\(.*\),\1,'`
VAL=yes VAL=yes
;; ;;
#Qt plugin options
-no-*-*|-plugin-*-*|-qt-*-*)
VAR=`echo $1 | sed 's,^-[^-]*-\(.*\),\1,'`
VAL=`echo $1 | sed 's,^-\([^-]*\).*,\1,'`
;;
#Qt style no options
-no-*)
VAR=`echo $1 | sed 's,^-no-\(.*\),\1,'`
VAL=no
;;
#Qt style options that pass an argument
-prefix| \
-docdir| \
-headerdir| \
-plugindir| \
-qmldir| \
-archdatadir| \
-datadir| \
-libdir| \
-bindir| \
-libexecdir| \
-translationdir| \
-sysconfdir| \
-examplesdir| \
-testsdir| \
-hostdatadir| \
-extprefix| \
-sysroot| \
-make| \
-nomake| \
-skip| \
-platform| \
-xplatform| \
-device| \
-device-option| \
-sdk| \
-android-sdk| \
-android-ndk| \
-android-ndk-platform| \
-android-arch)
VAR=`echo $1 | sed 's,^-\(.*\),\1,'`
shift
VAL="$1"
;;
#Qt style complex options in one command
-enable-*|-disable-*)
VAR=`echo $1 | sed 's,^-\([^-]*\)-.*,\1,'`
VAL=`echo $1 | sed 's,^-[^-]*-\(.*\),\1,'`
;;
#Qt Builtin/System style options
-no-*|-system-*|-qt-*)
VAR=`echo $1 | sed 's,^-[^-]*-\(.*\),\1,'`
VAL=`echo $1 | sed 's,^-\([^-]*\)-.*,\1,'`
;;
#General options, including Qt style yes options #General options, including Qt style yes options
-*) -*)
VAR=`echo $1 | sed 's,^-\(.*\),\1,'` VAR=`echo $1 | sed 's,^-\(.*\),\1,'`
@ -176,24 +95,16 @@ while [ "$#" -gt 0 ]; do
shift shift
UNKNOWN_OPT=no
case "$VAR" in case "$VAR" in
h|help) h|help)
if [ "$VAL" = "yes" ]; then if [ "$VAL" = "yes" ]; then
OPT_HELP="$VAL" OPT_HELP="$VAL"
else
UNKNOWN_OPT=yes
fi fi
;; ;;
*) *)
;; ;;
esac esac
if [ "$UNKNOWN_OPT" = "yes" ]; then
echo "${CURRENT_OPT}: invalid command-line switch"
ERROR=yes
fi
done done
[ "x$ERROR" = "xyes" ] && exit 1
} }
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@ -222,18 +133,27 @@ parseCommandline "$@"
handleHelp handleHelp
determineOptFilePath "$@" determineOptFilePath "$@"
optfilepath=${outpathPrefix}/config.opt
opttmpfilepath=${outpathPrefix}/config.opt.in
redofilepath=${outpathPrefix}/config.redo
redotmpfilepath=${outpathPrefix}/config.redo.in
fresh_requested_arg= fresh_requested_arg=
optfilename=config.opt
if [ -z "$optfile" ]; then # only write optfile if not currently redoing if [ -z "$optfile" ]; then # only write optfile if not currently redoing
optfilepath=${outpathPrefix}${optfilename} > "$opttmpfilepath"
> "$optfilepath" > "$redotmpfilepath"
for arg in "$@"; do
if [ "$arg" = "-top-level" ]; then for arg in "$@"; do echo \"$arg\" >> "$opttmpfilepath"; done
continue
fi cmake -DIN_FILE="${opttmpfilepath}" -DOUT_FILE="${optfilepath}" -DIGNORE_ARGS=-top-level -P "${relpath}/cmake/QtWriteArgsFile.cmake"
echo $arg >> "$optfilepath"
done
else else
# Rewriting config.opt into config.opt.in anyway. Allows for direct manipulation of config.opt
> "$opttmpfilepath"
for arg in `cat $optfile`; do echo \"$arg\" >> "$opttmpfilepath"; done
cmake -DIN_FILE="${opttmpfilepath}" -DREDO_FILE="${redotmpfilepath}" -DOUT_FILE="${redofilepath}" -DIGNORE_ARGS=-top-level -P "${relpath}/cmake/QtWriteArgsFile.cmake"
optfilepath=${redofilepath}
fresh_requested_arg=-DFRESH_REQUESTED=TRUE fresh_requested_arg=-DFRESH_REQUESTED=TRUE
fi fi
@ -243,4 +163,6 @@ if [ -n "$CFG_TOPLEVEL" ]; then
cd .. cd ..
fi fi
cmake "-DOPTFILE=$optfilename" $top_level_arg $fresh_requested_arg -P "$relpath/cmake/QtProcessConfigureArgs.cmake" cmake "-DOPTFILE=${optfilepath}" ${top_level_arg} ${fresh_requested_arg} -P "${relpath}/cmake/QtProcessConfigureArgs.cmake"
IFS=$SAVED_IFS

View File

@ -65,9 +65,8 @@ goto doneargs
:redo :redo
if not exist "%TOPQTDIR%\config.opt" goto redoerr if not exist "%TOPQTDIR%\config.opt" goto redoerr
set rargs= echo %ARGS% > %TOPQTDIR%\config.redo.in
for /f "usebackq delims=" %%i in ("%TOPQTDIR%\config.opt") do set rargs=!rargs! "%%i" set redoing=""
call :doargs %rargs%
goto nextarg goto nextarg
:redoerr :redoerr
echo No config.opt present - cannot redo configuration. >&2 echo No config.opt present - cannot redo configuration. >&2
@ -78,15 +77,26 @@ goto doneargs
cd "%TOPQTDIR%" cd "%TOPQTDIR%"
rem Write config.opt if we're not currently -redo'ing rem Write config.opt if we're not currently -redo'ing
set OPT_FILE_PATH=%TOPQTDIR%\config.opt
set OPT_TMP_FILE_PATH=%TOPQTDIR%\config.opt.in
set REDO_FILE_PATH=%TOPQTDIR%\config.redo
set REDO_TMP_FILE_PATH=%TOPQTDIR%\config.redo.in
set FRESH_REQUESTED_ARG= set FRESH_REQUESTED_ARG=
if "!rargs!" == "" ( if not defined redoing (
echo.%*>config.opt.in echo.%*>"%OPT_TMP_FILE_PATH%"
cmake -DIN_FILE=config.opt.in -DOUT_FILE=config.opt -DIGNORE_ARGS=-top-level -P "%QTSRC%\cmake\QtWriteArgsFile.cmake"
) else if NOT "!rargs!" == "" ( cmake -DIN_FILE="%OPT_TMP_FILE_PATH%" -DOUT_FILE="%OPT_FILE_PATH%" -DIGNORE_ARGS=-top-level -P "%QTSRC%\cmake\QtWriteArgsFile.cmake"
) else (
echo. 2> "%OPT_TMP_FILE_PATH%"
for /F "usebackq tokens=*" %%A in ("%OPT_FILE_PATH%") do echo "%%A" >> "%OPT_TMP_FILE_PATH%"
cmake -DIN_FILE="%OPT_TMP_FILE_PATH%" -DREDO_FILE="%REDO_TMP_FILE_PATH%" -DOUT_FILE="%REDO_FILE_PATH%" -DIGNORE_ARGS="-top-level;-redo;--redo" -P "%QTSRC%\cmake\QtWriteArgsFile.cmake"
set OPT_FILE_PATH=%REDO_FILE_PATH%
set FRESH_REQUESTED_ARG=-DFRESH_REQUESTED=TRUE set FRESH_REQUESTED_ARG=-DFRESH_REQUESTED=TRUE
) )
rem Launch CMake-based configure rem Launch CMake-based configure
set TOP_LEVEL_ARG= set TOP_LEVEL_ARG=
if %TOPLEVEL% == true set TOP_LEVEL_ARG=-DTOP_LEVEL=TRUE if %TOPLEVEL% == true set TOP_LEVEL_ARG=-DTOP_LEVEL=TRUE
cmake -DOPTFILE=config.opt %TOP_LEVEL_ARG% %FRESH_REQUESTED_ARG% -P "%QTSRC%\cmake\QtProcessConfigureArgs.cmake" cmake -DOPTFILE="%OPT_FILE_PATH%" %TOP_LEVEL_ARG% %FRESH_REQUESTED_ARG% -P "%QTSRC%\cmake\QtProcessConfigureArgs.cmake"

View File

@ -22,6 +22,7 @@ qt_find_package(WrapOpenSSLHeaders PROVIDED_TARGETS WrapOpenSSLHeaders::WrapOpen
# openssl_headers # openssl_headers
# OPENSSL_VERSION_MAJOR is not defined for OpenSSL 1.1.1 # OPENSSL_VERSION_MAJOR is not defined for OpenSSL 1.1.1
qt_config_compile_test(opensslv11_headers qt_config_compile_test(opensslv11_headers
LABEL "opensslv11_headers"
LIBRARIES LIBRARIES
WrapOpenSSLHeaders::WrapOpenSSLHeaders WrapOpenSSLHeaders::WrapOpenSSLHeaders
CODE CODE
@ -46,6 +47,7 @@ qt_find_package(WrapOpenSSL PROVIDED_TARGETS WrapOpenSSL::WrapOpenSSL MODULE_NAM
# openssl # openssl
# OPENSSL_VERSION_MAJOR is not defined for OpenSSL 1.1.1 # OPENSSL_VERSION_MAJOR is not defined for OpenSSL 1.1.1
qt_config_compile_test(opensslv11 qt_config_compile_test(opensslv11
LABEL "opensslv11"
LIBRARIES LIBRARIES
WrapOpenSSL::WrapOpenSSL WrapOpenSSL::WrapOpenSSL
CODE CODE
@ -70,6 +72,7 @@ SSL_free(SSL_new(0));
# opensslv30 # opensslv30
# openssl_headers # openssl_headers
qt_config_compile_test(opensslv30_headers qt_config_compile_test(opensslv30_headers
LABEL "opensslv30_headers"
LIBRARIES LIBRARIES
WrapOpenSSLHeaders::WrapOpenSSLHeaders WrapOpenSSLHeaders::WrapOpenSSLHeaders
CODE CODE
@ -87,6 +90,7 @@ int main(void)
} }
") ")
qt_config_compile_test(opensslv30 qt_config_compile_test(opensslv30
LABEL "opensslv30"
LIBRARIES LIBRARIES
WrapOpenSSL::WrapOpenSSL WrapOpenSSL::WrapOpenSSL
CODE CODE
@ -331,11 +335,13 @@ int main(void)
"# FIXME: qmake: ['TEMPLATE = lib', 'CONFIG += dll bsymbolic_functions', 'isEmpty(QMAKE_LFLAGS_BSYMBOLIC_FUNC): error("Nope")'] "# FIXME: qmake: ['TEMPLATE = lib', 'CONFIG += dll bsymbolic_functions', 'isEmpty(QMAKE_LFLAGS_BSYMBOLIC_FUNC): error("Nope")']
) )
if(NOT MSVC AND NOT APPLE)
qt_config_compile_test("separate_debug_info"
LABEL "separate debug information support"
PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/separate_debug_info"
)
endif()
qt_config_compile_test("separate_debug_info"
LABEL "separate debug information support"
PROJECT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/separate_debug_info"
)
# signaling_nan # signaling_nan
qt_config_compile_test(signaling_nan qt_config_compile_test(signaling_nan
LABEL "Signaling NaN for doubles" LABEL "Signaling NaN for doubles"
@ -535,7 +541,7 @@ qt_feature("developer-build" PRIVATE
LABEL "Developer build" LABEL "Developer build"
AUTODETECT OFF AUTODETECT OFF
) )
qt_feature("no-prefix" PRIVATE qt_feature("no-prefix"
LABEL "No prefix build" LABEL "No prefix build"
AUTODETECT NOT QT_WILL_INSTALL AUTODETECT NOT QT_WILL_INSTALL
CONDITION NOT QT_WILL_INSTALL CONDITION NOT QT_WILL_INSTALL
@ -567,7 +573,7 @@ qt_feature_config("force_debug_info" QMAKE_PRIVATE_CONFIG)
qt_feature("separate_debug_info" PUBLIC qt_feature("separate_debug_info" PUBLIC
LABEL "Split off debug information" LABEL "Split off debug information"
AUTODETECT OFF AUTODETECT OFF
CONDITION ( QT_FEATURE_shared ) AND ( QT_FEATURE_debug OR QT_FEATURE_debug_and_release OR QT_FEATURE_force_debug_info ) AND ( APPLE OR TEST_separate_debug_info ) CONDITION ( QT_FEATURE_shared ) AND ( QT_FEATURE_debug OR QT_FEATURE_debug_and_release OR QT_FEATURE_force_debug_info ) AND ( MSVC OR APPLE OR TEST_separate_debug_info )
) )
qt_feature_config("separate_debug_info" QMAKE_PUBLIC_QT_CONFIG) qt_feature_config("separate_debug_info" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("appstore-compliant" PUBLIC qt_feature("appstore-compliant" PUBLIC
@ -1157,6 +1163,18 @@ qt_configure_add_summary_entry(
ARGS "ccache" ARGS "ccache"
CONDITION UNIX CONDITION UNIX
) )
qt_configure_add_summary_entry(
TYPE "message" ARGS "Unity Build" MESSAGE "yes" CONDITION QT_UNITY_BUILD
)
qt_configure_add_summary_entry(
TYPE "message" ARGS "Unity Build" MESSAGE "no" CONDITION NOT QT_UNITY_BUILD
)
qt_configure_add_summary_entry(
TYPE "message"
ARGS "Unity Build Batch Size"
MESSAGE "${QT_UNITY_BUILD_BATCH_SIZE}"
CONDITION QT_UNITY_BUILD
)
qt_configure_add_summary_entry( qt_configure_add_summary_entry(
TYPE "firstAvailableFeature" TYPE "firstAvailableFeature"
ARGS "use_bfd_linker use_gold_linker use_lld_linker use_mold_linker" ARGS "use_bfd_linker use_gold_linker use_lld_linker use_mold_linker"
@ -1326,3 +1344,11 @@ qt_extra_definition("QT_VERSION_PATCH" ${PROJECT_VERSION_PATCH} PUBLIC)
qt_extra_definition("QT_COPYRIGHT" \"${QT_COPYRIGHT}\" PRIVATE) qt_extra_definition("QT_COPYRIGHT" \"${QT_COPYRIGHT}\" PRIVATE)
qt_extra_definition("QT_COPYRIGHT_YEAR" \"${QT_COPYRIGHT_YEAR}\" PRIVATE) qt_extra_definition("QT_COPYRIGHT_YEAR" \"${QT_COPYRIGHT_YEAR}\" PRIVATE)
qt_configure_add_report_entry(
TYPE WARNING
MESSAGE "QT_ALLOW_SYMLINK_IN_PATHS is enabled. This is not recommended, and it may lead to unexpected issues.
E.g., When building QtWebEngine, enabling this option may result in build issues in certain platforms.
See https://bugreports.qt.io/browse/QTBUG-59769."
CONDITION QT_ALLOW_SYMLINK_IN_PATHS
)

View File

@ -0,0 +1 @@
url.examples = "https://code.qt.io/cgit/qt/qtpositioning.git/tree/examples/\1?h=$QT_VER"

View File

@ -29,6 +29,5 @@ url = https://doc.qt.io/qt
defines += qt6 defines += qt6
# Uncomment the following two lines to generate documentation marked as \internal # Require Qt modules to define qhp.projects
# alias.internal = disable qhp = true
# macro.internal.HTML = "<span style="color:red">[internal]</span>"

View File

@ -2,11 +2,13 @@
#specify the CSS file used by this template #specify the CSS file used by this template
HTML.stylesheets = template/style/offline.css \ HTML.stylesheets = template/style/offline.css \
template/style/offline-dark.css template/style/offline-dark.css \
template/style/tech_preview.svg
#for including files into the qch file #for including files into the qch file
qhp.extraFiles += style/offline.css \ qhp.extraFiles += style/offline.css \
style/offline-dark.css style/offline-dark.css \
style/tech_preview.svg
HTML.headerstyles = \ HTML.headerstyles = \
" <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n" " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n"

View File

@ -11,8 +11,10 @@ HTML.stylesheets = template/style/online.css \
template/style/icomoon.woff \ template/style/icomoon.woff \
template/style/cookiebar-x.png \ template/style/cookiebar-x.png \
template/style/doc_search.png \ template/style/doc_search.png \
template/style/tech_preview.svg \
template/style/theqtcompany.png template/style/theqtcompany.png
#for including files into the qch file. Relative to the outputdir of a QDoc build. #for including files into the qch file. Relative to the outputdir of a QDoc build.
qhp.extraFiles += style/online.css \ qhp.extraFiles += style/online.css \
style/cookie-confirm.css \ style/cookie-confirm.css \
@ -25,6 +27,7 @@ qhp.extraFiles += style/online.css \
style/icomoon.woff \ style/icomoon.woff \
style/cookiebar-x.png \ style/cookiebar-x.png \
style/doc_search.png \ style/doc_search.png \
style/tech_preview.svg \
style/theqtcompany.png style/theqtcompany.png
HTML.headerstyles = \ HTML.headerstyles = \

View File

@ -56,6 +56,19 @@ macro.endqdoc.HTML = "*/"
macro.borderedimage = "\\div {class=\"border\"} \\image \1\n\\enddiv" macro.borderedimage = "\\div {class=\"border\"} \\image \1\n\\enddiv"
macro.examplecategory = "\\meta category {\1}\n\\ingroup category \1" macro.examplecategory = "\\meta category {\1}\n\\ingroup category \1"
macro.QDS = "Qt Design Studio"
macro.QDV = "Qt Design Viewer"
macro.QB = "Qt Bridge"
macro.QBPS = "Qt Bridge for Adobe Photoshop"
macro.QBXD = "Qt Bridge for Adobe XD"
macro.QBSK = "Qt Bridge for Sketch"
macro.QBF = "Qt Bridge for Figma"
macro.QMCU = "Qt for MCUs"
macro.QUL = "Qt Quick Ultralite"
macro.QtAA = "Qt for Android Automotive"
macro.QOI = "Qt Online Installer"
macro.QMT = "Qt Maintenance Tool"
macro.beginfloatleft.HTML = "<div style=\"float: left; margin-right: 2em\">" macro.beginfloatleft.HTML = "<div style=\"float: left; margin-right: 2em\">"
macro.beginfloatright.HTML = "<div style=\"float: right; margin-left: 2em\">" macro.beginfloatright.HTML = "<div style=\"float: right; margin-left: 2em\">"
macro.endfloat.HTML = "</div>" macro.endfloat.HTML = "</div>"
@ -111,3 +124,8 @@ macro.cmakepropertywebassemblyonly = "\\note This property is used only if targe
macro.cmakepropertyiosonly = "\\note This property is used only if targeting iOS." macro.cmakepropertyiosonly = "\\note This property is used only if targeting iOS."
macro.cmakevariableiosonly = "\\note This variable is used only if targeting iOS." macro.cmakevariableiosonly = "\\note This variable is used only if targeting iOS."
#Appends the tech preview link to the brief sentence and adds to tech_preview
#group.
#Must be placed directly under a \brief command
macro.techpreview = "(Technical preview)\n\n\\meta status {Technical preview}\n\\ingroup tech_preview\n"

View File

@ -94,7 +94,6 @@ manifestmeta.android.names = "Qt3D/Qt 3D: Basic Shapes C++ Example" \
"QtQuickControls/Qt Quick Controls - Flat Style" \ "QtQuickControls/Qt Quick Controls - Flat Style" \
"QtQuickControls/Qt Quick Controls - Gallery" \ "QtQuickControls/Qt Quick Controls - Gallery" \
"QtQuickControls/Qt Quick Controls - Imagine Style Example: Automotive" \ "QtQuickControls/Qt Quick Controls - Imagine Style Example: Automotive" \
"QtQuickControls/Qt Quick Controls - Imagine Style Example: Music Player" \
"QtQuickControls/Qt Quick Controls - Side Panel" \ "QtQuickControls/Qt Quick Controls - Side Panel" \
"QtQuickControls/Qt Quick Controls - Swipe to Remove" \ "QtQuickControls/Qt Quick Controls - Swipe to Remove" \
"QtQuickControls/Qt Quick Controls - Text Editor" \ "QtQuickControls/Qt Quick Controls - Text Editor" \
@ -166,7 +165,6 @@ manifestmeta.ios.names = "QtCore/Contiguous Cache Example" \
"QtWidgets/Easing Curves Example" \ "QtWidgets/Easing Curves Example" \
"QtWidgets/Move Blocks Example" \ "QtWidgets/Move Blocks Example" \
"QtWidgets/States Example" \ "QtWidgets/States Example" \
"QtWidgets/Class Wizard Example" \
"QtWidgets/Find Files Example" \ "QtWidgets/Find Files Example" \
"QtWidgets/License Wizard Example" \ "QtWidgets/License Wizard Example" \
"QtWidgets/Standard Dialogs Example" \ "QtWidgets/Standard Dialogs Example" \

View File

@ -574,6 +574,20 @@ ol.I > li {
padding: 3px 15px 3px 0 padding: 3px 15px 3px 0
} }
span.status.technical-preview {
display: inline-block;
position: relative;
background: center/contain no-repeat url(tech_preview.svg);
width: 26px;
height: 23px;
}
td.memItemRight span.status {
margin-top: -10px;
right: -10px;
top: 6px;
}
.qml { .qml {
display: block; display: block;
margin: 10px; margin: 10px;

View File

@ -505,6 +505,18 @@ h1,h2,h3,h4,h5,h6 {
font-size:150%; font-size:150%;
margin-bottom: 1em margin-bottom: 1em
} }
span.status.technical-preview {
display:inline-block;
position:relative;
background:center/contain no-repeat url(tech_preview.svg);
width:26px;
height:23px
}
td.memItemRight span.status {
margin-top:-10px;
right:-10px;
top:6px
}
article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section { article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section {
display:block display:block
} }

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="49" height="43" viewBox="0 0 13 11" stroke="#09102b"><path d="M12.82 11.125L.155 11.121 6.491.155z" opacity=".999" fill="#ffe353" stroke-linejoin="round" stroke-width=".31"/><path d="M4.914 7.071L3.521 8.302l1.287 1.084m1.144.027l1.394-1.231-1.287-1.084m-.283-.539l-.788 2.974" fill="none" stroke-linecap="round" stroke-width=".151"/><path d="M7.287 9.358l-.013.259 1.695.025-.021-.297-1.662.013zm.706.017L7.989 5.7l.367-.004.017 3.658m.33-3.512l-.238.008.004.255.238.033-.004-.297zm-.221.05l-3.199.008.004.238 3.165-.021.029-.226zm-2.965.255l.025.447.28-.15.23.163-.267.313m-.23-.322l-.242-.046-.084.163.288.226" fill="#41cd52" stroke-width=".151"/></svg>

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 222 KiB

View File

@ -5,7 +5,6 @@ qt_examples_build_begin(EXTERNAL_BUILD)
add_subdirectory(corelib) add_subdirectory(corelib)
add_subdirectory(embedded) add_subdirectory(embedded)
add_subdirectory(qpa)
if(TARGET Qt6::DBus) if(TARGET Qt6::DBus)
add_subdirectory(dbus) add_subdirectory(dbus)
endif() endif()

View File

@ -6,9 +6,6 @@ add_subdirectory(mimetypes)
add_subdirectory(serialization) add_subdirectory(serialization)
add_subdirectory(tools) add_subdirectory(tools)
add_subdirectory(platform) add_subdirectory(platform)
if(QT_FEATURE_permissions)
add_subdirectory(permissions)
endif()
if(QT_FEATURE_thread) if(QT_FEATURE_thread)
add_subdirectory(threads) add_subdirectory(threads)
endif() endif()

View File

@ -38,8 +38,7 @@ double BindableSubscription::calculateDiscount() const
case Yearly: case Yearly:
return 0.6; return 0.6;
} }
Q_ASSERT(false); Q_UNREACHABLE_RETURN(-1);
return -1;
} }
int BindableSubscription::basePrice() const int BindableSubscription::basePrice() const

View File

@ -11,6 +11,10 @@
#include <QPushButton> #include <QPushButton>
#include <QRadioButton> #include <QRadioButton>
#include <QSpinBox> #include <QSpinBox>
#include <QProperty>
#include <QString>
#include <QDateTimeEdit>
#include <QBindable>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -19,6 +23,8 @@ int main(int argc, char *argv[])
BindableSubscription subscription(&user); BindableSubscription subscription(&user);
SubscriptionWindow w; SubscriptionWindow w;
// clazy:excludeall=lambda-in-connect
// when subscription is out of scope so is window
// Initialize subscription data // Initialize subscription data
QRadioButton *monthly = w.findChild<QRadioButton *>("btnMonthly"); QRadioButton *monthly = w.findChild<QRadioButton *>("btnMonthly");
@ -49,9 +55,8 @@ int main(int argc, char *argv[])
}); });
QSpinBox *ageSpinBox = w.findChild<QSpinBox *>("ageSpinBox"); QSpinBox *ageSpinBox = w.findChild<QSpinBox *>("ageSpinBox");
QObject::connect(ageSpinBox, &QSpinBox::valueChanged, [&](int value) { QBindable<int> ageBindable(ageSpinBox, "value");
user.setAge(value); user.bindableAge().setBinding([ageBindable](){ return ageBindable.value();});
});
QLabel *priceDisplay = w.findChild<QLabel *>("priceDisplay"); QLabel *priceDisplay = w.findChild<QLabel *>("priceDisplay");

View File

@ -4,6 +4,7 @@
/*! /*!
\title Qt Android Notifier \title Qt Android Notifier
\example platform/androidnotifier \example platform/androidnotifier
\examplecategory {Mobile}
\brief Demonstrates calling Java code from Qt in an Android application. \brief Demonstrates calling Java code from Qt in an Android application.
\image androidnotifier.png \image androidnotifier.png

View File

@ -1,11 +1,10 @@
# Copyright (C) 2022 The Qt Company Ltd. # Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_example(cbordump) if(NOT ANDROID)
qt_internal_add_example(convert) qt_internal_add_example(cbordump)
qt_internal_add_example(savegame) qt_internal_add_example(convert)
if(TARGET Qt6::Network AND TARGET Qt6::Widgets) qt_internal_add_example(savegame)
qt_internal_add_example(rsslisting)
endif() endif()
if(TARGET Qt6::Widgets) if(TARGET Qt6::Widgets)
qt_internal_add_example(streambookmarks) qt_internal_add_example(streambookmarks)

View File

@ -4,6 +4,10 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(cbordump LANGUAGES CXX) project(cbordump LANGUAGES CXX)
if (ANDROID)
message(FATAL_ERROR "This project cannot be built on Android.")
endif()
if(NOT DEFINED INSTALL_EXAMPLESDIR) if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples") set(INSTALL_EXAMPLESDIR "examples")
endif() endif()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -3,7 +3,8 @@
/*! /*!
\example serialization/cbordump \example serialization/cbordump
\examplecategory {Input/Output} \examplecategory {Data Processing & I/O}
\meta tag {network}
\title Parsing and displaying CBOR data \title Parsing and displaying CBOR data
\brief A demonstration of how to parse files in CBOR format. \brief A demonstration of how to parse files in CBOR format.

View File

@ -14,6 +14,8 @@
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
using namespace Qt::StringLiterals;
/* /*
* To regenerate: * To regenerate:
* curl -O https://www.iana.org/assignments/cbor-tags/cbor-tags.xml * curl -O https://www.iana.org/assignments/cbor-tags/cbor-tags.xml
@ -33,7 +35,7 @@
struct CborTagDescription struct CborTagDescription
{ {
QCborTag tag; QCborTag tag;
const char *description; // with space and parentheses const char *description; // with space and parentheses
}; };
// CBOR Tags // CBOR Tags
@ -216,22 +218,18 @@ static const CborTagDescription tagDescriptions[] = {
enum { enum {
// See RFC 7049 section 2. // See RFC 7049 section 2.
SmallValueBitLength = 5, SmallValueBitLength = 5,
SmallValueMask = (1 << SmallValueBitLength) - 1, /* 0x1f */ SmallValueMask = (1 << SmallValueBitLength) - 1, /* 0x1f */
Value8Bit = 24, Value8Bit = 24,
Value16Bit = 25, Value16Bit = 25,
Value32Bit = 26, Value32Bit = 26,
Value64Bit = 27 Value64Bit = 27
}; };
//! [0] //! [0]
struct CborDumper struct CborDumper
{ {
enum DumpOption { enum DumpOption { ShowCompact = 0x01, ShowWidthIndicators = 0x02, ShowAnnotated = 0x04 };
ShowCompact = 0x01,
ShowWidthIndicators = 0x02,
ShowAnnotated = 0x04
};
Q_DECLARE_FLAGS(DumpOptions, DumpOption) Q_DECLARE_FLAGS(DumpOptions, DumpOption)
CborDumper(QFile *f, DumpOptions opts_); CborDumper(QFile *f, DumpOptions opts_);
@ -268,8 +266,7 @@ static int cborNumberSize(quint64 value)
return normalSize; return normalSize;
} }
CborDumper::CborDumper(QFile *f, DumpOptions opts_) CborDumper::CborDumper(QFile *f, DumpOptions opts_) : opts(opts_)
: opts(opts_)
{ {
// try to mmap the file, this is faster // try to mmap the file, this is faster
char *ptr = reinterpret_cast<char *>(f->map(0, f->size(), QFile::MapPrivateOption)); char *ptr = reinterpret_cast<char *>(f->map(0, f->size(), QFile::MapPrivateOption));
@ -316,7 +313,8 @@ QCborError CborDumper::dump()
return err; return err;
} }
template <typename T> static inline bool canConvertTo(double v) template<typename T>
static inline bool canConvertTo(double v)
{ {
using TypeInfo = std::numeric_limits<T>; using TypeInfo = std::numeric_limits<T>;
// The [conv.fpint] (7.10 Floating-integral conversions) section of the // The [conv.fpint] (7.10 Floating-integral conversions) section of the
@ -337,31 +335,32 @@ template <typename T> static inline bool canConvertTo(double v)
return v == floor(v); return v == floor(v);
} }
static QString fpToString(double v, const char *suffix) static QString fpToString(double v, QLatin1StringView suffix = ""_L1)
{ {
if (qIsInf(v)) if (qIsInf(v))
return v < 0 ? QStringLiteral("-inf") : QStringLiteral("inf"); return v < 0 ? "-inf"_L1 : "inf"_L1;
if (qIsNaN(v)) if (qIsNaN(v))
return QStringLiteral("nan"); return "nan"_L1;
if (canConvertTo<qint64>(v)) if (canConvertTo<qint64>(v))
return QString::number(qint64(v)) + ".0" + suffix; return QString::number(qint64(v)) + ".0"_L1 + suffix;
if (canConvertTo<quint64>(v)) if (canConvertTo<quint64>(v))
return QString::number(quint64(v)) + ".0" + suffix; return QString::number(quint64(v)) + ".0"_L1 + suffix;
QString s = QString::number(v, 'g', QLocale::FloatingPointShortest); QString s = QString::number(v, 'g', QLocale::FloatingPointShortest);
if (!s.contains('.') && !s.contains('e')) if (!s.contains(u'.') && !s.contains(u'e'))
s += '.'; s += u'.';
s += suffix; if (suffix.size())
s += suffix;
return s; return s;
}; };
void CborDumper::dumpOne(int nestingLevel) void CborDumper::dumpOne(int nestingLevel)
{ {
QString indent(1, QLatin1Char(' ')); QString indent(1, u' ');
QString indented = indent; QString indented = indent;
if (!opts.testFlag(ShowCompact)) { if (!opts.testFlag(ShowCompact)) {
indent = QLatin1Char('\n') + QString(4 * nestingLevel, QLatin1Char(' ')); indent = u'\n' + QString(4 * nestingLevel, u' ');
indented = QLatin1Char('\n') + QString(4 + 4 * nestingLevel, QLatin1Char(' ')); indented = u'\n' + QString(4 + 4 * nestingLevel, u' ');
} }
switch (reader.type()) { switch (reader.type()) {
@ -401,7 +400,7 @@ void CborDumper::dumpOne(int nestingLevel)
printStringWidthIndicator(r.data.size()); printStringWidthIndicator(r.data.size());
r = reader.readByteArray(); r = reader.readByteArray();
comma = QLatin1Char(',') + indented; comma = u',' + indented;
} }
} else { } else {
auto r = reader.readString(); auto r = reader.readString();
@ -410,7 +409,7 @@ void CborDumper::dumpOne(int nestingLevel)
printStringWidthIndicator(r.data.toUtf8().size()); printStringWidthIndicator(r.data.toUtf8().size());
r = reader.readString(); r = reader.readString();
comma = QLatin1Char(',') + indented; comma = u',' + indented;
} }
} }
@ -466,7 +465,7 @@ void CborDumper::dumpOne(int nestingLevel)
if (reader.next()) { if (reader.next()) {
printWidthIndicator(quint64(tag)); printWidthIndicator(quint64(tag));
printf("("); printf("(");
dumpOne(nestingLevel); // same level! dumpOne(nestingLevel); // same level!
printf(")"); printf(")");
} }
@ -498,15 +497,15 @@ void CborDumper::dumpOne(int nestingLevel)
break; break;
case QCborStreamReader::Float16: case QCborStreamReader::Float16:
printf("%s", qPrintable(fpToString(reader.toFloat16(), "f16"))); printf("%s", qPrintable(fpToString(reader.toFloat16(), "f16"_L1)));
reader.next(); reader.next();
break; break;
case QCborStreamReader::Float: case QCborStreamReader::Float:
printf("%s", qPrintable(fpToString(reader.toFloat(), "f"))); printf("%s", qPrintable(fpToString(reader.toFloat(), "f"_L1)));
reader.next(); reader.next();
break; break;
case QCborStreamReader::Double: case QCborStreamReader::Double:
printf("%s", qPrintable(fpToString(reader.toDouble(), ""))); printf("%s", qPrintable(fpToString(reader.toDouble())));
reader.next(); reader.next();
break; break;
case QCborStreamReader::Invalid: case QCborStreamReader::Invalid:
@ -559,7 +558,7 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
}; };
auto printFp = [=](const char *descr, double d) { auto printFp = [=](const char *descr, double d) {
QString s = fpToString(d, ""); QString s = fpToString(d);
if (s.size() <= 6) if (s.size() <= 6)
return print(descr, "%s", qPrintable(s)); return print(descr, "%s", qPrintable(s));
return print(descr, "%a", d); return print(descr, "%a", d);
@ -574,7 +573,7 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
qsizetype size = reader.currentStringChunkSize(); qsizetype size = reader.currentStringChunkSize();
if (size < 0) if (size < 0)
return; // error return; // error
if (size >= ChunkSizeLimit) { if (size >= ChunkSizeLimit) {
fprintf(stderr, "String length too big, %lli\n", qint64(size)); fprintf(stderr, "String length too big, %lli\n", qint64(size));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -619,7 +618,7 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
printf(" %s%s", indent.constData(), section.toHex(' ').constData()); printf(" %s%s", indent.constData(), section.toHex(' ').constData());
// print the decode // print the decode
QByteArray spaces(width > 0 ? width - section.size() * 3 + 1: 0, ' '); QByteArray spaces(width > 0 ? width - section.size() * 3 + 1 : 0, ' ');
printf("%s # \"", spaces.constData()); printf("%s # \"", spaces.constData());
auto ptr = reinterpret_cast<const uchar *>(section.constData()); auto ptr = reinterpret_cast<const uchar *>(section.constData());
for (int j = 0; j < section.size(); ++j) for (int j = 0; j < section.size(); ++j)
@ -631,7 +630,7 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
// get the next chunk // get the next chunk
size = reader.currentStringChunkSize(); size = reader.currentStringChunkSize();
if (size < 0) if (size < 0)
return; // error return; // error
if (size >= ChunkSizeLimit) { if (size >= ChunkSizeLimit) {
fprintf(stderr, "String length too big, %lli\n", qint64(size)); fprintf(stderr, "String length too big, %lli\n", qint64(size));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -770,7 +769,9 @@ void CborDumper::printByteArray(const QByteArray &ba)
break; break;
case quint8(QCborKnownTags::ExpectedBase64url): case quint8(QCborKnownTags::ExpectedBase64url):
printf("b64'%s'", ba.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals).constData()); printf("b64'%s'",
ba.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)
.constData());
break; break;
} }
} }
@ -811,23 +812,20 @@ int main(int argc, char *argv[])
setlocale(LC_ALL, "C"); setlocale(LC_ALL, "C");
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("CBOR Dumper tool")); parser.setApplicationDescription("CBOR Dumper tool"_L1);
parser.addHelpOption(); parser.addHelpOption();
QCommandLineOption compact({QStringLiteral("c"), QStringLiteral("compact")}, QCommandLineOption compact({"c"_L1, "compact"_L1}, "Use compact form (no line breaks)"_L1);
QStringLiteral("Use compact form (no line breaks)"));
parser.addOption(compact); parser.addOption(compact);
QCommandLineOption showIndicators({QStringLiteral("i"), QStringLiteral("indicators")}, QCommandLineOption showIndicators({ "i"_L1, "indicators"_L1 },
QStringLiteral("Show indicators for width of lengths and integrals")); "Show indicators for width of lengths and integrals"_L1);
parser.addOption(showIndicators); parser.addOption(showIndicators);
QCommandLineOption verbose({QStringLiteral("a"), QStringLiteral("annotated")}, QCommandLineOption verbose({"a"_L1, "annotated"_L1}, "Show bytes and annotated decoding"_L1);
QStringLiteral("Show bytes and annotated decoding"));
parser.addOption(verbose); parser.addOption(verbose);
parser.addPositionalArgument(QStringLiteral("[source]"), parser.addPositionalArgument("[source]"_L1, "CBOR file to read from"_L1);
QStringLiteral("CBOR file to read from"));
parser.process(app); parser.process(app);

View File

@ -4,6 +4,10 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(convert LANGUAGES CXX) project(convert LANGUAGES CXX)
if (ANDROID)
message(FATAL_ERROR "This project cannot be built on Android.")
endif()
if(NOT DEFINED INSTALL_EXAMPLESDIR) if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples") set(INSTALL_EXAMPLESDIR "examples")
endif() endif()
@ -18,6 +22,7 @@ qt_add_executable(convert
cborconverter.cpp cborconverter.h cborconverter.cpp cborconverter.h
converter.h converter.h
datastreamconverter.cpp datastreamconverter.h datastreamconverter.cpp datastreamconverter.h
debugtextdumper.cpp debugtextdumper.h
jsonconverter.cpp jsonconverter.h jsonconverter.cpp jsonconverter.h
main.cpp main.cpp
nullconverter.cpp nullconverter.h nullconverter.cpp nullconverter.h

View File

@ -3,19 +3,21 @@
#include "cborconverter.h" #include "cborconverter.h"
#include <QCborArray>
#include <QCborMap>
#include <QCborStreamReader> #include <QCborStreamReader>
#include <QCborStreamWriter> #include <QCborStreamWriter>
#include <QCborMap>
#include <QCborArray>
#include <QCborValue> #include <QCborValue>
#include <QDataStream> #include <QDataStream>
#include <QFloat16>
#include <QFile> #include <QFile>
#include <QFloat16>
#include <QMetaType> #include <QMetaType>
#include <QTextStream> #include <QTextStream>
#include <stdio.h> #include <stdio.h>
using namespace Qt::StringLiterals;
static CborConverter cborConverter; static CborConverter cborConverter;
static CborDiagnosticDumper cborDiagnosticDumper; static CborDiagnosticDumper cborDiagnosticDumper;
@ -118,33 +120,33 @@ static QCborValue convertFromVariant(const QVariant &v, TrimFloatingPoint fpTrim
} }
//! [1] //! [1]
QString CborDiagnosticDumper::name() QString CborDiagnosticDumper::name() const
{ {
return QStringLiteral("cbor-dump"); return "cbor-dump"_L1;
} }
Converter::Direction CborDiagnosticDumper::directions() Converter::Directions CborDiagnosticDumper::directions() const
{ {
return Out; return Direction::Out;
} }
Converter::Options CborDiagnosticDumper::outputOptions() Converter::Options CborDiagnosticDumper::outputOptions() const
{ {
return SupportsArbitraryMapKeys; return SupportsArbitraryMapKeys;
} }
const char *CborDiagnosticDumper::optionsHelp() const char *CborDiagnosticDumper::optionsHelp() const
{ {
return diagnosticHelp; return diagnosticHelp;
} }
bool CborDiagnosticDumper::probeFile(QIODevice *f) bool CborDiagnosticDumper::probeFile(QIODevice *f) const
{ {
Q_UNUSED(f); Q_UNUSED(f);
return false; return false;
} }
QVariant CborDiagnosticDumper::loadFile(QIODevice *f, Converter *&outputConverter) QVariant CborDiagnosticDumper::loadFile(QIODevice *f, const Converter *&outputConverter) const
{ {
Q_UNREACHABLE(); Q_UNREACHABLE();
Q_UNUSED(f); Q_UNUSED(f);
@ -152,7 +154,8 @@ QVariant CborDiagnosticDumper::loadFile(QIODevice *f, Converter *&outputConverte
return QVariant(); return QVariant();
} }
void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{ {
QCborValue::DiagnosticNotationOptions opts = QCborValue::LineWrapped; QCborValue::DiagnosticNotationOptions opts = QCborValue::LineWrapped;
for (const QString &s : options) { for (const QString &s : options) {
@ -181,8 +184,7 @@ void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents, cons
} }
QTextStream out(f); QTextStream out(f);
out << convertFromVariant(contents, Double).toDiagnosticNotation(opts) out << convertFromVariant(contents, Double).toDiagnosticNotation(opts) << Qt::endl;
<< Qt::endl;
} }
CborConverter::CborConverter() CborConverter::CborConverter()
@ -190,37 +192,37 @@ CborConverter::CborConverter()
qRegisterMetaType<QCborTag>(); qRegisterMetaType<QCborTag>();
} }
QString CborConverter::name() QString CborConverter::name() const
{ {
return "cbor"; return "cbor";
} }
Converter::Direction CborConverter::directions() Converter::Directions CborConverter::directions() const
{ {
return InOut; return Direction::InOut;
} }
Converter::Options CborConverter::outputOptions() Converter::Options CborConverter::outputOptions() const
{ {
return SupportsArbitraryMapKeys; return SupportsArbitraryMapKeys;
} }
const char *CborConverter::optionsHelp() const char *CborConverter::optionsHelp() const
{ {
return cborOptionHelp; return cborOptionHelp;
} }
bool CborConverter::probeFile(QIODevice *f) bool CborConverter::probeFile(QIODevice *f) const
{ {
if (QFile *file = qobject_cast<QFile *>(f)) { if (QFile *file = qobject_cast<QFile *>(f)) {
if (file->fileName().endsWith(QLatin1String(".cbor"))) if (file->fileName().endsWith(".cbor"_L1))
return true; return true;
} }
return f->isReadable() && f->peek(3) == QByteArray("\xd9\xd9\xf7", 3); return f->isReadable() && f->peek(3) == QByteArray("\xd9\xd9\xf7", 3);
} }
//! [2] //! [2]
QVariant CborConverter::loadFile(QIODevice *f, Converter *&outputConverter) QVariant CborConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{ {
const char *ptr = nullptr; const char *ptr = nullptr;
if (auto file = qobject_cast<QFile *>(f)) if (auto file = qobject_cast<QFile *>(f))
@ -256,7 +258,7 @@ QVariant CborConverter::loadFile(QIODevice *f, Converter *&outputConverter)
} }
//! [2] //! [2]
//! [3] //! [3]
void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) const
{ {
//! [3] //! [3]
bool useSignature = true; bool useSignature = true;
@ -318,8 +320,9 @@ void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStri
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
//! [4] //! [4]
QCborValue v = convertFromVariant(contents, QCborValue v =
useFloat16 == Always ? Float16 : useFloat == Always ? Float : Double); convertFromVariant(contents,
useFloat16 == Always ? Float16 : useFloat == Always ? Float : Double);
QCborStreamWriter writer(f); QCborStreamWriter writer(f);
if (useSignature) if (useSignature)
writer.append(QCborKnownTags::Signature); writer.append(QCborKnownTags::Signature);

View File

@ -10,13 +10,14 @@ class CborDiagnosticDumper : public Converter
{ {
// Converter interface // Converter interface
public: public:
QString name() override; QString name() const override;
Direction directions() override; Directions directions() const override;
Options outputOptions() override; Options outputOptions() const override;
const char *optionsHelp() override; const char *optionsHelp() const override;
bool probeFile(QIODevice *f) override; bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, Converter *&outputConverter) override; QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override; void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
}; };
class CborConverter : public Converter class CborConverter : public Converter
@ -26,13 +27,14 @@ public:
// Converter interface // Converter interface
public: public:
QString name() override; QString name() const override;
Direction directions() override; Directions directions() const override;
Options outputOptions() override; Options outputOptions() const override;
const char *optionsHelp() override; const char *optionsHelp() const override;
bool probeFile(QIODevice *f) override; bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, Converter *&outputConverter) override; QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override; void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
}; };
#endif // CBORCONVERTER_H #endif // CBORCONVERTER_H

View File

@ -12,17 +12,19 @@ INSTALLS += target
SOURCES += main.cpp \ SOURCES += main.cpp \
cborconverter.cpp \ cborconverter.cpp \
jsonconverter.cpp \
datastreamconverter.cpp \ datastreamconverter.cpp \
debugtextdumper.cpp \
jsonconverter.cpp \
nullconverter.cpp \
textconverter.cpp \ textconverter.cpp \
xmlconverter.cpp \ xmlconverter.cpp
nullconverter.cpp
HEADERS += \ HEADERS += \
converter.h \ converter.h \
cborconverter.h \ cborconverter.h \
jsonconverter.h \
datastreamconverter.h \ datastreamconverter.h \
debugtextdumper.h \
jsonconverter.h \
nullconverter.h \
textconverter.h \ textconverter.h \
xmlconverter.h \ xmlconverter.h
nullconverter.h

View File

@ -5,10 +5,10 @@
#define CONVERTER_H #define CONVERTER_H
#include <QIODevice> #include <QIODevice>
#include <QList>
#include <QPair> #include <QPair>
#include <QVariant> #include <QVariant>
#include <QVariantMap> #include <QVariantMap>
#include <QList>
class VariantOrderedMap : public QList<QPair<QVariant, QVariant>> class VariantOrderedMap : public QList<QPair<QVariant, QVariant>>
{ {
@ -32,26 +32,25 @@ protected:
public: public:
static Converter *null; static Converter *null;
enum Direction { enum class Direction { In = 1, Out = 2, InOut = In | Out };
In = 1, Out = 2, InOut = 3 Q_DECLARE_FLAGS(Directions, Direction)
};
enum Option { enum Option { SupportsArbitraryMapKeys = 0x01 };
SupportsArbitraryMapKeys = 0x01
};
Q_DECLARE_FLAGS(Options, Option) Q_DECLARE_FLAGS(Options, Option)
virtual ~Converter() = 0; virtual ~Converter() = 0;
virtual QString name() = 0; virtual QString name() const = 0;
virtual Direction directions() = 0; virtual Directions directions() const = 0;
virtual Options outputOptions() = 0; virtual Options outputOptions() const = 0;
virtual const char *optionsHelp() = 0; virtual const char *optionsHelp() const = 0;
virtual bool probeFile(QIODevice *f) = 0; virtual bool probeFile(QIODevice *f) const = 0;
virtual QVariant loadFile(QIODevice *f, Converter *&outputConverter) = 0; virtual QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const = 0;
virtual void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) = 0; virtual void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const = 0;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Directions)
Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Options) Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Options)
#endif // CONVERTER_H #endif // CONVERTER_H

View File

@ -2,20 +2,21 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "datastreamconverter.h" #include "datastreamconverter.h"
#include "debugtextdumper.h"
#include <QDataStream> #include <QDataStream>
#include <QDebug>
#include <QTextStream> using namespace Qt::StringLiterals;
static const char dataStreamOptionHelp[] = static const char dataStreamOptionHelp[] =
"byteorder=host|big|little Byte order to use.\n" "byteorder=host|big|little Byte order to use.\n"
"version=<n> QDataStream version (default: Qt 5.0).\n" "version=<n> QDataStream version (default: Qt 6.0).\n"
; ;
static const char signature[] = "qds"; static const char signature[] = "qds";
static DataStreamDumper dataStreamDumper; static DataStreamConverter dataStreamConverter;
static DataStreamConverter DataStreamConverter; static DebugTextDumper debugTextDumper;
QDataStream &operator<<(QDataStream &ds, const VariantOrderedMap &map) QDataStream &operator<<(QDataStream &ds, const VariantOrderedMap &map)
{ {
@ -42,123 +43,43 @@ QDataStream &operator>>(QDataStream &ds, VariantOrderedMap &map)
return ds; return ds;
} }
static QString dumpVariant(const QVariant &v, const QString &indent = QLatin1String("\n"))
{
QString result;
QString indented = indent + QLatin1String(" ");
int type = v.userType();
if (type == qMetaTypeId<VariantOrderedMap>() || type == QMetaType::QVariantMap) {
const auto map = (type == QMetaType::QVariantMap) ?
VariantOrderedMap(v.toMap()) : qvariant_cast<VariantOrderedMap>(v);
result = QLatin1String("Map {");
for (const auto &pair : map) {
result += indented + dumpVariant(pair.first, indented);
result.chop(1); // remove comma
result += QLatin1String(" => ") + dumpVariant(pair.second, indented);
}
result.chop(1); // remove comma
result += indent + QLatin1String("},");
} else if (type == QMetaType::QVariantList) {
const QVariantList list = v.toList();
result = QLatin1String("List [");
for (const auto &item : list)
result += indented + dumpVariant(item, indented);
result.chop(1); // remove comma
result += indent + QLatin1String("],");
} else {
QDebug debug(&result);
debug.nospace() << v << ',';
}
return result;
}
QString DataStreamDumper::name()
{
return QStringLiteral("datastream-dump");
}
Converter::Direction DataStreamDumper::directions()
{
return Out;
}
Converter::Options DataStreamDumper::outputOptions()
{
return SupportsArbitraryMapKeys;
}
const char *DataStreamDumper::optionsHelp()
{
return nullptr;
}
bool DataStreamDumper::probeFile(QIODevice *f)
{
Q_UNUSED(f);
return false;
}
QVariant DataStreamDumper::loadFile(QIODevice *f, Converter *&outputConverter)
{
Q_UNREACHABLE();
Q_UNUSED(f);
Q_UNUSED(outputConverter);
return QVariant();
}
void DataStreamDumper::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
{
Q_UNUSED(options);
QString s = dumpVariant(contents);
s[s.size() - 1] = QLatin1Char('\n'); // replace the comma with newline
QTextStream out(f);
out << s;
}
DataStreamConverter::DataStreamConverter() DataStreamConverter::DataStreamConverter()
{ {
qRegisterMetaType<VariantOrderedMap>(); qRegisterMetaType<VariantOrderedMap>();
} }
QString DataStreamConverter::name() QString DataStreamConverter::name() const
{ {
return QStringLiteral("datastream"); return "datastream"_L1;
} }
Converter::Direction DataStreamConverter::directions() Converter::Directions DataStreamConverter::directions() const
{ {
return InOut; return Direction::InOut;
} }
Converter::Options DataStreamConverter::outputOptions() Converter::Options DataStreamConverter::outputOptions() const
{ {
return SupportsArbitraryMapKeys; return SupportsArbitraryMapKeys;
} }
const char *DataStreamConverter::optionsHelp() const char *DataStreamConverter::optionsHelp() const
{ {
return dataStreamOptionHelp; return dataStreamOptionHelp;
} }
bool DataStreamConverter::probeFile(QIODevice *f) bool DataStreamConverter::probeFile(QIODevice *f) const
{ {
return f->isReadable() && f->peek(sizeof(signature) - 1) == signature; return f->isReadable() && f->peek(sizeof(signature) - 1) == signature;
} }
QVariant DataStreamConverter::loadFile(QIODevice *f, Converter *&outputConverter) QVariant DataStreamConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{ {
if (!outputConverter) if (!outputConverter)
outputConverter = &dataStreamDumper; outputConverter = &debugTextDumper;
char c; char c;
if (f->read(sizeof(signature) -1) != signature || if (f->read(sizeof(signature) - 1) != signature || !f->getChar(&c) || (c != 'l' && c != 'B')) {
!f->getChar(&c) || (c != 'l' && c != 'B')) {
fprintf(stderr, "Could not load QDataStream file: invalid signature.\n"); fprintf(stderr, "Could not load QDataStream file: invalid signature.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -175,9 +96,10 @@ QVariant DataStreamConverter::loadFile(QIODevice *f, Converter *&outputConverter
return result; return result;
} }
void DataStreamConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) void DataStreamConverter::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{ {
QDataStream::Version version = QDataStream::Qt_5_0; QDataStream::Version version = QDataStream::Qt_6_0;
auto order = QDataStream::ByteOrder(QSysInfo::ByteOrder); auto order = QDataStream::ByteOrder(QSysInfo::ByteOrder);
for (const QString &option : options) { for (const QString &option : options) {
const QStringList pair = option.split('='); const QStringList pair = option.split('=');
@ -213,7 +135,7 @@ void DataStreamConverter::saveFile(QIODevice *f, const QVariant &contents, const
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
char c = order == QDataStream::LittleEndian ? 'l' : 'B'; char c = order == QDataStream::LittleEndian ? 'l' : 'B';
f->write(signature); f->write(signature);
f->write(&c, 1); f->write(&c, 1);

View File

@ -6,19 +6,6 @@
#include "converter.h" #include "converter.h"
class DataStreamDumper : public Converter
{
// Converter interface
public:
QString name() override;
Direction directions() override;
Options outputOptions() override;
const char *optionsHelp() override;
bool probeFile(QIODevice *f) override;
QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
};
class DataStreamConverter : public Converter class DataStreamConverter : public Converter
{ {
public: public:
@ -26,13 +13,14 @@ public:
// Converter interface // Converter interface
public: public:
QString name() override; QString name() const override;
Direction directions() override; Directions directions() const override;
Options outputOptions() override; Options outputOptions() const override;
const char *optionsHelp() override; const char *optionsHelp() const override;
bool probeFile(QIODevice *f) override; bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, Converter *&outputConverter) override; QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override; void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
}; };
#endif // DATASTREAMCONVERTER_H #endif // DATASTREAMCONVERTER_H

View File

@ -0,0 +1,89 @@
// Copyright (C) 2018 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "debugtextdumper.h"
#include <QDebug>
#include <QTextStream>
using namespace Qt::StringLiterals;
// Static instance is declared in datastreamconverter.cpp, since it uses it.
static QString dumpVariant(const QVariant &v, const QString &indent = "\n"_L1)
{
QString result;
QString indented = indent + " "_L1;
int type = v.userType();
if (type == qMetaTypeId<VariantOrderedMap>() || type == QMetaType::QVariantMap) {
const auto map = (type == QMetaType::QVariantMap) ? VariantOrderedMap(v.toMap())
: qvariant_cast<VariantOrderedMap>(v);
result = "Map {"_L1;
for (const auto &pair : map) {
result += indented + dumpVariant(pair.first, indented);
result.chop(1); // remove comma
result += " => "_L1 + dumpVariant(pair.second, indented);
}
result.chop(1); // remove comma
result += indent + "},"_L1;
} else if (type == QMetaType::QVariantList) {
const QVariantList list = v.toList();
result = "List ["_L1;
for (const auto &item : list)
result += indented + dumpVariant(item, indented);
result.chop(1); // remove comma
result += indent + "],"_L1;
} else {
QDebug debug(&result);
debug.nospace() << v << ',';
}
return result;
}
QString DebugTextDumper::name() const
{
return "debugtext-dump"_L1;
}
Converter::Directions DebugTextDumper::directions() const
{
return Direction::Out;
}
Converter::Options DebugTextDumper::outputOptions() const
{
return SupportsArbitraryMapKeys;
}
const char *DebugTextDumper::optionsHelp() const
{
return nullptr;
}
bool DebugTextDumper::probeFile(QIODevice *f) const
{
Q_UNUSED(f);
return false;
}
QVariant DebugTextDumper::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
Q_UNREACHABLE();
Q_UNUSED(f);
Q_UNUSED(outputConverter);
return QVariant();
}
void DebugTextDumper::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{
Q_UNUSED(options);
QString s = dumpVariant(contents);
s[s.size() - 1] = u'\n'; // replace the comma with newline
QTextStream out(f);
out << s;
}

View File

@ -0,0 +1,23 @@
// Copyright (C) 2018 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef DEBUGTEXTDUMPER_H
#define DEBUGTEXTDUMPER_H
#include "converter.h"
class DebugTextDumper : public Converter
{
// Converter interface
public:
QString name() const override;
Directions directions() const override;
Options outputOptions() const override;
const char *optionsHelp() const override;
bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
};
#endif // DEBUGTEXTDUMPER_H

View File

@ -3,7 +3,8 @@
/*! /*!
\example serialization/convert \example serialization/convert
\examplecategory {Input/Output} \examplecategory {Data Processing & I/O}
\meta tag {network}
\title Convert Example \title Convert Example
\brief The Convert example demonstrates how to convert between different \brief The Convert example demonstrates how to convert between different
@ -59,7 +60,7 @@
\section1 The DataStreamConverter Class \section1 The DataStreamConverter Class
The DataStreamConverter class is used to serialize to and from the The DataStreamConverter class is used to serialize to and from the
QDataStream format. There is also the DataStreamDumper class for outputting QDataStream format. There is also the DebugTextDumper class for outputting
the data lossless in a non-standardized human readable format. the data lossless in a non-standardized human readable format.
\section1 The JsonConverter Class \section1 The JsonConverter Class

View File

@ -9,10 +9,11 @@
#include <QJsonObject> #include <QJsonObject>
#include <QJsonValue> #include <QJsonValue>
using namespace Qt::StringLiterals;
static JsonConverter jsonConverter; static JsonConverter jsonConverter;
static const char jsonOptionHelp[] = static const char jsonOptionHelp[] = "compact=no|yes Use compact JSON form.\n";
"compact=no|yes Use compact JSON form.\n";
static QJsonDocument convertFromVariant(const QVariant &v) static QJsonDocument convertFromVariant(const QVariant &v)
{ {
@ -24,34 +25,30 @@ static QJsonDocument convertFromVariant(const QVariant &v)
return doc; return doc;
} }
JsonConverter::JsonConverter() QString JsonConverter::name() const
{ {
return "json"_L1;
} }
QString JsonConverter::name() Converter::Directions JsonConverter::directions() const
{ {
return "json"; return Direction::InOut;
} }
Converter::Direction JsonConverter::directions() Converter::Options JsonConverter::outputOptions() const
{
return InOut;
}
Converter::Options JsonConverter::outputOptions()
{ {
return {}; return {};
} }
const char *JsonConverter::optionsHelp() const char *JsonConverter::optionsHelp() const
{ {
return jsonOptionHelp; return jsonOptionHelp;
} }
bool JsonConverter::probeFile(QIODevice *f) bool JsonConverter::probeFile(QIODevice *f) const
{ {
if (QFile *file = qobject_cast<QFile *>(f)) { if (QFile *file = qobject_cast<QFile *>(f)) {
if (file->fileName().endsWith(QLatin1String(".json"))) if (file->fileName().endsWith(".json"_L1))
return true; return true;
} }
@ -62,7 +59,7 @@ bool JsonConverter::probeFile(QIODevice *f)
return false; return false;
} }
QVariant JsonConverter::loadFile(QIODevice *f, Converter *&outputConverter) QVariant JsonConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{ {
if (!outputConverter) if (!outputConverter)
outputConverter = this; outputConverter = this;
@ -87,13 +84,14 @@ QVariant JsonConverter::loadFile(QIODevice *f, Converter *&outputConverter)
return doc.toVariant(); return doc.toVariant();
} }
void JsonConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) void JsonConverter::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{ {
QJsonDocument::JsonFormat format = QJsonDocument::Indented; QJsonDocument::JsonFormat format = QJsonDocument::Indented;
for (const QString &s : options) { for (const QString &s : options) {
if (s == QLatin1String("compact=no")) { if (s == "compact=no"_L1) {
format = QJsonDocument::Indented; format = QJsonDocument::Indented;
} else if (s == QLatin1String("compact=yes")) { } else if (s == "compact=yes"_L1) {
format = QJsonDocument::Compact; format = QJsonDocument::Compact;
} else { } else {
fprintf(stderr, "Unknown option '%s' to JSON output. Valid options are:\n%s", fprintf(stderr, "Unknown option '%s' to JSON output. Valid options are:\n%s",

View File

@ -8,18 +8,16 @@
class JsonConverter : public Converter class JsonConverter : public Converter
{ {
public:
JsonConverter();
// Converter interface // Converter interface
public: public:
QString name() override; QString name() const override;
Direction directions() override; Directions directions() const override;
Options outputOptions() override; Options outputOptions() const override;
const char *optionsHelp() override; const char *optionsHelp() const override;
bool probeFile(QIODevice *f) override; bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, Converter *&outputConverter) override; QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override; void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
}; };
#endif // JSONCONVERTER_H #endif // JSONCONVERTER_H

View File

@ -11,12 +11,14 @@
#include <stdio.h> #include <stdio.h>
static QList<Converter *> *availableConverters; using namespace Qt::StringLiterals;
static QList<const Converter *> *availableConverters;
Converter::Converter() Converter::Converter()
{ {
if (!availableConverters) if (!availableConverters)
availableConverters = new QList<Converter *>; availableConverters = new QList<const Converter *>;
availableConverters->append(this); availableConverters->append(this);
} }
@ -31,64 +33,68 @@ int main(int argc, char *argv[])
QStringList inputFormats; QStringList inputFormats;
QStringList outputFormats; QStringList outputFormats;
for (Converter *conv : std::as_const(*availableConverters)) { for (const Converter *conv : std::as_const(*availableConverters)) {
auto direction = conv->directions(); auto direction = conv->directions();
QString name = conv->name(); QString name = conv->name();
if (direction & Converter::In) if (direction.testFlag(Converter::Direction::In))
inputFormats << name; inputFormats << name;
if (direction & Converter::Out) if (direction.testFlag(Converter::Direction::Out))
outputFormats << name; outputFormats << name;
} }
inputFormats.sort(); inputFormats.sort();
outputFormats.sort(); outputFormats.sort();
inputFormats.prepend("auto"); inputFormats.prepend("auto"_L1);
outputFormats.prepend("auto"); outputFormats.prepend("auto"_L1);
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription(QStringLiteral("Qt file format conversion tool")); parser.setApplicationDescription("Qt file format conversion tool"_L1);
parser.addHelpOption(); parser.addHelpOption();
QCommandLineOption inputFormatOption(QStringList{"I", "input-format"}); QCommandLineOption inputFormatOption(QStringList{ "I"_L1, "input-format"_L1 });
inputFormatOption.setDescription(QLatin1String("Select the input format for the input file. Available formats: ") + inputFormatOption.setDescription(
inputFormats.join(", ")); "Select the input format for the input file. Available formats: "_L1
inputFormatOption.setValueName("format"); + inputFormats.join(", "_L1));
inputFormatOption.setValueName("format"_L1);
inputFormatOption.setDefaultValue(inputFormats.constFirst()); inputFormatOption.setDefaultValue(inputFormats.constFirst());
parser.addOption(inputFormatOption); parser.addOption(inputFormatOption);
QCommandLineOption outputFormatOption(QStringList{"O", "output-format"}); QCommandLineOption outputFormatOption(QStringList{ "O"_L1, "output-format"_L1 });
outputFormatOption.setDescription(QLatin1String("Select the output format for the output file. Available formats: ") + outputFormatOption.setDescription(
outputFormats.join(", ")); "Select the output format for the output file. Available formats: "_L1
outputFormatOption.setValueName("format"); + outputFormats.join(", "_L1));
outputFormatOption.setValueName("format"_L1);
outputFormatOption.setDefaultValue(outputFormats.constFirst()); outputFormatOption.setDefaultValue(outputFormats.constFirst());
parser.addOption(outputFormatOption); parser.addOption(outputFormatOption);
QCommandLineOption optionOption(QStringList{"o", "option"}); QCommandLineOption optionOption(QStringList{ "o"_L1, "option"_L1 });
optionOption.setDescription(QStringLiteral("Format-specific options. Use --format-options to find out what options are available.")); optionOption.setDescription(
optionOption.setValueName("options..."); "Format-specific options. Use --format-options to find out what options are available."_L1);
optionOption.setValueName("options..."_L1);
optionOption.setDefaultValues({}); optionOption.setDefaultValues({});
parser.addOption(optionOption); parser.addOption(optionOption);
QCommandLineOption formatOptionsOption("format-options"); QCommandLineOption formatOptionsOption("format-options"_L1);
formatOptionsOption.setDescription(QStringLiteral("Prints the list of valid options for --option for the converter format <format>.")); formatOptionsOption.setDescription(
formatOptionsOption.setValueName("format"); "Prints the list of valid options for --option for the converter format <format>."_L1);
formatOptionsOption.setValueName("format"_L1);
parser.addOption(formatOptionsOption); parser.addOption(formatOptionsOption);
parser.addPositionalArgument(QStringLiteral("[source]"), parser.addPositionalArgument("[source]"_L1, "File to read from (stdin if none)"_L1);
QStringLiteral("File to read from (stdin if none)")); parser.addPositionalArgument("[destination]"_L1, "File to write to (stdout if none)"_L1);
parser.addPositionalArgument(QStringLiteral("[destination]"),
QStringLiteral("File to write to (stdout if none)"));
parser.process(app); parser.process(app);
if (parser.isSet(formatOptionsOption)) { if (parser.isSet(formatOptionsOption)) {
QString format = parser.value(formatOptionsOption); QString format = parser.value(formatOptionsOption);
for (Converter *conv : std::as_const(*availableConverters)) { for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->name() == format) { if (conv->name() == format) {
const char *help = conv->optionsHelp(); const char *help = conv->optionsHelp();
if (help) if (help) {
printf("The following options are available for format '%s':\n\n%s", qPrintable(format), help); printf("The following options are available for format '%s':\n\n%s",
else qPrintable(format), help);
} else {
printf("Format '%s' supports no options.\n", qPrintable(format)); printf("Format '%s' supports no options.\n", qPrintable(format));
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
} }
@ -97,10 +103,10 @@ int main(int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
Converter *inconv = nullptr; const Converter *inconv = nullptr;
QString format = parser.value(inputFormatOption); QString format = parser.value(inputFormatOption);
if (format != "auto") { if (format != "auto"_L1) {
for (Converter *conv : std::as_const(*availableConverters)) { for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->name() == format) { if (conv->name() == format) {
inconv = conv; inconv = conv;
break; break;
@ -113,10 +119,10 @@ int main(int argc, char *argv[])
} }
} }
Converter *outconv = nullptr; const Converter *outconv = nullptr;
format = parser.value(outputFormatOption); format = parser.value(outputFormatOption);
if (format != "auto") { if (format != "auto"_L1) {
for (Converter *conv : std::as_const(*availableConverters)) { for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->name() == format) { if (conv->name() == format) {
outconv = conv; outconv = conv;
break; break;
@ -155,8 +161,9 @@ int main(int argc, char *argv[])
if (!inconv) { if (!inconv) {
// probe the input to find a file format // probe the input to find a file format
for (Converter *conv : std::as_const(*availableConverters)) { for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->directions() & Converter::In && conv->probeFile(&input)) { if (conv->directions().testFlag(Converter::Direction::In)
&& conv->probeFile(&input)) {
inconv = conv; inconv = conv;
break; break;
} }
@ -170,8 +177,9 @@ int main(int argc, char *argv[])
if (!outconv) { if (!outconv) {
// probe the output to find a file format // probe the output to find a file format
for (Converter *conv : std::as_const(*availableConverters)) { for (const Converter *conv : std::as_const(*availableConverters)) {
if (conv->directions() & Converter::Out && conv->probeFile(&output)) { if (conv->directions().testFlag(Converter::Direction::Out)
&& conv->probeFile(&output)) {
outconv = conv; outconv = conv;
break; break;
} }

View File

@ -3,36 +3,38 @@
#include "nullconverter.h" #include "nullconverter.h"
using namespace Qt::StringLiterals;
static NullConverter nullConverter; static NullConverter nullConverter;
Converter* Converter::null = &nullConverter; Converter *Converter::null = &nullConverter;
QString NullConverter::name() QString NullConverter::name() const
{ {
return QLatin1String("null"); return "null"_L1;
} }
Converter::Direction NullConverter::directions() Converter::Directions NullConverter::directions() const
{ {
return Out; return Direction::Out;
} }
Converter::Options NullConverter::outputOptions() Converter::Options NullConverter::outputOptions() const
{ {
return SupportsArbitraryMapKeys; return SupportsArbitraryMapKeys;
} }
const char *NullConverter::optionsHelp() const char *NullConverter::optionsHelp() const
{ {
return nullptr; return nullptr;
} }
bool NullConverter::probeFile(QIODevice *f) bool NullConverter::probeFile(QIODevice *f) const
{ {
Q_UNUSED(f); Q_UNUSED(f);
return false; return false;
} }
QVariant NullConverter::loadFile(QIODevice *f, Converter *&outputConverter) QVariant NullConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{ {
Q_UNUSED(f); Q_UNUSED(f);
Q_UNUSED(outputConverter); Q_UNUSED(outputConverter);
@ -40,10 +42,12 @@ QVariant NullConverter::loadFile(QIODevice *f, Converter *&outputConverter)
return QVariant(); return QVariant();
} }
void NullConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) void NullConverter::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{ {
if (!options.isEmpty()) { if (!options.isEmpty()) {
fprintf(stderr, "Unknown option '%s' to null output. This format has no options.\n", qPrintable(options.first())); fprintf(stderr, "Unknown option '%s' to null output. This format has no options.\n",
qPrintable(options.first()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@ -10,13 +10,14 @@ class NullConverter : public Converter
{ {
// Converter interface // Converter interface
public: public:
QString name() override; QString name() const override;
Direction directions() override; Directions directions() const override;
Options outputOptions() override; Options outputOptions() const override;
const char *optionsHelp() override; const char *optionsHelp() const override;
bool probeFile(QIODevice *f) override; bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, Converter *&outputConverter) override; QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override; void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
}; };
#endif // NULLCONVERTER_H #endif // NULLCONVERTER_H

View File

@ -6,6 +6,8 @@
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
using namespace Qt::StringLiterals;
static void dumpVariant(QTextStream &out, const QVariant &v) static void dumpVariant(QTextStream &out, const QVariant &v)
{ {
switch (v.userType()) { switch (v.userType()) {
@ -42,67 +44,62 @@ static void dumpVariant(QTextStream &out, const QVariant &v)
} }
} }
QString TextConverter::name() QString TextConverter::name() const
{ {
return QStringLiteral("text"); return "text"_L1;
} }
Converter::Direction TextConverter::directions() Converter::Directions TextConverter::directions() const
{ {
return InOut; return Direction::InOut;
} }
Converter::Options TextConverter::outputOptions() Converter::Options TextConverter::outputOptions() const
{ {
return {}; return {};
} }
const char *TextConverter::optionsHelp() const char *TextConverter::optionsHelp() const
{ {
return nullptr; return nullptr;
} }
bool TextConverter::probeFile(QIODevice *f) bool TextConverter::probeFile(QIODevice *f) const
{ {
if (QFile *file = qobject_cast<QFile *>(f)) if (QFile *file = qobject_cast<QFile *>(f))
return file->fileName().endsWith(QLatin1String(".txt")); return file->fileName().endsWith(".txt"_L1);
return false; return false;
} }
QVariant TextConverter::loadFile(QIODevice *f, Converter *&outputConverter) QVariant TextConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{ {
if (!outputConverter) if (!outputConverter)
outputConverter = this; outputConverter = this;
QVariantList list; QVariantList list;
QTextStream in(f); QTextStream in(f);
QString line ; QString line;
while (!in.atEnd()) { while (!in.atEnd()) {
in.readLineInto(&line); in.readLineInto(&line);
bool ok; bool ok;
qint64 v = line.toLongLong(&ok);
if (ok) { if (qint64 v = line.toLongLong(&ok); ok)
list.append(v); list.append(v);
continue; else if (double d = line.toDouble(&ok); ok)
}
double d = line.toDouble(&ok);
if (ok) {
list.append(d); list.append(d);
continue; else
} list.append(line);
list.append(line);
} }
return list; return list;
} }
void TextConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) void TextConverter::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{ {
if (!options.isEmpty()) { if (!options.isEmpty()) {
fprintf(stderr, "Unknown option '%s' to text output. This format has no options.\n", qPrintable(options.first())); fprintf(stderr, "Unknown option '%s' to text output. This format has no options.\n",
qPrintable(options.first()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View File

@ -8,16 +8,16 @@
class TextConverter : public Converter class TextConverter : public Converter
{ {
// Converter interface // Converter interface
public: public:
QString name() override; QString name() const override;
Direction directions() override; Directions directions() const override;
Options outputOptions() override; Options outputOptions() const override;
const char *optionsHelp() override; const char *optionsHelp() const override;
bool probeFile(QIODevice *f) override; bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, Converter *&outputConverter) override; QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override; void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
}; };
#endif // TEXTCONVERTER_H #endif // TEXTCONVERTER_H

View File

@ -13,8 +13,9 @@
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QXmlStreamWriter> #include <QXmlStreamWriter>
static const char xmlOptionHelp[] = using namespace Qt::StringLiterals;
"compact=no|yes Use compact XML form.\n";
static const char xmlOptionHelp[] = "compact=no|yes Use compact XML form.\n";
static XmlConverter xmlConverter; static XmlConverter xmlConverter;
@ -23,7 +24,7 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
static QVariantList listFromXml(QXmlStreamReader &xml, Converter::Options options) static QVariantList listFromXml(QXmlStreamReader &xml, Converter::Options options)
{ {
QVariantList list; QVariantList list;
while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == QLatin1String("list"))) { while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == "list"_L1)) {
xml.readNext(); xml.readNext();
switch (xml.tokenType()) { switch (xml.tokenType()) {
case QXmlStreamReader::StartElement: case QXmlStreamReader::StartElement:
@ -47,8 +48,7 @@ static QVariantList listFromXml(QXmlStreamReader &xml, Converter::Options option
break; break;
} }
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString())); qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -57,10 +57,11 @@ static QVariantList listFromXml(QXmlStreamReader &xml, Converter::Options option
return list; return list;
} }
static VariantOrderedMap::value_type mapEntryFromXml(QXmlStreamReader &xml, Converter::Options options) static VariantOrderedMap::value_type mapEntryFromXml(QXmlStreamReader &xml,
Converter::Options options)
{ {
QVariant key, value; QVariant key, value;
while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == QLatin1String("entry"))) { while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == "entry"_L1)) {
xml.readNext(); xml.readNext();
switch (xml.tokenType()) { switch (xml.tokenType()) {
case QXmlStreamReader::StartElement: case QXmlStreamReader::StartElement:
@ -89,8 +90,7 @@ static VariantOrderedMap::value_type mapEntryFromXml(QXmlStreamReader &xml, Conv
break; break;
} }
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString())); qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -103,11 +103,11 @@ static QVariant mapFromXml(QXmlStreamReader &xml, Converter::Options options)
QVariantMap map1; QVariantMap map1;
VariantOrderedMap map2; VariantOrderedMap map2;
while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == QLatin1String("map"))) { while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == "map"_L1)) {
xml.readNext(); xml.readNext();
switch (xml.tokenType()) { switch (xml.tokenType()) {
case QXmlStreamReader::StartElement: case QXmlStreamReader::StartElement:
if (xml.name() == QLatin1String("entry")) { if (xml.name() == "entry"_L1) {
auto pair = mapEntryFromXml(xml, options); auto pair = mapEntryFromXml(xml, options);
if (options & Converter::SupportsArbitraryMapKeys) if (options & Converter::SupportsArbitraryMapKeys)
map2.append(pair); map2.append(pair);
@ -134,8 +134,7 @@ static QVariant mapFromXml(QXmlStreamReader &xml, Converter::Options options)
break; break;
} }
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(xml.name().toString())); qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -149,18 +148,18 @@ static QVariant mapFromXml(QXmlStreamReader &xml, Converter::Options options)
static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options) static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options)
{ {
QStringView name = xml.name(); QStringView name = xml.name();
if (name == QLatin1String("list")) if (name == "list"_L1)
return listFromXml(xml, options); return listFromXml(xml, options);
if (name == QLatin1String("map")) if (name == "map"_L1)
return mapFromXml(xml, options); return mapFromXml(xml, options);
if (name != QLatin1String("value")) { if (name != "value"_L1) {
fprintf(stderr, "%lld:%lld: Invalid XML key '%s'.\n", fprintf(stderr, "%lld:%lld: Invalid XML key '%s'.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(name.toString())); xml.lineNumber(), xml.columnNumber(), qPrintable(name.toString()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
QXmlStreamAttributes attrs = xml.attributes(); QXmlStreamAttributes attrs = xml.attributes();
QStringView type = attrs.value(QLatin1String("type")); QStringView type = attrs.value("type"_L1);
forever { forever {
xml.readNext(); xml.readNext();
@ -169,8 +168,7 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
if (xml.isCDATA() || xml.isCharacters() || xml.isEndElement()) if (xml.isCDATA() || xml.isCharacters() || xml.isEndElement())
break; break;
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(name.toString())); qPrintable(xml.tokenString()), qPrintable(name.toString()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -180,45 +178,45 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
text = text.trimmed(); text = text.trimmed();
QVariant result; QVariant result;
bool ok;
if (type.isEmpty()) { if (type.isEmpty()) {
// ok // ok
} else if (type == QLatin1String("number")) { } else if (type == "number"_L1) {
// try integer first // try integer first
bool ok;
qint64 v = text.toLongLong(&ok); qint64 v = text.toLongLong(&ok);
if (ok) { if (ok) {
result = v; result = v;
} else { } else {
// let's see floating point // let's see floating point
double d = text.toDouble(&ok); double d = text.toDouble(&ok);
result = d;
if (!ok) { if (!ok) {
fprintf(stderr, "%lld:%lld: Invalid XML: could not interpret '%s' as a number.\n", fprintf(stderr, "%lld:%lld: Invalid XML: could not interpret '%s' as a number.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString())); xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
result = d;
} }
} else if (type == QLatin1String("bytes")) { } else if (type == "bytes"_L1) {
QByteArray data = text.toLatin1(); QByteArray data = text.toLatin1();
QStringView encoding = attrs.value("encoding"); QStringView encoding = attrs.value("encoding");
if (encoding == QLatin1String("base64url")) { if (encoding == "base64url"_L1) {
result = QByteArray::fromBase64(data, QByteArray::Base64UrlEncoding); result = QByteArray::fromBase64(data, QByteArray::Base64UrlEncoding);
} else if (encoding == QLatin1String("hex")) { } else if (encoding == "hex"_L1) {
result = QByteArray::fromHex(data); result = QByteArray::fromHex(data);
} else if (encoding.isEmpty() || encoding == QLatin1String("base64")) { } else if (encoding.isEmpty() || encoding == "base64"_L1) {
result = QByteArray::fromBase64(data); result = QByteArray::fromBase64(data);
} else { } else {
fprintf(stderr, "%lld:%lld: Invalid XML: unknown encoding '%s' for bytes.\n", fprintf(stderr, "%lld:%lld: Invalid XML: unknown encoding '%s' for bytes.\n",
xml.lineNumber(), xml.columnNumber(), qPrintable(encoding.toString())); xml.lineNumber(), xml.columnNumber(), qPrintable(encoding.toString()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} else if (type == QLatin1String("string")) { } else if (type == "string"_L1) {
result = text.toString(); result = text.toString();
} else if (type == QLatin1String("null")) { } else if (type == "null"_L1) {
result = QVariant::fromValue(nullptr); result = QVariant::fromValue(nullptr);
} else if (type == QLatin1String("CBOR simple type")) { } else if (type == "CBOR simple type"_L1) {
result = QVariant::fromValue(QCborSimpleType(text.toShort())); result = QVariant::fromValue(QCborSimpleType(text.toShort()));
} else if (type == QLatin1String("bits")) { } else if (type == "bits"_L1) {
QBitArray ba; QBitArray ba;
ba.resize(text.size()); ba.resize(text.size());
qsizetype n = 0; qsizetype n = 0;
@ -238,13 +236,13 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
result = ba; result = ba;
} else { } else {
int id = QMetaType::UnknownType; int id = QMetaType::UnknownType;
if (type == QLatin1String("datetime")) if (type == "datetime"_L1)
id = QMetaType::QDateTime; id = QMetaType::QDateTime;
else if (type == QLatin1String("url")) else if (type == "url"_L1)
id = QMetaType::QUrl; id = QMetaType::QUrl;
else if (type == QLatin1String("uuid")) else if (type == "uuid"_L1)
id = QMetaType::QUuid; id = QMetaType::QUuid;
else if (type == QLatin1String("regex")) else if (type == "regex"_L1)
id = QMetaType::QRegularExpression; id = QMetaType::QRegularExpression;
else else
id = QMetaType::fromName(type.toLatin1()).id(); id = QMetaType::fromName(type.toLatin1()).id();
@ -267,8 +265,7 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
} while (xml.isComment() || xml.isWhitespace()); } while (xml.isComment() || xml.isWhitespace());
if (!xml.isEndElement()) { if (!xml.isEndElement()) {
fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n", xml.lineNumber(), xml.columnNumber(),
xml.lineNumber(), xml.columnNumber(),
qPrintable(xml.tokenString()), qPrintable(name.toString())); qPrintable(xml.tokenString()), qPrintable(name.toString()));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -287,9 +284,9 @@ static void variantToXml(QXmlStreamWriter &xml, const QVariant &v)
variantToXml(xml, v); variantToXml(xml, v);
xml.writeEndElement(); xml.writeEndElement();
} else if (type == QMetaType::QVariantMap || type == qMetaTypeId<VariantOrderedMap>()) { } else if (type == QMetaType::QVariantMap || type == qMetaTypeId<VariantOrderedMap>()) {
const VariantOrderedMap map = (type == QMetaType::QVariantMap) ? const VariantOrderedMap map = (type == QMetaType::QVariantMap)
VariantOrderedMap(v.toMap()) : ? VariantOrderedMap(v.toMap())
qvariant_cast<VariantOrderedMap>(v); : qvariant_cast<VariantOrderedMap>(v);
xml.writeStartElement("map"); xml.writeStartElement("map");
for (const auto &pair : map) { for (const auto &pair : map) {
@ -301,7 +298,7 @@ static void variantToXml(QXmlStreamWriter &xml, const QVariant &v)
xml.writeEndElement(); xml.writeEndElement();
} else { } else {
xml.writeStartElement("value"); xml.writeStartElement("value");
QString typeString = QStringLiteral("type"); QString typeString = "type"_L1;
switch (type) { switch (type) {
case QMetaType::Short: case QMetaType::Short:
case QMetaType::UShort: case QMetaType::UShort:
@ -399,37 +396,37 @@ static void variantToXml(QXmlStreamWriter &xml, const QVariant &v)
} }
} }
QString XmlConverter::name() QString XmlConverter::name() const
{ {
return QStringLiteral("xml"); return "xml"_L1;
} }
Converter::Direction XmlConverter::directions() Converter::Directions XmlConverter::directions() const
{ {
return InOut; return Direction::InOut;
} }
Converter::Options XmlConverter::outputOptions() Converter::Options XmlConverter::outputOptions() const
{ {
return SupportsArbitraryMapKeys; return SupportsArbitraryMapKeys;
} }
const char *XmlConverter::optionsHelp() const char *XmlConverter::optionsHelp() const
{ {
return xmlOptionHelp; return xmlOptionHelp;
} }
bool XmlConverter::probeFile(QIODevice *f) bool XmlConverter::probeFile(QIODevice *f) const
{ {
if (QFile *file = qobject_cast<QFile *>(f)) { if (QFile *file = qobject_cast<QFile *>(f)) {
if (file->fileName().endsWith(QLatin1String(".xml"))) if (file->fileName().endsWith(".xml"_L1))
return true; return true;
} }
return f->isReadable() && f->peek(5) == "<?xml"; return f->isReadable() && f->peek(5) == "<?xml";
} }
QVariant XmlConverter::loadFile(QIODevice *f, Converter *&outputConverter) QVariant XmlConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{ {
if (!outputConverter) if (!outputConverter)
outputConverter = this; outputConverter = this;
@ -445,13 +442,14 @@ QVariant XmlConverter::loadFile(QIODevice *f, Converter *&outputConverter)
return v; return v;
} }
void XmlConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) void XmlConverter::saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const
{ {
bool compact = false; bool compact = false;
for (const QString &s : options) { for (const QString &s : options) {
if (s == QLatin1String("compact=no")) { if (s == "compact=no"_L1) {
compact = false; compact = false;
} else if (s == QLatin1String("compact=yes")) { } else if (s == "compact=yes"_L1) {
compact = true; compact = true;
} else { } else {
fprintf(stderr, "Unknown option '%s' to XML output. Valid options are:\n%s", fprintf(stderr, "Unknown option '%s' to XML output. Valid options are:\n%s",

View File

@ -10,13 +10,14 @@ class XmlConverter : public Converter
{ {
// Converter interface // Converter interface
public: public:
QString name() override; QString name() const override;
Direction directions() override; Directions directions() const override;
Options outputOptions() override; Options outputOptions() const override;
const char *optionsHelp() override; const char *optionsHelp() const override;
bool probeFile(QIODevice *f) override; bool probeFile(QIODevice *f) const override;
QVariant loadFile(QIODevice *f, Converter *&outputConverter) override; QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override; void saveFile(QIODevice *f, const QVariant &contents,
const QStringList &options) const override;
}; };
#endif // XMLCONVERTER_H #endif // XMLCONVERTER_H

View File

@ -1,26 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
/*
main.cpp
Provides the main function for the RSS news reader example.
*/
#include <QtWidgets>
#include "rsslisting.h"
/*!
Create an application and a main widget. Open the main widget for
user input, and exit with an appropriate return value when it is
closed.
*/
int main(int argc, char **argv)
{
QApplication app(argc, argv);
RSSListing *rsslisting = new RSSListing;
rsslisting->show();
return app.exec();
}

View File

@ -1,211 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
/*
rsslisting.cpp
Provides a widget for displaying news items from RDF news sources.
RDF is an XML-based format for storing items of information (see
http://www.w3.org/RDF/ for details).
The widget itself provides a simple user interface for specifying
the URL of a news source, and controlling the downloading of news.
The widget downloads and parses the XML asynchronously, feeding the
data to an XML reader in pieces. This allows the user to interrupt
its operation, and also allows very large data sources to be read.
*/
#include <QtCore>
#include <QtWidgets>
#include <QtNetwork>
#include "rsslisting.h"
/*
Constructs an RSSListing widget with a simple user interface, and sets
up the XML reader to use a custom handler class.
The user interface consists of a line edit, a push button, and a
list view widget. The line edit is used for entering the URLs of news
sources; the push button starts the process of reading the
news.
*/
RSSListing::RSSListing(QWidget *parent)
: QWidget(parent), currentReply(0)
{
lineEdit = new QLineEdit(this);
lineEdit->setText("http://blog.qt.io/feed/");
fetchButton = new QPushButton(tr("Fetch"), this);
treeWidget = new QTreeWidget(this);
connect(treeWidget, &QTreeWidget::itemActivated,
this, &RSSListing::itemActivated);
QStringList headerLabels;
headerLabels << tr("Title") << tr("Link");
treeWidget->setHeaderLabels(headerLabels);
treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
connect(&manager, &QNetworkAccessManager::finished,
this, &RSSListing::finished);
connect(lineEdit, &QLineEdit::returnPressed, this, &RSSListing::fetch);
connect(fetchButton, &QPushButton::clicked, this, &RSSListing::fetch);
QVBoxLayout *layout = new QVBoxLayout(this);
QHBoxLayout *hboxLayout = new QHBoxLayout;
hboxLayout->addWidget(lineEdit);
hboxLayout->addWidget(fetchButton);
layout->addLayout(hboxLayout);
layout->addWidget(treeWidget);
setWindowTitle(tr("RSS listing example"));
resize(640,480);
}
/*
Starts the network request and connects the needed signals
*/
void RSSListing::get(const QUrl &url)
{
QNetworkRequest request(url);
if (currentReply) {
currentReply->disconnect(this);
currentReply->deleteLater();
}
currentReply = manager.get(request);
connect(currentReply, &QNetworkReply::readyRead, this, &RSSListing::readyRead);
connect(currentReply, &QNetworkReply::metaDataChanged, this, &RSSListing::metaDataChanged);
connect(currentReply, &QNetworkReply::errorOccurred, this, &RSSListing::error);
}
/*
Starts fetching data from a news source specified in the line
edit widget.
The line edit is made read only to prevent the user from modifying its
contents during the fetch; this is only for cosmetic purposes.
The fetch button is disabled, the list view is cleared, and we
define the last list view item to be 0, meaning that there are no
existing items in the list.
A URL is created with the raw contents of the line edit and
a get is initiated.
*/
void RSSListing::fetch()
{
lineEdit->setReadOnly(true);
fetchButton->setEnabled(false);
treeWidget->clear();
xml.clear();
QUrl url(lineEdit->text());
get(url);
}
void RSSListing::metaDataChanged()
{
QUrl redirectionTarget = currentReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
if (redirectionTarget.isValid()) {
get(redirectionTarget);
}
}
/*
Reads data received from the RDF source.
We read all the available data, and pass it to the XML
stream reader. Then we call the XML parsing function.
*/
void RSSListing::readyRead()
{
int statusCode = currentReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode >= 200 && statusCode < 300) {
QByteArray data = currentReply->readAll();
xml.addData(data);
parseXml();
}
}
/*
Finishes processing an HTTP request.
The default behavior is to keep the text edit read only.
If an error has occurred, the user interface is made available
to the user for further input, allowing a new fetch to be
started.
If the HTTP get request has finished, we make the
user interface available to the user for further input.
*/
void RSSListing::finished(QNetworkReply *reply)
{
Q_UNUSED(reply);
lineEdit->setReadOnly(false);
fetchButton->setEnabled(true);
}
/*
Parses the XML data and creates treeWidget items accordingly.
*/
void RSSListing::parseXml()
{
while (!xml.atEnd()) {
xml.readNext();
if (xml.isStartElement()) {
if (xml.name() == u"item")
linkString = xml.attributes().value("rss:about").toString();
currentTag = xml.name().toString();
} else if (xml.isEndElement()) {
if (xml.name() == u"item") {
QTreeWidgetItem *item = new QTreeWidgetItem;
item->setText(0, titleString);
item->setText(1, linkString);
treeWidget->addTopLevelItem(item);
titleString.clear();
linkString.clear();
}
} else if (xml.isCharacters() && !xml.isWhitespace()) {
if (currentTag == "title")
titleString += xml.text();
else if (currentTag == "link")
linkString += xml.text();
}
}
if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString();
}
}
/*
Open the link in the browser
*/
void RSSListing::itemActivated(QTreeWidgetItem * item)
{
QDesktopServices::openUrl(QUrl(item->text(1)));
}
void RSSListing::error(QNetworkReply::NetworkError)
{
qWarning("error retrieving RSS feed");
currentReply->disconnect(this);
currentReply->deleteLater();
currentReply = 0;
}

View File

@ -4,6 +4,10 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(savegame LANGUAGES CXX) project(savegame LANGUAGES CXX)
if (ANDROID)
message(FATAL_ERROR "This project cannot be built on Android.")
endif()
if(NOT DEFINED INSTALL_EXAMPLESDIR) if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples") set(INSTALL_EXAMPLESDIR "examples")
endif() endif()

View File

@ -6,15 +6,10 @@
#include <QMetaEnum> #include <QMetaEnum>
#include <QTextStream> #include <QTextStream>
Character::Character() Character::Character() = default;
= default;
Character::Character(const QString &name, Character::Character(const QString &name, int level, Character::ClassType classType)
int level, : mName(name), mLevel(level), mClassType(classType)
Character::ClassType classType) :
mName(name),
mLevel(level),
mClassType(classType)
{ {
} }
@ -48,35 +43,41 @@ void Character::setClassType(Character::ClassType classType)
mClassType = classType; mClassType = classType;
} }
//! [0] //! [fromJson]
void Character::read(const QJsonObject &json) Character Character::fromJson(const QJsonObject &json)
{ {
if (json.contains("name") && json["name"].isString()) Character result;
mName = json["name"].toString();
if (json.contains("level") && json["level"].isDouble()) if (const QJsonValue v = json["name"]; v.isString())
mLevel = json["level"].toInt(); result.mName = v.toString();
if (json.contains("classType") && json["classType"].isDouble()) if (const QJsonValue v = json["level"]; v.isDouble())
mClassType = ClassType(json["classType"].toInt()); result.mLevel = v.toInt();
if (const QJsonValue v = json["classType"]; v.isDouble())
result.mClassType = ClassType(v.toInt());
return result;
} }
//! [0] //! [fromJson]
//! [1] //! [toJson]
void Character::write(QJsonObject &json) const QJsonObject Character::toJson() const
{ {
QJsonObject json;
json["name"] = mName; json["name"] = mName;
json["level"] = mLevel; json["level"] = mLevel;
json["classType"] = mClassType; json["classType"] = mClassType;
return json;
} }
//! [1] //! [toJson]
void Character::print(int indentation) const void Character::print(QTextStream &s, int indentation) const
{ {
const QString indent(indentation * 2, ' '); const QString indent(indentation * 2, ' ');
QTextStream(stdout) << indent << "Name:\t" << mName << "\n"; const QString className = QMetaEnum::fromType<ClassType>().valueToKey(mClassType);
QTextStream(stdout) << indent << "Level:\t" << mLevel << "\n";
QString className = QMetaEnum::fromType<ClassType>().valueToKey(mClassType); s << indent << "Name:\t" << mName << "\n"
QTextStream(stdout) << indent << "Class:\t" << className << "\n"; << indent << "Level:\t" << mLevel << "\n"
<< indent << "Class:\t" << className << "\n";
} }

View File

@ -8,15 +8,15 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
QT_FORWARD_DECLARE_CLASS(QTextStream)
//! [0] //! [0]
class Character class Character
{ {
Q_GADGET Q_GADGET
public: public:
enum ClassType { enum ClassType { Warrior, Mage, Archer };
Warrior, Mage, Archer
};
Q_ENUM(ClassType) Q_ENUM(ClassType)
Character(); Character();
@ -31,10 +31,11 @@ public:
ClassType classType() const; ClassType classType() const;
void setClassType(ClassType classType); void setClassType(ClassType classType);
void read(const QJsonObject &json); static Character fromJson(const QJsonObject &json);
void write(QJsonObject &json) const; QJsonObject toJson() const;
void print(QTextStream &s, int indentation = 0) const;
void print(int indentation = 0) const;
private: private:
QString mName; QString mName;
int mLevel = 0; int mLevel = 0;

View File

@ -3,7 +3,7 @@
/*! /*!
\example serialization/savegame \example serialization/savegame
\examplecategory {Input/Output} \examplecategory {Data Processing & I/O}
\title JSON Save Game Example \title JSON Save Game Example
\brief The JSON Save Game example demonstrates how to save and load a \brief The JSON Save Game example demonstrates how to save and load a
@ -11,11 +11,12 @@
Many games provide save functionality, so that the player's progress through Many games provide save functionality, so that the player's progress through
the game can be saved and loaded at a later time. The process of saving a the game can be saved and loaded at a later time. The process of saving a
game generally involves serializing each game object's member variables game generally involves serializing each game object's member variables to a
to a file. Many formats can be used for this purpose, one of which is JSON. file. Many formats can be used for this purpose, one of which is JSON. With
With QJsonDocument, you also have the ability to serialize a document in a QJsonDocument, you also have the ability to serialize a document in a \l
\l {RFC 7049} {CBOR} format, which is great if you {RFC 7049} {CBOR} format, which is great if you don't want the save file to
don't want the save file to be readable, or if you need to keep the file size down. be easy to read (but see \l {Parsing and displaying CBOR data} for how it \e
can be read), or if you need to keep the file size down.
In this example, we'll demonstrate how to save and load a simple game to In this example, we'll demonstrate how to save and load a simple game to
and from JSON and binary formats. and from JSON and binary formats.
@ -25,45 +26,83 @@
The Character class represents a non-player character (NPC) in our game, and The Character class represents a non-player character (NPC) in our game, and
stores the player's name, level, and class type. stores the player's name, level, and class type.
It provides read() and write() functions to serialise its member variables. It provides static fromJson() and non-static toJson() functions to
serialise itself.
\note This pattern (fromJson()/toJson()) works because QJsonObjects can be
constructed independent of an owning QJsonDocument, and because the data
types being (de)serialized here are value types, so can be copied. When
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()
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.
\snippet serialization/savegame/character.h 0 \snippet serialization/savegame/character.h 0
Of particular interest to us are the read and write function Of particular interest to us are the fromJson() and toJson() function
implementations: implementations:
\snippet serialization/savegame/character.cpp 0 \snippet serialization/savegame/character.cpp fromJson
In the read() function, we assign Character's members values from the In the fromJson() function, we construct a local \c result Character object
QJsonObject argument. You can use either \l QJsonObject::operator[]() or and assign \c{result}'s members values from the QJsonObject argument. You
QJsonObject::value() to access values within the JSON object; both are can use either \l QJsonObject::operator[]() or QJsonObject::value() to
const functions and return QJsonValue::Undefined if the key is invalid. We access values within the JSON object; both are const functions and return
check if the keys are valid before attempting to read them with QJsonValue::Undefined if the key is invalid. In particular, the \c{is...}
QJsonObject::contains(). functions (for example \l QJsonValue::isString(), \l
QJsonValue::isDouble()) return \c false for QJsonValue::Undefined, so we
can check for existence as well as the correct type in a single lookup.
\snippet serialization/savegame/character.cpp 1 If a value does not exist in the JSON object, or has the wrong type, we
don't write to the corresponding \c result member, either, thereby
preserving any values the default constructor may have set. This means
default values are centrally defined in one location (the default
constructor) and need not be repeated in serialisation code
(\l{https://en.wikipedia.org/wiki/Don%27t_repeat_yourself}{DRY}).
In the write() function, we do the reverse of the read() function; assign Observe the use of
values from the Character object to the JSON object. As with accessing \l{https://en.cppreference.com/w/cpp/language/if#If_statements_with_initializer}
values, there are two ways to set values on a QJsonObject: {C++17 if-with-initializer} to separate scoping and checking of the variable \c v.
\l QJsonObject::operator[]() and QJsonObject::insert(). Both will override This means we can keep the variable name short, because its scope is limited.
any existing value at the given key.
Next up is the Level class: Compare that to the naïve approach using \c QJsonObject::contains():
\badcode
if (json.contains("name") && json["name"].isString())
result.mName = json["name"].toString();
\endcode
which, beside being less readable, requires a total of three lookups (no,
the compiler will \e not optimize these into one), so is three times
slower and repeats \c{"name"} three times (violating the DRY principle).
\snippet serialization/savegame/character.cpp toJson
In the toJson() function, we do the reverse of the fromJson() function;
assign values from the Character object to a new JSON object we then
return. As with accessing values, there are two ways to set values on a
QJsonObject: \l QJsonObject::operator[]() and \l QJsonObject::insert().
Both will override any existing value at the given key.
\section1 The Level Class
\snippet serialization/savegame/level.h 0 \snippet serialization/savegame/level.h 0
We want to have several levels in our game, each with several NPCs, so we We want the levels in our game to each each have several NPCs, so we keep a QList
keep a QList of Character objects. We also provide the familiar read() and of Character objects. We also provide the familiar fromJson() and toJson()
write() functions. functions.
\snippet serialization/savegame/level.cpp 0 \snippet serialization/savegame/level.cpp fromJson
Containers can be written and read to and from JSON using QJsonArray. In our Containers can be written to and read from JSON using QJsonArray. In our
case, we construct a QJsonArray from the value associated with the key case, we construct a QJsonArray from the value associated with the key
\c "npcs". Then, for each QJsonValue element in the array, we call \c "npcs". Then, for each QJsonValue element in the array, we call
toObject() to get the Character's JSON object. The Character object can then toObject() to get the Character's JSON object. Character::fromJson() can
read their JSON and be appended to our NPC array. then turn that QJSonObject into a Character object to append to our NPC array.
\note \l{Container Classes}{Associate containers} can be written by storing \note \l{Container Classes}{Associate containers} can be written by storing
the key in each value object (if it's not already). With this approach, the the key in each value object (if it's not already). With this approach, the
@ -71,11 +110,13 @@
element is used as the key to construct the container when reading it back element is used as the key to construct the container when reading it back
in. in.
\snippet serialization/savegame/level.cpp 1 \snippet serialization/savegame/level.cpp toJson
Again, the write() function is similar to the read() function, except Again, the toJson() function is similar to the fromJson() function, except
reversed. reversed.
\section1 The Game Class
Having established the Character and Level classes, we can move on to Having established the Character and Level classes, we can move on to
the Game class: the Game class:
@ -87,26 +128,43 @@
Next, we provide accessors for the player and levels. We then expose three Next, we provide accessors for the player and levels. We then expose three
functions: newGame(), saveGame() and loadGame(). functions: newGame(), saveGame() and loadGame().
The read() and write() functions are used by saveGame() and loadGame(). The read() and toJson() functions are used by saveGame() and loadGame().
\snippet serialization/savegame/game.cpp 0 \div{class="admonition note"}\b{Note:}
Despite \c Game being a value class, we assume that the author wants a game to have
identity, much like your main window would have. We therefore don't use a
static fromJson() function, which would create a new object, but a read()
function we can call on existing objects. There's a 1:1 correspondence
between read() and fromJson(), in that one can be implemented in terms of
the other:
\code
void read(const QJsonObject &json) { *this = fromJson(json); }
static Game fromObject(const QJsonObject &json) { Game g; g.read(json); return g; }
\endcode
We just use what's more convenient for callers of the functions.
\enddiv
\snippet serialization/savegame/game.cpp newGame
To setup a new game, we create the player and populate the levels and their To setup a new game, we create the player and populate the levels and their
NPCs. NPCs.
\snippet serialization/savegame/game.cpp 1 \snippet serialization/savegame/game.cpp read
The first thing we do in the read() function is tell the player to read The read() function starts by replacing the player with the
itself. We then clear the level array so that calling loadGame() on the one read from JSON. We then clear() the level array so that calling
same Game object twice doesn't result in old levels hanging around. loadGame() on the same Game object twice doesn't result in old levels
hanging around.
We then populate the level array by reading each Level from a QJsonArray. We then populate the level array by reading each Level from a QJsonArray.
\snippet serialization/savegame/game.cpp 2 \snippet serialization/savegame/game.cpp toJson
We write the game to JSON similarly to how we write Level. Writing the game to JSON is similar to writing a level.
\snippet serialization/savegame/game.cpp 3 \snippet serialization/savegame/game.cpp loadGame
When loading a saved game in loadGame(), the first thing we do is open the When loading a saved game in loadGame(), the first thing we do is open the
save file based on which format it was saved to; \c "save.json" for JSON, save file based on which format it was saved to; \c "save.json" for JSON,
@ -120,14 +178,16 @@
After constructing the QJsonDocument, we instruct the Game object to read After constructing the QJsonDocument, we instruct the Game object to read
itself and then return \c true to indicate success. itself and then return \c true to indicate success.
\snippet serialization/savegame/game.cpp 4 \snippet serialization/savegame/game.cpp saveGame
Not surprisingly, saveGame() looks very much like loadGame(). We determine Not surprisingly, saveGame() looks very much like loadGame(). We determine
the file extension based on the format, print a warning and return \c false the file extension based on the format, print a warning and return \c false
if the opening of the file fails. We then write the Game object to a if the opening of the file fails. We then write the Game object to a
QJsonDocument, and call either QJsonDocument::toJson() or to QJsonObject. To save the game in the format that was specified, we
QJsonDocument::toBinaryData() to save the game, depending on which format convert the JSON object into either a QJsonDocument for a subsequent
was specified. QJsonDocument::toJson() call, or a QCborValue for QCborValue::toCbor().
\section1 Tying It All Together
We are now ready to enter main(): We are now ready to enter main():

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