diff options
Diffstat (limited to 'cmake')
36 files changed, 2332 insertions, 689 deletions
diff --git a/cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake b/cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake index ed9c4c4c9a..13291afcda 100644 --- a/cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake +++ b/cmake/3rdparty/extra-cmake-modules/find-modules/FindWaylandScanner.cmake @@ -129,11 +129,15 @@ function(ecm_add_wayland_client_protocol out_var) add_custom_command(OUTPUT "${_client_header}" COMMAND ${WaylandScanner_EXECUTABLE} client-header ${_infile} ${_client_header} - DEPENDS ${_infile} VERBATIM) + DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile} + VERBATIM + ) add_custom_command(OUTPUT "${_code}" COMMAND ${WaylandScanner_EXECUTABLE} code ${_infile} ${_code} - DEPENDS ${_infile} ${_client_header} VERBATIM) + DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile} ${_client_header} + VERBATIM + ) list(APPEND ${out_var} "${_client_header}" "${_code}") set(${out_var} ${${out_var}} PARENT_SCOPE) @@ -160,7 +164,9 @@ function(ecm_add_wayland_server_protocol out_var) add_custom_command(OUTPUT "${_server_header}" COMMAND ${WaylandScanner_EXECUTABLE} server-header ${_infile} ${_server_header} - DEPENDS ${_infile} VERBATIM) + DEPENDS ${WaylandScanner_EXECUTABLE} ${_infile} + VERBATIM + ) list(APPEND ${out_var} "${_server_header}") set(${out_var} ${${out_var}} PARENT_SCOPE) diff --git a/cmake/3rdparty/kwin/FindLibdrm.cmake b/cmake/3rdparty/kwin/FindLibdrm.cmake index 9936e07eee..10822e693a 100644 --- a/cmake/3rdparty/kwin/FindLibdrm.cmake +++ b/cmake/3rdparty/kwin/FindLibdrm.cmake @@ -105,13 +105,19 @@ if(NOT WIN32) INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}" INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}/libdrm" ) + if(EXISTS "${Libdrm_INCLUDE_DIR}/drm") + set_property(TARGET Libdrm::Libdrm APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}/drm" + ) + endif() + endif() mark_as_advanced(Libdrm_LIBRARY Libdrm_INCLUDE_DIR) # compatibility variables set(Libdrm_LIBRARIES ${Libdrm_LIBRARY}) - set(Libdrm_INCLUDE_DIRS ${Libdrm_INCLUDE_DIR} "${Libdrm_INCLUDE_DIR}/libdrm") + set(Libdrm_INCLUDE_DIRS ${Libdrm_INCLUDE_DIR} "${Libdrm_INCLUDE_DIR}/libdrm" "${Libdrm_INCLUDE_DIR}/drm") set(Libdrm_VERSION_STRING ${Libdrm_VERSION}) else() diff --git a/cmake/3rdpartyConfig.cmake.in b/cmake/3rdpartyConfig.cmake.in index fe15a1efc6..6af3792333 100644 --- a/cmake/3rdpartyConfig.cmake.in +++ b/cmake/3rdpartyConfig.cmake.in @@ -10,4 +10,6 @@ set(CMAKE_MODULE_PATH "${_import_prefix}" ${CMAKE_MODULE_PATH} ) set(CMAKE_MODULE_PATH "${old_CMAKE_MODULE_PATH}") -include("${CMAKE_CURRENT_LIST_DIR}/@target@Targets.cmake") +if (NOT QT_NO_CREATE_TARGETS) + include("${CMAKE_CURRENT_LIST_DIR}/@target@Targets.cmake") +endif() diff --git a/cmake/FindGLESv2.cmake b/cmake/FindGLESv2.cmake index 02df910285..49e757ef55 100644 --- a/cmake/FindGLESv2.cmake +++ b/cmake/FindGLESv2.cmake @@ -5,8 +5,8 @@ include(CheckCXXSourceCompiles) if(EMSCRIPTEN) set(HAVE_GLESv2 ON) else() - find_library(GLESv2_LIBRARY NAMES GLESv2) - find_path(GLESv2_INCLUDE_DIR NAMES "GLES2/gl2.h" DOC "The OpenGLES 2 include path") + find_library(GLESv2_LIBRARY NAMES GLESv2 OpenGLES) + find_path(GLESv2_INCLUDE_DIR NAMES "GLES2/gl2.h" "OpenGLES/ES2/gl.h" DOC "The OpenGLES 2 include path") set(_libraries "${CMAKE_REQUIRED_LIBRARIES}") list(APPEND CMAKE_REQUIRED_LIBRARIES "${GLESv2_LIBRARY}") set(_includes "${CMAKE_REQUIRED_INCLUDES}") @@ -32,6 +32,20 @@ int main(int argc, char *argv[]) { set(package_args GLESv2_INCLUDE_DIR GLESv2_LIBRARY HAVE_GLESv2) endif() +# Framework handling partially inspired by FindGLUT.cmake. +if(GLESv2_LIBRARY MATCHES "/([^/]+)\\.framework$") + # TODO: Might need to handle non .tbd suffixes, but didn't find an + # example like that. + # TODO: Might need to handle INTERFACE_INCLUDE_DIRECTORIES differently. + set(_library_imported_location "${GLESv2_LIBRARY}/${CMAKE_MATCH_1}.tbd") + if(NOT EXISTS "${_library_imported_location}") + set(_library_imported_location "") + endif() +else() + set(_library_imported_location "${GLESv2_LIBRARY}") +endif() +set(GLESv2_LIBRARY "${_library_imported_location}") + list(APPEND package_args HAVE_GLESv2) include(FindPackageHandleStandardArgs) @@ -40,8 +54,15 @@ find_package_handle_standard_args(GLESv2 DEFAULT_MSG ${package_args}) mark_as_advanced(${package_args}) if(GLESv2_FOUND AND NOT TARGET GLESv2::GLESv2) - if(EMSCRIPTEN) + if(EMSCRIPTEN OR APPLE_UIKIT) add_library(GLESv2::GLESv2 INTERFACE IMPORTED) + if(APPLE_UIKIT) + # For simulator_and_device builds we can't specify the full library path, because + # it's specific to either the device or the simulator. Resort to passing a link + # flag instead. + set_target_properties(GLESv2::GLESv2 PROPERTIES + INTERFACE_LINK_LIBRARIES "-framework OpenGLES") + endif() else() add_library(GLESv2::GLESv2 UNKNOWN IMPORTED) set_target_properties(GLESv2::GLESv2 PROPERTIES diff --git a/cmake/FindMtdev.cmake b/cmake/FindMtdev.cmake index c852a77c1c..6184fe9b3c 100644 --- a/cmake/FindMtdev.cmake +++ b/cmake/FindMtdev.cmake @@ -2,6 +2,6 @@ find_package(PkgConfig) pkg_check_modules(Mtdev mtdev IMPORTED_TARGET) -if (NOT TARGET PkgConfig::MtDev) +if (NOT TARGET PkgConfig::Mtdev) set(Mtdev_FOUND 0) endif() diff --git a/cmake/FindWrapDBus1.cmake b/cmake/FindWrapDBus1.cmake index c2668d6cc8..55f9757c45 100644 --- a/cmake/FindWrapDBus1.cmake +++ b/cmake/FindWrapDBus1.cmake @@ -2,6 +2,10 @@ # Work around that:-/ # See https://gitlab.freedesktop.org/dbus/dbus/issues/267 for more information +if(DBus1_FOUND OR WrapDBus1_FOUND) + return() +endif() + if(DEFINED ENV{PKG_CONFIG_DIR}) set(__qt_dbus_pcd "$ENV{PKG_CONFIG_DIR}") endif() diff --git a/cmake/FindWrapHarfbuzz.cmake b/cmake/FindWrapHarfbuzz.cmake new file mode 100644 index 0000000000..f7845b28bd --- /dev/null +++ b/cmake/FindWrapHarfbuzz.cmake @@ -0,0 +1,45 @@ +# We can't create the same interface imported target multiple times, CMake will complain if we do +# that. This can happen if the find_package call is done in multiple different subdirectories. +if(TARGET WrapHarfbuzz::WrapHarfbuzz) + set(WrapHarfbuzz_FOUND ON) + return() +endif() + +set(WrapHarfbuzz_FOUND OFF) + +find_package(harfbuzz) + +# Gentoo has some buggy version of a harfbuzz Config file. Check if include paths are valid. +set(__harfbuzz_target_name "harfbuzz::harfbuzz") +if(harfbuzz_FOUND AND TARGET "${__harfbuzz_target_name}") + get_property(__harfbuzz_include_paths TARGET "${__harfbuzz_target_name}" + PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + foreach(__harfbuzz_include_dir ${__harfbuzz_include_paths}) + if(NOT EXISTS "${__harfbuzz_include_dir}") + # Must be the broken Gentoo harfbuzzConfig.cmake file. Try to use pkg-config instead. + set(__harfbuzz_broken_config_file TRUE) + break() + endif() + endforeach() +endif() + +if(__harfbuzz_broken_config_file) + find_package(PkgConfig) + + pkg_check_modules(harfbuzz harfbuzz IMPORTED_TARGET) + set(__harfbuzz_target_name "PkgConfig::harfbuzz") + + if (NOT TARGET "${__harfbuzz_target_name}") + set(harfbuzz_FOUND 0) + endif() +endif() + +if(TARGET "${__harfbuzz_target_name}") + set(WrapHarfbuzz_FOUND ON) + + add_library(WrapHarfbuzz::WrapHarfbuzz INTERFACE IMPORTED) + target_link_libraries(WrapHarfbuzz::WrapHarfbuzz INTERFACE ${__harfbuzz_target_name}) +endif() +unset(__harfbuzz_target_name) +unset(__harfbuzz_include_dir) +unset(__harfbuzz_broken_config_file) diff --git a/cmake/FindWrapPCRE2.cmake b/cmake/FindWrapPCRE2.cmake index b69c5078a5..08f660bdfc 100644 --- a/cmake/FindWrapPCRE2.cmake +++ b/cmake/FindWrapPCRE2.cmake @@ -1,4 +1,7 @@ -include_guard(GLOBAL) # pragma once equivalent +if(TARGET WrapPCRE2::WrapPCRE2) + set(WrapPCRE2_FOUND TRUE) + return() +endif() find_package(PCRE2 CONFIG QUIET) diff --git a/cmake/ModuleDescription.json.in b/cmake/ModuleDescription.json.in new file mode 100644 index 0000000000..e29f3f176d --- /dev/null +++ b/cmake/ModuleDescription.json.in @@ -0,0 +1,11 @@ +{ + "module_name": "${target}", + "version": "${CMAKE_PROJECT_VERSION}", + "built_with": { + "compiler_id": "${CMAKE_CXX_COMPILER_ID}", + "compiler_target": "${CMAKE_CXX_COMPILER_TARGET}", + "compiler_version": "${CMAKE_CXX_COMPILER_VERSION}", + "cross_compiled": ${cross_compilation}, + "target_system": "${CMAKE_SYSTEM_NAME}" + } +} diff --git a/cmake/Qt3rdPartyLibraryConfig.cmake.in b/cmake/Qt3rdPartyLibraryConfig.cmake.in new file mode 100644 index 0000000000..0facce906f --- /dev/null +++ b/cmake/Qt3rdPartyLibraryConfig.cmake.in @@ -0,0 +1,26 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +get_filename_component(_import_prefix "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_import_prefix "${_import_prefix}" REALPATH) + +# Extra cmake code begin +@extra_cmake_code@ +# Extra cmake code end + +# Find required dependencies, if any. +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake") +endif() + +if (NOT QT_NO_CREATE_TARGETS) + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake") + if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS) + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake") + endif() +endif() + +foreach(extra_cmake_include @extra_cmake_includes@) + include("${CMAKE_CURRENT_LIST_DIR}/${extra_cmake_include}") +endforeach() diff --git a/cmake/QtAutoDetect.cmake b/cmake/QtAutoDetect.cmake index a1e66ffcbe..95ace249ad 100644 --- a/cmake/QtAutoDetect.cmake +++ b/cmake/QtAutoDetect.cmake @@ -2,9 +2,12 @@ # Collection of auto dection routines to improve the user eperience when # building Qt from source. # +# Make sure to not run detection when building standalone tests, because the detection was already +# done when initially configuring qtbase. function(qt_auto_detect_android) - if(DEFINED CMAKE_TOOLCHAIN_FILE AND NOT DEFINED QT_AUTODETECT_ANDROID) + if(DEFINED CMAKE_TOOLCHAIN_FILE AND NOT DEFINED QT_AUTODETECT_ANDROID + AND NOT QT_BUILD_STANDALONE_TESTS) file(READ ${CMAKE_TOOLCHAIN_FILE} toolchain_file_content OFFSET 0 LIMIT 80) string(FIND ${toolchain_file_content} "The Android Open Source Project" find_result REVERSE) @@ -31,7 +34,7 @@ function(qt_auto_detect_android) endfunction() function(qt_auto_detect_vpckg) - if(DEFINED ENV{VCPKG_ROOT}) + if(DEFINED ENV{VCPKG_ROOT} AND NOT QT_BUILD_STANDALONE_TESTS) set(vcpkg_toolchain_file "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake") get_filename_component(vcpkg_toolchain_file "${vcpkg_toolchain_file}" ABSOLUTE) @@ -49,9 +52,128 @@ function(qt_auto_detect_vpckg) message(STATUS "Using vcpkg triplet ${VCPKG_TARGET_TRIPLET}") endif() unset(vcpkg_toolchain_file) + message(STATUS "CMAKE_TOOLCHAIN_FILE is: ${CMAKE_TOOLCHAIN_FILE}") + if(DEFINED VCPKG_CHAINLOAD_TOOLCHAIN_FILE) + message(STATUS "VCPKG_CHAINLOAD_TOOLCHAIN_FILE is: ${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}") + endif() endif() endfunction() +function(qt_auto_detect_ios) + if(CMAKE_SYSTEM_NAME STREQUAL iOS + OR CMAKE_SYSTEM_NAME STREQUAL watchOS + OR CMAKE_SYSTEM_NAME STREQUAL tvOS) + message(STATUS "Using internal CMake ${CMAKE_SYSTEM_NAME} toolchain file.") + + # The QT_UIKIT_SDK check simulates the input.sdk condition for simulator_and_device in + # configure.json. + # If the variable is explicitly provided, assume simulator_and_device to be off. + if(QT_UIKIT_SDK) + set(simulator_and_device OFF) + elseif(QT_FORCE_SIMULATOR_AND_DEVICE) + # TODO: Once we get simulator_and_device support in upstream CMake, only then allow + # usage of simulator_and_device without forcing. + set(simulator_and_device ON) + else() + # If QT_UIKIT_SDK is not provided, default to simulator. + set(simulator_and_device OFF) + set(QT_UIKIT_SDK "iphonesimulator" CACHE "STRING" "Chosen uikit SDK.") + endif() + + message(STATUS "simulator_and_device set to: \"${simulator_and_device}\".") + + # Choose relevant architectures. + # Using a non xcode generator requires explicit setting of the + # architectures, otherwise compilation fails with unknown defines. + if(CMAKE_SYSTEM_NAME STREQUAL iOS) + if(simulator_and_device) + set(osx_architectures "arm64;x86_64") + elseif(QT_UIKIT_SDK STREQUAL "iphoneos") + set(osx_architectures "arm64") + elseif(QT_UIKIT_SDK STREQUAL "iphonesimulator") + set(osx_architectures "x86_64") + else() + if(NOT DEFINED QT_UIKIT_SDK) + message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK." + " Possible values: iphoneos, iphonesimulator.") + else() + message(FATAL_ERROR + "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.") + endif() + endif() + elseif(CMAKE_SYSTEM_NAME STREQUAL tvOS) + if(simulator_and_device) + set(osx_architectures "arm64;x86_64") + elseif(QT_UIKIT_SDK STREQUAL "appletvos") + set(osx_architectures "arm64") + elseif(QT_UIKIT_SDK STREQUAL "appletvsimulator") + set(osx_architectures "x86_64") + else() + if(NOT DEFINED QT_UIKIT_SDK) + message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK." + " Possible values: appletvos, appletvsimulator.") + else() + message(FATAL_ERROR + "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.") + endif() + endif() + elseif(CMAKE_SYSTEM_NAME STREQUAL watchOS) + if(simulator_and_device) + set(osx_architectures "armv7k;i386") + elseif(QT_UIKIT_SDK STREQUAL "watchos") + set(osx_architectures "armv7k") + elseif(QT_UIKIT_SDK STREQUAL "watchsimulator") + set(osx_architectures "i386") + else() + if(NOT DEFINED QT_UIKIT_SDK) + message(FATAL_ERROR "Please proviude a value for -DQT_UIKIT_SDK." + " Possible values: watchos, watchsimulator.") + else() + message(FATAL_ERROR + "Unknown SDK argument given to QT_UIKIT_SDK: ${QT_UIKIT_SDK}.") + endif() + endif() + endif() + + # For non simulator_and_device builds, we need to explicitly set the SYSROOT aka the sdk + # value. + if(QT_UIKIT_SDK) + set(CMAKE_OSX_SYSROOT "${QT_UIKIT_SDK}" CACHE STRING "") + endif() + message(STATUS "CMAKE_OSX_SYSROOT set to: \"${CMAKE_OSX_SYSROOT}\".") + + message(STATUS "CMAKE_OSX_ARCHITECTURES set to: \"${osx_architectures}\".") + set(CMAKE_OSX_ARCHITECTURES "${osx_architectures}" CACHE STRING "") + + if(NOT DEFINED BUILD_SHARED_LIBS) + set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build Qt statically or dynamically" FORCE) + endif() + + if(BUILD_SHARED_LIBS) + message(FATAL_ERROR + "Building Qt for ${CMAKE_SYSTEM_NAME} as shared libraries is not supported.") + endif() + endif() +endfunction() + +function(qt_auto_detect_cmake_config) + if(CMAKE_CONFIGURATION_TYPES) + # Allow users to specify this option. + if(NOT QT_MULTI_CONFIG_FIRST_CONFIG) + list(GET CMAKE_CONFIGURATION_TYPES 0 first_config_type) + set(QT_MULTI_CONFIG_FIRST_CONFIG "${first_config_type}") + set(QT_MULTI_CONFIG_FIRST_CONFIG "${first_config_type}" PARENT_SCOPE) + endif() + + set(CMAKE_TRY_COMPILE_CONFIGURATION "${QT_MULTI_CONFIG_FIRST_CONFIG}" PARENT_SCOPE) + if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config") + set(CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE ON PARENT_SCOPE) + set(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE "${QT_MULTI_CONFIG_FIRST_CONFIG}" PARENT_SCOPE) + endif() + endif() +endfunction() +qt_auto_detect_cmake_config() +qt_auto_detect_ios() qt_auto_detect_android() qt_auto_detect_vpckg() diff --git a/cmake/QtBaseConfigureTests.cmake b/cmake/QtBaseConfigureTests.cmake index 34e4e6e6f1..0d6bb1407b 100644 --- a/cmake/QtBaseConfigureTests.cmake +++ b/cmake/QtBaseConfigureTests.cmake @@ -1,26 +1,47 @@ include(CheckCXXSourceCompiles) -function(run_config_test_architecture) - set(qt_base_configure_tests_vars_to_export) - # Test architecture - set(_arch_file "${CMAKE_CURRENT_BINARY_DIR}/architecture_test") - set(saved_executable_suffix "${CMAKE_EXECUTABLE_SUFFIX}") - - # With emscripten the application entry point is a .js file (to be run with node for example), but the - # real "data" is in the .wasm file, so that's where we need to look for the ABI, etc. information. - if (EMSCRIPTEN) - set(CMAKE_EXECUTABLE_SUFFIX ".wasm") - endif() - try_compile(_arch_result "${CMAKE_CURRENT_BINARY_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/arch/arch.cpp" - COPY_FILE "${_arch_file}") +function(qt_run_config_test_architecture) + set(QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT + "" CACHE INTERNAL "Test variables that should be exported" FORCE) + + # Compile test to find the target architecture and sub-architectures. + set(flags "") + qt_get_platform_try_compile_vars(platform_try_compile_vars) + list(APPEND flags ${platform_try_compile_vars}) - set(CMAKE_EXECUTABLE_SUFFIX "${saved_executable_suffix}") + try_compile( + _arch_result + "${CMAKE_CURRENT_BINARY_DIR}/config.tests/arch" + "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/arch" + arch + CMAKE_FLAGS ${flags} + ) if (NOT _arch_result) message(FATAL_ERROR "Failed to compile architecture detection file.") endif() + set(_arch_file_suffix "${CMAKE_EXECUTABLE_SUFFIX}") + # With emscripten the application entry point is a .js file (to be run with node for example), + # but the real "data" is in the .wasm file, so that's where we need to look for the ABI, etc. + # information. + if (EMSCRIPTEN) + set(_arch_file_suffix ".wasm") + endif() + + set(arch_test_location "config.tests/arch") + if(QT_MULTI_CONFIG_FIRST_CONFIG) + string(APPEND arch_test_location "/${QT_MULTI_CONFIG_FIRST_CONFIG}") + endif() + + set(_arch_file + "${CMAKE_CURRENT_BINARY_DIR}/${arch_test_location}/architecture_test${_arch_file_suffix}") + if (NOT EXISTS "${_arch_file}") + message(FATAL_ERROR + "Failed to find compiled architecture detection executable at ${_arch_file}.") + endif() + message(STATUS "Extracting architecture info from ${_arch_file}.") + file(STRINGS "${_arch_file}" _arch_lines LENGTH_MINIMUM 16 LENGTH_MAXIMUM 1024 ENCODING UTF-8) foreach (_line ${_arch_lines}) @@ -49,20 +70,23 @@ function(run_config_test_architecture) set(TEST_architecture 1 CACHE INTERNAL "Ran the architecture test") set(TEST_architecture_arch "${_architecture}" CACHE INTERNAL "Target machine architecture") - list(APPEND qt_base_configure_tests_vars_to_export TEST_architecture_arch) + list(APPEND QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT TEST_architecture_arch) set(TEST_subarch 1 CACHE INTERNAL "Ran machine subArchitecture test") foreach(it ${_sub_architecture}) # Equivalent to qmake's QT_CPU_FEATURES.$arch. set(TEST_arch_${TEST_architecture_arch}_subarch_${it} 1 CACHE INTERNAL "Target sub architecture result") - list(APPEND qt_base_configure_tests_vars_to_export TEST_arch_${TEST_architecture_arch}_subarch_${it}) + list(APPEND QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT TEST_arch_${TEST_architecture_arch}_subarch_${it}) endforeach() set(TEST_buildAbi "${_build_abi}" CACHE INTERNAL "Target machine buildAbi") - list(APPEND qt_base_configure_tests_vars_to_export TEST_buildAbi) - set(qt_base_configure_tests_vars_to_export ${qt_base_configure_tests_vars_to_export} CACHE INTERNAL "Test variables that should be exported") + list(APPEND QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT TEST_buildAbi) + set(QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT ${QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT} CACHE INTERNAL "Test variables that should be exported") + + list(JOIN _sub_architecture " " subarch_summary) + message(STATUS "Building for: ${QT_QMAKE_TARGET_MKSPEC} (${TEST_architecture_arch}, CPU features: ${subarch_summary})") endfunction() -function(run_config_test_posix_iconv) +function(qt_run_config_test_posix_iconv) set(source "#include <iconv.h> int main(int, char **) @@ -94,7 +118,7 @@ int main(int, char **) endfunction() -function(run_config_test_sun_iconv) +function(qt_run_config_test_sun_iconv) set(source "#include <iconv.h> int main(int, char **) @@ -120,7 +144,7 @@ int main(int, char **) set(TEST_sun_iconv "${HAVE_SUN_ICONV}" CACHE INTERNAL "SUN libiconv") endfunction() -function(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; @@ -147,8 +171,8 @@ VERS_1; set(TEST_ld_version_script "${HAVE_LD_VERSION_SCRIPT}" CACHE INTERNAL "linker version script support") endfunction() -function(run_config_tests) - run_config_test_posix_iconv() +function(qt_run_qtbase_config_tests) + qt_run_config_test_posix_iconv() add_library(Iconv INTERFACE) if(TEST_iconv_needlib) @@ -156,10 +180,19 @@ function(run_config_tests) endif() if(NOT TEST_posix_iconv) - run_config_test_sun_iconv() + qt_run_config_test_sun_iconv() endif() - run_config_test_architecture() - run_linker_version_script_support() + qt_run_config_test_architecture() + qt_run_linker_version_script_support() endfunction() -run_config_tests() +# The qmake build of android does not perform the right architecture tests and +# forcefully disables sse4 on android x86. We have to mimic this behavior +# for now +if (CMAKE_ANDROID_ARCH_ABI STREQUAL x86) + set(QT_FEATURE_sse4_1 OFF CACHE BOOL INTERNAL FORCE) + set(QT_FEATURE_sse4_2 OFF CACHE BOOL INTERNAL FORCE) + set(TEST_subarch_sse4_1 FALSE CACHE BOOL INTERNAL FORCE) + set(TEST_subarch_sse4_2 FALSE CACHE BOOL INTERNAL FORCE) +endif() +qt_run_qtbase_config_tests() diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake index df3ceb88c0..fb27618499 100644 --- a/cmake/QtBaseGlobalTargets.cmake +++ b/cmake/QtBaseGlobalTargets.cmake @@ -3,9 +3,9 @@ add_library(Platform INTERFACE) add_library(Qt::Platform ALIAS Platform) target_include_directories(Platform INTERFACE - $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/${QT_PLATFORM_DEFINITION_DIR}> - $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include> - $<INSTALL_INTERFACE:${INSTALL_DATADIR}/${QT_PLATFORM_DEFINITION_DIR}> + $<BUILD_INTERFACE:${QT_PLATFORM_DEFINITION_DIR_ABSOLUTE}> + $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/${INSTALL_INCLUDEDIR}> + $<INSTALL_INTERFACE:${QT_PLATFORM_DEFINITION_DIR}> $<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}> ) target_compile_definitions(Platform INTERFACE ${QT_PLATFORM_DEFINITIONS}) @@ -91,11 +91,27 @@ list(APPEND init_platform "set(CMAKE_CXX_COMPILER \"${CMAKE_CXX_COMPILER}\" CACH list(APPEND init_platform "set(CMAKE_C_COMPILER \"${CMAKE_C_COMPILER}\" CACHE STRING \"\")") if(APPLE) - if(CMAKE_OSX_SYSROOT) + # For simulator_and_device build, we should not explicitly set the sysroot. + list(LENGTH CMAKE_OSX_ARCHITECTURES _qt_osx_architectures_count) + if(CMAKE_OSX_SYSROOT AND NOT _qt_osx_architectures_count GREATER 1 AND APPLE_UIKIT) list(APPEND init_platform "set(CMAKE_OSX_SYSROOT \"${CMAKE_OSX_SYSROOT}\" CACHE PATH \"\")") endif() + unset(_qt_osx_architectures_count) + if(CMAKE_OSX_DEPLOYMENT_TARGET) - list(APPEND init_platform "set(CMAKE_OSX_DEPLOYMENT_TARGET \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" CACHE STRING \"\")") + list(APPEND init_platform + "set(CMAKE_OSX_DEPLOYMENT_TARGET \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" CACHE STRING \"\")") + endif() + + if(APPLE_UIKIT) + list(APPEND init_platform + "set(CMAKE_SYSTEM_NAME \"${CMAKE_SYSTEM_NAME}\" CACHE STRING \"\")") + set(_qt_osx_architectures_escaped "${CMAKE_OSX_ARCHITECTURES}") + string(REPLACE ";" "LITERAL_SEMICOLON" + _qt_osx_architectures_escaped "${_qt_osx_architectures_escaped}") + list(APPEND init_platform + "set(CMAKE_OSX_ARCHITECTURES \"${_qt_osx_architectures_escaped}\" CACHE STRING \"\")") + unset(_qt_osx_architectures_escaped) endif() elseif(ANDROID) list(APPEND init_platform "set(ANDROID_NATIVE_API_LEVEL \"${ANDROID_NATIVE_API_LEVEL}\" CACHE STRING \"\")") @@ -108,18 +124,39 @@ endif() string(REPLACE ";" "\n" init_vcpkg "${init_vcpkg}") string(REPLACE ";" "\n" init_platform "${init_platform}") +string(REPLACE "LITERAL_SEMICOLON" ";" init_platform "${init_platform}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt.toolchain.cmake.in" "${__GlobalConfig_build_dir}/qt.toolchain.cmake" @ONLY) qt_install(FILES "${__GlobalConfig_build_dir}/qt.toolchain.cmake" DESTINATION "${__GlobalConfig_install_dir}" COMPONENT Devel) # Also provide a convenience cmake wrapper if(UNIX) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.in" "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake" @ONLY) - qt_install(PROGRAMS "${QT_BUILD_DIR}/bin/qt-cmake" DESTINATION "${INSTALL_BINDIR}") + qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake" DESTINATION "${INSTALL_BINDIR}") else() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.bat.in" "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake.bat" @ONLY) - qt_install(PROGRAMS "${QT_BUILD_DIR}/bin/qt-cmake.bat" DESTINATION "${INSTALL_BINDIR}") + qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake.bat" DESTINATION "${INSTALL_BINDIR}") endif() +# Provide a private convenience wrapper with options which should not be propagated via the public +# qt-cmake wrapper e.g. CMAKE_GENERATOR. +# These options can not be set in a toolchain file, but only on the command line. +# These options should not be in the public wrapper, because a consumer of Qt might want to build +# their CMake app with the Unix Makefiles generator, while Qt should be built with the Ninja +# generator. +# The private wrapper is more conveient for building Qt itself, because a developer doesn't need +# to specify the same options for each qt module built. +set(__qt_cmake_extra "-G\"${CMAKE_GENERATOR}\"") +if(UNIX) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.in" + "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private" @ONLY) +qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private" DESTINATION "${INSTALL_BINDIR}") +else() + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/bin/qt-cmake.bat.in" + "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private.bat" @ONLY) +qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_BINDIR}/qt-cmake-private.bat" DESTINATION "${INSTALL_BINDIR}") +endif() +unset(__qt_cmake_extra) + ## Library to hold global features: ## These features are stored and accessed via Qt::GlobalConfig, but the ## files always lived in Qt::Core, so we keep it that way @@ -135,6 +172,16 @@ qt_feature_module_begin(NO_MODULE PRIVATE_FILE src/corelib/global/qconfig_p.h ) include("${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake") + +# Do what mkspecs/features/uikit/default_pre.prf does, aka enable sse2 for +# simulator_and_device_builds. +if(APPLE_UIKIT AND NOT QT_UIKIT_SDK) + set(__QtFeature_custom_enabled_cache_variables + TEST_subarch_sse2 + FEATURE_sse2 + QT_FEATURE_sse2) +endif() + qt_feature_module_end(GlobalConfig OUT_VAR_PREFIX "__GlobalConfig_") qt_generate_global_config_pri_file() @@ -174,7 +221,9 @@ qt_internal_export_modern_cmake_config_targets_file(TARGETS ${__export_targets} ## Install some QtBase specific CMake files: qt_copy_or_install(FILES + cmake/ModuleDescription.json.in cmake/QtBuild.cmake + cmake/QtBuildInformation.cmake cmake/QtCompilerFlags.cmake cmake/QtCompilerOptimization.cmake cmake/QtFeature.cmake @@ -186,18 +235,15 @@ qt_copy_or_install(FILES cmake/QtModuleDependencies.cmake.in cmake/QtModuleToolsDependencies.cmake.in cmake/QtModuleToolsConfig.cmake.in + cmake/QtModuleToolsVersionlessTargets.cmake.in + cmake/QtStandaloneTestsConfig.cmake.in cmake/QtPlugins.cmake.in cmake/QtPluginConfig.cmake.in cmake/QtPluginDependencies.cmake.in DESTINATION "${__GlobalConfig_install_dir}" ) -if(QT_WILL_INSTALL) - # NOTE: QtFeature.cmake is included by the Qt module config files unconditionally - # In a prefix build, QtFeature.cmake is not copied to the build dir by default - # Thus do it explicitly in that case so we can use the module config files in the examples - file(COPY cmake/QtFeature.cmake DESTINATION "${__GlobalConfig_install_dir}") -endif() +file(COPY cmake/QtFeature.cmake DESTINATION "${__GlobalConfig_build_dir}") # TODO: Check whether this is the right place to install these qt_copy_or_install(DIRECTORY cmake/3rdparty DESTINATION "${__GlobalConfig_install_dir}") diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index 537979ad8a..4456ea99f1 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -1,11 +1,12 @@ include(CMakePackageConfigHelpers) # Install locations: -set(INSTALL_BINDIR "bin" CACHE PATH "Executables [PREFIX/bin]") -set(INSTALL_INCLUDEDIR "include" CACHE PATH "Header files [PREFIX/include]") -set(INSTALL_LIBDIR "lib" CACHE PATH "Libraries [PREFIX/lib]") -set(INSTALL_ARCHDATADIR "." CACHE PATH "Arch-dependent data [PREFIX]") -set(INSTALL_PLUGINSDIR "${INSTALL_ARCHDATADIR}/plugins" CACHE PATH +set(INSTALL_BINDIR "bin" CACHE STRING "Executables [PREFIX/bin]") +set(INSTALL_INCLUDEDIR "include" CACHE STRING "Header files [PREFIX/include]") +set(INSTALL_LIBDIR "lib" CACHE STRING "Libraries [PREFIX/lib]") +set(INSTALL_MKSPECSDIR "mkspecs" CACHE STRING "Mkspecs files [PREFIX/mkspecs]") +set(INSTALL_ARCHDATADIR "." CACHE STRING "Arch-dependent data [PREFIX]") +set(INSTALL_PLUGINSDIR "${INSTALL_ARCHDATADIR}/plugins" CACHE STRING "Plugins [ARCHDATADIR/plugins]") set(INSTALL_TARGETS_DEFAULT_ARGS @@ -21,20 +22,20 @@ else() set(_default_libexec "${INSTALL_ARCHDATADIR}/libexec") endif() -set(INSTALL_LIBEXECDIR "${_default_libexec}" CACHE PATH +set(INSTALL_LIBEXECDIR "${_default_libexec}" CACHE STRING "Helper programs [ARCHDATADIR/bin on Windows, ARCHDATADIR/libexec otherwise]") -set(INSTALL_IMPORTDIR "${INSTALL_ARCHDATADIR}/imports" CACHE PATH - "QML1 imports [ARCHDATADIR/imports]") -set(INSTALL_QMLDIR "${INSTALL_ARCHDATADIR}/qml" CACHE PATH +set(INSTALL_QMLDIR "${INSTALL_ARCHDATADIR}/qml" CACHE STRING "QML2 imports [ARCHDATADIR/qml]") -set(INSTALL_DATADIR "." CACHE PATH "Arch-independent data [PREFIX]") -set(INSTALL_DOCDIR "${INSTALL_DATADIR}/doc" CACHE PATH "Documentation [DATADIR/doc]") -set(INSTALL_TRANSLATIONSDIR "${INSTALL_DATADIR}/translations" CACHE PATH +set(INSTALL_DATADIR "." CACHE STRING "Arch-independent data [PREFIX]") +set(INSTALL_DOCDIR "${INSTALL_DATADIR}/doc" CACHE STRING "Documentation [DATADIR/doc]") +set(INSTALL_TRANSLATIONSDIR "${INSTALL_DATADIR}/translations" CACHE STRING "Translations [DATADIR/translations]") -set(INSTALL_SYSCONFDIR "etc/xdg" CACHE PATH +set(INSTALL_SYSCONFDIR "etc/xdg" CACHE STRING "Settings used by Qt programs [PREFIX/etc/xdg]") -set(INSTALL_EXAMPLESDIR "examples" CACHE PATH "Examples [PREFIX/examples]") -set(INSTALL_TESTSDIR "tests" CACHE PATH "Tests [PREFIX/tests]") +set(INSTALL_EXAMPLESDIR "examples" CACHE STRING "Examples [PREFIX/examples]") +set(INSTALL_TESTSDIR "tests" CACHE STRING "Tests [PREFIX/tests]") +set(INSTALL_DESCRIPTIONSDIR "${INSTALL_DATADIR}/modules" CACHE STRING + "Module description files directory") # The variables might have already been set in QtBuildInternalsExtra.cmake if the file is included # while building a new module and not QtBase. In that case, stop overriding the value. @@ -49,10 +50,22 @@ endif() set(QT_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}") +# Find the path to mkspecs/, depending on whether we are building as part of a standard qtbuild, +# or a module against an already installed version of qt. +if(NOT QT_MKSPECS_DIR) + if("${QT_BUILD_INTERNALS_PATH}" STREQUAL "") + get_filename_component(QT_MKSPECS_DIR "${CMAKE_CURRENT_LIST_DIR}/../mkspecs" ABSOLUTE) + else() + # We can rely on CMAKE_INSTALL_PREFIX being set by QtBuildInternalsExtra.cmake + get_filename_component(QT_MKSPECS_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_MKSPECSDIR}" ABSOLUTE) + endif() + set(QT_MKSPECS_DIR "${QT_MKSPECS_DIR}" CACHE INTERNAL "") +endif() + # the default RPATH to be used when installing, but only if it's not a system directory -LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) +LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}" isSystemDir) IF("${isSystemDir}" STREQUAL "-1") - SET(_default_install_rpath "${CMAKE_INSTALL_PREFIX}/lib") + SET(_default_install_rpath "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") ENDIF("${isSystemDir}" STREQUAL "-1") # Default rpath settings: Use rpath for build tree as well as a full path for the installed binaries. @@ -63,6 +76,23 @@ SET(CMAKE_INSTALL_RPATH "${_default_install_rpath}" CACHE PATH "RPATH for instal # which point to directories outside the build tree to the install RPATH SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +# Generate a module description file based on the template in ModuleDescription.json.in +function(qt_describe_module target) + set(path_suffix "${INSTALL_DESCRIPTIONSDIR}") + qt_path_join(build_dir ${QT_BUILD_DIR} ${path_suffix}) + qt_path_join(install_dir ${QT_INSTALL_DIR} ${path_suffix}) + + set(descfile_in "${QT_CMAKE_DIR}/ModuleDescription.json.in") + set(descfile_out "${build_dir}/${target}.json") + set(cross_compilation "false") + if(CMAKE_CROSSCOMPILE) + set(cross_compilation "true") + endif() + configure_file("${descfile_in}" "${descfile_out}") + + qt_install(FILES "${descfile_out}" DESTINATION "${install_dir}") +endfunction() + function(qt_setup_tool_path_command) if(NOT WIN32) return() @@ -84,10 +114,13 @@ if(WIN32) endif() if(MSVC) set(QT_QMAKE_TARGET_MKSPEC win32-msvc) - elseif(CLANG) - set(QT_QMAKE_TARGET_MKSPEC win32-clang) + elseif(CLANG AND MINGW) + set(QT_QMAKE_TARGET_MKSPEC win32-clang-g++) elseif(MINGW) set(QT_QMAKE_TARGET_MKSPEC win32-g++) + endif() + + if (MINGW) list(APPEND QT_DEFAULT_PLATFORM_DEFINITIONS _WIN32_WINNT=0x0601) endif() elseif(LINUX) @@ -113,8 +146,19 @@ endif() # TODO: Fixme to be correct. set(QT_QMAKE_HOST_MKSPEC "${QT_QMAKE_TARGET_MKSPEC}") -if(QT_QMAKE_TARGET_MKSPEC) - set(QT_DEFAULT_PLATFORM_DEFINITION_DIR mkspecs/${QT_QMAKE_TARGET_MKSPEC}) +# Platform definition dir provided by user on command line. +# Derive the absolute one relative to the current source dir. +if(QT_PLATFORM_DEFINITION_DIR) + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR "${QT_PLATFORM_DEFINITION_DIR}") + get_filename_component( + QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE + "${QT_PLATFORM_DEFINITION_DIR}" + ABSOLUTE) +elseif(QT_QMAKE_TARGET_MKSPEC) + # Used by consumers of prefix builds via INSTALL_INTERFACE (relative path). + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR "${INSTALL_MKSPECSDIR}/${QT_QMAKE_TARGET_MKSPEC}") + # Used by qtbase itself and consumers of non-prefix builds via BUILD_INTERFACE (absolute path). + set(QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE "${QT_MKSPECS_DIR}/${QT_QMAKE_TARGET_MKSPEC}") endif() if(NOT DEFINED QT_DEFAULT_PLATFORM_DEFINITIONS) @@ -123,8 +167,10 @@ endif() set(QT_PLATFORM_DEFINITIONS ${QT_DEFAULT_PLATFORM_DEFINITIONS} CACHE STRING "Qt platform specific pre-processor defines") -set(QT_PLATFORM_DEFINITION_DIR ${QT_DEFAULT_PLATFORM_DEFINITION_DIR} +set(QT_PLATFORM_DEFINITION_DIR "${QT_DEFAULT_PLATFORM_DEFINITION_DIR}" CACHE PATH "Path to directory that contains qplatformdefs.h") +set(QT_PLATFORM_DEFINITION_DIR_ABSOLUTE "${QT_DEFAULT_PLATFORM_DEFINITION_DIR_ABSOLUTE}" + CACHE INTERNAL "Path to directory that contains qplatformdefs.h") set(QT_NAMESPACE "" CACHE STRING "Qt Namespace") if(QT_NAMESPACE STREQUAL "") set(QT_HAS_NAMESPACE OFF) @@ -192,6 +238,8 @@ macro(qt_internal_append_known_modules_with_tools module) if(NOT ${module} IN_LIST QT_KNOWN_MODULES_WITH_TOOLS) set(QT_KNOWN_MODULES_WITH_TOOLS "${QT_KNOWN_MODULES_WITH_TOOLS};${module}" CACHE INTERNAL "Known Qt modules with tools" FORCE) + set(QT_KNOWN_MODULE_${module}_TOOLS "" + CACHE INTERNAL "Known Qt module ${module} tools" FORCE) endif() endmacro() @@ -217,7 +265,8 @@ else() endif() # Compute the values of QT_BUILD_DIR, QT_INSTALL_DIR, QT_CONFIG_BUILD_DIR, QT_CONFIG_INSTALL_DIR -# taking into account whether the current build is a prefix build or a non-prefix build. +# taking into account whether the current build is a prefix build or a non-prefix build, +# and whether it is a superbuild or non-superbuild. # # These values should be prepended to file paths in commands or properties, # in order to correctly place generated Config files, generated Targets files, @@ -226,17 +275,29 @@ endif() # The build dir variables will always be absolute paths. # The QT_INSTALL_DIR variable will have a relative path in a prefix build, # which means that it can be empty, so use qt_join_path to prevent accidental absolute paths. -if(QT_WILL_INSTALL) - # In the usual prefix build case, the build dir is the current module build dir, - # and the install dir is the prefix, so we don't set it. - set(QT_BUILD_DIR "${CMAKE_BINARY_DIR}") - set(QT_INSTALL_DIR "") +if(QT_SUPERBUILD) + # In this case, we always copy all the build products in qtbase/{bin,lib,...} + if(QT_WILL_INSTALL) + set(QT_BUILD_DIR "${QtBase_BINARY_DIR}") + set(QT_INSTALL_DIR "") + else() + set(QT_BUILD_DIR "${QtBase_BINARY_DIR}") + set(QT_INSTALL_DIR "${QtBase_BINARY_DIR}") + endif() else() - # When doing a non-prefix build, both the build dir and install dir are the same, - # pointing to the qtbase build dir. - set(QT_BUILD_DIR "${CMAKE_INSTALL_PREFIX}") - set(QT_INSTALL_DIR "${QT_BUILD_DIR}") + if(QT_WILL_INSTALL) + # In the usual prefix build case, the build dir is the current module build dir, + # and the install dir is the prefix, so we don't set it. + set(QT_BUILD_DIR "${CMAKE_BINARY_DIR}") + set(QT_INSTALL_DIR "") + else() + # When doing a non-prefix build, both the build dir and install dir are the same, + # pointing to the qtbase build dir. + set(QT_BUILD_DIR "${CMAKE_INSTALL_PREFIX}") + set(QT_INSTALL_DIR "${QT_BUILD_DIR}") + endif() endif() + set(__config_path_part "${INSTALL_LIBDIR}/cmake") set(QT_CONFIG_BUILD_DIR "${QT_BUILD_DIR}/${__config_path_part}") set(QT_CONFIG_INSTALL_DIR "${QT_INSTALL_DIR}") @@ -398,7 +459,15 @@ endfunction() # at CMake configuration step, and use it as an input to a custom command that replaces the # cmake_install.cmake file with an empty one. This means we will always replace the file on # every reconfiguration, but not when doing null builds. -function(remove_install_target) +function(qt_remove_install_target) + # On superbuilds we only do this for qtbase - it will correctly remove the + # cmake_install.cmake at the root of the repository. + if(QT_SUPERBUILD) + if(NOT (PROJECT_NAME STREQUAL "QtBase")) + return() + endif() + endif() + set(file_in "${CMAKE_BINARY_DIR}/.remove_cmake_install_in.txt") set(file_generated "${CMAKE_BINARY_DIR}/.remove_cmake_install_generated.txt") set(cmake_install_file "${CMAKE_BINARY_DIR}/cmake_install.cmake") @@ -416,7 +485,7 @@ endfunction() function(qt_set_up_nonprefix_build) if(NOT QT_WILL_INSTALL) - remove_install_target() + qt_remove_install_target() endif() endfunction() @@ -519,7 +588,7 @@ QT.${module_lower}_private.disabled_features = ${disabled_private_features} endfunction() function(qt_generate_global_config_pri_file) - qt_path_join(qconfig_pri_target_path ${PROJECT_BINARY_DIR} mkspecs) + qt_path_join(qconfig_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR}) qt_path_join(qconfig_pri_target_path "${qconfig_pri_target_path}" "qconfig.pri") get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PUBLIC_FEATURES) @@ -571,7 +640,7 @@ CONFIG -= link_prl # we do not create prl files right now CONFIG += ${config_entries} " ) - qt_install(FILES "${qconfig_pri_target_path}" DESTINATION mkspecs) + qt_install(FILES "${qconfig_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR}) endfunction() # Takes a list of path components and joins them into one path separated by forward slashes "/", @@ -668,8 +737,11 @@ function(qt_create_nolink_target target dependee_target) # Create the nolink interface target, assign the properties from the original target, # associate the nolink target with the same export which contains # the target that uses the _nolink target. - # Also create a namespaced alias of the form {$target}::${target}_nolink which is used by + # Also create a namespaced alias of the form ${target}::${target}_nolink which is used by # our modules. + # Also create a Qt namespaced alias target, because when exporting via install(EXPORT) + # Vulkan::Vulkan_nolink transforms into Qt6::Vulkan_nolink, and the latter needs to be an + # accessible alias for standalone tests. if(NOT TARGET "${nolink_target}") add_library("${nolink_target}" INTERFACE) set(prefixed_nolink_target "${target}_nolink") @@ -686,6 +758,7 @@ function(qt_create_nolink_target target dependee_target) $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_FEATURES>) add_library(${prefixed_nolink_target} ALIAS ${nolink_target}) + add_library("${INSTALL_CMAKE_NAMESPACE}::${nolink_target}" ALIAS ${nolink_target}) set(export_name "${INSTALL_CMAKE_NAMESPACE}${dependee_target}Targets") qt_install(TARGETS ${nolink_target} EXPORT ${export_name}) @@ -718,6 +791,12 @@ function(qt_ensure_sync_qt) qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_LIBEXECDIR}) qt_copy_or_install(PROGRAMS "${SYNCQT_FROM_SOURCE}" DESTINATION "${syncqt_install_dir}") + elseif(QT_HOST_PATH) + get_filename_component(syncqt_absolute_path + "${QT_HOST_PATH}/${INSTALL_LIBEXECDIR}/syncqt.pl" + ABSOLUTE) + set(QT_SYNCQT "${syncqt_absolute_path}" CACHE FILEPATH "syncqt script") + message(STATUS "Using host syncqt found at: ${QT_SYNCQT}") else() get_filename_component(syncqt_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBEXECDIR}/syncqt.pl" @@ -736,17 +815,30 @@ macro(qt_parse_all_arguments result type flags options multiopts) endif() endmacro() +include(CheckCXXSourceCompiles) function(qt_internal_add_link_flags_no_undefined target) if (NOT QT_BUILD_SHARED_LIBS) return() endif() if (GCC OR CLANG) - if(APPLE) + set(previous_CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) + + set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,-undefined,error") + check_cxx_source_compiles("int main() {}" HAVE_DASH_UNDEFINED_ERROR) + if(HAVE_DASH_UNDEFINED_ERROR) set(no_undefined_flag "-Wl,-undefined,error") - elseif(LINUX OR MINGW OR ANDROID) + endif() + + set(CMAKE_REQUIRED_LINK_OPTIONS "-Wl,--no-undefined") + check_cxx_source_compiles("int main() {}" HAVE_DASH_DASH_NO_UNDEFINED) + if(HAVE_DASH_DASH_NO_UNDEFINED) set(no_undefined_flag "-Wl,--no-undefined") - else() + endif() + + set(CMAKE_REQUIRED_LINK_OPTIONS ${previous_CMAKE_REQUIRED_LINK_OPTIONS}) + + if (NOT HAVE_DASH_UNDEFINED_ERROR AND NOT HAVE_DASH_DASH_NO_UNDEFINED) message(FATAL_ERROR "Platform linker doesn't support erroring upon encountering undefined symbols. Target:\"${target}\".") endif() target_link_options("${target}" PRIVATE "${no_undefined_flag}") @@ -810,7 +902,7 @@ function(qt_internal_add_linker_version_script target) qt_ensure_perl() add_custom_command(TARGET "${target}" PRE_LINK - COMMAND "${HOST_PERL}" "${PROJECT_SOURCE_DIR}/mkspecs/features/data/unix/findclasslist.pl" < "${infile}" > "${outfile}" + COMMAND "${HOST_PERL}" "${QT_MKSPECS_DIR}/features/data/unix/findclasslist.pl" < "${infile}" > "${outfile}" BYPRODUCTS "${outfile}" DEPENDS "${infile}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMENT "Generating version linker script" @@ -845,8 +937,8 @@ function(qt_internal_module_info result target) string(REPLACE "." "_" define "${define}") set("${result}_upper" "${upper}" PARENT_SCOPE) set("${result}_lower" "${lower}" PARENT_SCOPE) - set("${result}_repo_include_dir" "${QT_BUILD_DIR}/include" PARENT_SCOPE) - set("${result}_include_dir" "${QT_BUILD_DIR}/include/${module}" PARENT_SCOPE) + set("${result}_repo_include_dir" "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}" PARENT_SCOPE) + set("${result}_include_dir" "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}/${module}" PARENT_SCOPE) set("${result}_define" "${define}" PARENT_SCOPE) endfunction() @@ -854,7 +946,7 @@ endfunction() set(__default_private_args "SOURCES;LIBRARIES;INCLUDE_DIRECTORIES;DEFINES;DBUS_ADAPTOR_BASENAME;DBUS_ADAPTOR_FLAGS;DBUS_ADAPTOR_SOURCES;DBUS_INTERFACE_BASENAME;DBUS_INTERFACE_FLAGS;DBUS_INTERFACE_SOURCES;FEATURE_DEPENDENCIES;COMPILE_OPTIONS;LINK_OPTIONS;MOC_OPTIONS;DISABLE_AUTOGEN_TOOLS;ENABLE_AUTOGEN_TOOLS;PLUGIN_TYPES") set(__default_public_args "PUBLIC_LIBRARIES;PUBLIC_INCLUDE_DIRECTORIES;PUBLIC_DEFINES;PUBLIC_COMPILE_OPTIONS;PUBLIC_LINK_OPTIONS") - +set(__default_private_module_args "PRIVATE_MODULE_INTERFACE") option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF) @@ -865,8 +957,10 @@ function(qt_autogen_tools_initial_setup target) set_property(TARGET "${target}" APPEND PROPERTY COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION) set_directory_properties(PROPERTIES - QT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} - QT_VERSION_MINOR ${PROJECT_VERSION_MINOR}) + QT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} + QT_VERSION_MINOR ${PROJECT_VERSION_MINOR} + QT_VERSION_PATCH ${PROJECT_VERSION_PATCH} + ) qt_enable_autogen_tool(${target} "moc" ON) endfunction() @@ -930,7 +1024,14 @@ function(qt_register_target_dependencies target public_libs private_libs) set(target_deps "") endif() - foreach(lib IN LISTS public_libs private_libs) + # Only process private dependencies if target is a static library + get_target_property(target_type ${target} TYPE) + set(lib_list ${public_libs}) + if (target_type STREQUAL "STATIC_LIBRARY") + list(APPEND lib_list ${private_libs}) + endif() + + foreach(lib IN LISTS lib_list) if ("${lib}" MATCHES "^Qt::(.*)") set(lib "${CMAKE_MATCH_1}") if (lib STREQUAL Platform @@ -980,7 +1081,7 @@ endfunction() # This function can be used to add sources/libraries/etc. to the specified CMake target # if the provided CONDITION evaluates to true. -function(extend_target target) +function(qt_extend_target target) # Don't try to extend_target when cross compiling an imported host target (like a tool). qt_is_imported_target("${target}" is_imported) if(is_imported) @@ -990,8 +1091,8 @@ function(extend_target target) if (NOT TARGET "${target}") message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".") endif() - qt_parse_all_arguments(arg "extend_target" "HEADER_MODULE" "PRECOMPILED_HEADER" - "CONDITION;${__default_public_args};${__default_private_args};COMPILE_FLAGS;NO_PCH_SOURCES" ${ARGN}) + qt_parse_all_arguments(arg "qt_extend_target" "HEADER_MODULE" "PRECOMPILED_HEADER" + "CONDITION;${__default_public_args};${__default_private_args};${__default_private_module_args};COMPILE_FLAGS;NO_PCH_SOURCES" ${ARGN}) if ("x${arg_CONDITION}" STREQUAL x) set(arg_CONDITION ON) endif() @@ -999,7 +1100,7 @@ function(extend_target target) qt_evaluate_config_expression(result ${arg_CONDITION}) if (${result}) if(QT_CMAKE_DEBUG_EXTEND_TARGET) - message("extend_target(${target} CONDITION ${arg_CONDITION} ...): Evaluated") + message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Evaluated") endif() set(dbus_sources "") foreach(adaptor ${arg_DBUS_ADAPTOR_SOURCES}) @@ -1073,10 +1174,12 @@ function(extend_target target) ${private_visibility_option} ${arg_LINK_OPTIONS}) if(NOT arg_HEADER_MODULE) - set_target_properties("${target}" PROPERTIES + set_property (TARGET "${target}" APPEND PROPERTY AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}" - _qt_target_deps "${target_deps}" ) + set_property(TARGET "${target}" PROPERTY + _qt_target_deps "${target_deps}" + ) endif() # When computing the private library dependencies, we need to check not only the known @@ -1097,7 +1200,8 @@ function(extend_target target) set(target_private "${target}Private") if(TARGET "${target_private}") - target_link_libraries("${target_private}" INTERFACE "${target}" "${qt_libs_private}") + target_link_libraries("${target_private}" + INTERFACE "${target}" ${arg_PRIVATE_MODULE_INTERFACE}) endif() qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" @@ -1115,7 +1219,7 @@ function(extend_target target) else() if(QT_CMAKE_DEBUG_EXTEND_TARGET) - message("extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped") + message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped") endif() endif() endfunction() @@ -1125,17 +1229,25 @@ function(qt_internal_library_deprecation_level result) if(WIN32) # On Windows, due to the way DLLs work, we need to export all functions, # including the inlines - set("${result}" "QT_DISABLE_DEPRECATED_BEFORE=0x040800" PARENT_SCOPE) + list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x040800") else() # On other platforms, Qt's own compilation goes needs to compile the Qt 5.0 API - set("${result}" "QT_DISABLE_DEPRECATED_BEFORE=0x050000" PARENT_SCOPE) + list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x050000") endif() - set("${result}" "QT_DEPRECATED_WARNINGS_SINCE=0x060000" PARENT_SCOPE) + list(APPEND deprecations "QT_DEPRECATED_WARNINGS_SINCE=0x060000") + set("${result}" deprecations PARENT_SCOPE) endfunction() -function(qt_install_injections module build_dir install_dir) +function(qt_install_injections target build_dir install_dir) set(injections ${ARGN}) + set(module "Qt${target}") + get_target_property(target_type ${target} TYPE) + if (target_type STREQUAL "INTERFACE_LIBRARY") + set(is_framework FALSE) + else() + get_target_property(is_framework ${target} FRAMEWORK) + endif() # examples: # SYNCQT.INJECTIONS = src/corelib/global/qconfig.h:qconfig.h:QtConfig src/corelib/global/qconfig_p.h:5.12.0/QtCore/private/qconfig_p.h # SYNCQT.INJECTIONS = src/gui/vulkan/qvulkanfunctions.h:^qvulkanfunctions.h:QVulkanFunctions:QVulkanDeviceFunctions src/gui/vulkan/qvulkanfunctions_p.h:^5.12.0/QtGui/private/qvulkanfunctions_p.h @@ -1191,14 +1303,24 @@ function(qt_install_injections module build_dir install_dir) file(GENERATE OUTPUT "${lower_case_forwarding_header_path}/${original_file_name}" CONTENT "${main_contents}") - # Copy the actual injected (generated) header file (not the just created forwarding one) - # to its install location when doing a prefix build. In an non-prefix build, the qt_install - # will be a no-op. - qt_path_join(install_destination - ${install_dir} ${INSTALL_INCLUDEDIR} ${module} ${destinationdir}) - qt_install(FILES ${current_repo_build_dir}/${file} - DESTINATION ${install_destination} - RENAME ${destinationname} OPTIONAL) + if(is_framework) + if(file MATCHES "_p\\.h$") + set(header_type PRIVATE) + else() + set(header_type PUBLIC) + endif() + qt_copy_framework_headers(${target} ${header_type} + ${current_repo_build_dir}/${file}) + else() + # Copy the actual injected (generated) header file (not the just created forwarding one) + # to its install location when doing a prefix build. In an non-prefix build, the qt_install + # will be a no-op. + qt_path_join(install_destination + ${install_dir} ${INSTALL_INCLUDEDIR} ${module} ${destinationdir}) + qt_install(FILES ${current_repo_build_dir}/${file} + DESTINATION ${install_destination} + RENAME ${destinationname} OPTIONAL) + endif() # Generate UpperCaseNamed forwarding headers (part 3). foreach(fwd_hdr ${fwd_hdrs}) @@ -1211,11 +1333,17 @@ function(qt_install_injections module build_dir install_dir) file(GENERATE OUTPUT "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" CONTENT "#include \"${destinationname}\"\n") - # Install the forwarding header. - qt_path_join(install_destination - ${install_dir} ${upper_case_forwarding_header_path}) - qt_install(FILES "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" - DESTINATION ${install_destination} OPTIONAL) + if(is_framework) + # Copy the forwarding header to the framework's Headers directory. + qt_copy_framework_headers(${target} PUBLIC + "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}") + else() + # Install the forwarding header. + qt_path_join(install_destination + ${install_dir} ${upper_case_forwarding_header_path}) + qt_install(FILES "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" + DESTINATION ${install_destination} OPTIONAL) + endif() endforeach() endforeach() endfunction() @@ -1281,6 +1409,121 @@ function(qt_internal_set_no_exceptions_flags target) endif() endfunction() +function(qt_skip_warnings_are_errors target) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + set_target_properties("${target}" PROPERTIES QT_SKIP_WARNINGS_ARE_ERRORS ON) +endfunction() + +function(qt_skip_warnings_are_errors_when_repo_unclean target) + if(QT_REPO_NOT_WARNINGS_CLEAN) + qt_skip_warnings_are_errors("${target}") + endif() +endfunction() + +function(qt_get_sanitized_plugin_type plugin_type out_var) + # Used to handle some edge cases such as platforms/darwin + string(REGEX REPLACE "[-/]" "_" plugin_type "${plugin_type}") + set("${out_var}" "${plugin_type}" PARENT_SCOPE) +endfunction() + +# Copy header files to QtXYZ.framework/Versions/6/Headers/ +# Use this function for header files that +# - are not added as source files to the target +# - are not marked as PUBLIC_HEADER +# - or are private and supposed to end up in the 6.7.8/QtXYZ/private subdir. +function(qt_copy_framework_headers target) + get_target_property(is_fw ${target} FRAMEWORK) + if(NOT "${is_fw}") + return() + endif() + + set(options PUBLIC PRIVATE QPA) + set(oneValueArgs) + set(multiValueArgs) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + get_target_property(fw_version ${target} FRAMEWORK_VERSION) + get_target_property(fw_bundle_version ${target} MACOSX_FRAMEWORK_BUNDLE_VERSION) + get_target_property(fw_dir ${target} LIBRARY_OUTPUT_DIRECTORY) + get_target_property(fw_name ${target} OUTPUT_NAME) + set(fw_headers_dir ${fw_dir}/${fw_name}.framework/Versions/${fw_version}/Headers/) + if(ARG_PRIVATE) + string(APPEND fw_headers_dir "${fw_bundle_version}/Qt${target}/private/") + elseif(ARG_QPA) + string(APPEND fw_headers_dir "${fw_bundle_version}/Qt${target}/qpa/") + endif() + + set(out_files) + foreach(hdr IN LISTS ARG_UNPARSED_ARGUMENTS) + get_filename_component(in_file_path ${hdr} ABSOLUTE) + get_filename_component(in_file_name ${hdr} NAME) + set(out_file_path ${fw_headers_dir}${in_file_name}) + add_custom_command( + OUTPUT ${out_file_path} + DEPENDS ${in_file_path} + COMMAND ${CMAKE_COMMAND} -E make_directory "${fw_headers_dir}" + COMMAND ${CMAKE_COMMAND} -E copy "${in_file_path}" "${fw_headers_dir}") + list(APPEND out_files ${out_file_path}) + endforeach() + + get_target_property(fw_copied_headers ${target} QT_COPIED_FRAMEWORK_HEADERS) + if(NOT fw_copied_headers) + set(fw_copied_headers "") + endif() + list(APPEND fw_copied_headers ${out_files}) + set_target_properties(${target} PROPERTIES QT_COPIED_FRAMEWORK_HEADERS "${fw_copied_headers}") +endfunction() + +function(qt_finalize_framework_headers_copy target) + get_target_property(target_type ${target} TYPE) + if(${target_type} STREQUAL "INTERFACE_LIBRARY") + return() + endif() + get_target_property(is_fw ${target} FRAMEWORK) + if(NOT "${is_fw}") + return() + endif() + get_target_property(headers ${target} QT_COPIED_FRAMEWORK_HEADERS) + if(headers) + # Hack to create the "Headers" symlink in the framework: + # Create a fake header file and copy it into the framework by marking it as PUBLIC_HEADER. + # CMake now takes care of creating the symlink. + set(fake_header ${target}_fake_header.h) + qt_get_main_cmake_configuration(main_config) + file(GENERATE OUTPUT ${fake_header} CONTENT "// ignore this file\n" + CONDITION "$<CONFIG:${main_config}>") + string(PREPEND fake_header "${CMAKE_CURRENT_BINARY_DIR}/") + target_sources(${target} PRIVATE ${fake_header}) + set_source_files_properties(${fake_header} PROPERTIES GENERATED ON) + set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER ${fake_header}) + + # Add a target, e.g. Core_framework_headers, that triggers the header copy. + add_custom_target(${target}_framework_headers DEPENDS ${headers}) + add_dependencies(${target} ${target}_framework_headers) + endif() +endfunction() + +function(qt_clone_property_for_configs target property configs) + get_target_property(value "${target}" "${property}") + foreach(config ${configs}) + string(TOUPPER "${config}" upper_config) + set_property(TARGET "${target}" PROPERTY "${property}_${upper_config}" "${value}") + endforeach() +endfunction() + +function(qt_handle_multi_config_output_dirs target) + set(possible_configs "${CMAKE_BUILD_TYPE}") + if(CMAKE_CONFIGURATION_TYPES) + set(possible_configs "${CMAKE_CONFIGURATION_TYPES}") + endif() + qt_clone_property_for_configs(${target} LIBRARY_OUTPUT_DIRECTORY "${possible_configs}") + qt_clone_property_for_configs(${target} RUNTIME_OUTPUT_DIRECTORY "${possible_configs}") + qt_clone_property_for_configs(${target} ARCHIVE_OUTPUT_DIRECTORY "${possible_configs}") +endfunction() + # This is the main entry function for creating a Qt module, that typically # consists of a library, public header files, private header files and configurable # features. @@ -1291,14 +1534,14 @@ endfunction() # this module are imported into the scope of the calling feature. # # Target is without leading "Qt". So e.g. the "QtCore" module has the target "Core". -function(add_qt_module target) +function(qt_add_module target) qt_internal_module_info(module "${target}") # Process arguments: - qt_parse_all_arguments(arg "add_qt_module" - "NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT;NO_PRIVATE_MODULE;HEADER_MODULE" + qt_parse_all_arguments(arg "qt_add_module" + "NO_MODULE_HEADERS;STATIC;DISABLE_TOOLS_EXPORT;EXCEPTIONS;INTERNAL_MODULE;NO_SYNC_QT;NO_PRIVATE_MODULE;HEADER_MODULE;GENERATE_METATYPES" "CONFIG_MODULE_NAME;PRECOMPILED_HEADER" - "${__default_private_args};${__default_public_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN}) + "${__default_private_args};${__default_public_args};${__default_private_module_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN}) if(NOT DEFINED arg_CONFIG_MODULE_NAME) set(arg_CONFIG_MODULE_NAME "${module_lower}") @@ -1307,8 +1550,10 @@ function(add_qt_module target) qt_internal_add_qt_repo_known_module("${target}") ### Define Targets: + set(is_interface_lib 0) if(${arg_HEADER_MODULE}) add_library("${target}" INTERFACE) + set(is_interface_lib 1) elseif(${arg_STATIC}) add_library("${target}" STATIC) elseif(${QT_BUILD_SHARED_LIBS}) @@ -1317,10 +1562,23 @@ function(add_qt_module target) add_library("${target}" STATIC) endif() + set(is_framework 0) + if(QT_FEATURE_framework AND NOT ${arg_HEADER_MODULE} AND NOT ${arg_STATIC}) + set(is_framework 1) + set_target_properties(${target} PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR} + MACOSX_FRAMEWORK_IDENTIFIER org.qt-project.Qt${target} + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + ) + endif() + if (ANDROID) qt_android_apply_arch_suffix("${target}") endif() qt_internal_add_target_aliases("${target}") + qt_skip_warnings_are_errors_when_repo_unclean("${target}") # Add _private target to link against the private headers: if(NOT ${arg_NO_PRIVATE_MODULE}) @@ -1329,6 +1587,27 @@ function(add_qt_module target) qt_internal_add_target_aliases("${target_private}") endif() + if(NOT arg_HEADER_MODULE) + set_target_properties(${target} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + ) + qt_handle_multi_config_output_dirs("${target}") + + if(is_framework) + set_target_properties(${target} PROPERTIES + OUTPUT_NAME Qt${target} + ) + else() + set_target_properties(${target} PROPERTIES + OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" + ) + endif() + endif() + # Module headers: if(${arg_NO_MODULE_HEADERS} OR ${arg_NO_SYNC_QT}) set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS OFF) @@ -1351,41 +1630,52 @@ function(add_qt_module target) ### FIXME: Can we replace headers.pri? qt_read_headers_pri("${target}" "module_headers") - set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${module_headers_public}") - set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${module_include_dir}/${module}Depends") - set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${module_headers_private}") + set(module_depends_header "${module_include_dir}/${module}Depends") + if(is_framework) + if(NOT is_interface_lib) + set(public_headers_to_copy "${module_headers_public}" "${module_depends_header}") + qt_copy_framework_headers(${target} PUBLIC "${public_headers_to_copy}") + qt_copy_framework_headers(${target} PRIVATE "${module_headers_private}") + endif() + else() + set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER "${module_headers_public}") + set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER ${module_depends_header}) + set_property(TARGET ${target} APPEND PROPERTY PRIVATE_HEADER "${module_headers_private}") + endif() if (NOT ${arg_HEADER_MODULE}) set_property(TARGET "${target}" PROPERTY MODULE_HEADER "${module_include_dir}/${module}") endif() if(module_headers_qpa) - qt_install(FILES ${module_headers_qpa} DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/qpa) + if(is_framework) + qt_copy_framework_headers(${target} QPA "${module_headers_qpa}") + else() + qt_install( + FILES ${module_headers_qpa} + DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/qpa) + endif() endif() endif() if(NOT arg_HEADER_MODULE) + # This property is used for super builds with static libraries. We use + # it in QtPlugins.cmake.in to avoid "polluting" the dependency chain + # for the target in it's project directory. + # E.g: When we process find_package(Qt6 ... Gui) in QtDeclarative, the + # rules in QtPugins.cmake add all the known Gui plugins as interface + # dependencies. This in turn causes circular dependencies on every + # plugin which links against Gui. Plugin A -> GUI -> Plugin A .... + + set_target_properties(${target} PROPERTIES QT_BUILD_PROJECT_NAME ${PROJECT_NAME}) # Plugin types associated to a module if(NOT "x${arg_PLUGIN_TYPES}" STREQUAL "x") # Reset the variable containing the list of plugins for the given plugin type foreach(plugin_type ${arg_PLUGIN_TYPES}) - # Used to handle some edge cases such as platforms/darwin - string(REGEX REPLACE "[-/]" "_" plugin_type "${plugin_type}") - + qt_get_sanitized_plugin_type("${plugin_type}" plugin_type) set_property(TARGET "${target}" APPEND PROPERTY MODULE_PLUGIN_TYPES "${plugin_type}") qt_internal_add_qt_repo_known_plugin_types("${plugin_type}") endforeach() endif() - - set_target_properties("${target}" PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" - RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" - RUNTIME_OUTPUT_DIRECTORY_RELEASE "${QT_BUILD_DIR}/${INSTALL_BINDIR}" - RUNTIME_OUTPUT_DIRECTORY_DEBUG "${QT_BUILD_DIR}/${INSTALL_BINDIR}" - ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" - ) endif() qt_internal_library_deprecation_level(deprecation_define) @@ -1401,15 +1691,37 @@ function(add_qt_module target) ) set(public_includes "") + set(public_headers_list "public_includes") + if(is_framework) + set(public_headers_list "private_includes") + set(fw_bundle_subdir "${INSTALL_LIBDIR}/Qt${target}.framework") + set(fw_headers_subdir "Versions/${PROJECT_VERSION_MAJOR}/Headers") + list(APPEND public_includes + # Add the lib/Foo.framework dir as include path to let CMake generate + # the -F compiler flag. + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${fw_bundle_subdir}>" + "$<INSTALL_INTERFACE:${fw_bundle_subdir}>" + + # Add the fully resolved Headers subdir, because the Headers symlink might + # not be there yet. + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${fw_bundle_subdir}/${fw_headers_subdir}>" + + # After installing, the Headers symlink is guaranteed to exist. + "$<INSTALL_INTERFACE:${fw_bundle_subdir}/Headers>" + ) + endif() # Handle cases like QmlDevTools which do not have their own headers, but rather borrow them # from another module. if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS) - list(APPEND private_includes - "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>" - "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>") + # Don't include private headers unless they exist, aka syncqt created them. + if(module_headers_private) + list(APPEND private_includes + "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>" + "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>") + endif() - list(APPEND public_includes + list(APPEND ${public_headers_list} # For the syncqt headers "$<BUILD_INTERFACE:${module_repo_include_dir}>" "$<BUILD_INTERFACE:${module_include_dir}>") @@ -1417,16 +1729,16 @@ function(add_qt_module target) if(NOT arg_NO_MODULE_HEADERS AND NOT arg_NO_SYNC_QT) # For the syncqt headers - list(APPEND public_includes "$<INSTALL_INTERFACE:include/${module}>") + list(APPEND ${public_headers_list} "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}>") endif() - list(APPEND public_includes ${arg_PUBLIC_INCLUDE_DIRECTORIES}) + list(APPEND ${public_headers_list} ${arg_PUBLIC_INCLUDE_DIRECTORIES}) set(header_module) if(arg_HEADER_MODULE) set(header_module "HEADER_MODULE") endif() - extend_target("${target}" + qt_extend_target("${target}" ${header_module} SOURCES ${arg_SOURCES} INCLUDE_DIRECTORIES @@ -1447,6 +1759,7 @@ function(add_qt_module target) "${deprecation_define}" PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} LIBRARIES ${arg_LIBRARIES} Qt::PlatformModuleInternal + PRIVATE_MODULE_INTERFACE ${arg_PRIVATE_MODULE_INTERFACE} FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} DBUS_ADAPTOR_SOURCES ${arg_DBUS_ADAPTOR_SOURCES} DBUS_ADAPTOR_FLAGS ${arg_DBUS_ADAPTOR_FLAGS} @@ -1483,10 +1796,12 @@ function(add_qt_module target) set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config_p.h") endif() - if(DEFINED module_headers_private) - qt_internal_add_linker_version_script("${target}" PRIVATE_HEADERS ${module_headers_private} ${module_headers_qpa}) - else() - qt_internal_add_linker_version_script("${target}") + if(NOT arg_HEADER_MODULE) + if(DEFINED module_headers_private) + qt_internal_add_linker_version_script("${target}" PRIVATE_HEADERS ${module_headers_private} ${module_headers_qpa}) + else() + qt_internal_add_linker_version_script("${target}") + endif() endif() # Handle injections. Aka create forwarding headers for certain headers that have been @@ -1503,7 +1818,7 @@ function(add_qt_module target) endif() if(final_injections) - qt_install_injections("${module}" "${QT_BUILD_DIR}" "${QT_INSTALL_DIR}" ${final_injections}) + qt_install_injections(${target} "${QT_BUILD_DIR}" "${QT_INSTALL_DIR}" ${final_injections}) endif() # Handle creation of cmake files for consumers of find_package(). @@ -1542,11 +1857,32 @@ function(add_qt_module target) set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") endif() + # Generate metatypes + set(QT_MODULE_HAS_META_TYPES_FILE FALSE) + if (${arg_GENERATE_METATYPES}) + set(QT_MODULE_HAS_META_TYPES_FILE TRUE) + set(metatypes_install_dir ${INSTALL_LIBDIR}/metatypes) + set(args) + if (NOT QT_WILL_INSTALL) + set(args COPY_OVER_INSTALL INSTALL_DIR "${QT_BUILD_DIR}/${metatypes_install_dir}") + else() + set(args INSTALL_DIR "${metatypes_install_dir}") + endif() + qt6_generate_meta_types_json_file(${target} ${args}) + endif() configure_package_config_file( "${QT_CMAKE_DIR}/QtModuleConfig.cmake.in" "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" INSTALL_DESTINATION "${config_install_dir}" ) + + if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake") + configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake" + @ONLY) + list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}BuildInternals.cmake") + endif() + write_basic_package_version_file( "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" VERSION ${PROJECT_VERSION} @@ -1571,11 +1907,12 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") RUNTIME DESTINATION ${INSTALL_BINDIR} LIBRARY DESTINATION ${INSTALL_LIBDIR} ARCHIVE DESTINATION ${INSTALL_LIBDIR} + FRAMEWORK DESTINATION ${INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module} PRIVATE_HEADER DESTINATION ${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}/private ) - if (ANDROID) + if (ANDROID AND NOT arg_HEADER_MODULE) # Record install library location so it can be accessed by # qt_android_dependencies without having to specify it again. set_target_properties(${target} PROPERTIES @@ -1597,14 +1934,14 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") unset(arg_INTERNAL_MODULE) endif() - qt_path_join(pri_target_path ${PROJECT_BINARY_DIR} mkspecs/modules) + qt_path_join(pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR}/modules) qt_generate_module_pri_file("${target}" "${pri_target_path}" module_pri_files ${arg_INTERNAL_MODULE} ${header_module} QMAKE_MODULE_CONFIG ${arg_QMAKE_MODULE_CONFIG} ) - qt_install(FILES "${module_pri_files}" DESTINATION mkspecs/modules) + qt_install(FILES "${module_pri_files}" DESTINATION ${INSTALL_MKSPECSDIR}/modules) ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins # that belong to Qt. @@ -1617,21 +1954,37 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})") # Handle cases like QmlDevTools which do not have their own headers, but rather borrow them # from another module. if(NOT arg_NO_SYNC_QT) - list(APPEND interface_includes - "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>" - "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>" - "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>") + list(APPEND interface_includes "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>") if(NOT arg_NO_MODULE_HEADERS) list(APPEND interface_includes - "$<INSTALL_INTERFACE:include/${module}/${PROJECT_VERSION}>" - "$<INSTALL_INTERFACE:include/${module}/${PROJECT_VERSION}/${module}>") + "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}>" + "$<BUILD_INTERFACE:${module_include_dir}/${PROJECT_VERSION}/${module}>") + + if(is_framework) + set(fw_headers_dir + "${INSTALL_LIBDIR}/${module}.framework/Headers/") + list(APPEND interface_includes + "$<INSTALL_INTERFACE:${fw_headers_dir}${PROJECT_VERSION}>" + "$<INSTALL_INTERFACE:${fw_headers_dir}${PROJECT_VERSION}/${module}>") + else() + list(APPEND interface_includes + "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}>" + "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}/${PROJECT_VERSION}/${module}>") + endif() endif() endif() if(NOT ${arg_NO_PRIVATE_MODULE}) target_include_directories("${target_private}" INTERFACE ${interface_includes}) endif() + + if(is_framework AND NOT is_interface_lib) + qt_finalize_framework_headers_copy(${target}) + endif() + + qt_describe_module(${target}) + endfunction() function(qt_export_tools module_name) @@ -1654,7 +2007,19 @@ function(qt_export_tools module_name) # Also assemble a list of tool targets to expose in the config file for informational purposes. set(extra_cmake_statements "") set(tool_targets "") + set(tool_targets_non_prefixed "") + + # List of package dependencies that need be find_package'd when using the Tools package. + set(package_deps "") + foreach(tool_name ${QT_KNOWN_MODULE_${module_name}_TOOLS}) + # Specific tools can have package dependencies. + # e.g. qtwaylandscanner depends on WaylandScanner (non-qt package). + get_target_property(extra_packages "${tool_name}" QT_EXTRA_PACKAGE_DEPENDENCIES) + if(extra_packages) + list(APPEND package_deps "${extra_packages}") + endif() + set(extra_cmake_statements "${extra_cmake_statements} if (NOT QT_NO_CREATE_TARGETS) get_property(is_global TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL) @@ -1664,11 +2029,37 @@ if (NOT QT_NO_CREATE_TARGETS) endif() ") list(APPEND tool_targets "${QT_CMAKE_EXPORT_NAMESPACE}::${tool_name}") + list(APPEND tool_targets_non_prefixed "${tool_name}") endforeach() string(APPEND extra_cmake_statements "set(${QT_CMAKE_EXPORT_NAMESPACE}${module_name}Tools_TARGETS \"${tool_targets}\")") + # Extract package dependencies that were determined in QtPostProcess, but only if ${module_name} + # is an actual target. + # module_name can be a non-existent target, if the tool doesn't have an existing associated + # module, e.g. qtwaylandscanner. + if(TARGET "${module_name}") + get_target_property(module_package_deps "${module_name}" _qt_tools_package_deps) + if(module_package_deps) + list(APPEND package_deps "${module_package_deps}") + endif() + endif() + + # Configure and install dependencies file for the ${module_name}Tools package. + configure_file( + "${QT_CMAKE_DIR}/QtModuleToolsDependencies.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake" + @ONLY + ) + + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Dependencies.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + # Configure and install the ${module_name}Tools package Config file. configure_package_config_file( "${QT_CMAKE_DIR}/QtModuleToolsConfig.cmake.in" "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" @@ -1692,17 +2083,57 @@ endif() NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::" DESTINATION "${config_install_dir}") - # Temporarily disable creation of versionless targets for tools, - # because it breaks qtdeclarative build. - #qt_internal_export_modern_cmake_config_targets_file(TARGETS ${QT_KNOWN_MODULE_${module_name}_TOOLS} - # EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} - # CONFIG_INSTALL_DIR ${config_install_dir}) + + # Create versionless targets file. + configure_file( + "${QT_CMAKE_DIR}/QtModuleToolsVersionlessTargets.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}VersionlessTargets.cmake" + @ONLY + ) + + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}VersionlessTargets.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) +endfunction() + +# This function records a dependency between ${target_name} and ${dep_package_name}. +# at the CMake package level. +# E.g. The Tools package that provides the qtwaylandscanner target +# needs to call find_package(WaylandScanner) (non-qt-package). +# main_target_name = qtwaylandscanner +# dep_package_name = WaylandScanner +function(qt_record_extra_package_dependency main_target_name dep_package_name dep_package_version) + get_target_property(extra_packages "${main_target_name}" QT_EXTRA_PACKAGE_DEPENDENCIES) + if(NOT extra_packages) + set(extra_packages "") + endif() + + list(APPEND extra_packages "${dep_package_name}\;${dep_package_version}") + set_target_properties("${main_target_name}" PROPERTIES QT_EXTRA_PACKAGE_DEPENDENCIES + "${extra_packages}") +endfunction() + +# This function records a dependency between ${main_target_name} and ${dep_target_name} +# at the CMake package level. +# E.g. Qt6CoreConfig.cmake needs to find_package(Qt6WinMain). +# main_target_name = Core +# dep_target_name = WinMain +# This is just a convenience function that deals with Qt targets and their associated packages +# instead of raw package names. +function(qt_record_extra_qt_package_dependency main_target_name dep_target_name + dep_package_version) + # WinMain -> Qt6WinMain. + qt_internal_module_info(qtfied_target_name "${dep_target_name}") + qt_record_extra_package_dependency("${main_target_name}" "${qtfied_target_name_versioned}" + "${dep_package_version}") endfunction() function(qt_internal_check_directory_or_type name dir type default result_var) if ("x${dir}" STREQUAL x) if("x${type}" STREQUAL x) - message(FATAL_ERROR "add_qt_plugin called without setting either TYPE or ${name}.") + message(FATAL_ERROR "qt_add_plugin called without setting either TYPE or ${name}.") endif() set(${result_var} "${default}" PARENT_SCOPE) else() @@ -1714,6 +2145,8 @@ endfunction() # This will set the QT_MODULE target property on the plug-in - e.g. "Gui", "Sql"... function(qt_get_module_for_plugin target target_type) qt_internal_get_qt_all_known_modules(known_modules) + + qt_get_sanitized_plugin_type("${target_type}" target_type) foreach(qt_module ${known_modules}) get_target_property(module_type "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" TYPE) # Assuming interface libraries can't have plugins. Otherwise we'll need to fix the property @@ -1738,32 +2171,34 @@ function(qt_get_module_for_plugin target target_type) endfunction() -# Collection of add_qt_plugin arguments so they can be shared across different +# Collection of qt_add_plugin arguments so they can be shared across different # plugin type wrappers -set(__add_qt_plugin_optional_args - "STATIC;EXCEPTIONS" +set(__qt_add_plugin_optional_args + "STATIC;EXCEPTIONS;ALLOW_UNDEFINED_SYMBOLS" ) -set(__add_qt_plugin_single_args - "TYPE;CLASS_NAME;OUTPUT_DIRECTORY;INSTALL_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY;QML_TARGET_PATH" +set(__qt_add_plugin_single_args + "TYPE;CLASS_NAME;OUTPUT_DIRECTORY;INSTALL_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY;QML_TARGET_PATH;OUTPUT_NAME" ) -set(__add_qt_plugin_multi_args +set(__qt_add_plugin_multi_args "${__default_private_args};${__default_public_args};DEFAULT_IF" ) # This is the main entry point for defining Qt plugins. # A CMake target is created with the given target. The TYPE parameter is needed to place the # plugin into the correct plugins/ sub-directory. -function(add_qt_plugin target) +function(qt_add_plugin target) qt_internal_module_info(module "${target}") qt_internal_set_qt_known_plugins("${QT_KNOWN_PLUGINS}" "${target}") - qt_parse_all_arguments(arg "add_qt_plugin" - "${__add_qt_plugin_optional_args};SKIP_INSTALL" - "${__add_qt_plugin_single_args}" - "${__add_qt_plugin_multi_args}" + qt_parse_all_arguments(arg "qt_add_plugin" + "${__qt_add_plugin_optional_args};SKIP_INSTALL" + "${__qt_add_plugin_single_args}" + "${__qt_add_plugin_multi_args}" "${ARGN}" ) + qt_get_sanitized_plugin_type("${arg_TYPE}" arg_TYPE) + set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${arg_TYPE}") set(install_directory_default "${INSTALL_PLUGINSDIR}/${arg_TYPE}") set(archive_install_directory_default "${INSTALL_LIBDIR}/${arg_TYPE}") @@ -1775,8 +2210,11 @@ function(add_qt_plugin target) set(archive_install_directory_default "${INSTALL_QMLDIR}/${target_path}") endif() - if ("x${arg_CLASS_NAME}" STREQUAL "x" AND NOT "${arg_TYPE}" STREQUAL "qml_plugin") - message(AUTHOR_WARNING "add_qt_plugin called without setting CLASS_NAME.") + # Derive the class name from the target name if it's not explicitly specified. + # Don't set it for qml plugins though. + set(plugin_class_name "") + if (NOT arg_CLASS_NAME AND NOT "${arg_TYPE}" STREQUAL "qml_plugin") + set(plugin_class_name "${target}") endif() qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${arg_TYPE}" @@ -1800,16 +2238,40 @@ function(add_qt_plugin target) endif() endif() + # Make sure the Qt6 plugin library names are like they were in Qt5 qmake land. + # Whereas the Qt6 CMake target names are like the Qt5 CMake target names. + set(output_name "${target}") + if(arg_OUTPUT_NAME) + set(output_name "${arg_OUTPUT_NAME}") + endif() + set_property(TARGET "${target}" PROPERTY OUTPUT_NAME "${output_name}") + + # Add a custom target with the Qt5 qmake name for a more user friendly ninja experience. + if(arg_OUTPUT_NAME AND NOT TARGET "${output_name}") + add_custom_target("${output_name}") + add_dependencies("${output_name}" "${target}") + endif() + if (ANDROID) qt_android_apply_arch_suffix("${target}") + set_target_properties(${target} + PROPERTIES + LIBRARY_OUTPUT_NAME "plugins_${arg_TYPE}_${output_name}" + ) endif() qt_internal_add_target_aliases("${target}") + qt_skip_warnings_are_errors_when_repo_unclean("${target}") + + # Disable linking of plugins against other plugins during static regular and + # super builds. The latter causes cyclic dependencies otherwise. + set_target_properties(${target} PROPERTIES QT_DEFAULT_PLUGINS 0) set_target_properties("${target}" PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${output_directory}" RUNTIME_OUTPUT_DIRECTORY "${output_directory}" ARCHIVE_OUTPUT_DIRECTORY "${output_directory}" - QT_PLUGIN_CLASS_NAME "${arg_CLASS_NAME}") + QT_PLUGIN_CLASS_NAME "${plugin_class_name}") + qt_handle_multi_config_output_dirs("${target}") qt_internal_library_deprecation_level(deprecation_define) @@ -1853,7 +2315,7 @@ function(add_qt_plugin target) ${arg_PUBLIC_INCLUDE_DIRECTORIES} ) - extend_target("${target}" + qt_extend_target("${target}" SOURCES ${arg_SOURCES} INCLUDE_DIRECTORIES ${private_includes} @@ -1930,7 +2392,7 @@ function(add_qt_plugin target) ) # Make the export name of plugins be consistent with modules, so that - # add_qt_resource adds its additional targets to the same export set in a static Qt build. + # qt_add_resource adds its additional targets to the same export set in a static Qt build. set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") qt_install(TARGETS "${target}" EXPORT ${export_name} @@ -1947,80 +2409,13 @@ function(add_qt_plugin target) # Store the plug-in type in the target property set_property(TARGET "${target}" PROPERTY QT_PLUGIN_TYPE "${arg_TYPE}") - ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins - # that belong to Qt. - qt_internal_add_link_flags_no_undefined("${target}") - - qt_internal_add_linker_version_script(${target}) -endfunction() - -# Generate custom ${target}_qmltypes target for Qml Plugins -function(qt_add_qmltypes_target target) - - # Do nothing when cross compiling - if (CMAKE_CROSSCOMPILING) - return() - endif() - - # Do nothing during a Qt static build (because the tool isn't built in that case). - if (NOT QT_BUILD_SHARED_LIBS) - return() - endif() - - qt_parse_all_arguments(arg "qt_generate_qmltypes" - "" - "TARGET_PATH;IMPORT_VERSION;IMPORT_NAME;QML_PLUGINDUMP_DEPENDENCIES" - "" - ${ARGN}) - - # scan repos for qml repositories - foreach(repo IN LISTS QT_REPOS) - if (IS_DIRECTORY "${repo}/qml") - list(APPEND import_paths "${repo}/qml") - endif() - endforeach() - list(REMOVE_DUPLICATES import_paths) - if (UNIX) - list(JOIN import_paths ":" import_paths_env) - else() - list(JOIN import_paths "\;" import_paths_env) - endif() - - if(NOT arg_IMPORT_NAME) - string(REGEX REPLACE "\\.\\d+$" "" import_name ${arg_TARGET_PATH}) - else() - set(import_name ${arg_IMPORT_NAME}) - endif() - - if(NOT arg_IMPORT_VERSION) - message(FATAL_ERROR "Import version parameter was not specified. Specify the import version using the IMPORT_VERSION.") - endif() - - get_target_property(source_dir ${target} SOURCE_DIR) - - # qml1_target check is no longer required - set(qmltypes_command_args "-nonrelocatable") - if (NOT arg_QML_PLUGINDUMP_DEPENDENCIES AND EXISTS "${source_dir}/dependencies.json") - list(APPEND qmltypes_command_args "-dependencies" "${source_dir}/dependencies.json") - elseif(arg_QML_PLUGINDUMP_DEPENDENCIES) - list(APPEND qmltypes_command_args "-dependencies" "${arg_QML_PLUGINDUMP_DEPENDENCIES}") + if (NOT arg_ALLOW_UNDEFINED_SYMBOLS) + ### fixme: cmake is missing a built-in variable for this. We want to apply it only to + # modules and plugins that belong to Qt. + qt_internal_add_link_flags_no_undefined("${target}") endif() - string(REPLACE "/" "." import_name_arg ${import_name}) - - list(APPEND qmltypes_command_args "${import_name_arg}" "${arg_IMPORT_VERSION}") - - set(qml_plugindump_target ${QT_CMAKE_EXPORT_NAMESPACE}::qmlplugindump) - - # Manually set dependency on plugindump target since CMake will not add - # this rule because it's not the main executable argument to the COMMAND - # parameter. - add_custom_target( - "${target}_qmltypes" - DEPENDS ${qml_plugindump_target} - COMMAND ${CMAKE_COMMAND} -E env "QML2_IMPORTPATH=${import_paths_env}" - $<TARGET_FILE:${qml_plugindump_target}> ${qmltypes_command_args} > "${source_dir}/plugins.qmltypes" - ) + qt_internal_add_linker_version_script(${target}) endfunction() function(qt_install_qml_files target) @@ -2046,7 +2441,7 @@ function(qt_install_qml_files target) endfunction() -function(add_qt_resource target resourceName) +function(qt_add_resource target resourceName) # Don't try to add resources when cross compiling, and the target is actually a host target # (like a tool). qt_is_imported_target("${target}" is_imported) @@ -2054,7 +2449,7 @@ function(add_qt_resource target resourceName) return() endif() - qt_parse_all_arguments(arg "add_qt_resource" "" "PREFIX;LANG;BASE" "FILES" ${ARGN}) + qt_parse_all_arguments(arg "qt_add_resource" "" "PREFIX;LANG;BASE" "FILES" ${ARGN}) QT6_PROCESS_RESOURCE(${target} ${resourceName} PREFIX "${arg_PREFIX}" @@ -2073,198 +2468,56 @@ function(add_qt_resource target resourceName) endfunction() - -# This function creates a CMake target for qml modules. It will also make -# sure that if no C++ source are present, that qml files show up in the project -# in an IDE. Finally, it will also create a custom ${target}_qmltypes which -# can be used to generate the respective plugin.qmltypes file. -# -# CPP_PLUGIN: Whether this qml module has any c++ source files. -# URI: Module's uri. -# TARGET_PATH: Expected installation path for the Qml Module. Equivalent -# to the module's URI where '.' is replaced with '/'. Use this to override the -# default substitution pattern. -# VERSION: Version of the qml module -# QML_PLUGINDUMP_DEPENDENCIES: Path to a dependencies.json file to be consumed -# with the ${target}_qmltypes target (optional) -# SKIP_TYPE_REGISTRATION: All qml files are expected to be registered by the -# c++ plugin code. -# -function(add_qml_module target) - - set(qml_module_optional_args - DESIGNER_SUPPORTED - DO_NOT_INSTALL - SKIP_TYPE_REGISTRATION - ) - - set(qml_module_single_args - URI - TARGET_PATH - VERSION - QML_PLUGINDUMP_DEPENDENCIES - CLASSNAME - ) - - set(qml_module_multi_args - IMPORTS - TYPEINFO - DEPENDENCIES - ) - - qt_parse_all_arguments(arg "add_qml_module" - "${__add_qt_plugin_optional_args};${qml_module_optional_args}" - "${__add_qt_plugin_single_args};${qml_module_single_args}" - "${__add_qt_plugin_multi_args};${qml_module_multi_args}" ${ARGN}) - - if (NOT arg_URI) - message(FATAL_ERROR "add_qml_module called without specifying the module's uri. Please specify one using the URI parameter.") - endif() - - set(target_path ${arg_TARGET_PATH}) - - if (NOT arg_VERSION) - message(FATAL_ERROR "add_qml_module called without specifying the module's import version. Please specify one using the VERSION parameter.") - endif() - - if (NOT arg_TARGET_PATH) - string(REPLACE "." "/" arg_TARGET_PATH ${arg_URI}) - endif() - - qt_remove_args(plugin_args - ARGS_TO_REMOVE - ${target} - ${qml_module_multi_args} - ${qml_module_single_args} - ALL_ARGS - ${__add_qt_plugin_optional_args} - ${__add_qt_plugin_single_args} - ${qml_module_single_args} - ${__add_qt_plugin_multi_args} - ${qml_module_multi_args} - ARGS - ${ARGV} - ) - - # If we have no sources, but qml files, create a custom target so the - # qml file will be visibile in an IDE. - if (arg_SOURCES) - add_qt_plugin(${target} - TYPE - qml_plugin - QML_TARGET_PATH - "${arg_TARGET_PATH}" - ${plugin_args} - ) - endif() - - - if (arg_CPP_PLUGIN) - set(no_create_option DO_NOT_CREATE_TARGET) - endif() - - if (arg_CLASSNAME) - set(classname_arg CLASSNAME ${arg_CLASSNAME}) - endif() - - if (arg_DESIGNER_SUPPORTED) - set(designer_supported_arg DESIGNER_SUPPORTED) - endif() - - if (arg_SKIP_TYPE_REGISTRATION) - set(skip_registration_arg SKIP_TYPE_REGISTRATION) - endif() - - qt6_add_qml_module(${target} - ${designer_supported_arg} - ${no_create_option} - ${skip_registration_arg} - ${classname_arg} - RESOURCE_PREFIX "/qt-project.org/imports" - TARGET_PATH ${arg_TARGET_PATH} - URI ${arg_URI} - VERSION ${arg_VERSION} - QML_FILES ${arg_QML_FILES} - IMPORTS "${arg_IMPORTS}" - TYPEINFO "${arg_TYPEINFO}" - DO_NOT_INSTALL_METADATA - DO_NOT_CREATE_TARGET - INSTALL_QML_FILES - DEPENDENCIES ${arg_DEPENDENCIES} - RESOURCE_EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets" - ) - - get_target_property(qmldir_file ${target} QT_QML_MODULE_QMLDIR_FILE) - qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${arg_TARGET_PATH}") - set(plugin_types "${CMAKE_CURRENT_SOURCE_DIR}/plugins.qmltypes") - if (EXISTS ${plugin_types}) - qt_copy_or_install(FILES ${plugin_types} - DESTINATION "${qml_module_install_dir}" - ) - - if(QT_WILL_INSTALL) - # plugin.qmltypes when present should also be copied to the - # cmake binary dir when doing prefix builds - file(COPY ${plugin_types} - DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}" - ) - endif() - endif() - - - qt_copy_or_install( - FILES - "${qmldir_file}" - DESTINATION - "${qml_module_install_dir}" - ) - - if(QT_WILL_INSTALL) - # qmldir should also be copied to the cmake binary dir when doing - # prefix builds - file(COPY "${qmldir_file}" - DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}" - ) - endif() - -endfunction() - -# Collection of add_qt_executable arguments so they can be shared across add_qt_executable -# and add_qt_test_helper. -set(__add_qt_executable_optional_args +# Collection of qt_add_executable arguments so they can be shared across qt_add_executable +# and qt_add_test_helper. +set(__qt_add_executable_optional_args "GUI;BOOTSTRAP;NO_QT;NO_INSTALL;EXCEPTIONS" ) -set(__add_qt_executable_single_args +set(__qt_add_executable_single_args "OUTPUT_DIRECTORY;INSTALL_DIRECTORY" ) -set(__add_qt_executable_multi_args +set(__qt_add_executable_multi_args "EXE_FLAGS;${__default_private_args};${__default_public_args}" ) # This function creates a CMake target for a generic console or GUI binary. # Please consider to use a more specific version target like the one created -# by add_qt_test or add_qt_tool below. -function(add_qt_executable name) - qt_parse_all_arguments(arg "add_qt_executable" - "${__add_qt_executable_optional_args}" - "${__add_qt_executable_single_args}" - "${__add_qt_executable_multi_args}" +# by qt_add_test or qt_add_tool below. +function(qt_add_executable name) + qt_parse_all_arguments(arg "qt_add_executable" + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" ${ARGN}) if ("x${arg_OUTPUT_DIRECTORY}" STREQUAL "x") - set(arg_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${INSTALL_BINDIR}") + set(arg_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}") endif() get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" - ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}") + ABSOLUTE BASE_DIR "${QT_BUILD_DIR}") if ("x${arg_INSTALL_DIRECTORY}" STREQUAL "x") set(arg_INSTALL_DIRECTORY "${INSTALL_BINDIR}") endif() - add_executable("${name}" ${arg_EXE_FLAGS}) + if (ANDROID) + add_library("${name}" MODULE) + qt_android_apply_arch_suffix("${name}") + qt_android_generate_deployment_settings("${name}") + qt_android_add_apk_target("${name}") + # On our qmake builds we don't compile the executables with + # visibility=hidden. Not having this flag set will cause the + # executable to have main() hidden and can then no longer be loaded + # through dlopen() + set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default) + else() + add_executable("${name}" ${arg_EXE_FLAGS}) + endif() qt_autogen_tools_initial_setup(${name}) + qt_skip_warnings_are_errors_when_repo_unclean("${name}") set(extra_libraries "") if(NOT arg_BOOTSTRAP AND NOT arg_NO_QT) @@ -2277,7 +2530,7 @@ function(add_qt_executable name) ${arg_INCLUDE_DIRECTORIES} ) - extend_target("${name}" + qt_extend_target("${name}" SOURCES ${arg_SOURCES} INCLUDE_DIRECTORIES ${private_includes} DEFINES ${arg_DEFINES} @@ -2295,6 +2548,7 @@ function(add_qt_executable name) ) set_target_properties("${name}" PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + LIBRARY_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" WIN32_EXECUTABLE "${arg_GUI}" MACOSX_BUNDLE "${arg_GUI}" ) @@ -2306,16 +2560,85 @@ function(add_qt_executable name) if(NOT arg_NO_INSTALL) qt_install(TARGETS "${name}" RUNTIME DESTINATION "${arg_INSTALL_DIRECTORY}" + LIBRARY DESTINATION "${arg_INSTALL_DIRECTORY}" BUNDLE DESTINATION "${arg_INSTALL_DIRECTORY}") endif() endfunction() +# Simple wrapper around qt_add_executable for benchmarks which insure that +# the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed. +# See qt_add_executable() for more details. +function(qt_add_benchmark target) + + qt_parse_all_arguments(arg "qt_add_benchmark" + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ${ARGN} + ) + + qt_remove_args(exec_args + ARGS_TO_REMOVE + ${target} + OUTPUT_DIRECTORY + INSTALL_DIRECTORY + ALL_ARGS + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ARGS + ${ARGV} + ) + + qt_add_executable(${target} + NO_INSTALL # we don't install benchmarks + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" # avoid polluting bin directory + ${exec_args} + ) + +endfunction() + +# Simple wrapper around qt_add_executable for manual tests which insure that +# the binary is built under ${CMAKE_CURRENT_BINARY_DIR} and never installed. +# See qt_add_executable() for more details. +function(qt_add_manual_test target) + + qt_parse_all_arguments(arg "qt_add_manual_test" + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ${ARGN} + ) + + qt_remove_args(exec_args + ARGS_TO_REMOVE + ${target} + OUTPUT_DIRECTORY + INSTALL_DIRECTORY + ALL_ARGS + "${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" + ARGS + ${ARGV} + ) + + qt_add_executable(${target} + NO_INSTALL # we don't install benchmarks + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" # avoid polluting bin directory + ${exec_args} + ) + +endfunction() + # This function creates a CMake test target with the specified name for use with CTest. -function(add_qt_test name) - qt_parse_all_arguments(arg "add_qt_test" +function(qt_add_test name) + qt_parse_all_arguments(arg "qt_add_test" "RUN_SERIAL;EXCEPTIONS;GUI;QMLTEST" - "OUTPUT_DIRECTORY" "QML_IMPORTPATH;TESTDATA;${__default_private_args};${__default_public_args}" ${ARGN}) + "OUTPUT_DIRECTORY;WORKING_DIRECTORY;TIMEOUT" + "QML_IMPORTPATH;TESTDATA;${__default_private_args};${__default_public_args}" ${ARGN} + ) if (NOT arg_OUTPUT_DIRECTORY) set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") @@ -2334,11 +2657,11 @@ function(add_qt_test name) set(private_includes "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" - "$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>" + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}>" ${arg_INCLUDE_DIRECTORIES} ) - add_qt_executable("${name}" + qt_add_executable("${name}" ${exceptions_text} ${gui_text} NO_INSTALL @@ -2369,16 +2692,16 @@ function(add_qt_test name) # QMLTest specifics - extend_target("${name}" CONDITION arg_QMLTEST + qt_extend_target("${name}" CONDITION arg_QMLTEST PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest ) - extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID + qt_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID DEFINES QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" ) - extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID + qt_extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID DEFINES QUICK_TEST_SOURCE_DIR=":/" ) @@ -2392,20 +2715,31 @@ function(add_qt_test name) # and use it also for XML output file(RELATIVE_PATH label "${PROJECT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}") - if(arg_QMLTEST AND NOT arg_SOURCES) - set(test_working_dir "${CMAKE_CURRENT_SOURCE_DIR}") - set(test_executable ${QT_CMAKE_EXPORT_NAMESPACE}::qmltestrunner) + if (ANDROID) + qt_android_add_test("${name}") else() - set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}") - set(test_executable "${name}") - endif() + if(arg_QMLTEST AND NOT arg_SOURCES) + set(test_working_dir "${CMAKE_CURRENT_SOURCE_DIR}") + set(test_executable ${QT_CMAKE_EXPORT_NAMESPACE}::qmltestrunner) + else() + if (arg_WORKING_DIRECTORY) + set(test_working_dir "${arg_WORKING_DIRECTORY}") + else() + set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}") + endif() + set(test_executable "${name}") + endif() - add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args} -o ${name}.xml,xml -o -,txt WORKING_DIRECTORY "${test_working_dir}") + add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args} -o ${name}.xml,xml -o -,txt WORKING_DIRECTORY "${test_working_dir}") + endif() set_tests_properties("${name}" PROPERTIES RUN_SERIAL "${arg_RUN_SERIAL}" LABELS "${label}") - + if (arg_TIMEOUT) + set_tests_properties(${name} PROPERTIES TIMEOUT ${arg_TIMEOUT}) + endif() # Get path to qtbase/bin, then prepend this path containing the shared libraries to PATH - set(INSTALL_PREFIX_BIN "${CMAKE_INSTALL_PREFIX}/bin") + set(INSTALL_PREFIX_BIN "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "PATH=${CMAKE_CURRENT_BINARY_DIR}${QT_PATH_SEPARATOR}${INSTALL_PREFIX_BIN}${QT_PATH_SEPARATOR}$ENV{PATH}") + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_TEST_RUNNING_IN_CTEST=1") # Add the install prefix to list of plugin paths when doing a prefix build if(NOT QT_INSTALL_DIR) @@ -2445,7 +2779,7 @@ function(add_qt_test name) endforeach() if (builtin_files) - add_qt_resource(${name} "testdata" + qt_add_resource(${name} "${name}_testdata_builtin" PREFIX "/" FILES ${builtin_files} BASE ${CMAKE_CURRENT_SOURCE_DIR}) @@ -2479,27 +2813,27 @@ endfunction() # tests launch separate programs to test certain input/output behavior. # Specify OVERRIDE_OUTPUT_DIRECTORY if you dont' want to place the helper in the parent directory, # in which case you should specify OUTPUT_DIRECTORY "/foo/bar" manually. -function(add_qt_test_helper name) +function(qt_add_test_helper name) - set(add_qt_test_helper_optional_args + set(qt_add_test_helper_optional_args "OVERRIDE_OUTPUT_DIRECTORY" ) - qt_parse_all_arguments(arg "add_qt_test_helper" - "${add_qt_test_helper_optional_args};${__add_qt_executable_optional_args}" - "${__add_qt_executable_single_args}" - "${__add_qt_executable_multi_args}" + qt_parse_all_arguments(arg "qt_add_test_helper" + "${qt_add_test_helper_optional_args};${__qt_add_executable_optional_args}" + "${__qt_add_executable_single_args}" + "${__qt_add_executable_multi_args}" ${ARGN}) qt_remove_args(forward_args ARGS_TO_REMOVE "${name}" - ${add_qt_test_helper_optional_args} + ${qt_add_test_helper_optional_args} ALL_ARGS - ${add_qt_test_helper_optional_args} - ${__add_qt_executable_optional_args} - ${__add_qt_executable_single_args} - ${__add_qt_executable_multi_args} + ${qt_add_test_helper_optional_args} + ${__qt_add_executable_optional_args} + ${__qt_add_executable_single_args} + ${__qt_add_executable_multi_args} ARGS ${ARGV} ) @@ -2509,7 +2843,7 @@ function(add_qt_test_helper name) set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..") endif() - add_qt_executable("${name}" NO_INSTALL ${extra_args_to_pass} ${forward_args}) + qt_add_executable("${name}" NO_INSTALL ${extra_args_to_pass} ${forward_args}) endfunction() # Sets QT_WILL_BUILD_TOOLS if tools will be built. @@ -2524,9 +2858,9 @@ endfunction() # Wrapper function to create a regular cmake target and forward all the # arguments collected by the conversion script. This is only meant for tests! -function(add_cmake_library target) +function(qt_add_cmake_library target) # Process arguments: - qt_parse_all_arguments(arg "add_cmake_library" + qt_parse_all_arguments(arg "qt_add_cmake_library" "SHARED;MODULE;STATIC;INTERFACE" "OUTPUT_DIRECTORY;ARCHIVE_INSTALL_DIRECTORY;INSTALL_DIRECTORY" "${__default_private_args};${__default_public_args}" @@ -2536,10 +2870,20 @@ function(add_cmake_library target) ### Define Targets: if(${arg_INTERFACE}) add_library("${target}" INTERFACE) - elseif(${arg_STATIC}) + elseif(${arg_STATIC} OR (${arg_MODULE} AND NOT BUILD_SHARED_LIBS)) add_library("${target}" STATIC) elseif(${arg_SHARED}) add_library("${target}" SHARED) + elseif(${arg_MODULE}) + add_library("${target}" MODULE) + set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default) + + if(APPLE) + # CMake defaults to using .so extensions for loadable modules, aka plugins, + # but Qt plugins are actually suffixed with .dylib. + set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib") + endif() else() add_library("${target}") endif() @@ -2551,6 +2895,7 @@ function(add_cmake_library target) if (ANDROID) qt_android_apply_arch_suffix("${target}") endif() + qt_skip_warnings_are_errors_when_repo_unclean("${target}") if (arg_INSTALL_DIRECTORY) set(install_arguments @@ -2567,7 +2912,7 @@ function(add_cmake_library target) ) endif() - extend_target("${target}" + qt_extend_target("${target}" SOURCES ${arg_SOURCES} INCLUDE_DIRECTORIES ${arg_INCLUDE_DIRECTORIES} @@ -2591,11 +2936,162 @@ function(add_cmake_library target) endfunction() +# +# This function replaces qmake's qt_helper_lib feature. It is intended to +# compile 3rdparty libraries as part of the build. +# +function(qt_add_3rdparty_library target) + # Process arguments: + qt_parse_all_arguments(arg "qt_add_3rdparty_library" + "SHARED;MODULE;STATIC;INTERFACE;EXCEPTIONS" + "OUTPUT_DIRECTORY" + "${__default_private_args};${__default_public_args}" + ${ARGN} + ) + + ### Define Targets: + if(${arg_INTERFACE}) + add_library("${target}" INTERFACE) + elseif(${arg_STATIC} OR (${arg_MODULE} AND NOT BUILD_SHARED_LIBS)) + add_library("${target}" STATIC) + elseif(${arg_SHARED}) + add_library("${target}" SHARED) + elseif(${arg_MODULE}) + add_library("${target}" MODULE) + set_property(TARGET ${name} PROPERTY C_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY CXX_VISIBILITY_PRESET default) + + if(APPLE) + # CMake defaults to using .so extensions for loadable modules, aka plugins, + # but Qt plugins are actually suffixed with .dylib. + set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib") + endif() + else() + add_library("${target}") + endif() + + if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY) + set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}") + endif() + + qt_internal_add_qt_repo_known_module(${target}) + qt_internal_add_target_aliases(${target}) + + if (ANDROID) + qt_android_apply_arch_suffix("${target}") + endif() + + qt_skip_warnings_are_errors_when_repo_unclean("${target}") + + if(NOT arg_HEADER_MODULE) + set_target_properties(${target} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + RUNTIME_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ARCHIVE_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + QT_MODULE_IS_3RDPARTY_LIBRARY TRUE + ) + qt_handle_multi_config_output_dirs("${target}") + + set_target_properties(${target} PROPERTIES + OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" + ) + endif() + + if(NOT arg_INTERFACE) + # This property is used for super builds with static libraries. We use + # it in QtPlugins.cmake.in to avoid "polluting" the dependency chain + # for the target in it's project directory. + # E.g: When we process find_package(Qt6 ... Gui) in QtDeclarative, the + # rules in QtPugins.cmake add all the known Gui plugins as interface + # dependencies. This in turn causes circular dependencies on every + # plugin which links against Gui. Plugin A -> GUI -> Plugin A .... + set_target_properties(${target} PROPERTIES QT_BUILD_PROJECT_NAME ${PROJECT_NAME}) + endif() + + if(NOT arg_EXCEPTIONS AND NOT arg_INTERFACE) + qt_internal_set_no_exceptions_flags("${target}") + endif() + + qt_extend_target("${target}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${arg_INCLUDE_DIRECTORIES} + PUBLIC_INCLUDE_DIRECTORIES + ${arg_PUBLIC_INCLUDE_DIRECTORIES} + PUBLIC_DEFINES + ${arg_PUBLIC_DEFINES} + DEFINES + ${arg_DEFINES} + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + LIBRARIES ${arg_LIBRARIES} + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + PUBLIC_COMPILE_OPTIONS ${arg_PUBLIC_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + PUBLIC_LINK_OPTIONS ${arg_PUBLIC_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ${install_arguments} + ) + + if(NOT BUILD_SHARED_LIBS OR arg_SHARED) + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}") + qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix}) + qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) + set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") + + configure_package_config_file( + "${QT_CMAKE_DIR}/Qt3rdPartyLibraryConfig.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + INSTALL_DESTINATION "${config_install_dir}" + ) + + write_basic_package_version_file( + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + qt_install(TARGETS ${target} + EXPORT "${export_name}" + DESTINATION "${config_install_dir}" + ) + + qt_install(EXPORT ${export_name} + NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::" + DESTINATION "${config_install_dir}" + ) + + qt_internal_export_modern_cmake_config_targets_file( + TARGETS ${target} + EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} + CONFIG_INSTALL_DIR "${config_install_dir}" + ) + endif() +endfunction() + +function(qt_get_tool_cmake_configuration out_var) + qt_get_main_cmake_configuration("${out_var}") + string(TOUPPER "${${out_var}}" upper_config) + set("${out_var}" "${upper_config}" PARENT_SCOPE) +endfunction() + +function(qt_get_main_cmake_configuration out_var) + if(CMAKE_BUILD_TYPE) + set(config "${CMAKE_BUILD_TYPE}") + elseif(QT_MULTI_CONFIG_FIRST_CONFIG) + set(config "${QT_MULTI_CONFIG_FIRST_CONFIG}") + endif() + set("${out_var}" "${config}" PARENT_SCOPE) +endfunction() + # This function is used to define a "Qt tool", such as moc, uic or rcc. # The BOOTSTRAP option allows building it as standalone program, otherwise # it will be linked against QtCore. -function(add_qt_tool name) - qt_parse_all_arguments(arg "add_qt_tool" "BOOTSTRAP;NO_QT;NO_INSTALL" "TOOLS_TARGET" +function(qt_add_tool name) + qt_parse_all_arguments(arg "qt_add_tool" "BOOTSTRAP;NO_QT;NO_INSTALL" "TOOLS_TARGET" "${__default_private_args}" ${ARGN}) # Handle case when a tool does not belong to a module and it can't be built either (like @@ -2692,7 +3188,7 @@ function(add_qt_tool name) set(no_install NO_INSTALL) endif() - add_qt_executable("${name}" OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + qt_add_executable("${name}" OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" ${bootstrap} ${no_qt} ${no_install} @@ -2709,8 +3205,11 @@ function(add_qt_tool name) ) qt_internal_add_target_aliases("${name}") + # If building with a multi-config configuration, the main configuration tool will be placed in + # ./bin, while the rest will be in <CONFIG> specific subdirectories. + qt_get_tool_cmake_configuration(tool_cmake_configuration) set_target_properties("${name}" PROPERTIES - RUNTIME_OUTPUT_DIRECTORY_RELEASE "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + RUNTIME_OUTPUT_DIRECTORY_${tool_cmake_configuration} "${QT_BUILD_DIR}/${INSTALL_BINDIR}" ) if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET) @@ -2737,11 +3236,11 @@ endfunction() # Handle files that need special SIMD-related flags. # This creates an object library and makes target link # to it (privately). -function(add_qt_simd_part target) - qt_parse_all_arguments(arg "add_qt_simd_part" "" "" +function(qt_add_simd_part target) + qt_parse_all_arguments(arg "qt_add_simd_part" "" "" "NAME;SIMD;${__default_private_args};COMPILE_FLAGS" ${ARGN}) if ("x${arg_SIMD}" STREQUAL x) - message(FATAL_ERROR "add_qt_simd_part needs a SIMD type to be set.") + message(FATAL_ERROR "qt_add_simd_part needs a SIMD type to be set.") endif() set(condition "QT_FEATURE_${arg_SIMD}") @@ -2761,11 +3260,13 @@ function(add_qt_simd_part target) qt_evaluate_config_expression(result ${condition}) if(${result}) if(QT_CMAKE_DEBUG_EXTEND_TARGET) - message("add_qt_simd_part(${target} SIMD ${arg_SIMD} ...): Evaluated") + message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Evaluated") endif() string(TOUPPER "QT_CFLAGS_${arg_SIMD}" simd_flags) - add_library("${name}" OBJECT) + if (NOT TARGET "${name}") + add_library("${name}" OBJECT) + endif() target_sources("${name}" PRIVATE ${arg_SOURCES}) target_include_directories("${name}" PRIVATE ${arg_INCLUDE_DIRECTORIES} @@ -2779,6 +3280,11 @@ function(add_qt_simd_part target) target_link_libraries("${target}" PRIVATE "${name}") + # Add a link-only dependency on the parent library, to force copying of framework headers + # before trying to compile a source file. + target_link_libraries("${name}" PRIVATE + $<FILTER:$<TARGET_PROPERTY:${target},LINK_LIBRARIES>,EXCLUDE,^${target}_simd_>) + if(NOT BUILD_SHARED_LIBS) qt_install( TARGETS ${name} @@ -2787,7 +3293,7 @@ function(add_qt_simd_part target) endif() else() if(QT_CMAKE_DEBUG_EXTEND_TARGET) - message("add_qt_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped") + message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped") endif() endif() endfunction() @@ -2818,8 +3324,9 @@ endfunction() # Complete manual moc invocation with full control. # Use AUTOMOC whenever possible. function(qt_manual_moc result) - cmake_parse_arguments(arg "" "" "FLAGS" ${ARGN}) + cmake_parse_arguments(arg "" "OUTPUT_MOC_JSON_FILES" "FLAGS" ${ARGN}) set(moc_files) + set(metatypes_json_list) foreach(infile ${arg_UNPARSED_ARGUMENTS}) qt_make_output_file("${infile}" "moc_" ".cpp" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}" outfile) @@ -2827,16 +3334,30 @@ function(qt_manual_moc result) set(moc_parameters_file "${outfile}_parameters$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>") set(moc_parameters ${arg_FLAGS} -o "${outfile}" "${infile}") + + set(metatypes_byproducts) + if (arg_OUTPUT_MOC_JSON_FILES) + set(moc_json_file "${outfile}.json") + list(APPEND moc_parameters --output-json) + list(APPEND metatypes_json_list "${outfile}.json") + set(metatypes_byproducts "${outfile}.json") + endif() + string (REPLACE ";" "\n" moc_parameters "${moc_parameters}") file(GENERATE OUTPUT "${moc_parameters_file}" CONTENT "${moc_parameters}\n") - add_custom_command(OUTPUT "${outfile}" + add_custom_command(OUTPUT "${outfile}" ${metatypes_byproducts} COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc "@${moc_parameters_file}" DEPENDS "${infile}" ${moc_depends} ${QT_CMAKE_EXPORT_NAMESPACE}::moc WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" VERBATIM) endforeach() set("${result}" ${moc_files} PARENT_SCOPE) + + # Register generated json files + if (arg_OUTPUT_MOC_JSON_FILES) + set(${arg_OUTPUT_MOC_JSON_FILES} "${metatypes_json_list}" PARENT_SCOPE) + endif() endfunction() @@ -2889,7 +3410,7 @@ function(qt_create_qdbusxml2cpp_command target infile) add_custom_command(OUTPUT "${header_file}" "${source_file}" COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp ${arg_FLAGS} "${option}" "${header_file}:${source_file}" "${absolute_in_file_path}" - DEPENDS "${absolute_in_file_path}" + DEPENDS "${absolute_in_file_path}" ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" VERBATIM) @@ -2903,7 +3424,7 @@ function(qt_compute_injection_forwarding_header target) get_filename_component(file_name "${arg_SOURCE}" NAME) set(source_absolute_path "${CMAKE_CURRENT_BINARY_DIR}/${arg_SOURCE}") - file(RELATIVE_PATH relpath "${CMAKE_BINARY_DIR}" "${source_absolute_path}") + file(RELATIVE_PATH relpath "${PROJECT_BINARY_DIR}" "${source_absolute_path}") if (arg_PRIVATE) set(fwd "${PROJECT_VERSION}/${module}/private/${file_name}") @@ -2916,18 +3437,191 @@ function(qt_compute_injection_forwarding_header target) endfunction() -function(add_qt_docs) +function(qt_add_docs) if(${ARGC} EQUAL 1) # Function called from old generated CMakeLists.txt that was missing the target parameter return() endif() if(NOT ${ARGC} EQUAL 2) - message(FATAL_ERROR "add_qt_docs called with the wrong number of arguments. Should be add_qt_docs(target path_to_project.qdocconf).") + message(FATAL_ERROR "qt_add_docs called with the wrong number of arguments. Should be qt_add_docs(target path_to_project.qdocconf).") return() endif() set(target ${ARGV0}) set(doc_project ${ARGV1}) - # TODO + + if (NOT QT_SUPERBUILD OR QT_WILL_INSTALL) + set(qdoc_bin "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qdoc") + set(qtattributionsscanner_bin "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qtattributionsscanner") + set(qhelpgenerator_bin "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qhelpgenerator") + else() + set(qdoc_bin "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qdoc") + set(qtattributionsscanner_bin "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qtattributionsscanner") + set(qhelpgenerator_bin "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qhelpgenerator") + endif() + + get_target_property(target_type ${target} TYPE) + if (NOT target_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(target_bin_dir ${target} BINARY_DIR) + get_target_property(target_source_dir ${target} SOURCE_DIR) + else() + set(target_bin_dir ${CMAKE_CURRENT_BINARY_DIR}) + set(target_source_dir ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + set(doc_ouput_dir "${target_bin_dir}/.doc") + + + # Generate include dir list + set(target_include_dirs_file "${doc_ouput_dir}/$<CONFIG>/includes.txt") + + set(include_paths_property "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>") + if (NOT target_type STREQUAL "INTERFACE_LIBRARY") + file(GENERATE + OUTPUT ${target_include_dirs_file} + CONTENT "-I$<JOIN:${include_paths_property},\n-I>" + ) + set(include_path_args "@${target_include_dirs_file}") + else() + set(include_path_args "") + endif() + + get_filename_component(doc_target "${doc_project}" NAME_WLE) + if (QT_WILL_INSTALL) + set(qdoc_output_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}/${doc_target}") + set(index_dir "${CMAKE_BINARY_DIR}/${INSTALL_DOCDIR}") + elseif (QT_SUPERBUILD) + set(qdoc_output_dir "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}/${doc_target}") + set(index_dir "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}") + else() + set(qdoc_output_dir "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}") + set(index_dir "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}") + endif() + + # qtattributionsscanner + add_custom_target(qattributionsscanner_${target} + DEPENDS ${qattributionsscanner_bin} + COMMAND ${qtattributionsscanner_bin} + ${PROJECT_SOURCE_DIR} + --filter "QDocModule=${qdoc_target}" + -o "${target_bin_dir}/codeattributions.qdoc" + ) + + # prepare docs target + set(prepare_qdoc_args + -outputdir "${qdoc_output_dir}" + -installdir "${QT_INSTALL_DIR}/${INSTALL_DOCDIR}" + "${target_source_dir}/${doc_project}" + -prepare + -indexdir "${index_dir}" + -no-link-errors + "${include_path_args}" + ) + + if (QT_SUPERBUILD AND NOT QT_WILL_INSTALL) + set(qt_install_docs_env "${CMAKE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}") + else() + set(qt_install_docs_env "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}") + endif() + + set(qdoc_env_args + "QT_INSTALL_DOCS=\"${qt_install_docs_env}\"" + "QT_VERSION=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}" + "QT_VER=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" + "QT_VERSION_TAG=${PROJECT_VERSION_MAJOR}${PROJECT_VERSION_MINOR}${PROJECT_VERSION_PATCH}" + "BUILDDIR=${target_bin_dir}" + ) + + add_custom_target(prepare_docs_${target} + DEPENDS ${qdoc_bin} + COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args} + ${qdoc_bin} + ${prepare_qdoc_args} + ) + + add_dependencies(prepare_docs_${target} qattributionsscanner_${target}) + + # generate docs target + set(generate_qdocs_args + -outputdir "${qdoc_output_dir}" + -installdir "${INSTALL_DOCDIR}" + "${target_source_dir}/${doc_project}" + -generate + -indexdir "${index_dir}" + "${include_path_args}" + ) + + add_custom_target(generate_docs_${target} + DEPENDS ${qdoc_bin} + COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args} + ${qdoc_bin} + ${generate_qdocs_args} + ) + + add_dependencies(generate_docs_${target} prepare_docs_${target}) + + # generate html + set(html_qdocs_args + -outputdir "${qdoc_output_dir}" + -installdir "${INSTALL_DOCDIR}" + "${target_source_dir}/${doc_project}" + -indexdir "${index_dir}" + "${include_path_args}" + ) + + add_custom_target(html_docs_${target} + DEPENDS ${qdoc_bin} + COMMAND ${CMAKE_COMMAND} -E env ${qdoc_env_args} + ${qdoc_bin} + ${html_qdocs_args} + ) + + add_dependencies(html_docs_${target} generate_docs_${target}) + + # generate .qch + set(qch_file_name ${doc_target}.qch) + set(qch_file_path ${qdoc_output_dir}/${qch_file_name}) + + add_custom_target(qch_docs_${target} + DEPENDS ${qhelpgenerator_bin} + COMMAND ${qhelpgenerator_bin} + "${qdoc_output_dir}/${doc_target}.qhp" + -o "${qch_file_path}" + ) + add_dependencies(qch_docs_${target} generate_docs_${target}) + + if (QT_WILL_INSTALL) + add_custom_target(install_html_docs_${target} + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${qdoc_output_dir}" + "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}" + COMMENT "Installing html docs for target ${target}" + ) + + add_custom_target(install_qch_docs_${target} + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${qch_file_path}" + "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${qch_file_name}" + COMMENT "Installing qch docs for target ${target}" + ) + else() + # Don't need to do anything when not installing + add_custom_target(install_html_docs_${target}) + add_custom_target(install_qch_docs_${target}) + endif() + + add_dependencies(install_html_docs_${target} html_docs_${target}) + add_dependencies(install_qch_docs_${target} qch_docs_${target}) + + add_custom_target(install_docs_${target}) + add_dependencies(install_docs_${target} install_html_docs_${target} install_qch_docs_${target}) + + add_dependencies(${qt_docs_prepare_target_name} prepare_docs_${target}) + add_dependencies(${qt_docs_generate_target_name} generate_docs_${target}) + add_dependencies(${qt_docs_html_target_name} html_docs_${target}) + add_dependencies(${qt_docs_qch_target_name} qch_docs_${target}) + add_dependencies(${qt_docs_install_html_target_name} install_html_docs_${target}) + add_dependencies(${qt_docs_install_qch_target_name} install_qch_docs_${target}) + add_dependencies(${qt_docs_install_target_name} install_docs_${target}) + endfunction() macro(qt_find_package) @@ -3139,10 +3833,14 @@ endfunction() macro(qt_find_apple_system_frameworks) if(APPLE) find_library(FWAppKit AppKit) + find_library(FWAssetsLibrary AssetsLibrary) + find_library(FWAudioToolbox AudioToolbox) find_library(FWApplicationServices ApplicationServices) find_library(FWCarbon Carbon) find_library(FWCoreFoundation CoreFoundation) find_library(FWCoreServices CoreServices) + find_library(FWCoreGraphics CoreGraphics) + find_library(FWCoreText CoreText) find_library(FWCoreVideo CoreVideo) find_library(FWcups cups) find_library(FWDiskArbitration DiskArbitration) @@ -3204,6 +3902,7 @@ function(qt_process_qlalr consuming_target input_file_list flags) add_custom_command( OUTPUT ${cpp_file} ${private_file} ${decl_file} ${impl_file} COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr ${flags} ${input_file} + DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::qlalr MAIN_DEPENDENCY ${input_file} ) target_sources(${consuming_target} PRIVATE ${cpp_file} ${impl_file}) @@ -3229,7 +3928,6 @@ function(qt_generate_qconfig_cpp) qt_add_string_to_qconfig_cpp("libexec") qt_add_string_to_qconfig_cpp("bin") qt_add_string_to_qconfig_cpp("plugins") - qt_add_string_to_qconfig_cpp("imports") qt_add_string_to_qconfig_cpp("qml") qt_add_string_to_qconfig_cpp(".") qt_add_string_to_qconfig_cpp(".") @@ -3268,19 +3966,19 @@ function(qt_generate_qconfig_cpp) # TODO: Clean this up, there's a bunch of unrealistic assumptions here. # See qtConfOutput_preparePaths in qtbase/configure.pri. if(WIN32) - set(lib_location_absolute_path "${CMAKE_INSTALL_PREFIX}/bin") + set(lib_location_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") else() - set(lib_location_absolute_path "${CMAKE_INSTALL_PREFIX}/lib") + set(lib_location_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") endif() file(RELATIVE_PATH from_lib_location_to_prefix "${lib_location_absolute_path}" "${CMAKE_INSTALL_PREFIX}") if(QT_HOST_PATH) set(host_prefix "${QT_HOST_PATH}") - set(host_bin_dir_absolute_path "${QT_HOST_PATH}/bin") + set(host_bin_dir_absolute_path "${QT_HOST_PATH}/${INSTALL_BINDIR}") else() set(host_prefix "${CMAKE_INSTALL_PREFIX}") - set(host_bin_dir_absolute_path "${CMAKE_INSTALL_PREFIX}/bin") + set(host_bin_dir_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") endif() file(RELATIVE_PATH from_host_bin_dir_to_host_prefix @@ -3298,3 +3996,75 @@ function(qt_generate_qconfig_cpp) configure_file(global/qconfig.cpp.in global/qconfig.cpp @ONLY) endfunction() + +function(qt_set_language_standards) + ## Use the latest standard the compiler supports (same as qt_common.prf) + if (QT_FEATURE_cxx2a) + set(CMAKE_CXX_STANDARD 20 PARENT_SCOPE) + elseif (QT_FEATURE_cxx17) + set(CMAKE_CXX_STANDARD 17 PARENT_SCOPE) + elseif (QT_FEATURE_cxx14) + set(CMAKE_CXX_STANDARD 14 PARENT_SCOPE) + elseif (QT_FEATURE_cxx11) + set(CMAKE_CXX_STANDARD 11 PARENT_SCOPE) + endif() + + if (c_std_11 IN_LIST CMAKE_C_COMPILE_FEATURES) + set(CMAKE_C_STANDARD 11 PARENT_SCOPE) + elseif (c_std_99 IN_LIST CMAKE_C_COMPILE_FEATURES) + set(CMAKE_C_STANDARD 99 PARENT_SCOPE) + endif() +endfunction() + +# Compatibility macros that should be removed once all their usages are removed. +function(extend_target) + qt_extend_target(${ARGV}) +endfunction() + +function(add_qt_module) + qt_add_module(${ARGV}) +endfunction() + +function(add_qt_plugin) + qt_add_plugin(${ARGV}) +endfunction() + +function(add_qt_tool) + qt_add_tool(${ARGV}) +endfunction() + +function(add_qt_test) + qt_add_test(${ARGV}) +endfunction() + +function(add_qt_test_helper) + qt_add_test_helper(${ARGV}) +endfunction() + +function(add_qt_manual_test) + qt_add_manual_test(${ARGV}) +endfunction() + +function(add_qt_benchmark) + qt_add_benchmark(${ARGV}) +endfunction() + +function(add_qt_executable) + qt_add_executable(${ARGV}) +endfunction() + +function(add_qt_simd_part) + qt_add_simd_part(${ARGV}) +endfunction() + +function(add_qt_docs) + qt_add_docs(${ARGV}) +endfunction() + +function(add_qt_resource) + qt_add_resource(${ARGV}) +endfunction() + +function(add_cmake_library) + qt_add_cmake_library(${ARGV}) +endfunction() diff --git a/cmake/QtBuildInformation.cmake b/cmake/QtBuildInformation.cmake new file mode 100644 index 0000000000..097192b2ab --- /dev/null +++ b/cmake/QtBuildInformation.cmake @@ -0,0 +1,35 @@ +function(qt_print_feature_summary) + include(FeatureSummary) + feature_summary(WHAT PACKAGES_FOUND + REQUIRED_PACKAGES_NOT_FOUND + RECOMMENDED_PACKAGES_NOT_FOUND + OPTIONAL_PACKAGES_NOT_FOUND + RUNTIME_PACKAGES_NOT_FOUND + FATAL_ON_MISSING_REQUIRED_PACKAGES) +endfunction() + +function(qt_print_build_instructions) + if((NOT PROJECT_NAME STREQUAL "QtBase" AND + NOT PROJECT_NAME STREQUAL "Qt") OR + QT_BUILD_STANDALONE_TESTS) + + return() + endif() + + set(build_command "cmake --build . --parallel") + set(install_command "cmake --install .") + + message("Qt is now configured for building. Just run '${build_command}'.") + if(QT_WILL_INSTALL) + message("Once everything is built, you must run '${install_command}'.") + message("Qt will be installed into '${CMAKE_INSTALL_PREFIX}'") + else() + message("Once everything is built, Qt is installed.") + message("You should NOT run '${install_command}'") + message("Note that this build cannot be deployed to other machines or devices.") + endif() + message("To configure and build other modules, you can use the following convenience script: + ${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qt-cmake") + message("\nIf reconfiguration fails for some reason, try to remove 'CMakeCache.txt' \ +from the build directory \n") +endfunction() diff --git a/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake b/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake index 7f8b6df232..51645f48d5 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsAndroid.cmake @@ -69,6 +69,10 @@ define_property(TARGET # androiddeploytoolqt to successfully copy all the plugins and other dependent # items into tha APK function(qt_android_dependencies target) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() get_target_property(arg_JAR_DEPENDENCIES ${target} QT_ANDROID_JAR_DEPENDENCIES) get_target_property(arg_BUNDLED_JAR_DEPENDENCIES ${target} QT_ANDROID_BUNDLED_JAR_DEPENDENCIES) diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake index 4bf09e5b15..2703e06fe5 100644 --- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake +++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake @@ -19,12 +19,12 @@ macro(qt_set_up_build_internals_paths) set(QT_CMAKE_MODULE_PATH "${QT_BUILD_INTERNALS_PATH}/../${QT_CMAKE_EXPORT_NAMESPACE}") list(PREPEND CMAKE_MODULE_PATH "${QT_CMAKE_MODULE_PATH}") - # When doing a non-prefix build, prepend the qtbase source cmake directory to CMAKE_MODULE_PATH, + # Prepend the qtbase source cmake directory to CMAKE_MODULE_PATH, # so that if a change is done in cmake/QtBuild.cmake, it gets automatically picked up when # building qtdeclarative, rather than having to build qtbase first (which will copy # QtBuild.cmake to the build dir). This is similar to qmake non-prefix builds, where the # source qtbase/mkspecs directory is used. - if(NOT QT_WILL_INSTALL) + if(EXISTS "${QT_SOURCE_TREE}/cmake") list(PREPEND CMAKE_MODULE_PATH "${QT_SOURCE_TREE}/cmake") endif() @@ -60,57 +60,67 @@ macro(qt_build_repo_begin) # Find Apple frameworks if needed. qt_find_apple_system_frameworks() -endmacro() -macro(qt_build_repo_end) - # Delayed actions on some of the Qt targets: - include(QtPostProcess) - - # Install the repo-specific cmake find modules. - qt_path_join(__qt_repo_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE}) - - if(NOT PROJECT_NAME STREQUAL "QtBase") - if (EXISTS cmake) - qt_copy_or_install(DIRECTORY cmake/ - DESTINATION "${__qt_repo_install_dir}" - FILES_MATCHING PATTERN "Find*.cmake" - ) - endif() - endif() + # Decide whether tools will be built. + qt_check_if_tools_will_be_built() - # Print a feature summary: - feature_summary(WHAT PACKAGES_FOUND - REQUIRED_PACKAGES_NOT_FOUND - RECOMMENDED_PACKAGES_NOT_FOUND - OPTIONAL_PACKAGES_NOT_FOUND - RUNTIME_PACKAGES_NOT_FOUND - FATAL_ON_MISSING_REQUIRED_PACKAGES) - qt_print_build_instructions() + string(TOLOWER ${PROJECT_NAME} project_name_lower) + + set(qt_docs_target_name docs_${project_name_lower}) + set(qt_docs_prepare_target_name prepare_docs_${project_name_lower}) + set(qt_docs_generate_target_name generate_docs_${project_name_lower}) + set(qt_docs_html_target_name html_docs_${project_name_lower}) + set(qt_docs_qch_target_name qch_docs_${project_name_lower}) + set(qt_docs_install_html_target_name install_html_docs_${project_name_lower}) + set(qt_docs_install_qch_target_name install_qch_docs_${project_name_lower}) + set(qt_docs_install_target_name install_docs_${project_name_lower}) + + add_custom_target(${qt_docs_target_name}) + add_custom_target(${qt_docs_prepare_target_name}) + add_custom_target(${qt_docs_generate_target_name}) + add_custom_target(${qt_docs_qch_target_name}) + add_custom_target(${qt_docs_html_target_name}) + add_custom_target(${qt_docs_install_html_target_name}) + add_custom_target(${qt_docs_install_qch_target_name}) + add_custom_target(${qt_docs_install_target_name}) + + add_dependencies(${qt_docs_generate_target_name} ${qt_docs_prepare_target_name}) + add_dependencies(${qt_docs_html_target_name} ${qt_docs_generate_target_name}) + add_dependencies(${qt_docs_target_name} ${qt_docs_html_target_name} ${qt_docs_qch_target_name}) + add_dependencies(${qt_docs_install_html_target_name} ${qt_docs_html_target_name}) + add_dependencies(${qt_docs_install_qch_target_name} ${qt_docs_qch_target_name}) + add_dependencies(${qt_docs_install_target_name} ${qt_docs_install_html_target_name} ${qt_docs_install_qch_target_name}) endmacro() -function(qt_print_build_instructions) - if(NOT PROJECT_NAME STREQUAL "QtBase") - return() +macro(qt_build_repo_end) + include(QtBuildInformation) + + if(NOT QT_BUILD_STANDALONE_TESTS) + # Delayed actions on some of the Qt targets: + include(QtPostProcess) + + # Install the repo-specific cmake find modules. + qt_path_join(__qt_repo_install_dir ${QT_CONFIG_INSTALL_DIR} ${INSTALL_CMAKE_NAMESPACE}) + + if(NOT PROJECT_NAME STREQUAL "QtBase") + if (EXISTS cmake) + qt_copy_or_install(DIRECTORY cmake/ + DESTINATION "${__qt_repo_install_dir}" + FILES_MATCHING PATTERN "Find*.cmake" + ) + endif() + endif() + + if(NOT QT_SUPERBUILD) + qt_print_feature_summary() + endif() endif() - set(build_command "cmake --build . --parallel") - set(install_command "cmake --install .") - - message("Qt is now configured for building. Just run '${build_command}'.") - if(QT_WILL_INSTALL) - message("Once everything is built, you must run '${install_command}'.") - message("Qt will be installed into '${CMAKE_INSTALL_PREFIX}'") - else() - message("Once everything is built, Qt is installed.") - message("You should NOT run '${install_command}'") - message("Note that this build cannot be deployed to other machines or devices.") + if(NOT QT_SUPERBUILD) + qt_print_build_instructions() endif() - message("To configure and build other modules, you can use the following convenience script: - ${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qt-cmake") - message("\nIf reconfiguration fails for some reason, try to remove 'CMakeCache.txt' \ -from the build directory \n") -endfunction() +endmacro() macro(qt_build_repo) qt_build_repo_begin(${ARGN}) @@ -118,50 +128,69 @@ macro(qt_build_repo) # If testing is enabled, try to find the qtbase Test package. # Do this before adding src, because there might be test related conditions # in source. - if (BUILD_TESTING) + if (BUILD_TESTING AND NOT QT_BUILD_STANDALONE_TESTS) find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test) endif() - ## Decide whether tools will be built. - qt_check_if_tools_will_be_built() - - if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt") - add_subdirectory(src) - endif() + if(NOT QT_BUILD_STANDALONE_TESTS) + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/CMakeLists.txt") + add_subdirectory(src) + endif() - if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt") - add_subdirectory(tools) + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt") + add_subdirectory(tools) + endif() endif() if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt") add_subdirectory(tests) + if(QT_NO_MAKE_TESTS) + set_property(DIRECTORY tests PROPERTY EXCLUDE_FROM_ALL TRUE) + endif() endif() qt_build_repo_end() - if (BUILD_EXAMPLES AND BUILD_SHARED_LIBS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt") + if (BUILD_EXAMPLES AND BUILD_SHARED_LIBS + AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/CMakeLists.txt" + AND NOT QT_BUILD_STANDALONE_TESTS) add_subdirectory(examples) + if(QT_NO_MAKE_EXAMPLES) + set_property(DIRECTORY examples PROPERTY EXCLUDE_FROM_ALL TRUE) + endif() endif() endmacro() macro(qt_set_up_standalone_tests_build) - qt_set_up_build_internals_paths() - include(QtSetup) - - # Optionally include a repo specific Setup module. - include(QtRepoSetup OPTIONAL) - - qt_find_apple_system_frameworks() - qt_check_if_tools_will_be_built() + # Remove this macro once all usages of it have been removed. + # Standalone tests are not handled via the main repo project and qt_build_tests. endmacro() macro(qt_build_tests) + if(QT_BUILD_STANDALONE_TESTS) + # Find location of TestsConfig.cmake. These contain the modules that need to be + # find_package'd when testing. + set(_qt_build_tests_install_prefix + "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}BuildInternals/StandaloneTests") + if(QT_WILL_INSTALL) + qt_path_join(_qt_build_tests_install_prefix + ${CMAKE_INSTALL_PREFIX} ${_qt_build_tests_install_prefix}) + endif() + include("${_qt_build_tests_install_prefix}/${PROJECT_NAME}TestsConfig.cmake" OPTIONAL) + + # Of course we always need the test module as well. + find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Test) + endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/auto/CMakeLists.txt") add_subdirectory(auto) endif() - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/CMakeLists.txt") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmarks/CMakeLists.txt" AND QT_BUILD_BENCHMARKS) add_subdirectory(benchmarks) endif() + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/manual/CMakeLists.txt") + add_subdirectory(manual) + endif() endmacro() macro(qt_examples_build_begin) @@ -170,8 +199,8 @@ macro(qt_examples_build_begin) # Appending to CMAKE_PREFIX_PATH helps find the initial Qt6Config.cmake. # Appending to QT_EXAMPLES_CMAKE_PREFIX_PATH helps find components of Qt6, because those # find_package calls use NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH is ignored. - list(APPEND CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}") - list(APPEND QT_EXAMPLES_CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}") + list(APPEND CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") + list(APPEND QT_EXAMPLES_CMAKE_PREFIX_PATH "${QT_BUILD_DIR}") # Also make sure the CMake config files do not recreate the already-existing targets set(QT_NO_CREATE_TARGETS TRUE) set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) diff --git a/cmake/QtBuildInternalsExtra.cmake.in b/cmake/QtBuildInternalsExtra.cmake.in index 04a0998cf1..5278890337 100644 --- a/cmake/QtBuildInternalsExtra.cmake.in +++ b/cmake/QtBuildInternalsExtra.cmake.in @@ -3,7 +3,6 @@ set(QT_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) option(BUILD_SHARED_LIBS "Build Qt statically or dynamically" @BUILD_SHARED_LIBS@) set(QT_CMAKE_EXPORT_NAMESPACE @QT_CMAKE_EXPORT_NAMESPACE@) set(INSTALL_CMAKE_NAMESPACE @INSTALL_CMAKE_NAMESPACE@) -set(CMAKE_BUILD_TYPE @CMAKE_BUILD_TYPE@) set(QT_BUILD_INTERNALS_PATH "${CMAKE_CURRENT_LIST_DIR}") # Propagate the original install prefix, so that a developer building a child module can @@ -26,6 +25,13 @@ set(QT_SOURCE_TREE "@QT_SOURCE_TREE@" CACHE PATH # Propagate decision of building tests and examples to other repositories. set(BUILD_TESTING @BUILD_TESTING@ CACHE BOOL "Build the testing tree.") set(BUILD_EXAMPLES @BUILD_EXAMPLES@ CACHE BOOL "Build Qt examples") +set(QT_NO_MAKE_TESTS @QT_NO_MAKE_TESTS@ CACHE BOOL + "Should tests be built as part of the default 'all' target.") +set(QT_NO_MAKE_EXAMPLES @QT_NO_MAKE_EXAMPLES@ CACHE BOOL + "Should examples be built as part of the default 'all' target.") + +# Propagate usage of ccache. +set(QT_USE_CCACHE @QT_USE_CCACHE@ CACHE BOOL "Enable the use of ccache") # Extra set of exported variables @QT_EXTRA_BUILD_INTERNALS_VARS@ diff --git a/cmake/QtCompilerOptimization.cmake b/cmake/QtCompilerOptimization.cmake index 5ca28c4de4..1f50044a6f 100644 --- a/cmake/QtCompilerOptimization.cmake +++ b/cmake/QtCompilerOptimization.cmake @@ -62,7 +62,9 @@ if(GCC OR CLANG) set(QT_CFLAGS_AVX512VBMI "-mavx512vbmi") set(QT_CFLAGS_AESNI "-maes") set(QT_CFLAGS_SHANI "-msha") - set(QT_CFLAGS_NEON "-mfpu=neon") + if(NOT APPLE_UIKIT AND NOT QT_64BIT) + set(QT_CFLAGS_NEON "-mfpu=neon") + endif() set(QT_CFLAGS_MIPS_DSP "-mdsp") set(QT_CFLAGS_MIPS_DSPR2 "-mdspr2") endif() diff --git a/cmake/QtConfig.cmake.in b/cmake/QtConfig.cmake.in index efce91d1c4..6d69c1f90e 100644 --- a/cmake/QtConfig.cmake.in +++ b/cmake/QtConfig.cmake.in @@ -10,13 +10,16 @@ set(_qt_@PROJECT_VERSION_MAJOR@_config_cmake_dir "${CMAKE_CURRENT_LIST_DIR}") if (NOT QT_NO_CREATE_TARGETS) include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@Targets.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@VersionlessTargets.cmake") + if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS) + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@VersionlessTargets.cmake") + endif() else() # For examples using `find_package(...)` inside their CMakeLists.txt files: # Make CMake's AUTOGEN detect this Qt version properly set_directory_properties(PROPERTIES QT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ - QT_VERSION_MINOR @PROJECT_VERSION_MINOR@) + QT_VERSION_MINOR @PROJECT_VERSION_MINOR@ + QT_VERSION_PATCH @PROJECT_VERSION_PATCH@) endif() # if (NOT @INSTALL_CMAKE_NAMESPACE@_FIND_COMPONENTS) diff --git a/cmake/QtFeature.cmake b/cmake/QtFeature.cmake index e3fb9c4232..faca42635c 100644 --- a/cmake/QtFeature.cmake +++ b/cmake/QtFeature.cmake @@ -23,10 +23,26 @@ function(qt_feature_module_begin) set(__QtFeature_private_extra "" PARENT_SCOPE) set(__QtFeature_public_extra "" PARENT_SCOPE) + set(__QtFeature_config_definitions "" PARENT_SCOPE) + set(__QtFeature_define_definitions "" PARENT_SCOPE) endfunction() +function(qt_feature_normalize_name name out_var) + # Normalize the feature name to something CMake can deal with. + if(name MATCHES "c\\+\\+") + string(REGEX REPLACE "[^a-zA-Z0-9_]" "x" name "${name}") + else() + string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" name "${name}") + endif() + set(${out_var} "${name}" PARENT_SCOPE) +endfunction() + function(qt_feature feature) + set(original_name "${feature}") + qt_feature_normalize_name("${feature}" feature) + set_property(GLOBAL PROPERTY QT_FEATURE_ORIGINAL_NAME_${feature} "${original_name}") + qt_parse_all_arguments(arg "qt_feature" "PRIVATE;PUBLIC" "LABEL;PURPOSE;SECTION;" "AUTODETECT;CONDITION;ENABLE;DISABLE;EMIT_IF" ${ARGN}) @@ -260,7 +276,63 @@ function(qt_evaluate_feature feature) qt_feature_set_value("${feature}" "${cache}" "${emit_if}" "${condition}" "${arg_LABEL}") endfunction() +function(qt_feature_config feature config_var_name) + qt_feature_normalize_name("${feature}" feature) + qt_parse_all_arguments(arg "qt_feature_config" "NEGATE" "NAME" "" ${ARGN}) + + # Store all the config related info in a unique variable key. + set(key_name "_QT_FEATURE_CONFIG_DEFINITION_${feature}_${config_var_name}") + set(${key_name} "FEATURE;${feature};CONFIG_VAR_NAME;${config_var_name};${ARGN}" PARENT_SCOPE) + + # Store the key for later evaluation. + list(APPEND __QtFeature_config_definitions "${key_name}") + + set(__QtFeature_config_definitions ${__QtFeature_config_definitions} PARENT_SCOPE) +endfunction() + +function(qt_evaluate_qmake_config_values key) + if(NOT DEFINED ${key}) + qt_debug_print_variables(DEDUP MATCH "^_QT_FEATURE_CONFIG_DEFINITION") + message(FATAL_ERROR + "Attempting to evaluate feature config ${key} but its definition is missing. ") + endif() + + cmake_parse_arguments(arg + "NEGATE" + "FEATURE;NAME;CONFIG_VAR_NAME" + "" ${${key}}) + + set(expected "NOT") + if (arg_NEGATE) + set(expected "") + endif() + + # If no custom name is specified, then the config value is the same as the feature name. + if(NOT arg_NAME) + set(arg_NAME "${arg_FEATURE}") + endif() + + # The feature condition is false, there is no need to export any config values. + if(${expected} ${QT_FEATURE_${arg_FEATURE}}) + return() + endif() + + if(arg_CONFIG_VAR_NAME STREQUAL "QMAKE_PUBLIC_CONFIG") + list(APPEND __QtFeature_qmake_public_config "${arg_NAME}") + set(__QtFeature_qmake_public_config "${__QtFeature_qmake_public_config}" PARENT_SCOPE) + endif() + if(arg_CONFIG_VAR_NAME STREQUAL "QMAKE_PRIVATE_CONFIG") + list(APPEND __QtFeature_qmake_private_config "${arg_NAME}") + set(__QtFeature_qmake_private_config "${__QtFeature_qmake_private_config}" PARENT_SCOPE) + endif() + if(arg_CONFIG_VAR_NAME STREQUAL "QMAKE_PUBLIC_QT_CONFIG") + list(APPEND __QtFeature_qmake_public_qt_config "${arg_NAME}") + set(__QtFeature_qmake_public_qt_config "${__QtFeature_qmake_public_qt_config}" PARENT_SCOPE) + endif() +endfunction() + function(qt_feature_definition feature name) + qt_feature_normalize_name("${feature}" feature) qt_parse_all_arguments(arg "qt_feature_definition" "NEGATE" "VALUE" "" ${ARGN}) # Store all the define related info in a unique variable key. @@ -360,6 +432,14 @@ function(qt_feature_module_end) qt_evaluate_feature(${feature}) endforeach() + # Evaluate custom cache assignments. + foreach(cache_var_name ${__QtFeature_custom_enabled_cache_variables}) + set(${cache_var_name} ON CACHE BOOL "Force enabled by platform." FORCE) + endforeach() + foreach(cache_var_name ${__QtFeature_custom_disabled_cache_variables}) + set(${cache_var_name} OFF CACHE BOOL "Force disabled by platform." FORCE) + endforeach() + set(enabled_public_features "") set(disabled_public_features "") set(enabled_private_features "") @@ -381,6 +461,11 @@ function(qt_feature_module_end) endif() endforeach() + foreach(key ${__QtFeature_config_definitions}) + qt_evaluate_qmake_config_values(${key}) + unset(${key} PARENT_SCOPE) + endforeach() + foreach(key ${__QtFeature_define_definitions}) qt_evaluate_feature_definition(${key}) unset(${key} PARENT_SCOPE) @@ -420,7 +505,7 @@ function(qt_feature_module_end) set(propertyPrefix "INTERFACE_") else() set(propertyPrefix "") - set_target_properties("${target}" PROPERTIES EXPORT_PROPERTIES "QT_ENABLED_PUBLIC_FEATURES;QT_DISABLED_PUBLIC_FEATURES;QT_ENABLED_PRIVATE_FEATURES;QT_DISABLED_PRIVATE_FEATURES;MODULE_PLUGIN_TYPES;QT_PLUGINS") + set_target_properties("${target}" PROPERTIES EXPORT_PROPERTIES "QT_ENABLED_PUBLIC_FEATURES;QT_DISABLED_PUBLIC_FEATURES;QT_ENABLED_PRIVATE_FEATURES;QT_DISABLED_PRIVATE_FEATURES;MODULE_PLUGIN_TYPES;QT_PLUGINS;QT_QMAKE_PUBLIC_CONFIG;QT_QMAKE_PRIVATE_CONFIG;QT_QMAKE_PUBLIC_QT_CONFIG") endif() foreach(visibility public private) string(TOUPPER "${visibility}" capitalVisibility) @@ -430,6 +515,36 @@ function(qt_feature_module_end) set_property(TARGET "${target}" PROPERTY ${propertyPrefix}QT_${capitalState}_${capitalVisibility}_FEATURES "${${state}_${visibility}_features}") endforeach() endforeach() + + set_property(TARGET "${target}" + PROPERTY ${propertyPrefix}QT_QMAKE_PUBLIC_CONFIG + "${__QtFeature_qmake_public_config}") + set_property(TARGET "${target}" + PROPERTY ${propertyPrefix}QT_QMAKE_PRIVATE_CONFIG + "${__QtFeature_qmake_private_config}") + set_property(TARGET "${target}" + PROPERTY ${propertyPrefix}QT_QMAKE_PUBLIC_QT_CONFIG + "${__QtFeature_qmake_public_qt_config}") + + # Config values were the old-school features before actual configure.json features were + # implemented. Therefore "CONFIG+=foo" values should be considered features as well, + # so that CMake can find them when building qtmultimedia for example. + if(__QtFeature_qmake_public_config) + set_property(TARGET "${target}" + APPEND PROPERTY ${propertyPrefix}QT_ENABLED_PUBLIC_FEATURES + ${__QtFeature_qmake_public_config}) + endif() + if(__QtFeature_qmake_private_config) + set_property(TARGET "${target}" + APPEND PROPERTY ${propertyPrefix}QT_ENABLED_PRIVATE_FEATURES + ${__QtFeature_qmake_private_config}) + endif() + if(__QtFeature_qmake_public_qt_config) + set_property(TARGET "${target}" + APPEND PROPERTY ${propertyPrefix}QT_ENABLED_PUBLIC_FEATURES + ${__QtFeature_qmake_public_qt_config}) + endif() + qt_feature_copy_global_config_features_to_core(${target}) endif() @@ -445,6 +560,8 @@ function(qt_feature_module_end) unset(__QtFeature_public_extra PARENT_SCOPE) unset(__QtFeature_define_definitions PARENT_SCOPE) + unset(__QtFeature_custom_enabled_features PARENT_SCOPE) + unset(__QtFeature_custom_disabled_features PARENT_SCOPE) endfunction() function(qt_feature_copy_global_config_features_to_core target) @@ -468,10 +585,27 @@ function(qt_feature_copy_global_config_features_to_core target) set_property(TARGET Core PROPERTY ${core_property_name} ${total_values}) endforeach() endforeach() + + set(config_property_names + QT_QMAKE_PUBLIC_CONFIG QT_QMAKE_PRIVATE_CONFIG QT_QMAKE_PUBLIC_QT_CONFIG ) + foreach(property_name ${config_property_names}) + set(core_property_name "${property_name}") + set(global_property_name "INTERFACE_${core_property_name}") + + get_property(core_values TARGET Core PROPERTY ${core_property_name}) + get_property(global_values TARGET GlobalConfig PROPERTY ${global_property_name}) + + set(total_values ${core_values} ${global_values}) + set_property(TARGET Core PROPERTY ${core_property_name} ${total_values}) + endforeach() endif() endfunction() function(qt_config_compile_test name) + if(DEFINED "TEST_${name}") + return() + endif() + cmake_parse_arguments(arg "" "LABEL;PROJECT_PATH;C_STANDARD;CXX_STANDARD" "LIBRARIES;CODE" ${ARGN}) if(arg_PROJECT_PATH) @@ -523,18 +657,65 @@ function(qt_config_compile_test name) set(TEST_${name} "${HAVE_${name}}" CACHE INTERNAL "${arg_LABEL}") endfunction() +# This function should be used for passing required try compile platform variables to the +# project-based try_compile() call. +# out_var will be a list of -Dfoo=bar strings, suitable to pass to CMAKE_FLAGS. +function(qt_get_platform_try_compile_vars out_var) + # Use the regular variables that are used for source-based try_compile() calls. + set(flags "${CMAKE_TRY_COMPILE_PLATFORM_VARIABLES}") + + # Pass toolchain files. + if(CMAKE_TOOLCHAIN_FILE) + list(APPEND flags "CMAKE_TOOLCHAIN_FILE") + endif() + if(VCPKG_CHAINLOAD_TOOLCHAIN_FILE) + list(APPEND flags "VCPKG_CHAINLOAD_TOOLCHAIN_FILE") + endif() + + # Assemble the list with regular options. + set(flags_cmd_line "") + foreach(flag ${flags}) + if(${flag}) + list(APPEND flags_cmd_line "-D${flag}=${${flag}}") + endif() + endforeach() + + # Pass darwin specific options. + if(APPLE_UIKIT) + if(CMAKE_OSX_ARCHITECTURES) + list(GET CMAKE_OSX_ARCHITECTURES 0 osx_first_arch) + + # Do what qmake does, aka when doing a simulator_and_device build, build the + # target architecture test only with the first given architecture, which should be the + # device architecture, aka some variation of "arm" (armv7, arm64). + list(APPEND flags_cmd_line "-DCMAKE_OSX_ARCHITECTURES:STRING=${osx_first_arch}") + endif() + # Also specify the sysroot, but only if not doing a simulator_and_device build. + # So keep the sysroot empty for simulator_and_device builds. + if(QT_UIKIT_SDK) + list(APPEND flags_cmd_line "-DCMAKE_OSX_SYSROOT:STRING=${QT_UIKIT_SDK}") + endif() + endif() + + set("${out_var}" "${flags_cmd_line}" PARENT_SCOPE) +endfunction() + function(qt_config_compile_test_x86simd extension label) if (DEFINED TEST_X86SIMD_${extension}) return() endif() + set(flags "-DSIMD:string=${extension}") + + qt_get_platform_try_compile_vars(platform_try_compile_vars) + list(APPEND flags ${platform_try_compile_vars}) + message(STATUS "Performing SIMD Test ${label}") try_compile("TEST_X86SIMD_${extension}" "${CMAKE_CURRENT_BINARY_DIR}/config.tests/x86_simd_${extension}" "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/x86_simd" x86_simd - CMAKE_FLAGS "-DSIMD:string=${extension}") - + CMAKE_FLAGS ${flags}) if(${TEST_X86SIMD_${extension}}) set(status_label "Success") else() @@ -545,8 +726,8 @@ function(qt_config_compile_test_x86simd extension label) endfunction() function(qt_make_features_available target) - if(NOT "${target}" MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::[a-zA-z][a-zA-Z0-9_-]*$") - message(FATAL_ERROR "${target} does not match ${QT_CMAKE_EXPORT_NAMESPACE}::[a-zA-z][a-zA-Z0-9_-]*. INVALID NAME.") + if(NOT "${target}" MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::[a-zA-Z][a-zA-Z0-9_-]*$") + message(FATAL_ERROR "${target} does not match ${QT_CMAKE_EXPORT_NAMESPACE}::[a-zA-Z][a-zA-Z0-9_-]*. INVALID NAME.") endif() if(NOT TARGET ${target}) message(FATAL_ERROR "${target} not found.") diff --git a/cmake/QtInternalTargets.cmake b/cmake/QtInternalTargets.cmake index ad8ded29cf..54e7f4f50e 100644 --- a/cmake/QtInternalTargets.cmake +++ b/cmake/QtInternalTargets.cmake @@ -1,37 +1,38 @@ function(qt_internal_set_warnings_are_errors_flags target) + set(flags "") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # Regular clang 3.0+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "3.0.0") - target_compile_options("${target}" INTERFACE -Werror -Wno-error=\#warnings -Wno-error=deprecated-declarations) + list(APPEND flags -Werror -Wno-error=\#warnings -Wno-error=deprecated-declarations) endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # using AppleClang # Apple clang 4.0+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "4.0.0" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL "9.2") - target_compile_options("${target}" INTERFACE -Werror -Wno-error=\#warnings -Wno-error=deprecated-declarations) + list(APPEND flags -Werror -Wno-error=\#warnings -Wno-error=deprecated-declarations) endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # using GCC - target_compile_options("${target}" INTERFACE -Werror -Wno-error=cpp -Wno-error=deprecated-declarations) + list(APPEND flags -Werror -Wno-error=cpp -Wno-error=deprecated-declarations) # GCC prints this bogus warning, after it has inlined a lot of code # error: assuming signed overflow does not occur when assuming that (X + c) < X is always false - target_compile_options("${target}" INTERFACE -Wno-error=strict-overflow) + list(APPEND flags -Wno-error=strict-overflow) # GCC 7 includes -Wimplicit-fallthrough in -Wextra, but Qt is not yet free of implicit fallthroughs. if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "7.0.0") - target_compile_options("${target}" INTERFACE -Wno-error=implicit-fallthrough) + list(APPEND flags -Wno-error=implicit-fallthrough) endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "9.0.0") # GCC 9 introduced these but we are not clean for it. - target_compile_options("${target}" INTERFACE -Wno-error=deprecated-copy -Wno-error=redundant-move -Wno-error=init-list-lifetime) + list(APPEND flags -Wno-error=deprecated-copy -Wno-error=redundant-move -Wno-error=init-list-lifetime) endif() # Work-around for bug https://code.google.com/p/android/issues/detail?id=58135 if (ANDROID) - target_compile_options("${target}" INTERFACE -Wno-error=literal-suffix) + list(APPEND flags -Wno-error=literal-suffix) endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") # Intel CC 13.0 +, on Linux only @@ -44,7 +45,7 @@ function(qt_internal_set_warnings_are_errors_flags target) # 1786: function "entity" (declared at line N of "file") was declared deprecated ("message") # 1881: argument must be a constant null pointer value # (NULL in C++ is usually a literal 0) - target_compile_options("${target}" INTERFACE -Werror -ww177,1224,1478,1786,1881) + list(APPEND flags -Werror -ww177,1224,1478,1786,1881) endif() endif() elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") @@ -52,9 +53,12 @@ function(qt_internal_set_warnings_are_errors_flags target) # MSVC 2012, 2013, 2015. # Respectively MSVC_VERRSIONs are: 1700-1799, 1800-1899, 1900-1909. if(MSVC_VERSION GREATER_EQUAL 1700 AND MSVC_VERSION LESS_EQUAL 1909) - target_compile_options("${target}" INTERFACE /WX) + list(APPEND flags /WX) endif() endif() + set(add_flags "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_SKIP_WARNINGS_ARE_ERRORS>>>") + set(flags_generator_expression "$<${add_flags}:${flags}>") + target_compile_options("${target}" INTERFACE "${flags_generator_expression}") endfunction() add_library(PlatformCommonInternal INTERFACE) @@ -96,3 +100,15 @@ endif() if(NOT CMAKE_BUILD_TYPE STREQUAL Debug) target_compile_definitions(PlatformCommonInternal INTERFACE QT_NO_DEBUG) endif() + +if(APPLE_UIKIT) + # Do what mkspecs/features/uikit/default_pre.prf does, aka enable sse2 for + # simulator_and_device_builds. + if(FEATURE_simulator_and_device) + # Setting the definition on PlatformCommonInternal behaves slightly differently from what + # is done in qmake land. This way the define is not propagated to tests, examples, or + # user projects built with qmake, but only modules, plugins and tools. + # TODO: Figure out if this ok or not (sounds ok to me). + target_compile_definitions(PlatformCommonInternal INTERFACE QT_COMPILER_SUPPORTS_SSE2) + endif() +endif() diff --git a/cmake/QtModuleConfig.cmake.in b/cmake/QtModuleConfig.cmake.in index f476c24913..b2e1511870 100644 --- a/cmake/QtModuleConfig.cmake.in +++ b/cmake/QtModuleConfig.cmake.in @@ -14,14 +14,11 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependenci include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Dependencies.cmake") endif() -# Guard against multiple inclusion of the plugins file in the same local directory scope. -if(NOT TARGET @QT_CMAKE_EXPORT_NAMESPACE@::@target@) - set(_QT_NEED_TO_INCLUDE_PLUGINS_@target@ TRUE) -endif() - if (NOT QT_NO_CREATE_TARGETS) include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake") + if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS) + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake") + endif() endif() foreach(extra_cmake_include @extra_cmake_includes@) @@ -33,15 +30,24 @@ include(${_qt_@PROJECT_VERSION_MAJOR@_config_cmake_dir}/QtFeature.cmake) qt_make_features_available(@QT_CMAKE_EXPORT_NAMESPACE@::@target@) set("@INSTALL_CMAKE_NAMESPACE@@target@_FOUND" TRUE) -if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake" - AND _QT_NEED_TO_INCLUDE_PLUGINS_@target@) +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake") include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Plugins.cmake") endif() -unset(_QT_NEED_TO_INCLUDE_PLUGINS_@target@) list(APPEND QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE "@target@") -get_target_property(_qt_module_plugin_types @INSTALL_CMAKE_NAMESPACE@::@target@ MODULE_PLUGIN_TYPES) -if(_qt_module_plugin_types) - list(APPEND QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE "${_qt_module_plugin_types}") +get_target_property(_qt_module_target_type "@INSTALL_CMAKE_NAMESPACE@::@target@" TYPE) +if(NOT _qt_module_target_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(_qt_module_plugin_types + @INSTALL_CMAKE_NAMESPACE@::@target@ MODULE_PLUGIN_TYPES) + if(_qt_module_plugin_types) + list(APPEND QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE "${_qt_module_plugin_types}") + endif() +endif() + + +# Load Module's BuildIntenals should any exist +if (@INSTALL_CMAKE_NAMESPACE@BuildInternals_DIR AND + EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@BuildInternals.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@BuildInternals.cmake") endif() diff --git a/cmake/QtModuleToolsConfig.cmake.in b/cmake/QtModuleToolsConfig.cmake.in index 6d7ff9c8fa..79ca620c13 100644 --- a/cmake/QtModuleToolsConfig.cmake.in +++ b/cmake/QtModuleToolsConfig.cmake.in @@ -9,6 +9,9 @@ if (NOT QT_NO_CREATE_TARGETS) endif() include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@Targets.cmake") + if(NOT QT_NO_CREATE_VERSIONLESS_TARGETS) + include("${CMAKE_CURRENT_LIST_DIR}/@INSTALL_CMAKE_NAMESPACE@@target@VersionlessTargets.cmake") + endif() endif() @extra_cmake_statements@ diff --git a/cmake/QtModuleToolsDependencies.cmake.in b/cmake/QtModuleToolsDependencies.cmake.in index bac8bb0e04..46c60b8484 100644 --- a/cmake/QtModuleToolsDependencies.cmake.in +++ b/cmake/QtModuleToolsDependencies.cmake.in @@ -1,5 +1,5 @@ # Find "ModuleTools" dependencies, which are other ModuleTools packages. -set(_tool_deps "@tool_deps@") +set(_tool_deps "@package_deps@") foreach(_target_dep ${_tool_deps}) list(GET _target_dep 0 pkg) list(GET _target_dep 1 version) @@ -9,7 +9,7 @@ foreach(_target_dep ${_tool_deps}) endif() if (NOT ${pkg}_FOUND) - set(@INSTALL_CMAKE_NAMESPACE@@target@Tools_FOUND FALSE) + set(@INSTALL_CMAKE_NAMESPACE@@target@_FOUND FALSE) return() endif() endforeach() diff --git a/cmake/QtModuleToolsVersionlessTargets.cmake.in b/cmake/QtModuleToolsVersionlessTargets.cmake.in new file mode 100644 index 0000000000..6d0f57e039 --- /dev/null +++ b/cmake/QtModuleToolsVersionlessTargets.cmake.in @@ -0,0 +1,23 @@ +foreach(__qt_tool @tool_targets_non_prefixed@) + if(NOT TARGET Qt::${__qt_tool} AND TARGET Qt6::${__qt_tool}) + add_executable(Qt::${__qt_tool} IMPORTED) + + # Check all the usual imported location properties to find one that contains a path. + foreach(__qt_imported_location_config + IMPORTED_LOCATION + IMPORTED_LOCATION_RELEASE + IMPORTED_LOCATION_RELWITHDEBINFO + IMPORTED_LOCATION_MINSIZEREL + IMPORTED_LOCATION_DEBUG) + + get_target_property(__qt_imported_location + Qt6::${__qt_tool} ${__qt_imported_location_config}) + if(__qt_imported_location AND EXISTS "${__qt_imported_location}") + break() + endif() + endforeach() + + set_target_properties(Qt::${__qt_tool} + PROPERTIES IMPORTED_LOCATION "${__qt_imported_location}") + endif() +endforeach() diff --git a/cmake/QtPlatformAndroid.cmake b/cmake/QtPlatformAndroid.cmake index cb335da831..4b5bf6ff13 100644 --- a/cmake/QtPlatformAndroid.cmake +++ b/cmake/QtPlatformAndroid.cmake @@ -27,6 +27,18 @@ if (NOT IS_DIRECTORY "${ANDROID_SDK_ROOT}") message(FATAL_ERROR "Could not find ANDROID_SDK_ROOT or path is not a directory: ${ANDROID_SDK_ROOT}") endif() +# Get the Android SDK jar for an API version other than the one specified with +# QT_ANDROID_API_VERSION. +function(qt_get_android_sdk_jar_for_api api out_jar_location) + set(jar_location "${ANDROID_SDK_ROOT}/platforms/${api}/android.jar") + if (NOT EXISTS "${jar_location}") + message(WARNING "Could not locate Android SDK jar for api '${api}', defaulting to ${QT_ANDROID_API_VERSION}") + set(${out_jar_location} ${QT_ANDROID_JAR} PARENT_SCOPE) + else() + set(${out_jar_location} ${jar_location} PARENT_SCOPE) + endif() +endfunction() + # Minimum recommend android SDK api version set(QT_ANDROID_API_VERSION "android-21") @@ -305,9 +317,62 @@ endfunction() function(qt_android_apply_arch_suffix target) get_target_property(target_type ${target} TYPE) - if (target_type STREQUAL "SHARED_LIBRARY") + if (target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY") set_property(TARGET "${target}" PROPERTY SUFFIX "_${CMAKE_ANDROID_ARCH_ABI}.so") elseif (target_type STREQUAL "STATIC_LIBRARY") set_property(TARGET "${target}" PROPERTY SUFFIX "_${CMAKE_ANDROID_ARCH_ABI}.a") endif() endfunction() + +# Add custom target to package the APK +function(qt_android_add_apk_target target) + get_target_property(deployment_file ${target} QT_ANDROID_DEPLOYMENT_SETTINGS_FILE) + if (NOT deployment_file) + message(FATAL_ERROR "Target ${target} is not a valid android executable target\n") + endif() + + set(deployment_tool "${QT_HOST_PATH}/bin/androiddeployqt") + set(apk_dir "$<TARGET_PROPERTY:${target},BINARY_DIR>/android-build") + add_custom_target(${target}_prepare_apk_dir + DEPENDS ${target} + COMMAND ${CMAKE_COMMAND} + -E copy $<TARGET_FILE:${target}> + "${apk_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>" + COMMENT "Copying ${target} binarty to apk folder" + ) + + add_custom_target(${target}_make_apk + DEPENDS ${target}_prepare_apk_dir + COMMAND ${deployment_tool} + --input ${deployment_file} + --output ${apk_dir} + COMMENT "Creating APK for ${target}" + ) +endfunction() + + +# Add a test for Android which will be run by the android test runner tool +function(qt_android_add_test target) + + set(deployment_tool "${QT_HOST_PATH}/bin/androiddeployqt") + set(test_runner "${QT_HOST_PATH}/bin/androidtestrunner") + + get_target_property(deployment_file ${target} QT_ANDROID_DEPLOYMENT_SETTINGS_FILE) + if (NOT deployment_file) + message(FATAL_ERROR "Target ${target} is not a valid android executable target\n") + endif() + + set(target_binary_dir "$<TARGET_PROPERTY:${target},BINARY_DIR>") + set(apk_dir "${target_binary_dir}/android-build") + + add_test(NAME "${target}" + COMMAND "${test_runner}" + --androiddeployqt "${deployment_tool} --input ${deployment_file}" + --adb "${ANDROID_SDK_ROOT}/platform-tools/adb" + --path "${apk_dir}" + --skip-install-root + --make "${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk" + --apk "${apk_dir}/${target}.apk" + --verbose + ) +endfunction() diff --git a/cmake/QtPlatformSupport.cmake b/cmake/QtPlatformSupport.cmake index 2c5df77ba4..b54d52eba4 100644 --- a/cmake/QtPlatformSupport.cmake +++ b/cmake/QtPlatformSupport.cmake @@ -1,4 +1,4 @@ -function(set01 result) +function(qt_set01 result) if (${ARGN}) set("${result}" 1 PARENT_SCOPE) else() @@ -6,32 +6,32 @@ function(set01 result) endif() endfunction() -set01(LINUX CMAKE_SYSTEM_NAME STREQUAL "Linux") -set01(HPUX CMAKE_SYSTEM_NAME STREQUAL "HPUX") -set01(ANDROID CMAKE_SYSTEM_NAME STREQUAL "Android") # FIXME: How to identify this? -set01(NACL CMAKE_SYSTEM_NAME STREQUAL "NaCl") # FIXME: How to identify this? -set01(INTEGRITY CMAKE_SYSTEM_NAME STREQUAL "Integrity") # FIXME: How to identify this? -set01(VXWORKS CMAKE_SYSTEM_NAME STREQUAL "VxWorks") # FIXME: How to identify this? -set01(QNX CMAKE_SYSTEM_NAME STREQUAL "QNX") # FIXME: How to identify this? -set01(OPENBSD CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") # FIXME: How to identify this? -set01(FREEBSD CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") # FIXME: How to identify this? -set01(NETBSD CMAKE_SYSTEM_NAME STREQUAL "NetBSD") # FIXME: How to identify this? -set01(WASM CMAKE_SYSTEM_NAME STREQUAL "Emscripten") +qt_set01(LINUX CMAKE_SYSTEM_NAME STREQUAL "Linux") +qt_set01(HPUX CMAKE_SYSTEM_NAME STREQUAL "HPUX") +qt_set01(ANDROID CMAKE_SYSTEM_NAME STREQUAL "Android") # FIXME: How to identify this? +qt_set01(NACL CMAKE_SYSTEM_NAME STREQUAL "NaCl") # FIXME: How to identify this? +qt_set01(INTEGRITY CMAKE_SYSTEM_NAME STREQUAL "Integrity") # FIXME: How to identify this? +qt_set01(VXWORKS CMAKE_SYSTEM_NAME STREQUAL "VxWorks") # FIXME: How to identify this? +qt_set01(QNX CMAKE_SYSTEM_NAME STREQUAL "QNX") # FIXME: How to identify this? +qt_set01(OPENBSD CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") # FIXME: How to identify this? +qt_set01(FREEBSD CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") # FIXME: How to identify this? +qt_set01(NETBSD CMAKE_SYSTEM_NAME STREQUAL "NetBSD") # FIXME: How to identify this? +qt_set01(WASM CMAKE_SYSTEM_NAME STREQUAL "Emscripten") -set01(BSD APPLE OR OPENBSD OR FREEBSD OR NETBSD) +qt_set01(BSD APPLE OR OPENBSD OR FREEBSD OR NETBSD) -set01(WINRT WIN32 AND CMAKE_VS_PLATFORM_TOOSLET STREQUAL "winrt") # FIXME: How to identify this? +qt_set01(WINRT WIN32 AND CMAKE_VS_PLATFORM_TOOSLET STREQUAL "winrt") # FIXME: How to identify this? -set01(APPLE_OSX APPLE) # FIXME: How to identify this? For now assume that always building for macOS. -set01(APPLE_UIKIT APPLE AND CMAKE_XCODE_PLATFORM_TOOLSET STREQUAL "uikit") # FIXME: How to identify this? -set01(APPLE_IOS APPLE AND CMAKE_XCODE_PLATFORM_TOOLSET STREQUAL "ios") # FIXME: How to identify this? -set01(APPLE_TVOS APPLE AND CMAKE_XCODE_PLATFORM_TOOLSET STREQUAL "tvos") # FIXME: How to identify this? -set01(APPLE_WATCHOS APPLE AND CMAKE_XCODE_PLATFORM_TOOLSET STREQUAL "watchos") # FIXME: How to identify this? +qt_set01(APPLE_IOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "iOS") +qt_set01(APPLE_TVOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "tvOS") +qt_set01(APPLE_WATCHOS APPLE AND CMAKE_SYSTEM_NAME STREQUAL "watchOS") +qt_set01(APPLE_UIKIT APPLE AND (APPLE_IOS OR APPLE_TVOS OR APPLE_WATCHOS)) +qt_set01(APPLE_OSX APPLE AND NOT APPLE_UIKIT) -set01(GCC CMAKE_CXX_COMPILER_ID STREQUAL "GNU") -set01(CLANG CMAKE_CXX_COMPILER_ID MATCHES "Clang") -set01(ICC CMAKE_C_COMPILER MATCHES "icc|icl") -set01(QCC CMAKE_C_COMPILER MATCHES "qcc") # FIXME: How to identify this? +qt_set01(GCC CMAKE_CXX_COMPILER_ID STREQUAL "GNU") +qt_set01(CLANG CMAKE_CXX_COMPILER_ID MATCHES "Clang") +qt_set01(ICC CMAKE_C_COMPILER MATCHES "icc|icl") +qt_set01(QCC CMAKE_C_COMPILER MATCHES "qcc") # FIXME: How to identify this? if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(QT_64BIT TRUE) diff --git a/cmake/QtPluginConfig.cmake.in b/cmake/QtPluginConfig.cmake.in index ab812abcf2..5fde0bc511 100644 --- a/cmake/QtPluginConfig.cmake.in +++ b/cmake/QtPluginConfig.cmake.in @@ -1,3 +1,5 @@ +include_guard(DIRECTORY) + @PACKAGE_INIT@ include(CMakeFindDependencyMacro) diff --git a/cmake/QtPlugins.cmake.in b/cmake/QtPlugins.cmake.in index fb87a54c0d..91884302c6 100644 --- a/cmake/QtPlugins.cmake.in +++ b/cmake/QtPlugins.cmake.in @@ -1,3 +1,5 @@ +include_guard(DIRECTORY) + @QT_MODULE_PLUGIN_INCLUDES@ if(NOT @BUILD_SHARED_LIBS@) @@ -17,9 +19,22 @@ if(NOT @BUILD_SHARED_LIBS@) set(_manual_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:QT_PLUGINS>>") set(_no_plugins_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:QT_NO_PLUGINS>>") + # In super builds the rules below pollute the dependency rule for the + # plugin target when it's being build, causing cyclic dependencies. + # to overcome this, we check if the current target where this rule evaluates + # has a QT_BUILD_PROJECT_NAME equal to the current PROJECT_NAME. + # If so we disable the injection of plugin link rules to avoid cyclic + # dependencies. + if (@QT_SUPERBUILD@) + set(_build_allow_plugin_link_rules_genex "$<NOT:$<STREQUAL:$<TARGET_PROPERTY:QT_BUILD_PROJECT_NAME>,@PROJECT_NAME@>>") + else() + set(_build_allow_plugin_link_rules_genex 1) + endif() + # The code in here uses the properties defined in qt_import_plugins (Qt6CoreMacros.cmake) foreach(target @qt_plugins@) set(_plugin_target "@INSTALL_CMAKE_NAMESPACE@::${target}") + set(_plugin_target_versionless "Qt::${target}") get_target_property(_classname "${_plugin_target}" QT_PLUGIN_CLASS_NAME) if(NOT _classname) message("Warning: plugin ${_plugin_target} has no class name, skipping.") @@ -38,6 +53,8 @@ if(NOT @BUILD_SHARED_LIBS@) # INCLUDE set(_plugin_is_whitelisted "$<IN_LIST:${_plugin_target},${_manual_plugins_genex}>") + set(_plugin_versionless_is_whitelisted + "$<IN_LIST:${_plugin_target_versionless},${_manual_plugins_genex}>") # Note: qt_import_plugins sets the QT_PLUGINS_${_plugin_type} to "-" # when excluding it with EXCLUDE_BY_TYPE, @@ -47,7 +64,11 @@ if(NOT @BUILD_SHARED_LIBS@) "$<NOT:" # EXCLUDE "$<IN_LIST:${_plugin_target},${_no_plugins_genex}>" ">," - # excludes both plugins targeted by EXCLUDE_BY_TYPE and not included in INCLUDE_BY_TYPE + "$<NOT:" + "$<IN_LIST:${_plugin_target_versionless},${_no_plugins_genex}>" + ">," + # Excludes both plugins targeted by EXCLUDE_BY_TYPE and not included in + # INCLUDE_BY_TYPE. "$<STREQUAL:,$<GENEX_EVAL:$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>>>" ">" ) @@ -61,16 +82,29 @@ if(NOT @BUILD_SHARED_LIBS@) ">" ">" ) + string(CONCAT _plugin_versionless_is_in_type_whitelist + "$<IN_LIST:" + "${_plugin_target_versionless}," + "$<GENEX_EVAL:" + "$<TARGET_PROPERTY:QT_PLUGINS_${_plugin_type}>" + ">" + ">" + ) # Complete condition that defines whether a static plugin is linked string(CONCAT _plugin_condition - "$<BOOL:$<OR:" - "${_plugin_is_whitelisted}," - "${_plugin_is_in_type_whitelist}," - "$<AND:" - "${_default_plugins_are_enabled_wrapped}," - "${_plugin_is_default}," - "${_plugin_is_not_blacklisted}" + "$<BOOL:$<AND:" + "${_build_allow_plugin_link_rules_genex}," + "$<OR:" + "${_plugin_is_whitelisted}," + "${_plugin_versionless_is_whitelisted}," + "${_plugin_is_in_type_whitelist}," + "${_plugin_versionless_is_in_type_whitelist}," + "$<AND:" + "${_default_plugins_are_enabled_wrapped}," + "${_plugin_is_default}," + "${_plugin_is_not_blacklisted}" + ">" ">" ">>" ) diff --git a/cmake/QtPostProcess.cmake b/cmake/QtPostProcess.cmake index ffa367cb9e..19cd4b699b 100644 --- a/cmake/QtPostProcess.cmake +++ b/cmake/QtPostProcess.cmake @@ -1,6 +1,6 @@ function(qt_internal_write_depends_file target) set(module Qt${target}) - set(outfile "${QT_BUILD_DIR}/include/${module}/${module}Depends") + set(outfile "${QT_BUILD_DIR}/${INSTALL_INCLUDEDIR}/${module}/${module}Depends") message("Generate ${outfile}...") set(contents "/* This file was generated by cmake with the info from ${module} target. */\n") string(APPEND contents "#ifdef __cplusplus /* create empty PCH in C mode */\n") @@ -68,9 +68,11 @@ function(qt_internal_create_module_depends_file target) set(arg_HEADER_MODULE OFF) endif() - if(NOT arg_HEADER_MODULE) + set(depends "") + if(target_type STREQUAL "STATIC_LIBRARY" AND NOT arg_HEADER_MODULE) get_target_property(depends "${target}" LINK_LIBRARIES) endif() + get_target_property(public_depends "${target}" INTERFACE_LINK_LIBRARIES) # Used for collecting Qt module dependencies that should be find_package()'d in @@ -82,7 +84,7 @@ function(qt_internal_create_module_depends_file target) get_target_property(extra_depends "${target}" QT_EXTRA_PACKAGE_DEPENDENCIES) endif() if(NOT extra_depends STREQUAL "${extra_depends}-NOTFOUND") - list(APPEND target_deps ${extra_depends}) + list(APPEND target_deps "${extra_depends}") endif() # Used for assembling the content of an include/Module/ModuleDepends.h header. @@ -183,23 +185,8 @@ function(qt_internal_create_module_depends_file target) endif() if(tool_deps) - set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}Tools") - qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} ${path_suffix}) - qt_path_join(config_install_dir ${QT_CONFIG_INSTALL_DIR} ${path_suffix}) - - # Configure and install ModuleToolDependencies file. - configure_file( - "${QT_CMAKE_DIR}/QtModuleToolsDependencies.cmake.in" - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ToolsDependencies.cmake" - @ONLY - ) - - qt_install(FILES - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ToolsDependencies.cmake" - DESTINATION "${config_install_dir}" - COMPONENT Devel - ) - + # The value of the property will be used by qt_export_tools. + set_property(TARGET "${target}" PROPERTY _qt_tools_package_deps "${tool_deps}") endif() endfunction() @@ -313,8 +300,7 @@ endfunction() function(qt_generate_build_internals_extra_cmake_code) if(PROJECT_NAME STREQUAL "QtBase") - set(QT_EXTRA_BUILD_INTERNALS_VARS) - foreach(var IN LISTS qt_base_configure_tests_vars_to_export) + foreach(var IN LISTS QT_BASE_CONFIGURE_TESTS_VARS_TO_EXPORT) string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "set(${var} \"${${var}}\" CACHE INTERNAL \"\")\n") endforeach() @@ -322,6 +308,36 @@ function(qt_generate_build_internals_extra_cmake_code) qt_path_join(extra_file_path ${QT_CONFIG_BUILD_DIR} ${INSTALL_CMAKE_NAMESPACE}BuildInternals/QtBuildInternalsExtra.cmake) + + if(CMAKE_BUILD_TYPE) + # Need to force set, because CMake itself initializes a value for CMAKE_BUILD_TYPE + # at the start of project configuration (with an empty value), + # so we need to force override it. + string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS + "set(CMAKE_BUILD_TYPE \"${CMAKE_BUILD_TYPE}\" CACHE STRING \"Choose the type of build.\" FORCE)\n") + + endif() + if(CMAKE_CONFIGURATION_TYPES) + string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS + "set(CMAKE_CONFIGURATION_TYPES \"${CMAKE_CONFIGURATION_TYPES}\")\n") + endif() + if(CMAKE_TRY_COMPILE_CONFIGURATION) + string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS + "set(CMAKE_TRY_COMPILE_CONFIGURATION \"${CMAKE_TRY_COMPILE_CONFIGURATION}\")\n") + endif() + if(QT_MULTI_CONFIG_FIRST_CONFIG) + string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS + "set(QT_MULTI_CONFIG_FIRST_CONFIG \"${QT_MULTI_CONFIG_FIRST_CONFIG}\")\n") + endif() + if(CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE) + string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS + "set(CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE \"${CMAKE_NINJA_MULTI_CROSS_CONFIG_ENABLE}\")\n") + endif() + if(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE) + string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS + "set(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE \"${CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE}\")\n") + endif() + configure_file( "${CMAKE_CURRENT_LIST_DIR}/QtBuildInternalsExtra.cmake.in" "${extra_file_path}" @@ -346,10 +362,45 @@ function(qt_create_tools_config_files) endforeach() endfunction() -qt_create_tools_config_files() +function(qt_internal_create_config_file_for_standalone_tests) + set(standalone_tests_config_dir "StandaloneTests") + qt_path_join(config_build_dir + ${QT_CONFIG_BUILD_DIR} + "${INSTALL_CMAKE_NAMESPACE}BuildInternals" "${standalone_tests_config_dir}") + qt_path_join(config_install_dir + ${QT_CONFIG_INSTALL_DIR} + "${INSTALL_CMAKE_NAMESPACE}BuildInternals" "${standalone_tests_config_dir}") + + list(JOIN QT_REPO_KNOWN_MODULES " " QT_REPO_KNOWN_MODULES_STRING) + string(STRIP "${QT_REPO_KNOWN_MODULES_STRING}" QT_REPO_KNOWN_MODULES_STRING) + + # Skip generating and installing file if no modules were built. This make sure not to install + # anything when build qtx11extras on macOS for example. + if(NOT QT_REPO_KNOWN_MODULES_STRING) + return() + endif() + + # Ceate a Config file that calls find_package on the modules that were built as part + # of the current repo. This is used for standalone tests. + configure_file( + "${QT_CMAKE_DIR}/QtStandaloneTestsConfig.cmake.in" + "${config_build_dir}/${PROJECT_NAME}TestsConfig.cmake" + @ONLY + ) + qt_install(FILES + "${config_build_dir}/${PROJECT_NAME}TestsConfig.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) +endfunction() + qt_internal_create_depends_files() qt_generate_build_internals_extra_cmake_code() qt_internal_create_plugins_files() +qt_internal_create_config_file_for_standalone_tests() + +# Needs to run after qt_internal_create_depends_files. +qt_create_tools_config_files() if (ANDROID) qt_modules_process_android_dependencies() diff --git a/cmake/QtProperties.cmake b/cmake/QtProperties.cmake index 5e2d6f0545..a12fa53252 100644 --- a/cmake/QtProperties.cmake +++ b/cmake/QtProperties.cmake @@ -93,7 +93,7 @@ define_property(TARGET BRIEF_DOCS "Specifies the default Qt resource prefix." FULL_DOCS - "When using add_qt_resource() without a PREFIX, then prefix of this target property + "When using qt_add_resource() without a PREFIX, then prefix of this target property will be used." ) diff --git a/cmake/QtResource.cmake.in b/cmake/QtResource.cmake.in index 335cbde33c..bef47707ea 100644 --- a/cmake/QtResource.cmake.in +++ b/cmake/QtResource.cmake.in @@ -28,7 +28,7 @@ function(__qt_propagate_generated_resource target resource_name generated_source endif() endfunction() -# Inspect all files passed to a call to add_qt_resource. If there are any +# Inspect all files passed to a call to qt_add_resource. If there are any # files present, invoke the quick compiler and return the remaining resource # files that have not been processed in OUTPUT_REMAINING_RESOURCES as well as the new # name for the resource in OUTPUT_RESOURCE_NAME. @@ -40,13 +40,11 @@ function(__qt_quick_compiler_process_resources target resource_name) set(qml_files) set(resource_files) - set(retained_files) # scan for qml files foreach(file IN LISTS arg_FILES) # check whether this resource should not be processed by the qt quick # compiler get_source_file_property(skip_compiler_check ${file} QT_SKIP_QUICKCOMPILER) - get_source_file_property(retain_compiler_check ${file} QT_RETAIN_QUICKCOMPILER) if (skip_compiler_check) list(APPEND resource_files ${file}) continue() @@ -56,19 +54,13 @@ function(__qt_quick_compiler_process_resources target resource_name) OR ${file} MATCHES "\.mjs$" OR ${file} MATCHES "\.qml$") list(APPEND qml_files ${file}) - if (retain_compiler_check) - list(APPEND retained_files ${file}) - list(APPEND resource_files ${file}) - endif() - else() - list(APPEND resource_files ${file}) endif() + list(APPEND resource_files ${file}) endforeach() if (NOT TARGET @QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen AND qml_files) message(WARNING "QT@PROJECT_VERSION_MAJOR@_PROCESS_RESOURCE: Qml files were detected but the qmlcachgen target is not defined. Consider adding QmlTools to your find_package command.") endif() - set(retained_resource_paths) if (TARGET @QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen AND qml_files) # Enable qt quick compiler support set(qml_resource_file "${CMAKE_CURRENT_BINARY_DIR}/.rcc/${resource_name}.qrc") @@ -86,9 +78,6 @@ function(__qt_quick_compiler_process_resources target resource_name) else() set(file_resource_path "${arg_PREFIX}/${file_resource_path}") endif() - if (file IN_LIST retained_files) - list(APPEND retained_resource_paths ${file_resource_path}) - endif() file(TO_CMAKE_PATH ${file_resource_path} file_resource_path) list(APPEND file_resource_paths ${file_resource_path}) string(REGEX REPLACE "\.js$" "_js" compiled_file ${file_relative}) @@ -102,13 +91,15 @@ function(__qt_quick_compiler_process_resources target resource_name) endif() add_custom_command( OUTPUT ${compiled_file} - DEPENDS ${file_absolute} ${QT_TOOL_PATH_SETUP_COMMAND} COMMAND @QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen - --resource-path ${file_resource_path} - -o ${compiled_file} - ${file_absolute} + --resource-path "${file_resource_path}" + -o "${compiled_file}" + "${file_absolute}" + DEPENDS + $<TARGET_FILE:@QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen> + "${file_absolute}" ) target_sources(${target} PRIVATE ${compiled_file}) endforeach() @@ -125,25 +116,17 @@ function(__qt_quick_compiler_process_resources target resource_name) set(resource_name_arg "${resource_name_arg}=${chained_resource_name}") endif() - if (retained_resource_paths) - set(retained_loader_list "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/${resource_name}/retained_file_list.rsp") - file(GENERATE - OUTPUT ${retained_loader_list} - CONTENT "$<JOIN:${retained_resource_paths},\n>" - ) - set(retained_args "--retain" "@${retained_loader_list}") - endif() - add_custom_command( OUTPUT ${qmlcache_loader_file} - DEPENDS ${qmlcache_loader_list} ${QT_TOOL_PATH_SETUP_COMMAND} COMMAND @QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen - ${retained_args} --resource-name "${resource_name_arg}" - -o ${qmlcache_loader_file} + -o "${qmlcache_loader_file}" "@${qmlcache_loader_list}" + DEPENDS + $<TARGET_FILE:@QT_CMAKE_EXPORT_NAMESPACE@::qmlcachegen> + "${qmlcache_loader_list}" ) __qt_propagate_generated_resource(${target} @@ -293,7 +276,10 @@ function(QT@PROJECT_VERSION_MAJOR@_PROCESS_RESOURCE target resourceName) add_custom_command(OUTPUT "${generatedSourceCode}" COMMAND "@QT_CMAKE_EXPORT_NAMESPACE@::rcc" ARGS ${rccArgs} - DEPENDS ${resource_dependencies} ${generatedResourceFile} + DEPENDS + ${resource_dependencies} + ${generatedResourceFile} + "@QT_CMAKE_EXPORT_NAMESPACE@::rcc" COMMENT "RCC ${newResourceName}" VERBATIM) diff --git a/cmake/QtSetup.cmake b/cmake/QtSetup.cmake index 16fd9b7520..90588c99b3 100644 --- a/cmake/QtSetup.cmake +++ b/cmake/QtSetup.cmake @@ -10,10 +10,22 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/.git") set(_default_build_type "Debug") endif() +# Reset content of extra build internal vars for each inclusion of QtSetup. +unset(QT_EXTRA_BUILD_INTERNALS_VARS) + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${_default_build_type}' as none was specified.") set(CMAKE_BUILD_TYPE "${_default_build_type}" CACHE STRING "Choose the type of build." FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo") # Set the possible values for cmake-gui. +elseif(CMAKE_CONFIGURATION_TYPES) + message(STATUS "Building for multiple configurations: ${CMAKE_CONFIGURATION_TYPES}.") + message(STATUS "Main configuration is: ${QT_MULTI_CONFIG_FIRST_CONFIG}.") + if(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE) + message(STATUS + "Default build configuration set to '${CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE}'.") + endif() endif() # Appends a 'debug postfix' to library targets (not executables) @@ -24,11 +36,6 @@ elseif(APPLE) set(CMAKE_DEBUG_POSTFIX "_debug") endif() -## Force C++ standard, do not fall back, do not use compiler extensions -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - ## Position independent code: set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -44,7 +51,7 @@ set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) # or when enabling developer builds and no prefix is specified. # This detection only happens when building qtbase, and later is propagated via the generated # QtBuildInternalsExtra.cmake file. -if (PROJECT_NAME STREQUAL "QtBase") +if (PROJECT_NAME STREQUAL "QtBase" AND NOT QT_BUILD_STANDALONE_TESTS) if((CMAKE_INSTALL_PREFIX STREQUAL CMAKE_BINARY_DIR) OR (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND FEATURE_developer_build)) @@ -78,24 +85,62 @@ if(FEATURE_developer_build) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) endif() set(QT_BUILD_TESTING ON) + set(__build_benchmarks ON) + + # Tests are not built by default with qmake for iOS and friends, and thus the overall build + # tends to fail. Disable them by default when targeting uikit. + if(APPLE_UIKIT) + set(QT_BUILD_TESTING OFF) + endif() + + # Disable benchmarks for single configuration generators which do not build + # with release configuration. + if (CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL Release) + set(__build_benchmarks OFF) + endif() else() set(QT_BUILD_TESTING OFF) + set(__build_benchmarks OFF) endif() ## Set up testing option(BUILD_TESTING "Build the testing tree." ${QT_BUILD_TESTING}) +if(QT_BUILD_STANDALONE_TESTS) + set(QT_BUILD_TESTING ON) + + # BuildInternals might have set it to OFF on initial configuration. So force it to ON when + # building standalone tests. + set(BUILD_TESTING ON CACHE BOOL "Build the testing tree." FORCE) + + # Also force the tests to be built as part of the default build target. + set(QT_NO_MAKE_TESTS OFF CACHE BOOL + "Should examples be built as part of the default 'all' target." FORCE) +endif() +option(QT_NO_MAKE_TESTS "Should tests be built as part of the default 'all' target." OFF) + include(CTest) enable_testing() # Set up building of examples. -option(BUILD_EXAMPLES "Build Qt examples" ON) +set(QT_BUILD_EXAMPLES ON) +# Examples are not built by default with qmake for iOS and friends, and thus the overall build +# tends to fail. Disable them by default when targeting uikit. +if(APPLE_UIKIT) + set(QT_BUILD_EXAMPLES OFF) +endif() + +option(BUILD_EXAMPLES "Build Qt examples" ${QT_BUILD_EXAMPLES}) +option(QT_NO_MAKE_EXAMPLES "Should examples be built as part of the default 'all' target." OFF) + +# Build Benchmarks +option(QT_BUILD_BENCHMARKS "Build Qt Benchmarks" ${__build_benchmarks}) ## Android platform settings if(ANDROID) include(QtPlatformAndroid) endif() -## add_qt_module and co.: +## qt_add_module and co.: include(QtBuild) ## Qt Feature support: @@ -110,6 +155,8 @@ include(QtCompilerFlags) ## Set up non-prefix build: qt_set_up_nonprefix_build() +qt_set_language_standards() + ## Find host tools (if non native): set(QT_HOST_PATH "" CACHE PATH "Installed Qt host directory path, used for cross compiling.") diff --git a/cmake/QtStandaloneTestsConfig.cmake.in b/cmake/QtStandaloneTestsConfig.cmake.in new file mode 100644 index 0000000000..3d08ae0c12 --- /dev/null +++ b/cmake/QtStandaloneTestsConfig.cmake.in @@ -0,0 +1,2 @@ +find_package(@INSTALL_CMAKE_NAMESPACE@ @PROJECT_VERSION@ + REQUIRED COMPONENTS @QT_REPO_KNOWN_MODULES_STRING@) diff --git a/cmake/README.md b/cmake/README.md index 5739b900f7..6b65f0e69a 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -114,8 +114,10 @@ install: QMake defines most features in configure.json files, like -developer-build or -no-opengl. -In CMake land, we currently generate configure.cmake files from the configure.json files. If the -feature in configure.json has the name "dlopen", you can specify whether to enable or disable that +In CMake land, we currently generate configure.cmake files from the configure.json files into +the source directory next to them using the helper script +``path_to_qtbase_source/util/cmake/configurejson2cmake.py``. They are checked into the repository. +If the feature in configure.json has the name "dlopen", you can specify whether to enable or disable that feature in CMake with a -D flag on the CMake command line. So for example -DFEATURE_dlopen=ON or -DFEATURE_sql_mysql=OFF. At the moment, if you change a FEATURE flag's value, you have to remove the CMakeCache.txt file and reconfigure with CMake. And even then you might stumble on some issues when @@ -201,7 +203,7 @@ When running cmake in qtbase, pass ``-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake -DQT_HOST_PATH=/path/to/your/host/build -DANDROID_SDK_ROOT=$ANDROID_SDK_HOME -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH`` If you don't supply the configuration argument ``-DANDROID_ABI=...``, it will default to -``armeabi-v7a``. To target other architectures, use on of the following values: +``armeabi-v7a``. To target other architectures, use one of the following values: * arm64: ``-DANDROID_ABI=arm64-v8`` * x86: ``-DANDROID_ABI=x86`` * x86_64: ``-DANDROID_ABI=x86_64`` @@ -209,6 +211,57 @@ If you don't supply the configuration argument ``-DANDROID_ABI=...``, it will de By default we set the android API level to 21. Should you need to change this supply the following configuration argument to the above CMake call: ``-DANDROID_NATIVE_API_LEVEL=${API_LEVEL}`` +### Cross compiling for iOS + +In order to cross-compile Qt to iOS, you need a host macOS build. +In addition, it is necessary to install a custom version of vcpkg. Vcpkg is +needed to supply third-party libraries that Qt requires, but that are not part of the iOS SDK. + +Vcpkg for iOS can be set up using the following steps: + + * ```git clone -b qt https://github.com/alcroito/vcpkg``` + * Run ```bootstrap-vcpkg.sh``` + * Set the ``VCPKG_DEFAULT_TRIPLET`` environment variable to one of the following values: + * ``x64-ios`` (simulator x86_64) + * ``x86-ios`` (simulator i386) + * ``arm64-ios`` (device arm64) + * ``arm-ios`` (device armv7) + * ``fat-ios`` (simulator_and_device x86_64 and arm64* - special considedrations) + * Set the ``VCPKG_ROOT`` environment variable to the path where you cloned vcpkg + * Build Qt dependencies: ``vcpkg install @qt-packages-ios.txt`` + +When running cmake in qtbase, pass +``-DCMAKE_SYSTEM_NAME=iOS -DQT_HOST_PATH=/path/to/your/host/build -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH`` + +If you don't supply the configuration argument ``-DQT_UIKIT_SDK=...``, it will default to +``iphonesimulator``. To target another SDK / device type, use one of the following values: + * iphonesimulator: ``-DQT_UIKIT_SDK=iphonesimulator`` + * iphoneos: ``-DQT_UIKIT_SDK=iphoneos`` + * simulator_and_device: ``-DQT_FORCE_SIMULATOR_AND_DEVICE=ON -DQT_UIKIT_SDK=`` + +Depending on what value you pass to ``-DQT_UIKIT_SDK=`` a list of target architectures is chosen +by default: + * iphonesimulator: ``x86_64`` + * iphoneos: ``arm64`` + * simulator_and_device: ``arm64;x86_64`` + +You can try choosing a different list of architectures by passing +``-DCMAKE_OSX_ARCHITECTURES=x86_64;i386``. +Note that if you choose different architectures compared to the default ones, the build might fail. +Only do it if you know what you are doing. + +#### simulator_and_device special considerations +To do a simulator_and_device build, a custom version of CMake is required in addition to the vcpkg +fork. The merge request can be found here: +https://gitlab.kitware.com/cmake/cmake/merge_requests/3617 + +After you build your own copy of CMake using this merge request, you need to use it for both +vcpkg and Qt. + +Note that vcpkg prefers its own version of CMake when building packages. +Make sure to put your custom built CMake in PATH, and force vcpkg to use this CMake by running +``export VCPKG_FORCE_SYSTEM_BINARIES=1`` in your shell. + # Debugging CMake files CMake allows specifying the ``--trace`` and ``--trace-expand`` options, which work like @@ -235,7 +288,7 @@ top-level source directory of a Qt repository. ``pro2cmake.py`` generates a skeleton CMakeLists.txt file from a .pro-file. You will need to polish the resulting CMakeLists.txt file, but e.g. the list of files, etc. should be extracted for you. -``pro2cmake.py`` is run like this: ``/path/to/pro2cmake.py some.pro``. +``pro2cmake.py`` is run like this: ``path_to_qtbase_source/util/cmake/pro2cmake.py some.pro``. ## run_pro2cmake.py @@ -243,7 +296,7 @@ the resulting CMakeLists.txt file, but e.g. the list of files, etc. should be ex `` A small helper script to run pro2cmake.py on all .pro-files in a directory. Very useful to e.g. convert all the unit tests for a Qt module over to cmake;-) -``run_pro2cmake.py`` is run like this: ``/path/to/run_pro2cmake.py some_dir``. +``run_pro2cmake.py`` is run like this: ``path_to_qtbase_source/util/cmake/run_pro2cmake.py some_dir``. ## How to convert certain constructs |