diff options
32 files changed, 5829 insertions, 5819 deletions
diff --git a/cmake/Qt3rdPartyLibraryHelpers.cmake b/cmake/Qt3rdPartyLibraryHelpers.cmake new file mode 100644 index 0000000000..1567ca94c6 --- /dev/null +++ b/cmake/Qt3rdPartyLibraryHelpers.cmake @@ -0,0 +1,263 @@ +# 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(qt_add_cmake_library target) + # Process arguments: + 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}" + ${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) + qt_internal_apply_win_prefix_and_suffix("${target}") + 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) + set_property(TARGET ${name} PROPERTY OBJC_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY OBJCXX_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() + qt_internal_apply_win_prefix_and_suffix("${target}") + else() + add_library("${target}") + endif() + + if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY) + set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}") + endif() + + 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 + ARCHIVE_INSTALL_DIRECTORY ${arg_ARCHIVE_INSTALL_DIRECTORY} + INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY} + ) + endif() + + if (arg_OUTPUT_DIRECTORY) + set_target_properties(${target} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} + RUNTIME_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} + LIBRARY_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} + ) + 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} Qt::PlatformCommonInternal + 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} + ) +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;INSTALL;SKIP_AUTOMOC" + "OUTPUT_DIRECTORY;QMAKE_LIB_NAME" + "${__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) + set_property(TARGET ${name} PROPERTY OBJC_VISIBILITY_PRESET default) + set_property(TARGET ${name} PROPERTY OBJCXX_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_INTERFACE) + qt_set_common_target_properties(${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}) + _qt_internal_apply_strict_cpp(${target}) + + if (ANDROID) + qt_android_apply_arch_suffix("${target}") + endif() + + qt_skip_warnings_are_errors_when_repo_unclean("${target}") + + 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_MODULE_SKIP_DEPENDS_INCLUDE TRUE + ) + qt_handle_multi_config_output_dirs("${target}") + + set_target_properties(${target} PROPERTIES + OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" + ) + + if(NOT arg_SKIP_AUTOMOC) + qt_autogen_tools_initial_setup(${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_generate_3rdparty_lib_pri_file("${target}" "${arg_QMAKE_LIB_NAME}" pri_file) + if(pri_file) + qt_install(FILES "${pri_file}" DESTINATION "${INSTALL_MKSPECSDIR}/modules") + 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} Qt::PlatformModuleInternal + 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_INSTALL) + 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(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + qt_install(TARGETS ${target} + EXPORT "${export_name}" + RUNTIME DESTINATION ${INSTALL_BINDIR} + LIBRARY DESTINATION ${INSTALL_LIBDIR} + ARCHIVE DESTINATION ${INSTALL_LIBDIR} + ) + + 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_install_3rdparty_library_wrap_config_extra_file target) + if(TARGET "${target}") + set(use_bundled "ON") + else() + set(use_bundled "OFF") + endif() + + set(QT_USE_BUNDLED_${target} "${use_bundled}" CACHE BOOL "" FORCE) + set(extra_cmake_code "set(QT_USE_BUNDLED_${target} ${use_bundled} CACHE BOOL \"\" FORCE)") + configure_file( + "${QT_CMAKE_DIR}/QtFindWrapConfigExtra.cmake.in" + "${QT_CONFIG_BUILD_DIR}/${INSTALL_CMAKE_NAMESPACE}/FindWrap${target}ConfigExtra.cmake" + @ONLY + ) + + qt_install(FILES + "${QT_CONFIG_BUILD_DIR}/${INSTALL_CMAKE_NAMESPACE}/FindWrap${target}ConfigExtra.cmake" + DESTINATION "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}" + COMPONENT Devel + ) +endfunction() diff --git a/cmake/QtApp.cmake b/cmake/QtAppHelpers.cmake index 0c99356db3..0c99356db3 100644 --- a/cmake/QtApp.cmake +++ b/cmake/QtAppHelpers.cmake diff --git a/cmake/QtAutogenHelpers.cmake b/cmake/QtAutogenHelpers.cmake new file mode 100644 index 0000000000..f028452320 --- /dev/null +++ b/cmake/QtAutogenHelpers.cmake @@ -0,0 +1,142 @@ +# Initial autogen setup for a target to specify certain CMake properties which are common +# to all autogen tools. Also enable AUTOMOC by default. +function(qt_autogen_tools_initial_setup target) + set_property(TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}) + 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_PATCH ${PROJECT_VERSION_PATCH} + ) + + qt_enable_autogen_tool(${target} "moc" ON) +endfunction() + +# Enables or disables an autogen tool like moc, uic or rcc on ${target}. +function(qt_enable_autogen_tool target tool enable) + string(TOUPPER "${tool}" captitalAutogenTool) + + get_target_property(tool_enabled ${target} AUTO${captitalAutogenTool}) + get_target_property(autogen_target_depends ${target} AUTOGEN_TARGET_DEPENDS) + + if(NOT autogen_target_depends) + set(autogen_target_depends "") + endif() + set(tool_executable "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${tool}>") + set(tool_target_name ${QT_CMAKE_EXPORT_NAMESPACE}::${tool}) + + if(enable) + list(APPEND autogen_target_depends ${tool_target_name}) + else() + list(REMOVE_ITEM autogen_target_depends ${tool_target_name}) + endif() + + # f66c1db16c050c9d685a44a38ad7c5cf9f6fcc96 in qtbase introduced a new macro + # that the moc scanner has to look for. Inform the CMake moc scanner about it. + if(tool STREQUAL "moc" AND enable) + set_target_properties("${target}" PROPERTIES + AUTOMOC_MACRO_NAMES "Q_OBJECT;Q_GADGET;Q_NAMESPACE;Q_NAMESPACE_EXPORT;Q_ENUM_NS") + + if (TARGET Qt::Platform) + get_target_property(_abi_tag Qt::Platform qt_libcpp_abi_tag) + if (_abi_tag) + set_property(TARGET "${target}" APPEND PROPERTY + AUTOMOC_MOC_OPTIONS --libcpp-abi-version "${_abi_tag}" + ) + endif() + endif() + endif() + + set_target_properties("${target}" + PROPERTIES + AUTO${captitalAutogenTool} "${enable}" + AUTO${captitalAutogenTool}_EXECUTABLE "${tool_executable}" + AUTOGEN_TARGET_DEPENDS "${autogen_target_depends}" + ) +endfunction() + +# This function adds or removes additional AUTOGEN tools to a target: AUTOMOC/UIC/RCC +function(qt_autogen_tools target) + qt_parse_all_arguments(arg "qt_autogen_tools" "" "" "${__default_private_args}" ${ARGN}) + + if(arg_ENABLE_AUTOGEN_TOOLS) + foreach(tool ${arg_ENABLE_AUTOGEN_TOOLS}) + qt_enable_autogen_tool(${target} ${tool} ON) + endforeach() + endif() + + if(arg_DISABLE_AUTOGEN_TOOLS) + foreach(tool ${arg_DISABLE_AUTOGEN_TOOLS}) + qt_enable_autogen_tool(${target} ${tool} OFF) + endforeach() + endif() +endfunction() + +# Complete manual moc invocation with full control. +# Use AUTOMOC whenever possible. +function(qt_manual_moc result) + 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) + list(APPEND moc_files "${outfile}") + + 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() + + if (TARGET Qt::Platform) + get_target_property(_abi_tag Qt::Platform qt_libcpp_abi_tag) + if (_abi_tag) + list(APPEND moc_parameters --libcpp-abi-version "${_abi_tag}") + endif() + endif() + + string (REPLACE ";" "\n" moc_parameters "${moc_parameters}") + + file(GENERATE OUTPUT "${moc_parameters_file}" CONTENT "${moc_parameters}\n") + + 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() + +# From Qt6CoreMacros +# Function used to create the names of output files preserving relative dirs +function(qt_make_output_file infile prefix suffix source_dir binary_dir result) + get_filename_component(outfilename "${infile}" NAME_WE) + + set(base_dir "${source_dir}") + string(FIND "${infile}" "${binary_dir}/" in_binary) + if (in_binary EQUAL 0) + set(base_dir "${binary_dir}") + endif() + + get_filename_component(abs_infile "${infile}" ABSOLUTE BASE_DIR "${base_dir}") + file(RELATIVE_PATH rel_infile "${base_dir}" "${abs_infile}") + string(REPLACE "../" "__/" mapped_infile "${rel_infile}") + + get_filename_component(abs_mapped_infile "${mapped_infile}" ABSOLUTE BASE_DIR "${binary_dir}") + get_filename_component(outpath "${abs_mapped_infile}" PATH) + + file(MAKE_DIRECTORY "${outpath}") + set("${result}" "${outpath}/${prefix}${outfilename}${suffix}" PARENT_SCOPE) +endfunction() diff --git a/cmake/QtBaseGlobalTargets.cmake b/cmake/QtBaseGlobalTargets.cmake index 15865603c6..1c61140f5b 100644 --- a/cmake/QtBaseGlobalTargets.cmake +++ b/cmake/QtBaseGlobalTargets.cmake @@ -348,36 +348,65 @@ qt_internal_export_modern_cmake_config_targets_file(TARGETS ${__export_targets} qt_copy_or_install(FILES cmake/ModuleDescription.json.in cmake/Qt3rdPartyLibraryConfig.cmake.in - cmake/QtApp.cmake + cmake/Qt3rdPartyLibraryHelpers.cmake + cmake/QtAppHelpers.cmake + cmake/QtAutogenHelpers.cmake cmake/QtBuild.cmake cmake/QtBuildInformation.cmake + cmake/QtCMakeHelpers.cmake + cmake/QtCompatibilityHelpers.cmake cmake/QtCompilerFlags.cmake cmake/QtCompilerOptimization.cmake cmake/QtConfigDependencies.cmake.in + cmake/QtDbusHelpers.cmake + cmake/QtDocsHelpers.cmake + cmake/QtExecutableHelpers.cmake cmake/QtFeature.cmake cmake/QtFeatureCommon.cmake - cmake/QtFinishPrlFile.cmake - cmake/QtFindWrapHelper.cmake - cmake/QtFindWrapConfigExtra.cmake.in cmake/QtFileConfigure.txt.in + cmake/QtFindPackageHelpers.cmake + cmake/QtFindWrapConfigExtra.cmake.in + cmake/QtFindWrapHelper.cmake + cmake/QtFinishPrlFile.cmake + cmake/QtFlagHandlingHelpers.cmake + cmake/QtFrameworkHelpers.cmake cmake/QtGenerateExtPri.cmake - cmake/QtGenerateLibPri.cmake cmake/QtGenerateLibHelpers.cmake - cmake/QtPlatformSupport.cmake - cmake/QtPlatformAndroid.cmake - cmake/QtPostProcess.cmake - cmake/QtSeparateDebugInfo.Info.plist.in - cmake/QtSeparateDebugInfo.cmake - cmake/QtSetup.cmake + cmake/QtGenerateLibPri.cmake + cmake/QtGlobalStateHelpers.cmake + cmake/QtInstallHelpers.cmake + cmake/QtLalrHelpers.cmake cmake/QtModuleConfig.cmake.in cmake/QtModuleDependencies.cmake.in - cmake/QtModuleToolsDependencies.cmake.in + cmake/QtModuleHelpers.cmake cmake/QtModuleToolsConfig.cmake.in + cmake/QtModuleToolsDependencies.cmake.in cmake/QtModuleToolsVersionlessTargets.cmake.in - cmake/QtStandaloneTestsConfig.cmake.in - cmake/QtPlugins.cmake.in + cmake/QtNoLinkTargetHelpers.cmake + cmake/QtPlatformAndroid.cmake + cmake/QtPlatformSupport.cmake cmake/QtPluginConfig.cmake.in cmake/QtPluginDependencies.cmake.in + cmake/QtPluginHelpers.cmake + cmake/QtPlugins.cmake.in + cmake/QtPostProcess.cmake + cmake/QtPrecompiledHeadersHelpers.cmake + cmake/QtPriHelpers.cmake + cmake/QtPrlHelpers.cmake + cmake/QtQmakeHelpers.cmake + cmake/QtResourceHelpers.cmake + cmake/QtRpathHelpers.cmake + cmake/QtSanitizerHelpers.cmake + cmake/QtScopeFinalizerHelpers.cmake + cmake/QtSeparateDebugInfo.Info.plist.in + cmake/QtSeparateDebugInfo.cmake + cmake/QtSetup.cmake + cmake/QtSimdHelpers.cmake + cmake/QtStandaloneTestsConfig.cmake.in + cmake/QtSyncQtHelpers.cmake + cmake/QtTargetHelpers.cmake + cmake/QtTestHelpers.cmake + cmake/QtToolHelpers.cmake DESTINATION "${__GlobalConfig_install_dir}" ) diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake index 4921391ebf..d85acbd1c9 100644 --- a/cmake/QtBuild.cmake +++ b/cmake/QtBuild.cmake @@ -245,23 +245,6 @@ set(CMAKE_INSTALL_RPATH "" CACHE STRING "RPATH for installed binaries") # 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_CROSSCOMPILING) - 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() @@ -353,78 +336,14 @@ else() set(QT_HAS_NAMESPACE ON) endif() +include(QtGlobalStateHelpers) -function(qt_internal_clear_qt_repo_known_modules) - set(QT_REPO_KNOWN_MODULES "" CACHE INTERNAL "Known current repo Qt modules" FORCE) -endfunction() - -function(qt_internal_add_qt_repo_known_module) - set(QT_REPO_KNOWN_MODULES ${QT_REPO_KNOWN_MODULES} ${ARGN} - CACHE INTERNAL "Known current repo Qt modules" FORCE) -endfunction() - -function(qt_internal_get_qt_repo_known_modules out_var) - set("${out_var}" "${QT_REPO_KNOWN_MODULES}" PARENT_SCOPE) -endfunction() - -# Gets the list of all known Qt modules both found and that were built as part of the -# current project. -function(qt_internal_get_qt_all_known_modules out_var) - qt_internal_get_qt_repo_known_modules(repo_known_modules) - set(known_modules ${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE} ${repo_known_modules}) - list(REMOVE_DUPLICATES known_modules) - set("${out_var}" "${known_modules}" PARENT_SCOPE) -endfunction() - -macro(qt_internal_set_qt_known_plugins) - set(QT_KNOWN_PLUGINS ${ARGN} CACHE INTERNAL "Known Qt plugins" FORCE) -endmacro() - -### Global plug-in types handling ### -# QT_REPO_KNOWN_PLUGIN_TYPES and QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE -# hold a list of plug-in types (e.G. "imageformats;bearer") -function(qt_internal_clear_qt_repo_known_plugin_types) - set(QT_REPO_KNOWN_PLUGIN_TYPES "" CACHE INTERNAL "Known current repo Qt plug-in types" FORCE) -endfunction() - -function(qt_internal_add_qt_repo_known_plugin_types) - set(QT_REPO_KNOWN_PLUGIN_TYPES ${QT_REPO_KNOWN_PLUGIN_TYPES} ${ARGN} - CACHE INTERNAL "Known current repo Qt plug-in types" FORCE) -endfunction() - -function(qt_internal_get_qt_repo_known_plugin_types out_var) - set("${out_var}" "${QT_REPO_KNOWN_PLUGIN_TYPES}" PARENT_SCOPE) -endfunction() - -function(qt_internal_get_qt_all_known_plugin_types out_var) - qt_internal_get_qt_repo_known_plugin_types(repo_known_plugin_types) - set(known ${QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE} ${repo_known_plugin_types}) - list(REMOVE_DUPLICATES known) - set("${out_var}" "${known}" PARENT_SCOPE) -endfunction() - -# Reset: +# Reset global state: qt_internal_clear_qt_repo_known_modules() qt_internal_clear_qt_repo_known_plugin_types() qt_internal_set_qt_known_plugins("") set(QT_KNOWN_MODULES_WITH_TOOLS "" CACHE INTERNAL "Known Qt modules with tools" FORCE) -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() - -macro(qt_internal_append_known_module_tool module tool) - if(NOT ${tool} IN_LIST QT_KNOWN_MODULE_${module}_TOOLS) - list(APPEND QT_KNOWN_MODULE_${module}_TOOLS "${tool}") - set(QT_KNOWN_MODULE_${module}_TOOLS "${QT_KNOWN_MODULE_${module}_TOOLS}" - CACHE INTERNAL "Known Qt module ${module} tools" FORCE) - endif() -endmacro() # Reset syncqt cache variable, to make sure it gets recomputed on reconfiguration, otherwise # it might not get installed. @@ -462,1406 +381,9 @@ endif() # Functions and macros: -# qt_remove_args can remove arguments from an existing list of function -# arguments in order to pass a filtered list of arguments to a different function. -# Parameters: -# out_var: result of remove all arguments specified by ARGS_TO_REMOVE from ALL_ARGS -# ARGS_TO_REMOVE: Arguments to remove. -# ALL_ARGS: All arguments supplied to cmake_parse_arguments or -# qt_parse_all_arguments -# from which ARGS_TO_REMOVE should be removed from. We require all the -# arguments or we can't properly identify the range of the arguments detailed -# in ARGS_TO_REMOVE. -# ARGS: Arguments passed into the function, usually ${ARGV} -# -# E.g.: -# We want to forward all arguments from foo to bar, execpt ZZZ since it will -# trigger an error in bar. -# -# foo(target BAR .... ZZZ .... WWW ...) -# bar(target BAR.... WWW...) -# -# function(foo target) -# qt_parse_all_arguments(arg "" "" "BAR;ZZZ;WWW ${ARGV}) -# qt_remove_args(forward_args -# ARGS_TO_REMOVE ${target} ZZZ -# ALL_ARGS ${target} BAR ZZZ WWW -# ARGS ${ARGV} -# ) -# bar(${target} ${forward_args}) -# endfunction() -# -function(qt_remove_args out_var) - cmake_parse_arguments(arg "" "" "ARGS_TO_REMOVE;ALL_ARGS;ARGS" ${ARGN}) - set(result ${arg_ARGS}) - foreach(arg IN LISTS arg_ARGS_TO_REMOVE) - # find arg - list(FIND result ${arg} find_result) - if (NOT find_result EQUAL -1) - # remove arg - list(REMOVE_AT result ${find_result}) - list(LENGTH result result_len) - list(GET result ${find_result} arg_current) - # remove values until we hit another arg - while(NOT ${arg_current} IN_LIST arg_ALL_ARGS AND find_result LESS result_len) - list(REMOVE_AT result ${find_result}) - list(GET result ${find_result} arg_current) - list(LENGTH result result_len) - endwhile() - endif() - endforeach() - set(${out_var} "${result}" PARENT_SCOPE) -endfunction() -# Wraps install() command. In a prefix build, simply passes along arguments to install(). -# In a non-prefix build, handles association of targets to export names, and also calls export(). -function(qt_install) - set(flags) - set(options EXPORT DESTINATION NAMESPACE) - set(multiopts TARGETS) - cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) - - if(arg_TARGETS) - set(is_install_targets TRUE) - endif() - - # In a prefix build, always invoke install() without modification. - # In a non-prefix build, pass install(TARGETS) commands to allow - # association of targets to export names, so we can later use the export names - # in export() commands. - if(QT_WILL_INSTALL OR is_install_targets) - install(${ARGV}) - endif() - - # Exit early if this is a prefix build. - if(QT_WILL_INSTALL) - return() - endif() - - # In a non-prefix build, when install(EXPORT) is called, - # also call export(EXPORT) to generate build tree target files. - if(NOT is_install_targets AND arg_EXPORT) - set(namespace_option "") - if(arg_NAMESPACE) - set(namespace_option NAMESPACE ${arg_NAMESPACE}) - endif() - export(EXPORT ${arg_EXPORT} - ${namespace_option} - FILE "${arg_DESTINATION}/${arg_EXPORT}.cmake") - endif() -endfunction() - -# Copies files using file(COPY) signature in non-prefix builds. -function(qt_non_prefix_copy) - if(NOT QT_WILL_INSTALL) - file(${ARGV}) - endif() -endfunction() - -# Retrieve the permissions that are set by install(PROGRAMS). -function(qt_get_install_executable_permissions out_var) - set(default_permissions ${CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS}) - if(NOT default_permissions) - set(default_permissions OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) - endif() - set(executable_permissions ${default_permissions} OWNER_EXECUTE) - if(GROUP_READ IN_LIST default_permissions) - list(APPEND executable_permissions GROUP_EXECUTE) - endif() - if(WORLD_READ IN_LIST default_permissions) - list(APPEND executable_permissions WORLD_EXECUTE) - endif() - set(${out_var} ${executable_permissions} PARENT_SCOPE) -endfunction() - -# Use case is installing files in a prefix build, or copying them to the correct build dir -# in a non-prefix build. -# Pass along arguments as you would pass them to install(). -# Only supports FILES, PROGRAMS and DIRECTORY signature, and without fancy things -# like OPTIONAL or RENAME or COMPONENT. -function(qt_copy_or_install) - set(flags FILES PROGRAMS DIRECTORY) - set(options) - set(multiopts) - cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) - - # Remember which option has to be passed to the install command. - set(copy_arguments "") - set(argv_copy ${ARGV}) - if(arg_FILES) - set(install_option "FILES") - elseif(arg_PROGRAMS) - set(install_option "PROGRAMS") - qt_get_install_executable_permissions(executable_permissions) - list(APPEND copy_arguments FILE_PERMISSIONS ${executable_permissions}) - elseif(arg_DIRECTORY) - set(install_option "DIRECTORY") - endif() - - list(REMOVE_AT argv_copy 0) - qt_install(${install_option} ${argv_copy}) - qt_non_prefix_copy(COPY ${argv_copy} ${copy_arguments}) -endfunction() - -# Hacky way to remove the install target in non-prefix builds. -# We need to associate targets with export names, and that is only possible to do with the -# install(TARGETS) command. But in a non-prefix build, we don't want to install anything. -# To make sure that developers don't accidentally run make install, replace the generated -# cmake_install.cmake file with an empty file. To do this, always create a new temporary file -# 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(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") - file(WRITE ${file_in} "") - - add_custom_command(OUTPUT ${file_generated} - COMMAND ${CMAKE_COMMAND} -E copy ${file_in} ${file_generated} - COMMAND ${CMAKE_COMMAND} -E remove ${cmake_install_file} - COMMAND ${CMAKE_COMMAND} -E touch ${cmake_install_file} - COMMENT "Removing cmake_install.cmake" - MAIN_DEPENDENCY ${file_in}) - - add_custom_target(remove_cmake_install ALL DEPENDS ${file_generated}) -endfunction() - -function(qt_set_up_nonprefix_build) - if(NOT QT_WILL_INSTALL) - qt_remove_install_target() - endif() -endfunction() - -function(qt_is_imported_target target out_var) - if(NOT TARGET "${target}") - set(target "${QT_CMAKE_EXPORT_NAMESPACE}::${target}") - endif() - if(NOT TARGET "${target}") - message(FATAL_ERROR "Invalid target given to qt_is_imported_target: ${target}") - endif() - get_target_property(is_imported "${target}" IMPORTED) - set(${out_var} "${is_imported}" PARENT_SCOPE) -endfunction() - -# Creates a regular expression that exactly matches the given string -# Found in https://gitlab.kitware.com/cmake/cmake/issues/18580 -function(qt_re_escape out_var str) - string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${str}") - set(${out_var} ${regex} PARENT_SCOPE) -endfunction() - -# Extracts the 3rdparty libraries for the module ${module_name} -# and stores the information in cmake language in -# ${output_root_dir}/$<CONFIG>/${output_file_name}. -# -# This function "follows" INTERFACE_LIBRARY targets to "real" targets -# and collects defines, include dirs and lib dirs on the way. -function(qt_generate_qmake_libraries_pri_content module_name output_root_dir output_file_name) - set(content "") - - # Set up a regular expression that matches all implicit include dirs - set(implicit_include_dirs_regex "") - foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) - qt_re_escape(regex "${dir}") - list(APPEND implicit_include_dirs_regex ${regex}) - endforeach() - list(JOIN implicit_include_dirs_regex "|" implicit_include_dirs_regex) - - foreach(lib ${QT_QMAKE_LIBS_FOR_${module_name}}) - set(lib_targets ${QT_QMAKE_LIB_TARGETS_${lib}}) - string(TOUPPER ${lib} uclib) - set(lib_defines "") - set(lib_incdir "") - set(lib_libdir "") - set(lib_libs "") - while(lib_targets) - list(POP_BACK lib_targets lib_target) - if(TARGET ${lib_target}) - get_target_property(lib_target_type ${lib_target} TYPE) - if(lib_target_type STREQUAL "INTERFACE_LIBRARY") - get_target_property(iface_libs ${lib_target} INTERFACE_LINK_LIBRARIES) - if(iface_libs) - list(PREPEND lib_targets ${iface_libs}) - endif() - else() - list(APPEND lib_libs "$<TARGET_LINKER_FILE:${lib_target}>") - endif() - list(APPEND lib_libdir "$<TARGET_PROPERTY:${lib_target},INTERFACE_LINK_DIRECTORIES>") - list(APPEND lib_incdir "$<TARGET_PROPERTY:${lib_target},INTERFACE_INCLUDE_DIRECTORIES>") - list(APPEND lib_defines "$<TARGET_PROPERTY:${lib_target},INTERFACE_COMPILE_DEFINITIONS>") - else() - if(lib_target MATCHES "/([^/]+).framework$") - list(APPEND lib_libs "-framework" "${CMAKE_MATCH_1}") - else() - list(APPEND lib_libs "${lib_target}") - endif() - endif() - endwhile() - - # Wrap in $<REMOVE_DUPLICATES:...> but not the libs, because - # we would have to preserve the right order for the linker. - foreach(sfx libdir incdir defines) - string(PREPEND lib_${sfx} "$<REMOVE_DUPLICATES:") - string(APPEND lib_${sfx} ">") - endforeach() - - # Filter out implicit include directories - string(PREPEND lib_incdir "$<FILTER:") - string(APPEND lib_incdir ",EXCLUDE,${implicit_include_dirs_regex}>") - - set(uccfg $<UPPER_CASE:$<CONFIG>>) - string(APPEND content "list(APPEND known_libs ${uclib}) -set(QMAKE_LIBS_${uclib}_${uccfg} \"${lib_libs}\") -set(QMAKE_LIBDIR_${uclib}_${uccfg} \"${lib_libdir}\") -set(QMAKE_INCDIR_${uclib}_${uccfg} \"${lib_incdir}\") -set(QMAKE_DEFINES_${uclib}_${uccfg} \"${lib_defines}\") -") - if(QT_QMAKE_LIB_DEPS_${lib}) - string(APPEND content "set(QMAKE_DEPENDS_${uclib}_CC, ${deps}) -set(QMAKE_DEPENDS_${uclib}_LD, ${deps}) -") - endif() - endforeach() - - file(GENERATE - OUTPUT "${output_root_dir}/$<CONFIG>/${output_file_name}" - CONTENT "${content}" - ) -endfunction() - -# Retrieves the public Qt module dependencies of the given Qt module or Qt Private module. -function(qt_get_direct_module_dependencies target out_var) - set(dependencies "") - get_target_property(libs ${target} INTERFACE_LINK_LIBRARIES) - if(NOT libs) - set(libs "") - endif() - get_target_property(target_type ${target} TYPE) - while(libs) - list(POP_FRONT libs lib) - string(GENEX_STRIP "${lib}" lib) - if(NOT lib OR NOT TARGET "${lib}") - continue() - endif() - get_target_property(lib_type ${lib} TYPE) - get_target_property(is_versionless_target ${lib} _qt_is_versionless_target) - if (lib_type STREQUAL "INTERFACE_LIBRARY" AND is_versionless_target) - # Found a version-less target like Qt::Core outside of qtbase. - # Skip this one and use what this target points to, e.g. Qt6::Core. - # Make sure to process Private interface libraries as-is. - get_target_property(ifacelibs ${lib} INTERFACE_LINK_LIBRARIES) - list(PREPEND libs ${ifacelibs}) - continue() - endif() - if(lib_type STREQUAL "OBJECT_LIBRARY") - # Skip object libraries, because they're already part of ${target}. - continue() - elseif(lib_type STREQUAL "STATIC_LIBRARY" AND target_type STREQUAL "SHARED_LIBRARY") - # Skip static libraries if ${target} is a shared library. - continue() - endif() - get_target_property(lib_config_module_name ${lib} "_qt_config_module_name") - if(lib_config_module_name) - list(APPEND dependencies ${lib_config_module_name}) - endif() - endwhile() - set(${out_var} ${dependencies} PARENT_SCOPE) -endfunction() - -# Generates module .pri files for consumption by qmake -function(qt_generate_module_pri_file target) - set(flags INTERNAL_MODULE HEADER_MODULE) - set(options) - set(multiopts) - cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) - - qt_internal_module_info(module "${target}") - set(pri_files) - - set(property_prefix) - if(arg_HEADER_MODULE) - set(property_prefix "INTERFACE_") - endif() - - get_target_property(enabled_features "${target}" - "${property_prefix}QT_ENABLED_PUBLIC_FEATURES") - get_target_property(disabled_features "${target}" - "${property_prefix}QT_DISABLED_PUBLIC_FEATURES") - get_target_property(enabled_private_features "${target}" - "${property_prefix}QT_ENABLED_PRIVATE_FEATURES") - get_target_property(disabled_private_features "${target}" - "${property_prefix}QT_DISABLED_PRIVATE_FEATURES") - qt_correct_features(enabled_features "${enabled_features}") - qt_correct_features(disabled_features "${disabled_features}") - qt_correct_features(enabled_private_features "${enabled_private_features}") - qt_correct_features(disabled_private_features "${disabled_private_features}") - - foreach(var enabled_features disabled_features enabled_private_features disabled_private_features) - if(${var} STREQUAL "${var}-NOTFOUND") - set(${var} "") - else() - string (REPLACE ";" " " ${var} "${${var}}") - endif() - endforeach() - - set(module_internal_config v2) - if(NOT QT_FEATURE_shared) - list(APPEND module_internal_config staticlib) - endif() - if(arg_INTERNAL_MODULE) - list(APPEND module_internal_config internal_module) - endif() - - get_target_property(target_type ${target} TYPE) - if (NOT target_type STREQUAL "INTERFACE_LIBRARY") - get_target_property(is_fw ${target} FRAMEWORK) - if(is_fw) - list(APPEND module_internal_config lib_bundle) - endif() - endif() - - # TODO: Add the value 'ltcg' to module_internal_config if LTCG is turned on. - - list(JOIN module_internal_config " " joined_module_internal_config) - - get_target_property(config_module_name ${target} _qt_config_module_name) - get_target_property(qmake_module_config ${target} ${property_prefix}QT_QMAKE_MODULE_CONFIG) - if(qmake_module_config) - string(REPLACE ";" " " module_build_config "${qmake_module_config}") - set(module_build_config "\nQT.${config_module_name}.CONFIG = ${module_build_config}") - else() - set(module_build_config "") - endif() - - if(is_fw) - set(framework_base_path "$$QT_MODULE_LIB_BASE/${module}.framework/Headers") - set(public_module_includes "${framework_base_path}") - set(public_module_frameworks "$$QT_MODULE_LIB_BASE") - set(private_module_includes "${framework_base_path}/${PROJECT_VERSION} ${framework_base_path}/${PROJECT_VERSION}/${module}") - set(module_name_in_pri "${module}") - else() - set(public_module_includes "$$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/${module}") - set(public_module_frameworks "") - set(private_module_includes "$$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION} $$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION}/${module}") - set(module_name_in_pri "${module_versioned}") - endif() - - qt_path_join(target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules) - if (arg_INTERNAL_MODULE) - string(PREPEND private_module_includes "${public_module_includes} ") - set(private_module_frameworks ${public_module_frameworks}) - else() - unset(private_module_frameworks) - if(arg_HEADER_MODULE) - set(module_plugin_types "") - else() - get_target_property(module_plugin_types ${target} QMAKE_MODULE_PLUGIN_TYPES) - if(module_plugin_types) - list(JOIN module_plugin_types " " module_plugin_types) - else() - set(module_plugin_types "") - endif() - endif() - - qt_get_direct_module_dependencies(${target} public_module_dependencies) - list(JOIN public_module_dependencies " " public_module_dependencies) - - qt_path_join(pri_file_name "${target_path}" "qt_lib_${config_module_name}.pri") - list(APPEND pri_files "${pri_file_name}") - - # Don't use $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS> genex because that - # will compute the transitive list of all defines for a module (so Gui would get Core - #defines too). Instead query just the public defines on the target. - get_target_property(target_defines "${target}" INTERFACE_COMPILE_DEFINITIONS) - - # We must filter out expressions of the form $<TARGET_PROPERTY:name>, because - # 1. They cannot be used in file(GENERATE) content. - # 2. They refer to the consuming target we have no access to here. - list(FILTER target_defines EXCLUDE REGEX "\\$<TARGET_PROPERTY:[^,>]+>") - list(JOIN target_defines " " joined_target_defines) - - file(GENERATE - OUTPUT "${pri_file_name}" - CONTENT - "QT.${config_module_name}.VERSION = ${PROJECT_VERSION} -QT.${config_module_name}.name = ${module} -QT.${config_module_name}.module = ${module_name_in_pri} -QT.${config_module_name}.libs = $$QT_MODULE_LIB_BASE -QT.${config_module_name}.includes = ${public_module_includes} -QT.${config_module_name}.frameworks = ${public_module_frameworks} -QT.${config_module_name}.bins = $$QT_MODULE_BIN_BASE -QT.${config_module_name}.plugin_types = ${module_plugin_types} -QT.${config_module_name}.depends = ${public_module_dependencies} -QT.${config_module_name}.uses = -QT.${config_module_name}.module_config = ${joined_module_internal_config} -QT.${config_module_name}.DEFINES = ${joined_target_defines} -QT.${config_module_name}.enabled_features = ${enabled_features} -QT.${config_module_name}.disabled_features = ${disabled_features}${module_build_config} -QT_CONFIG += ${enabled_features} -QT_MODULES += ${config_module_name} -" - ) - endif() - - set(pri_data_cmake_file "qt_lib_${config_module_name}_private.cmake") - qt_generate_qmake_libraries_pri_content(${config_module_name} "${CMAKE_CURRENT_BINARY_DIR}" - ${pri_data_cmake_file}) - - set(private_pri_file_name "qt_lib_${config_module_name}_private.pri") - - set(private_module_dependencies "") - if(NOT arg_HEADER_MODULE) - qt_get_direct_module_dependencies(${target}Private private_module_dependencies) - endif() - list(JOIN private_module_dependencies " " private_module_dependencies) - - # Generate a preliminary qt_lib_XXX_private.pri file - file(GENERATE - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}" - CONTENT - "QT.${config_module_name}_private.VERSION = ${PROJECT_VERSION} -QT.${config_module_name}_private.name = ${module} -QT.${config_module_name}_private.module = -QT.${config_module_name}_private.libs = $$QT_MODULE_LIB_BASE -QT.${config_module_name}_private.includes = ${private_module_includes} -QT.${config_module_name}_private.frameworks = ${private_module_frameworks} -QT.${config_module_name}_private.depends = ${private_module_dependencies} -QT.${config_module_name}_private.uses = -QT.${config_module_name}_private.module_config = ${joined_module_internal_config} -QT.${config_module_name}_private.enabled_features = ${enabled_private_features} -QT.${config_module_name}_private.disabled_features = ${disabled_private_features}" - ) - - if(QT_GENERATOR_IS_MULTI_CONFIG) - set(configs ${CMAKE_CONFIGURATION_TYPES}) - else() - set(configs ${CMAKE_BUILD_TYPE}) - endif() - set(inputs "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}") - foreach(cfg ${configs}) - list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/${pri_data_cmake_file}") - endforeach() - - qt_path_join(private_pri_file_path "${target_path}" "${private_pri_file_name}") - list(APPEND pri_files "${private_pri_file_path}") - - set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX}) - set(library_suffixes - ${CMAKE_SHARED_LIBRARY_SUFFIX} - ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES} - ${CMAKE_STATIC_LIBRARY_SUFFIX}) - add_custom_command( - OUTPUT "${private_pri_file_path}" - DEPENDS ${inputs} - "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake" - "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake" - COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${private_pri_file_path}" - "-DLIBRARY_PREFIXES=${library_prefixes}" - "-DLIBRARY_SUFFIXES=${library_suffixes}" - "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}" - "-DCONFIGS=${configs}" - -P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake" - VERBATIM) - add_custom_target(${target}_lib_pri DEPENDS "${private_pri_file_path}") - if(arg_HEADER_MODULE) - add_dependencies(${target}_timestamp ${target}_lib_pri) - else() - add_dependencies(${target} ${target}_lib_pri) - endif() - qt_install(FILES "${pri_files}" DESTINATION ${INSTALL_MKSPECSDIR}/modules) -endfunction() - -# Generates qt_ext_XXX.pri files for consumption by qmake -function(qt_generate_3rdparty_lib_pri_file target lib pri_file_var) - if(NOT lib) - # Don't write a pri file for projects that don't set QMAKE_LIB_NAME yet. - return() - endif() - - if(QT_GENERATOR_IS_MULTI_CONFIG) - set(configs ${CMAKE_CONFIGURATION_TYPES}) - else() - set(configs ${CMAKE_BUILD_TYPE}) - endif() - - file(GENERATE - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/qt_ext_${lib}.cmake" - CONTENT "set(cfg $<CONFIG>) -set(incdir $<TARGET_PROPERTY:${target},INTERFACE_INCLUDE_DIRECTORIES>) -set(defines $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS>) -set(libs $<TARGET_FILE:${target}>) -") - - set(inputs "") - foreach(cfg ${configs}) - list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/qt_ext_${lib}.cmake") - endforeach() - - qt_path_join(pri_target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules) - qt_path_join(pri_file "${pri_target_path}" "qt_ext_${lib}.pri") - qt_path_join(qt_build_libdir ${QT_BUILD_DIR} ${INSTALL_LIBDIR}) - add_custom_command( - OUTPUT "${pri_file}" - DEPENDS ${inputs} "${QT_CMAKE_DIR}/QtGenerateExtPri.cmake" - COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${pri_file}" -DLIB=${lib} - "-DCONFIGS=${configs}" - "-DQT_BUILD_LIBDIR=${qt_build_libdir}" - -P "${QT_CMAKE_DIR}/QtGenerateExtPri.cmake" - VERBATIM) - add_custom_target(${target}_ext_pri DEPENDS "${pri_file}") - add_dependencies(${target} ${target}_ext_pri) - set(${pri_file_var} ${pri_file} PARENT_SCOPE) -endfunction() - -# Transforms a CMake Qt module name to a qmake Qt module name. -# Example: Qt6FooPrivate becomes foo_private -function(qt_get_qmake_module_name result module) - string(REGEX REPLACE "^Qt6" "" module "${module}") - string(REGEX REPLACE "Private$" "_private" module "${module}") - string(REGEX REPLACE "Qpa$" "_qpa_lib_private" module "${module}") - string(TOLOWER "${module}" module) - set(${result} ${module} PARENT_SCOPE) -endfunction() - -# Generates qt_plugin_XXX.pri files for consumption by qmake -# -# QT_PLUGIN.XXX.EXTENDS is set to "-" for the following plugin types: -# - generic -# - platform, if the plugin is not the default QPA plugin -# Otherwise, this variable is empty. -function(qt_generate_plugin_pri_file target pri_file_var) - get_target_property(plugin_name ${target} OUTPUT_NAME) - get_target_property(plugin_type ${target} QT_PLUGIN_TYPE) - get_target_property(qmake_plugin_type ${target} QT_QMAKE_PLUGIN_TYPE) - get_target_property(default_plugin ${target} QT_DEFAULT_PLUGIN) - get_target_property(plugin_class_name ${target} QT_PLUGIN_CLASS_NAME) - - set(plugin_extends "") - if(NOT default_plugin AND (plugin_type STREQUAL "generic" OR plugin_type STREQUAL "platforms")) - set(plugin_extends "-") - endif() - - set(plugin_deps "") - get_target_property(target_deps ${target} _qt_target_deps) - foreach(dep ${target_deps}) - list(GET dep 0 dep_name) - qt_get_qmake_module_name(dep_name ${dep_name}) - list(APPEND plugin_deps ${dep_name}) - endforeach() - list(REMOVE_DUPLICATES plugin_deps) - list(JOIN plugin_deps " " plugin_deps) - - qt_path_join(pri_target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules) - qt_path_join(pri_file "${pri_target_path}" "qt_plugin_${plugin_name}.pri") - qt_configure_file(OUTPUT "${pri_file}" - CONTENT "QT_PLUGIN.${plugin_name}.TYPE = ${qmake_plugin_type} -QT_PLUGIN.${plugin_name}.EXTENDS = ${plugin_extends} -QT_PLUGIN.${plugin_name}.DEPENDS = ${plugin_deps} -QT_PLUGIN.${plugin_name}.CLASS_NAME = ${plugin_class_name} -QT_PLUGINS += ${plugin_name} -") - set(${pri_file_var} "${pri_file}" PARENT_SCOPE) -endfunction() - -function(qt_cmake_build_type_to_qmake_build_config out_var build_type) - if(build_type STREQUAL "Debug") - set(cfg debug) - else() - set(cfg release) - endif() - set(${out_var} ${cfg} PARENT_SCOPE) -endfunction() - -function(qt_guess_qmake_build_config out_var) - if(QT_GENERATOR_IS_MULTI_CONFIG) - unset(cfg) - foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) - qt_cmake_build_type_to_qmake_build_config(tmp ${config_type}) - list(APPEND cfg ${tmp}) - endforeach() - if(cfg) - list(REMOVE_DUPLICATES cfg) - else() - set(cfg debug) - endif() - else() - qt_cmake_build_type_to_qmake_build_config(cfg ${CMAKE_BUILD_TYPE}) - endif() - set(${out_var} ${cfg} PARENT_SCOPE) -endfunction() - -function(qt_correct_features out_var features) - set(corrected_features "") - foreach(feature ${features}) - get_property(feature_original_name GLOBAL PROPERTY "QT_FEATURE_ORIGINAL_NAME_${feature}") - list(APPEND corrected_features "${feature_original_name}") - endforeach() - set(${out_var} ${corrected_features} PARENT_SCOPE) -endfunction() - -# Get original names for config values (which correspond to feature names) and use them if they -# exist, otherwise just use the config value (which might be the case when a config value has -# a custom name). -function(qt_correct_config out_var config) - set(corrected_config "") - foreach(name ${config}) - # Is the config value a known feature? - get_property(feature_original_name GLOBAL PROPERTY "QT_FEATURE_ORIGINAL_NAME_${name}") - if(feature_original_name) - list(APPEND corrected_config "${feature_original_name}") - continue() - endif() - - # Is the config value a negated known feature, e.g. no_foo? - # Then add the config value no-foo. - if(name MATCHES "^no_(.*)") - get_property(feature_original_name GLOBAL PROPERTY - "QT_FEATURE_ORIGINAL_NAME_${CMAKE_MATCH_1}") - if(feature_original_name) - list(APPEND corrected_config "no-${feature_original_name}") - continue() - endif() - endif() - - # The config value is no known feature. Add the value as is. - list(APPEND corrected_config "${name}") - endforeach() - set(${out_var} ${corrected_config} PARENT_SCOPE) -endfunction() - -# Creates mkspecs/qconfig.pri which contains public global features among other things. -function(qt_generate_global_config_pri_file) - 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) - get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PUBLIC_FEATURES) - - qt_correct_features(corrected_enabled_features "${enabled_features}") - qt_correct_features(corrected_disabled_features "${disabled_features}") - - string (REPLACE ";" " " corrected_enabled_features "${corrected_enabled_features}") - string (REPLACE ";" " " corrected_disabled_features "${corrected_disabled_features}") - - # Add some required CONFIG entries. - set(config_entries "") - if(CMAKE_BUILD_TYPE STREQUAL Debug) - list(APPEND config_entries "debug") - elseif(CMAKE_BUILD_TYPE STREQUAL Release) - list(APPEND config_entries "release") - endif() - list(APPEND config_entries "${qt_build_config_type}") - string (REPLACE ";" " " config_entries "${config_entries}") - - get_target_property(public_config GlobalConfig INTERFACE_QT_QMAKE_PUBLIC_CONFIG) - get_target_property(qt_public_config GlobalConfig INTERFACE_QT_QMAKE_PUBLIC_QT_CONFIG) - qt_correct_config(corrected_public_config "${public_config}") - qt_correct_config(corrected_qt_public_config "${qt_public_config}") - qt_guess_qmake_build_config(qmake_build_config) - list(APPEND corrected_qt_public_config ${qmake_build_config}) - - list(JOIN corrected_public_config " " public_config_joined) - list(JOIN corrected_qt_public_config " " qt_public_config_joined) - - set(content "") - if(GCC OR CLANG AND NOT "${CMAKE_SYSROOT}" STREQUAL "") - string(APPEND content "!host_build { - QMAKE_CFLAGS += --sysroot=\$\$[QT_SYSROOT] - QMAKE_CXXFLAGS += --sysroot=\$\$[QT_SYSROOT] - QMAKE_LFLAGS += --sysroot=\$\$[QT_SYSROOT] -} -") - endif() - - if(CMAKE_CROSSCOMPILING) - string(APPEND content "host_build { - QT_ARCH = ${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_ARCH} - QT_BUILDABI = ${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BUILDABI} - QT_TARGET_ARCH = ${TEST_architecture_arch} - QT_TARGET_BUILDABI = ${TEST_buildAbi} -} else { - QT_ARCH = ${TEST_architecture_arch} - QT_BUILDABI = ${TEST_buildAbi} -} -") - else() - string(APPEND content "QT_ARCH = ${TEST_architecture_arch} -QT_BUILDABI = ${TEST_buildAbi} -") - endif() - - string(APPEND content "QT.global.enabled_features = ${corrected_enabled_features} -QT.global.disabled_features = ${corrected_disabled_features} -QT.global.disabled_features += release build_all -QT_CONFIG += ${qt_public_config_joined} -CONFIG += ${config_entries} ${public_config_joined} -QT_VERSION = ${PROJECT_VERSION} -QT_MAJOR_VERSION = ${PROJECT_VERSION_MAJOR} -QT_MINOR_VERSION = ${PROJECT_VERSION_MINOR} -QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH} -") - - set(extra_statements "") - if(QT_NAMESPACE) - list(APPEND extra_statements "QT_NAMESPACE = ${QT_NAMESPACE}") - endif() - # TODO: Add libinfix support. - - # TODO: Add QT_EMCC_VERSION when WASM is ported over. - if(APPLECLANG) - set(compiler_version_major_var_name "QT_APPLE_CLANG_MAJOR_VERSION") - set(compiler_version_minor_var_name "QT_APPLE_CLANG_MINOR_VERSION") - set(compiler_version_patch_var_name "QT_APPLE_CLANG_PATCH_VERSION") - elseif(CLANG) - set(compiler_version_major_var_name "QT_CLANG_MAJOR_VERSION") - set(compiler_version_minor_var_name "QT_CLANG_MINOR_VERSION") - set(compiler_version_patch_var_name "QT_CLANG_PATCH_VERSION") - elseif(GCC) - set(compiler_version_major_var_name "QT_GCC_MAJOR_VERSION") - set(compiler_version_minor_var_name "QT_GCC_MINOR_VERSION") - set(compiler_version_patch_var_name "QT_GCC_PATCH_VERSION") - elseif(ICC) - set(compiler_version_major_var_name "QT_ICC_MAJOR_VERSION") - set(compiler_version_minor_var_name "QT_ICC_MINOR_VERSION") - set(compiler_version_patch_var_name "QT_ICC_PATCH_VERSION") - elseif(MSVC) - set(compiler_version_major_var_name "QT_MSVC_MAJOR_VERSION") - set(compiler_version_minor_var_name "QT_MSVC_MINOR_VERSION") - set(compiler_version_patch_var_name "QT_MSVC_PATCH_VERSION") - endif() - - if(compiler_version_major_var_name) - list(APPEND extra_statements - "${compiler_version_major_var_name} = ${QT_COMPILER_VERSION_MAJOR}") - list(APPEND extra_statements - "${compiler_version_minor_var_name} = ${QT_COMPILER_VERSION_MINOR}") - list(APPEND extra_statements - "${compiler_version_patch_var_name} = ${QT_COMPILER_VERSION_PATCH}") - endif() - - if(APPLE) - list(APPEND extra_statements "QT_MAC_SDK_VERSION = ${QT_MAC_SDK_VERSION}") - list(APPEND extra_statements - "QMAKE_MACOSX_DEPLOYMENT_TARGET = ${CMAKE_OSX_DEPLOYMENT_TARGET}") - endif() - - list(APPEND extra_statements "QT_EDITION = Open Source") - - if(extra_statements) - string(REPLACE ";" "\n" extra_statements "${extra_statements}") - string(APPEND content "\n${extra_statements}\n") - endif() - - file(GENERATE - OUTPUT "${qconfig_pri_target_path}" - CONTENT "${content}" - ) - qt_install(FILES "${qconfig_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR}) -endfunction() - -# Creates mkspecs/qdevice.pri which contains target device information for cross-builds. -# The content of QT_QMAKE_DEVICE_OPTIONS is written verbatim into qdevice.pri. -function(qt_generate_global_device_pri_file) - if(NOT CMAKE_CROSSCOMPILING) - return() - endif() - - qt_path_join(qdevice_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR} "qdevice.pri") - - set(content "") - foreach(opt ${QT_QMAKE_DEVICE_OPTIONS}) - string(APPEND content "${opt}\n") - endforeach() - - # Write android specific device info. - if(ANDROID) - string(APPEND content "DEFAULT_ANDROID_SDK_ROOT = ${ANDROID_SDK_ROOT}\n") - string(APPEND content "DEFAULT_ANDROID_NDK_ROOT = ${ANDROID_NDK}\n") - - set(android_platform "android-23") - if(ANDROID_NATIVE_API_LEVEL) - set(android_platform "android-${ANDROID_NATIVE_API_LEVEL}") - endif() - string(APPEND content "DEFAULT_ANDROID_PLATFORM = ${android_platform}\n") - - string(APPEND content "DEFAULT_ANDROID_NDK_HOST = ${ANDROID_HOST_TAG}\n") - - # TODO: QTBUG-80943 When we eventually support Android multi-abi, this should be changed. - string(APPEND content "DEFAULT_ANDROID_ABIS = ${ANDROID_ABI}\n") - endif() - - set(gcc_machine_dump "") - if(TEST_machine_tuple) - set(gcc_machine_dump "${TEST_machine_tuple}") - endif() - string(APPEND content "GCC_MACHINE_DUMP = ${gcc_machine_dump}\n") - - file(GENERATE OUTPUT "${qdevice_pri_target_path}" CONTENT "${content}") - qt_install(FILES "${qdevice_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR}) -endfunction() - -function(qt_get_build_parts out_var) - set(parts "libs") - - if(BUILD_EXAMPLES AND NOT QT_NO_MAKE_EXAMPLES) - list(APPEND parts "examples") - endif() - - if(BUILD_TESTING AND NOT QT_NO_MAKE_TESTS) - list(APPEND parts "tests") - endif() - - if(NOT CMAKE_CROSSCOMPILING OR QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - list(APPEND parts "tools") - endif() - - set(${out_var} ${parts} PARENT_SCOPE) -endfunction() - -# Creates mkspecs/qmodule.pri which contains private global features among other things. -function(qt_generate_global_module_pri_file) - qt_path_join(qmodule_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR}) - qt_path_join(qmodule_pri_target_path "${qmodule_pri_target_path}" "qmodule.pri") - - get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PRIVATE_FEATURES) - get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PRIVATE_FEATURES) - - qt_correct_features(corrected_enabled_features "${enabled_features}") - qt_correct_features(corrected_disabled_features "${disabled_features}") - - string (REPLACE ";" " " corrected_enabled_features "${corrected_enabled_features}") - string (REPLACE ";" " " corrected_disabled_features "${corrected_disabled_features}") - - set(corrected_private_config "") - get_target_property(private_config GlobalConfig INTERFACE_QT_QMAKE_PRIVATE_CONFIG) - qt_correct_config(corrected_private_config "${private_config}") - list(JOIN corrected_private_config " " private_config_joined) - - set(content "") - set(arch "${TEST_architecture_arch}") - list(JOIN TEST_subarch_result " " subarchs) - if(CMAKE_CROSSCOMPILING) - set(host_arch "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_ARCH}") - list(JOIN QT${PROJECT_VERSION_MAJOR}_HOST_INFO_SUBARCHS " " host_subarchs) - string(APPEND content "host_build { - QT_CPU_FEATURES.${host_arch} = ${host_subarchs} -} else { - QT_CPU_FEATURES.${arch} = ${subarchs} -} -") - else() - string(APPEND content "QT_CPU_FEATURES.${arch} = ${subarchs}\n") - endif() - - string(APPEND content "QT.global_private.enabled_features = ${corrected_enabled_features} -QT.global_private.disabled_features = ${corrected_disabled_features} -CONFIG += ${private_config_joined} -") - if(PKG_CONFIG_FOUND) - string(APPEND content "PKG_CONFIG_EXECUTABLE = ${PKG_CONFIG_EXECUTABLE}\n") - endif() - - # TODO: Write QT_COORD_TYPE once we support setting it. - - qt_get_build_parts(build_parts) - string(REPLACE ";" " " build_parts "${build_parts}") - string(APPEND content "QT_BUILD_PARTS = ${build_parts}\n") - - if(QT_EXTRA_RPATHS) - list(JOIN QT_EXTRA_RPATHS " " extra_rpaths) - string(APPEND content "EXTRA_RPATHS += ${extra_rpaths}") - endif() - - set(preliminary_pri_root "${CMAKE_CURRENT_BINARY_DIR}/mkspecs/preliminary") - set(pri_data_cmake_file "qmodule.cmake") - qt_generate_qmake_libraries_pri_content(global ${preliminary_pri_root} ${pri_data_cmake_file}) - - # Generate a preliminary qmodule.pri file - set(preliminary_pri_file_path "${preliminary_pri_root}/qmodule.pri") - file(GENERATE - OUTPUT ${preliminary_pri_file_path} - CONTENT "${content}" - ) - - if(QT_GENERATOR_IS_MULTI_CONFIG) - set(configs ${CMAKE_CONFIGURATION_TYPES}) - else() - set(configs ${CMAKE_BUILD_TYPE}) - endif() - set(inputs ${preliminary_pri_file_path}) - foreach(cfg ${configs}) - list(APPEND inputs "${preliminary_pri_root}/${cfg}/${pri_data_cmake_file}") - endforeach() - - set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX}) - set(library_suffixes - ${CMAKE_SHARED_LIBRARY_SUFFIX} - ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES} - ${CMAKE_STATIC_LIBRARY_SUFFIX}) - add_custom_command( - OUTPUT "${qmodule_pri_target_path}" - DEPENDS ${inputs} - "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake" - "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake" - COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${qmodule_pri_target_path}" - "-DLIBRARY_PREFIXES=${library_prefixes}" - "-DLIBRARY_SUFFIXES=${library_suffixes}" - "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}" - "-DCONFIGS=${configs}" - -P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake" - VERBATIM) - add_custom_target(qmodule_pri DEPENDS "${qmodule_pri_target_path}") - qt_install(FILES "${qmodule_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR}) -endfunction() - -# In the cross-compiling case, creates a wrapper around the host Qt's -# qmake executable. Also creates a qmake configuration file that sets -# up the host qmake's properties for cross-compiling with this Qt -# build. -function(qt_generate_qmake_wrapper_for_target) - if(NOT CMAKE_CROSSCOMPILING) - return() - endif() - - # Call the configuration file something else but qt.conf to avoid - # being picked up by the qmake executable that's created if - # QT_BUILD_TOOLS_WHEN_CROSSCOMPILING is enabled. - qt_path_join(qt_conf_path "${INSTALL_BINDIR}" "target_qt.conf") - - set(prefix "${CMAKE_INSTALL_PREFIX}") - set(ext_prefix "${QT_STAGING_PREFIX}") - set(host_prefix "${QT_HOST_PATH}") - file(RELATIVE_PATH host_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}" - "${host_prefix}") - file(RELATIVE_PATH ext_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}" - "${ext_prefix}") - file(RELATIVE_PATH ext_prefix_relative_to_host_prefix "${host_prefix}" "${ext_prefix}") - - set(content "") - if(ext_prefix STREQUAL prefix) - set(sysrootify_prefix true) - else() - set(sysrootify_prefix false) - string(APPEND content "[DevicePaths] -Prefix=${prefix} -") - endif() - - if(NOT QT_WILL_INSTALL) - # The shadow build directory of a non-prefix build does not contain a copy of the mkspecs - # directory. Let $$[QT_HOST_DATA/src] point to the qtbase source directory. - string(APPEND content "[EffectiveSourcePaths] -HostData=${CMAKE_CURRENT_SOURCE_DIR} -") - - # Set $$[QT_HOST_DATA/get] to avoid falling back to the source dir where it isn't explicitly - # requested. - # Also make sure to specif the Prefix as well, because it doesn't get inherited from the - # [Paths] section. - string(APPEND content "[EffectivePaths] -HostData=${ext_prefix} -Prefix=${ext_prefix_relative_to_conf_file} -") - endif() - - # On Android CMAKE_SYSROOT is set, but for Qt's purposes it should not be set, because then - # qmake generates incorrect Qt module include flags (among other things). Do the same for darwin - # cross-compilation. - set(sysroot "") - if(CMAKE_SYSROOT AND NOT ANDROID AND NOT UIKIT) - set(sysroot "${CMAKE_SYSROOT}") - endif() - - string(APPEND content - "[Paths] -Prefix=${ext_prefix_relative_to_conf_file} -HostPrefix=${host_prefix_relative_to_conf_file} -HostData=${ext_prefix_relative_to_host_prefix} -Sysroot=${sysroot} -SysrootifyPrefix=${sysrootify_prefix} -TargetSpec=${QT_QMAKE_TARGET_MKSPEC} -HostSpec=${QT_QMAKE_HOST_MKSPEC} -") - file(GENERATE OUTPUT "${qt_conf_path}" CONTENT "${content}") - - qt_path_join(qmake_wrapper_in_file "${CMAKE_CURRENT_SOURCE_DIR}/bin/qmake-wrapper-for-target") - qt_path_join(qmake_wrapper "preliminary" "qmake") - if(QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - # Avoid collisions with the cross-compiled qmake binary. - string(PREPEND qmake_wrapper "host-") - endif() - if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") - string(APPEND qmake_wrapper_in_file ".bat") - string(APPEND qmake_wrapper ".bat") - endif() - string(APPEND qmake_wrapper_in_file ".in") - - set(host_qt_bindir "${host_prefix}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}") - - configure_file("${qmake_wrapper_in_file}" "${qmake_wrapper}" @ONLY) - qt_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${qt_conf_path}" - DESTINATION "${INSTALL_BINDIR}") - qt_copy_or_install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${qmake_wrapper}" - DESTINATION "${INSTALL_BINDIR}") -endfunction() - -# Takes a list of path components and joins them into one path separated by forward slashes "/", -# and saves the path in out_var. -function(qt_path_join out_var) - string(JOIN "/" path ${ARGN}) - set(${out_var} ${path} PARENT_SCOPE) -endfunction() - -function(qt_internal_export_modern_cmake_config_targets_file) - cmake_parse_arguments(__arg "" "EXPORT_NAME_PREFIX;CONFIG_INSTALL_DIR" "TARGETS" ${ARGN}) - - set(export_name "${__arg_EXPORT_NAME_PREFIX}VersionlessTargets") - foreach(target ${__arg_TARGETS}) - if (TARGET "${target}Versionless") - continue() - endif() - - add_library("${target}Versionless" INTERFACE) - target_link_libraries("${target}Versionless" INTERFACE "${target}") - set_target_properties("${target}Versionless" PROPERTIES - EXPORT_NAME "${target}" - _qt_is_versionless_target "TRUE") - set_property(TARGET "${target}Versionless" - APPEND PROPERTY EXPORT_PROPERTIES _qt_is_versionless_target) - - qt_install(TARGETS "${target}Versionless" EXPORT ${export_name}) - endforeach() - qt_install(EXPORT ${export_name} NAMESPACE Qt:: DESTINATION "${__arg_CONFIG_INSTALL_DIR}") -endfunction() - -# Print all variables defined in the current scope. -macro(qt_debug_print_variables) - cmake_parse_arguments(__arg "DEDUP" "" "MATCH;IGNORE" ${ARGN}) - message("Known Variables:") - get_cmake_property(__variableNames VARIABLES) - list (SORT __variableNames) - if (__arg_DEDUP) - list(REMOVE_DUPLICATES __variableNames) - endif() - - foreach(__var ${__variableNames}) - set(__ignore OFF) - foreach(__i ${__arg_IGNORE}) - if(__var MATCHES "${__i}") - set(__ignore ON) - break() - endif() - endforeach() - - if (__ignore) - continue() - endif() - - set(__show OFF) - foreach(__i ${__arg_MATCH}) - if(__var MATCHES "${__i}") - set(__show ON) - break() - endif() - endforeach() - - if (__show) - message(" ${__var}=${${__var}}.") - endif() - endforeach() -endmacro() - - -macro(assert) - if (${ARGN}) - else() - message(FATAL_ERROR "ASSERT: ${ARGN}.") - endif() -endmacro() - - -function(qt_create_nolink_target target dependee_target) - if(NOT TARGET "${target}") - message(FATAL_ERROR "${target} does not exist when trying to build a nolink target.") - endif() - get_target_property(type "${target}" TYPE) - if(type STREQUAL EXECUTABLE) - message(FATAL_ERROR "${target} must be a library of some kind.") - endif() - if(type STREQUAL OBJECT_LIBRARY) - message(FATAL_ERROR "${target} must not be an object library.") - endif() - - # Strip off the namespace prefix, so from Vulkan::Vulkan to Vulkan, and then append _nolink. - string(REGEX REPLACE "^.*::" "" non_prefixed_target ${target}) - set(nolink_target "${non_prefixed_target}_nolink") - - # 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 - # 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") - - # Whe configuring an example with qmake, if QtGui is built with Vulkan support but the - # user's machine where Qt is installed doesn't have Vulkan, qmake doesn't fail saying - # that vulkan is not installed. Instead it silently configures and just doesn't add - # the include headers. - # To mimic that in CMake, if the Vulkan CMake package is not found, we shouldn't fail - # at generation time saying that the Vulkan target does not exist. Instead check with a - # genex that the target exists to query the properties, otherwise just silently continue. - # FIXME: If we figure out that such behavior should only be applied to Vulkan, and not the - # other _nolink targets, we'll have to modify this to be configurable. - set(target_exists_genex "$<TARGET_EXISTS:${target}>") - set(props_to_set INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES - INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS - INTERFACE_COMPILE_FEATURES) - foreach(prop ${props_to_set}) - set_target_properties( - "${nolink_target}" PROPERTIES - ${prop} $<${target_exists_genex}:$<TARGET_PROPERTY:${target},${prop}>> - ) - endforeach() - - 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}) - endif() -endfunction() - -function(qt_ensure_perl) - if(DEFINED HOST_PERL) - return() - endif() - find_program(HOST_PERL "perl" DOC "Perl binary") - if (NOT HOST_PERL) - message(FATAL_ERROR "Perl needs to be available to build Qt.") - endif() -endfunction() - - -function(qt_ensure_sync_qt) - qt_ensure_perl() - if(DEFINED QT_SYNCQT) - return() - endif() - - # When building qtbase, use the source syncqt, otherwise use the installed one. - set(SYNCQT_FROM_SOURCE "${QtBase_SOURCE_DIR}/bin/syncqt.pl") - if(NOT ("${QtBase_SOURCE_DIR}" STREQUAL "") AND EXISTS "${SYNCQT_FROM_SOURCE}") - set(QT_SYNCQT "${SYNCQT_FROM_SOURCE}" CACHE FILEPATH "syncqt script") - message(STATUS "Using source syncqt found at: ${QT_SYNCQT}") - - qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_LIBEXECDIR}) - qt_copy_or_install(PROGRAMS "${SYNCQT_FROM_SOURCE}" - DESTINATION "${syncqt_install_dir}") - - qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_BINDIR}) - 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 - "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBEXECDIR}/syncqt.pl" - ABSOLUTE) - set(QT_SYNCQT "${syncqt_absolute_path}" CACHE FILEPATH "syncqt script") - message(STATUS "Using installed syncqt found at: ${QT_SYNCQT}") - endif() -endfunction() - -# A version of cmake_parse_arguments that makes sure all arguments are processed and errors out -# with a message about ${type} having received unknown arguments. -macro(qt_parse_all_arguments result type flags options multiopts) - cmake_parse_arguments(${result} "${flags}" "${options}" "${multiopts}" ${ARGN}) - if(DEFINED ${result}_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Unknown arguments were passed to ${type} (${${result}_UNPARSED_ARGUMENTS}).") - endif() -endmacro() - +# Needed for qt_internal_add_link_flags_no_undefined. include(CheckCXXSourceCompiles) -function(qt_internal_add_link_flags_no_undefined target) - if (NOT QT_BUILD_SHARED_LIBS) - return() - endif() - if (GCC OR CLANG) - 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_SYMBOLS) - if(HAVE_DASH_UNDEFINED_SYMBOLS) - set(no_undefined_flag "-Wl,-undefined,error") - 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") - endif() - - set(CMAKE_REQUIRED_LINK_OPTIONS ${previous_CMAKE_REQUIRED_LINK_OPTIONS}) - - if (NOT HAVE_DASH_UNDEFINED_SYMBOLS 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}") - endif() -endfunction() - -function(qt_internal_apply_gc_binaries_conditional target visibility) - # Should only be applied when the feature is enabled, aka for static builds. - if(NOT QT_FEATURE_gc_binaries) - return() - endif() - qt_internal_apply_gc_binaries("${target}" "${visibility}") -endfunction() - -function(qt_internal_apply_gc_binaries target visibility) - set(possible_visibilities PRIVATE INTERFACE PUBLIC) - list(FIND possible_visibilities "${visibility}" known_visibility) - if (known_visibility EQUAL "-1") - message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.") - endif() - - if ((GCC OR CLANG) AND NOT EMSCRIPTEN AND NOT UIKIT) - if(APPLE) - set(gc_sections_flag "-Wl,-dead_strip") - elseif(SOLARIS) - set(gc_sections_flag "-Wl,-z,ignore") - elseif(LINUX OR BSD OR WIN32 OR ANDROID) - set(gc_sections_flag "-Wl,--gc-sections") - endif() - endif() - if(gc_sections_flag) - target_link_options("${target}" ${visibility} "${gc_sections_flag}") - endif() - - if((GCC OR CLANG OR ICC) AND NOT EMSCRIPTEN AND NOT UIKIT) - set(split_sections_flags "-ffunction-sections" "-fdata-sections") - endif() - if(split_sections_flags) - target_compile_options("${target}" ${visibility} ${split_sections_flags}) - endif() -endfunction() - -function(qt_internal_apply_intel_cet target visibility) - if(NOT QT_FEATURE_intelcet) - return() - endif() - - set(possible_visibilities PRIVATE INTERFACE PUBLIC) - list(FIND possible_visibilities "${visibility}" known_visibility) - if (known_visibility EQUAL "-1") - message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.") - endif() - - if(GCC) - set(flags "-mshstk") - endif() - if(flags) - target_compile_options("${target}" ${visibility} "${flags}") - endif() -endfunction() - -function(qt_internal_add_linker_version_script target) - qt_parse_all_arguments(arg "qt_internal_add_linker" "INTERNAL" "" "PRIVATE_HEADERS" ${ARGN}) - - if (TEST_ld_version_script) - if (arg_INTERNAL) - set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API { *; };") - else() - set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API {\n qt_private_api_tag*;\n") - foreach(ph ${arg_PRIVATE_HEADERS}) - string(APPEND contents " @FILE:${ph}@\n") - endforeach() - string(APPEND contents "};\n") - set(current "Qt_${PROJECT_VERSION_MAJOR}") - if (QT_NAMESPACE STREQUAL "") - set(tag_symbol "qt_version_tag") - else() - set(tag_symbol "qt_version_tag_${QT_NAMESPACE}") - endif() - string(APPEND contents "${current} { *; };\n") - - foreach(minor_version RANGE ${PROJECT_VERSION_MINOR}) - set(previous "${current}") - set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}") - if (minor_version EQUAL ${PROJECT_VERSION_MINOR}) - string(APPEND contents "${current} { ${tag_symbol}; } ${previous};\n") - else() - string(APPEND contents "${current} {} ${previous};\n") - endif() - endforeach() - - set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in") - set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version") - - file(GENERATE OUTPUT "${infile}" CONTENT "${contents}") - - qt_ensure_perl() - - add_custom_command(TARGET "${target}" PRE_LINK - 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" - ) - target_link_options("${target}" PRIVATE "-Wl,--version-script,${outfile}") - endif() - endif() -endfunction() - - -# Get a set of Qt module related values based on the target name. -# When doing qt_internal_module_info(foo Core) this method will set -# the following variables in the caller's scope: -# * foo with the value "QtCore" -# * foo_versioned with the value "Qt6Core" (based on major Qt version) -# * foo_upper with the value "CORE" -# * foo_lower with the value "core" -# * foo_repo_include_dir with the module's include directory -# e.g for QtQuick it would be qtdeclarative_build_dir/include for a prefix build or -# qtbase_build_dir/include for a non-prefix build -# * foo_include_dir with the module's include directory -# e.g for QtQuick it would be qtdeclarative_build_dir/include/QtQuick for a prefix build or -# qtbase_build_dir/include/QtQuick for a non-prefix build -# * foo_define same as foo_uper but with - replaced as _ -function(qt_internal_module_info result target) - set(module "Qt${target}") - set("${result}" "${module}" PARENT_SCOPE) - set("${result}_versioned" "Qt${PROJECT_VERSION_MAJOR}${target}" PARENT_SCOPE) - string(TOUPPER "${target}" upper) - string(TOLOWER "${target}" lower)# * foo_upper with the value "CORE" - string(REPLACE "-" "_" define "${upper}") - 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}_define" "${define}" PARENT_SCOPE) -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") @@ -1869,1836 +391,6 @@ set(__default_private_module_args "PRIVATE_MODULE_INTERFACE") set(__default_target_info_args TARGET_VERSION TARGET_PRODUCT TARGET_DESCRIPTION TARGET_COMPANY TARGET_COPYRIGHT) -option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF) - -# Initial autogen setup for a target to specify certain CMake properties which are common -# to all autogen tools. Also enable AUTOMOC by default. -function(qt_autogen_tools_initial_setup target) - set_property(TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}) - 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_PATCH ${PROJECT_VERSION_PATCH} - ) - - qt_enable_autogen_tool(${target} "moc" ON) -endfunction() - -# Enables or disables an autogen tool like moc, uic or rcc on ${target}. -function(qt_enable_autogen_tool target tool enable) - string(TOUPPER "${tool}" captitalAutogenTool) - - get_target_property(tool_enabled ${target} AUTO${captitalAutogenTool}) - get_target_property(autogen_target_depends ${target} AUTOGEN_TARGET_DEPENDS) - - if(NOT autogen_target_depends) - set(autogen_target_depends "") - endif() - set(tool_executable "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::${tool}>") - set(tool_target_name ${QT_CMAKE_EXPORT_NAMESPACE}::${tool}) - - if(enable) - list(APPEND autogen_target_depends ${tool_target_name}) - else() - list(REMOVE_ITEM autogen_target_depends ${tool_target_name}) - endif() - - # f66c1db16c050c9d685a44a38ad7c5cf9f6fcc96 in qtbase introduced a new macro - # that the moc scanner has to look for. Inform the CMake moc scanner about it. - if(tool STREQUAL "moc" AND enable) - set_target_properties("${target}" PROPERTIES - AUTOMOC_MACRO_NAMES "Q_OBJECT;Q_GADGET;Q_NAMESPACE;Q_NAMESPACE_EXPORT;Q_ENUM_NS") - endif() - - set_target_properties("${target}" - PROPERTIES - AUTO${captitalAutogenTool} "${enable}" - AUTO${captitalAutogenTool}_EXECUTABLE "${tool_executable}" - AUTOGEN_TARGET_DEPENDS "${autogen_target_depends}" - ) -endfunction() - -# This function adds or removes additional AUTOGEN tools to a target: AUTOMOC/UIC/RCC -function(qt_autogen_tools target) - qt_parse_all_arguments(arg "qt_autogen_tools" "" "" "${__default_private_args}" ${ARGN}) - - if (arg_ENABLE_AUTOGEN_TOOLS) - foreach(tool ${arg_ENABLE_AUTOGEN_TOOLS}) - qt_enable_autogen_tool(${target} ${tool} ON) - endforeach() - endif() - - if (arg_DISABLE_AUTOGEN_TOOLS) - foreach(tool ${arg_DISABLE_AUTOGEN_TOOLS}) - qt_enable_autogen_tool(${target} ${tool} OFF) - endforeach() - endif() -endfunction() - -# This function stores the list of Qt modules a library depend on, -# along with their version info, for usage in ${target}Depends.cmake file -function(qt_register_target_dependencies target public_libs private_libs) - get_target_property(target_deps "${target}" _qt_target_deps) - if(NOT target_deps) - set(target_deps "") - endif() - - # 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 - OR lib STREQUAL GlobalConfig - OR lib STREQUAL GlobalConfigPrivate - OR lib STREQUAL PlatformModuleInternal - OR lib STREQUAL PlatformPluginInternal - OR lib STREQUAL PlatformToolInternal) - list(APPEND target_deps "Qt6\;${PROJECT_VERSION}") - elseif ("${lib}" MATCHES "(.*)Private") - list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${CMAKE_MATCH_1}\;${PROJECT_VERSION}") - else() - list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${lib}\;${PROJECT_VERSION}") - endif() - endif() - endforeach() - - set_target_properties("${target}" PROPERTIES _qt_target_deps "${target_deps}") -endfunction() - -function(qt_update_precompiled_header target precompiled_header) - if (precompiled_header AND BUILD_WITH_PCH) - set_property(TARGET "${target}" APPEND PROPERTY "PRECOMPILE_HEADERS" "$<$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:OBJCXX>>:${precompiled_header}>") - endif() -endfunction() - -function(qt_update_precompiled_header_with_library target library) - if (TARGET "${library}") - get_target_property(TARGET_TYPE "${library}" TYPE) - if (NOT TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") - get_target_property(HEADER "${library}" MODULE_HEADER) - qt_update_precompiled_header("${target}" "${HEADER}") - endif() - endif() -endfunction() - -function(qt_update_ignore_pch_source target sources) - if (sources) - set_source_files_properties(${sources} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) - endif() -endfunction() - -function(qt_ignore_pch_obj_c_sources target sources) - # No obj-cxx PCH support for versions lower than 3.16. - if(CMAKE_VERSION VERSION_LESS 3.16.0) - list(FILTER sources INCLUDE REGEX "\\.mm$") - qt_update_ignore_pch_source("${target}" "${sources}") - endif() -endfunction() - -# This function can be used to add sources/libraries/etc. to the specified CMake target -# if the provided CONDITION evaluates to true. -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) - return() - endif() - - if (NOT TARGET "${target}") - message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".") - endif() - 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() - - qt_evaluate_config_expression(result ${arg_CONDITION}) - if (${result}) - if(QT_CMAKE_DEBUG_EXTEND_TARGET) - message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Evaluated") - endif() - set(dbus_sources "") - foreach(adaptor ${arg_DBUS_ADAPTOR_SOURCES}) - qt_create_qdbusxml2cpp_command("${target}" "${adaptor}" ADAPTOR BASENAME "${arg_DBUS_ADAPTOR_BASENAME}" FLAGS "${arg_DBUS_ADAPTOR_FLAGS}") - list(APPEND dbus_sources "${sources}") - endforeach() - - foreach(interface ${arg_DBUS_INTERFACE_SOURCES}) - qt_create_qdbusxml2cpp_command("${target}" "${interface}" INTERFACE BASENAME "${arg_DBUS_INTERFACE_BASENAME}" FLAGS "${arg_DBUS_INTERFACE_FLAGS}") - list(APPEND dbus_sources "${sources}") - endforeach() - - get_target_property(target_type ${target} TYPE) - set(is_library FALSE) - if (${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY") - set(is_library TRUE) - endif() - foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES}) - # Automatically generate PCH for 'target' using dependencies - # if 'target' is a library/module! - if (${is_library}) - qt_update_precompiled_header_with_library("${target}" "${lib}") - endif() - - string(REGEX REPLACE "_nolink$" "" base_lib "${lib}") - if(NOT base_lib STREQUAL lib) - qt_create_nolink_target("${base_lib}" ${target}) - endif() - endforeach() - - # Set-up the target - target_sources("${target}" PRIVATE ${arg_SOURCES} ${dbus_sources}) - if (arg_COMPILE_FLAGS) - set_source_files_properties(${arg_SOURCES} PROPERTIES COMPILE_FLAGS "${arg_COMPILE_FLAGS}") - endif() - - set(public_visibility_option "PUBLIC") - set(private_visibility_option "PRIVATE") - if(arg_HEADER_MODULE) - set(public_visibility_option "INTERFACE") - set(private_visibility_option "INTERFACE") - endif() - target_include_directories("${target}" - ${public_visibility_option} ${arg_PUBLIC_INCLUDE_DIRECTORIES} - ${private_visibility_option} ${arg_INCLUDE_DIRECTORIES}) - target_compile_definitions("${target}" - ${public_visibility_option} ${arg_PUBLIC_DEFINES} - ${private_visibility_option} ${arg_DEFINES}) - target_link_libraries("${target}" - ${public_visibility_option} ${arg_PUBLIC_LIBRARIES} - ${private_visibility_option} ${arg_LIBRARIES}) - target_compile_options("${target}" - ${public_visibility_option} ${arg_PUBLIC_COMPILE_OPTIONS} - ${private_visibility_option} ${arg_COMPILE_OPTIONS}) - target_link_options("${target}" - ${public_visibility_option} ${arg_PUBLIC_LINK_OPTIONS} - ${private_visibility_option} ${arg_LINK_OPTIONS}) - - if(NOT arg_HEADER_MODULE) - set_property (TARGET "${target}" APPEND PROPERTY - AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}" - ) - endif() - - # When computing the private library dependencies, we need to check not only the known - # modules added by this repo's qt_build_repo(), but also all module dependencies that - # were found via find_package(). - qt_internal_get_qt_all_known_modules(known_modules) - - # When a public module depends on a private module (Gui on CorePrivate) - # make its private module depend on the other private module (GuiPrivate will depend on - # CorePrivate). - set(qt_libs_private "") - foreach(it ${known_modules}) - list(FIND arg_LIBRARIES "Qt::${it}Private" pos) - if(pos GREATER -1) - list(APPEND qt_libs_private "Qt::${it}Private") - endif() - endforeach() - - set(target_private "${target}Private") - if(TARGET "${target_private}") - target_link_libraries("${target_private}" - INTERFACE ${arg_PRIVATE_MODULE_INTERFACE}) - endif() - qt_register_target_dependencies("${target}" - "${arg_PUBLIC_LIBRARIES}" - "${qt_libs_private};${arg_LIBRARIES}") - - - qt_autogen_tools(${target} - ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} - DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}) - - qt_update_precompiled_header("${target}" "${arg_PRECOMPILED_HEADER}") - qt_update_ignore_pch_source("${target}" "${arg_NO_PCH_SOURCES}") - ## Ignore objective-c files for PCH (not supported atm) - qt_ignore_pch_obj_c_sources("${target}" "${arg_SOURCES}") - - else() - if(QT_CMAKE_DEBUG_EXTEND_TARGET) - message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped") - endif() - endif() -endfunction() - - -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 - 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 - list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x050000") - endif() - list(APPEND deprecations "QT_DEPRECATED_WARNINGS_SINCE=0x060000") - set("${result}" deprecations PARENT_SCOPE) -endfunction() - - -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 - # The are 3 parts to the assignment, divded by colons ':'. - # The first part contains a path to a generated file in a build folder. - # The second part contains the file name that the forwarding header should have, which points - # to the file in the first part. - # The third part contains multiple UpperCaseFileNames that should be forwarding headers to the - # header specified in the second part. - separate_arguments(injections UNIX_COMMAND "${injections}") - foreach(injection ${injections}) - string(REPLACE ":" ";" injection ${injection}) - # Part 1. - list(GET injection 0 file) - # Part 2. - list(GET injection 1 destination) - string(REGEX REPLACE "^\\^" "" destination "${destination}") - list(REMOVE_AT injection 0 1) - # Part 3. - set(fwd_hdrs ${injection}) - get_filename_component(destinationdir ${destination} DIRECTORY) - get_filename_component(destinationname ${destination} NAME) - get_filename_component(original_file_name ${file} NAME) - - # This describes a concrete example for easier comprehension: - # A file 'qtqml-config.h' is generated by qt_internal_feature_write_file into - # ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h (part 1). - # - # Generate a lower case forwarding header (part 2) 'qtqml-config.h' at the following - # location: - # ${some_prefix}/include/${module}/qtqml-config.h. - # - # Inside this file, we #include the originally generated file, - # ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h. - # - # ${some_prefix}'s value depends on the build type. - # If doing a prefix build, it should point to - # ${current_repo_build_dir} which is ${qtdeclarative_build_dir}. - # If doing a non-prefix build, it should point to - # ${qtbase_build_dir}. - # - # In the code below, ${some_prefix} == ${build_dir}. - set(lower_case_forwarding_header_path "${build_dir}/include/${module}") - if(destinationdir) - string(APPEND lower_case_forwarding_header_path "/${destinationdir}") - endif() - set(current_repo_build_dir "${PROJECT_BINARY_DIR}") - - file(RELATIVE_PATH relpath - "${lower_case_forwarding_header_path}" - "${current_repo_build_dir}/${file}") - set(main_contents "#include \"${relpath}\"") - - qt_configure_file(OUTPUT "${lower_case_forwarding_header_path}/${original_file_name}" - CONTENT "${main_contents}") - - 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}) - set(upper_case_forwarding_header_path "include/${module}") - if(destinationdir) - string(APPEND upper_case_forwarding_header_path "/${destinationdir}") - endif() - - # Generate upper case forwarding header like QVulkanFunctions or QtConfig. - qt_configure_file(OUTPUT "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" - CONTENT "#include \"${destinationname}\"\n") - - 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}" "${INSTALL_INCLUDEDIR}" ${module}) - qt_install(FILES "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" - DESTINATION ${install_destination} OPTIONAL) - endif() - endforeach() - endforeach() -endfunction() - - -function(qt_read_headers_pri module_include_dir resultVarPrefix) - file(STRINGS "${module_include_dir}/headers.pri" headers_pri_contents) - foreach(line ${headers_pri_contents}) - if("${line}" MATCHES "SYNCQT.HEADER_FILES = (.*)") - set(public_module_headers "${CMAKE_MATCH_1}") - separate_arguments(public_module_headers UNIX_COMMAND "${public_module_headers}") - elseif("${line}" MATCHES "SYNCQT.PRIVATE_HEADER_FILES = (.*)") - set(private_module_headers "${CMAKE_MATCH_1}") - separate_arguments(private_module_headers UNIX_COMMAND "${private_module_headers}") - elseif("${line}" MATCHES "SYNCQT.GENERATED_HEADER_FILES = (.*)") - set(generated_module_headers "${CMAKE_MATCH_1}") - separate_arguments(generated_module_headers UNIX_COMMAND "${generated_module_headers}") - foreach(generated_header ${generated_module_headers}) - list(APPEND public_module_headers "${module_include_dir}/${generated_header}") - endforeach() - elseif("${line}" MATCHES "SYNCQT.INJECTIONS = (.*)") - set(injections "${CMAKE_MATCH_1}") - elseif("${line}" MATCHES "SYNCQT.([A-Z_]+)_HEADER_FILES = (.+)") - set(prefix "${CMAKE_MATCH_1}") - string(TOLOWER "${prefix}" prefix) - set(entries "${CMAKE_MATCH_2}") - separate_arguments(entries UNIX_COMMAND "${entries}") - set("${resultVarPrefix}_${prefix}" "${entries}" PARENT_SCOPE) - endif() - endforeach() - set(${resultVarPrefix}_public "${public_module_headers}" PARENT_SCOPE) - set(${resultVarPrefix}_private "${private_module_headers}" PARENT_SCOPE) - set(${resultVarPrefix}_injections "${injections}" PARENT_SCOPE) -endfunction() - - -# Add Qt::target and Qt6::target as aliases for the target -function(qt_internal_add_target_aliases target) - get_target_property(type "${target}" TYPE) - if (type STREQUAL EXECUTABLE) - add_executable("Qt::${target}" ALIAS "${target}") - add_executable("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}") - else() - add_library("Qt::${target}" ALIAS "${target}") - add_library("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}") - endif() -endfunction() - -# Sets the exceptions flags for the given target -function(qt_internal_set_no_exceptions_flags target) - target_compile_definitions("${target}" PRIVATE "QT_NO_EXCEPTIONS") - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - target_compile_options("${target}" PRIVATE "/wd4530" "/wd4577") - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - target_compile_options("${target}" PRIVATE "-fno-exceptions") - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") - target_compile_options("${target}" PRIVATE "-fno-exceptions") - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - target_compile_options("${target}" PRIVATE "-fno-exceptions") - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") - target_compile_options("${target}" PRIVATE "-fno-exceptions") - 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_disable_warnings target) - get_target_property(target_type "${target}" TYPE) - if(target_type STREQUAL "INTERFACE_LIBRARY") - return() - endif() - set_target_properties("${target}" PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON) -endfunction() - -function(qt_set_symbol_visibility_preset target value) - get_target_property(target_type "${target}" TYPE) - if(target_type STREQUAL "INTERFACE_LIBRARY") - return() - endif() - - set_target_properties("${target}" PROPERTIES C_VISIBILITY_PRESET "${value}") - set_target_properties("${target}" PROPERTIES CXX_VISIBILITY_PRESET "${value}") - set_target_properties("${target}" PROPERTIES OBJC_VISIBILITY_PRESET "${value}") - set_target_properties("${target}" PROPERTIES OBJCXX_VISIBILITY_PRESET "${value}") -endfunction() - -function(qt_set_symbol_visibility_hidden target) - qt_set_symbol_visibility_preset("${target}" "hidden") -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_get_cmake_configurations out_var) - set(possible_configs "${CMAKE_BUILD_TYPE}") - if(CMAKE_CONFIGURATION_TYPES) - set(possible_configs "${CMAKE_CONFIGURATION_TYPES}") - endif() - set(${out_var} "${possible_configs}" PARENT_SCOPE) -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) - qt_get_cmake_configurations(possible_configs) - 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() - -# Add a finalizer function for the current CMake list file. -# -# You may add up to nine arguments that are passed to the finalizer. -# A finalizer that is registered with qt_add_list_file_finalizer(foo bar baz) -# will be called with nine arguments: foo(bar baz IGNORE IGNORE IGNORE...), -# because CMake's handling of empty list elements is a cruel joke. -# -# For CMake < 3.18 the function qt_watch_current_list_dir must know about the finalizer. -function(qt_add_list_file_finalizer func) - set_property(GLOBAL APPEND - PROPERTY QT_LIST_FILE_FINALIZER_FILES "${CMAKE_CURRENT_LIST_FILE}") - set_property(GLOBAL APPEND - PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${func}) - foreach(i RANGE 1 9) - set(arg "${ARGV${i}}") - if(i GREATER_EQUAL ARGC OR "${arg}" STREQUAL "") - set(arg "IGNORE") - endif() - set_property(GLOBAL APPEND - PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${arg}") - endforeach() -endfunction() - -# Watcher function for the variable CMAKE_CURRENT_LIST_DIR. -# This is the driver of the finalizer facility. -function(qt_watch_current_list_dir variable access value current_list_file stack) - if(NOT access STREQUAL "MODIFIED_ACCESS") - # We are only interested in modifications of CMAKE_CURRENT_LIST_DIR. - return() - endif() - list(GET stack -1 stack_top) - if(stack_top STREQUAL current_list_file) - # If the top of the stack equals the current list file then - # we're entering a file. We're not interested in this case. - return() - endif() - get_property(files GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES) - if(NOT files) - return() - endif() - get_property(funcs GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS) - foreach(i RANGE 1 9) - get_property(args${i} GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i}) - endforeach() - list(LENGTH files n) - set(i 0) - while(i LESS n) - list(GET files ${i} file) - if(file STREQUAL stack_top) - list(GET funcs ${i} func) - foreach(k RANGE 1 9) - list(GET args${k} ${i} a${k}) - endforeach() - # We've found a file we're looking for. Call the finalizer. - if(${CMAKE_VERSION} VERSION_LESS "3.18.0") - # Make finalizer known functions here: - if(func STREQUAL "qt_finalize_module") - qt_finalize_module(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) - elseif(func STREQUAL "qt_finalize_plugin") - qt_finalize_plugin(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) - elseif(func STREQUAL "qt_internal_finalize_app") - qt_internal_finalize_app(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) - else() - message(FATAL_ERROR "qt_watch_current_list_dir doesn't know about ${func}. Consider adding it.") - endif() - else() - cmake_language(CALL ${func} ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) - endif() - list(REMOVE_AT files ${i}) - list(REMOVE_AT funcs ${i}) - foreach(k RANGE 1 9) - list(REMOVE_AT args${k} ${i}) - endforeach() - math(EXPR n "${n} - 1") - else() - math(EXPR i "${i} + 1") - endif() - endwhile() - set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES ${files}) - set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${funcs}) - foreach(i RANGE 1 9) - set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${args${i}}") - endforeach() -endfunction() - -variable_watch(CMAKE_CURRENT_LIST_DIR qt_watch_current_list_dir) - -# Set target properties that are the same for all modules, plugins, executables -# and 3rdparty libraries. -function(qt_set_common_target_properties target) - if(FEATURE_static_runtime) - if(MSVC) - set_property(TARGET ${target} PROPERTY - MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") - elseif(MINGW) - target_link_options(${target} INTERFACE "LINKER:-static") - endif() - endif() -endfunction() - -# Set common, informational target properties. -# -# On Windows, these properties are used to generate the version information resource. -function(qt_set_target_info_properties target) - cmake_parse_arguments(arg "" "${__default_target_info_args}" "" ${ARGN}) - if("${arg_TARGET_VERSION}" STREQUAL "") - set(arg_TARGET_VERSION "${PROJECT_VERSION}.0") - endif() - if("${arg_TARGET_PRODUCT}" STREQUAL "") - set(arg_TARGET_PRODUCT "Qt6") - endif() - if("${arg_TARGET_DESCRIPTION}" STREQUAL "") - set(arg_TARGET_DESCRIPTION "C++ Application Development Framework") - endif() - if("${arg_TARGET_COMPANY}" STREQUAL "") - set(arg_TARGET_COMPANY "The Qt Company Ltd.") - endif() - if("${arg_TARGET_COPYRIGHT}" STREQUAL "") - set(arg_TARGET_COPYRIGHT "Copyright (C) 2020 The Qt Company Ltd.") - endif() - set_target_properties(${target} PROPERTIES - QT_TARGET_VERSION "${arg_TARGET_VERSION}" - QT_TARGET_COMPANY_NAME "${arg_TARGET_COMPANY}" - QT_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" - QT_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}" - QT_TARGET_PRODUCT_NAME "${arg_TARGET_PRODUCT}") -endfunction() - -# Uses the QT_DELAYED_TARGET_* property values to set the final QT_TARGET_* properties. -# Needed when doing executable finalization at the end of a subdirectory scope -# (aka scope finalization). -function(qt_internal_set_target_info_properties_from_delayed_properties target) - set(args "") - foreach(prop ${__default_target_info_args}) - get_target_property(prop_value "${target}" "QT_DELAYED_${prop}") - list(APPEND args "${prop}" "${prop_value}") - endforeach() - qt_set_target_info_properties(${target} ${args}) -endfunction() - -# Updates the QT_DELAYED_ properties with values from the QT_ variants, in case if they were -# set in-between a qt_add_* call and before scope finalization. -function(qt_internal_update_delayed_target_info_properties target) - foreach(prop ${__default_target_info_args}) - get_target_property(prop_value "${target}" "QT_${prop}") - get_target_property(delayed_prop_value ${target} "QT_DELAYED_${prop}") - set(final_value "${delayed_prop_value}") - if(prop_value) - set(final_value "${prop_value}") - endif() - set_target_properties(${target} PROPERTIES "QT_DELAYED_${prop}" "${final_value}") - endforeach() -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. -# -# A CMake target with the specified target parameter is created. If the current source -# directory has a configure.cmake file, then that is also processed for feature definition -# and testing. Any features defined as well as any features coming from dependencies to -# 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(qt_add_module target) - qt_internal_module_info(module "${target}") - - # Process arguments: - 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;NO_CONFIG_HEADER_FILE;SKIP_DEPENDS_INCLUDE" - "MODULE_INCLUDE_NAME;CONFIG_MODULE_NAME;PRECOMPILED_HEADER;CONFIGURE_FILE_PATH;${__default_target_info_args}" - "${__default_private_args};${__default_public_args};${__default_private_module_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN}) - - qt_internal_add_qt_repo_known_module("${target}") - - if(NOT DEFINED arg_CONFIG_MODULE_NAME) - set(arg_CONFIG_MODULE_NAME "${module_lower}") - endif() - - ### Define Targets: - set(is_interface_lib 0) - set(is_shared_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}) - add_library("${target}" SHARED) - set(is_shared_lib 1) - else() - add_library("${target}" STATIC) - endif() - - set(property_prefix "INTERFACE_") - if(NOT arg_HEADER_MODULE) - qt_set_common_target_properties(${target}) - set(property_prefix "") - endif() - - set_target_properties(${target} PROPERTIES - _qt_config_module_name "${arg_CONFIG_MODULE_NAME}" - ${property_prefix}QT_QMAKE_MODULE_CONFIG "${arg_QMAKE_MODULE_CONFIG}") - set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES _qt_config_module_name) - - 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(QT_FEATURE_reduce_relocations AND UNIX AND NOT is_interface_lib) - # On x86 and x86-64 systems with ELF binaries (especially Linux), due to - # a new optimization in GCC 5.x in combination with a recent version of - # GNU binutils, compiling Qt applications with -fPIE is no longer - # enough. - # Applications now need to be compiled with the -fPIC option if the Qt option - # \"reduce relocations\" is active. - target_compile_options(${target} INTERFACE -fPIC) - if(GCC AND is_shared_lib) - target_link_options(${target} PRIVATE LINKER:-Bsymbolic-functions) - endif() - endif() - - if(QT_FEATURE_separate_debug_info AND is_shared_lib AND (UNIX OR MINGW)) - qt_enable_separate_debug_info(${target} ${INSTALL_LIBDIR}) - 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}") - _qt_internal_apply_strict_cpp("${target}") - - # Add _private target to link against the private headers: - if(NOT ${arg_NO_PRIVATE_MODULE}) - set(target_private "${target}Private") - add_library("${target_private}" INTERFACE) - qt_internal_add_target_aliases("${target_private}") - set_target_properties(${target_private} PROPERTIES - _qt_config_module_name ${arg_CONFIG_MODULE_NAME}_private) - set_property(TARGET "${target_private}" APPEND PROPERTY - EXPORT_PROPERTIES _qt_config_module_name) - 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_set_target_info_properties(${target} ${ARGN}) - qt_handle_multi_config_output_dirs("${target}") - - if(NOT BUILD_SHARED_LIBS AND LINUX) - # Horrible workaround for static build failures due to incorrect static library link - # order. By increasing the multiplicity to 3, each library cycle will be repeated - # 3 times on the link line, reducing the probability of undefined symbols at - # link time. - # These failures are only observed on Linux with the ld linker (not sure about - # ld.gold). - # Allow opting out and modifying the value via cache value, in case if we urgently - # need to increase it without waiting for the qtbase change to propagate to - # other dependent repos. - # The proper fix will be to get rid of the cycles in the future. - # See QTBUG-83498 for details. - set(default_link_cycle_multiplicity "3") - if(DEFINED QT_LINK_CYCLE_MULTIPLICITY) - set(default_link_cycle_multiplicity "${QT_LINK_CYCLE_MULTIPLICITY}") - endif() - if(default_link_cycle_multiplicity) - set_property(TARGET "${target}" - PROPERTY - LINK_INTERFACE_MULTIPLICITY "${default_link_cycle_multiplicity}") - endif() - endif() - - if (arg_SKIP_DEPENDS_INCLUDE) - set_target_properties(${target} PROPERTIES QT_MODULE_SKIP_DEPENDS_INCLUDE TRUE) - endif() - 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() - - qt_internal_apply_win_prefix_and_suffix("${target}") - - if (WIN32 AND BUILD_SHARED_LIBS) - qt6_generate_win32_rc_file(${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) - else() - if(arg_MODULE_INCLUDE_NAME) - set(module_include_name ${arg_MODULE_INCLUDE_NAME}) - else() - set(module_include_name ${module}) - endif() - set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_INCLUDE_NAME "${module_include_name}") - - # Use QT_BUILD_DIR for the syncqt call. - # So we either write the generated files into the qtbase non-prefix build root, or the - # module specific build root. - qt_ensure_sync_qt() - set(syncqt_full_command "${HOST_PERL}" -w "${QT_SYNCQT}" - -quiet - -check-includes - -module "${module_include_name}" - -version "${PROJECT_VERSION}" - -outdir "${QT_BUILD_DIR}" - -builddir "${PROJECT_BINARY_DIR}" - "${PROJECT_SOURCE_DIR}") - message(STATUS "Running syncqt for module: '${module_include_name}' ") - execute_process(COMMAND ${syncqt_full_command}) - - set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS ON) - - ### FIXME: Can we replace headers.pri? - set(module_include_dir "${QT_BUILD_DIR}/include/${module_include_name}") - qt_read_headers_pri("${module_include_dir}" "module_headers") - 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_include_name}") - endif() - - if(module_headers_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_include_name}/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}) - 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() - - # Save the non-sanitized plugin type values for qmake consumption via .pri files. - set_property(TARGET "${target}" - PROPERTY QMAKE_MODULE_PLUGIN_TYPES "${arg_PLUGIN_TYPES}") - endif() - endif() - - qt_internal_library_deprecation_level(deprecation_define) - - if(NOT arg_HEADER_MODULE) - qt_autogen_tools_initial_setup(${target}) - endif() - - set(private_includes - "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>" - "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>" - ${arg_INCLUDE_DIRECTORIES} - ) - - set(public_includes "") - set(public_headers_list "public_includes") - if(is_framework) - set(public_headers_list "private_includes") - endif() - - # Make sure the BUILD_INTERFACE include paths come before the framework headers, so that the - # the compiler prefers the build dir includes. - # - # Make sure to add non-framework "build_dir/include" as an include path for moc to find the - # currently built module headers. qmake does this too. - # Framework-style include paths are found by moc when cmQtAutoMocUic.cxx detects frameworks by - # looking at an include path and detecting a "QtFoo.framework/Headers" path. - # Make sure to create such paths for both the the BUILD_INTERFACE and the INSTALL_INTERFACE. - # - # Only add syncqt headers if they exist. - # This handles cases like QmlDevTools which do not have their own headers, but borrow them - # from another module. - if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS) - # 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 - # For the syncqt headers - "$<BUILD_INTERFACE:${module_repo_include_dir}>" - "$<BUILD_INTERFACE:${module_include_dir}>") - endif() - - if(is_framework) - set(fw_bundle_subdir "${INSTALL_LIBDIR}/Qt${target}.framework") - list(APPEND public_includes - # Add the lib/Foo.framework dir as include path to let CMake generate - # the -F compiler flag for framework-style includes to work. - "$<INSTALL_INTERFACE:${fw_bundle_subdir}>" - - # Add the framework Headers subdir, so that non-framework-style includes work. The - # BUILD_INTERFACE Headers symlink was previously claimed not to exist at the relevant - # time, and a fully specified Header path was used instead. This doesn't seem to be a - # problem anymore. - "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${fw_bundle_subdir}/Headers>" - "$<INSTALL_INTERFACE:${fw_bundle_subdir}/Headers>" - ) - endif() - - if(NOT arg_NO_MODULE_HEADERS AND NOT arg_NO_SYNC_QT) - # For the syncqt headers - list(APPEND ${public_headers_list} "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}>") - endif() - list(APPEND ${public_headers_list} ${arg_PUBLIC_INCLUDE_DIRECTORIES}) - - set(header_module) - if(arg_HEADER_MODULE) - set(header_module "HEADER_MODULE") - - # Provide a *_timestamp target that can be used to trigger the build of custom_commands. - set(timestamp_file "${CMAKE_CURRENT_BINARY_DIR}/timestamp") - add_custom_command(OUTPUT "${timestamp_file}" - COMMAND ${CMAKE_COMMAND} -E touch "${timestamp_file}" - DEPENDS ${module_headers_public} - VERBATIM) - add_custom_target(${target}_timestamp ALL DEPENDS "${timestamp_file}") - endif() - - set(defines_for_extend_target "") - - if(NOT arg_HEADER_MODULE) - list(APPEND defines_for_extend_target - QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS - QT_MOC_COMPAT #we don't need warnings from calling moc code in our generated code - QT_USE_QSTRINGBUILDER - QT_DEPRECATED_WARNINGS - QT_BUILDING_QT - QT_BUILD_${module_define}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore - "${deprecation_define}" - ) - endif() - - qt_extend_target("${target}" - ${header_module} - SOURCES ${arg_SOURCES} - INCLUDE_DIRECTORIES - ${private_includes} - PUBLIC_INCLUDE_DIRECTORIES - ${public_includes} - PUBLIC_DEFINES - ${arg_PUBLIC_DEFINES} - QT_${module_define}_LIB - DEFINES - ${arg_DEFINES} - ${defines_for_extend_target} - 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} - DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES} - DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS} - 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} - PRECOMPILED_HEADER ${arg_PRECOMPILED_HEADER} - NO_PCH_SOURCES ${arg_NO_PCH_SOURCES} - ) - - if(NOT ${arg_EXCEPTIONS} AND NOT ${arg_HEADER_MODULE}) - qt_internal_set_no_exceptions_flags("${target}") - endif() - - set(configureFile "${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake") - if(arg_CONFIGURE_FILE_PATH) - set(configureFile "${arg_CONFIGURE_FILE_PATH}") - endif() - if(EXISTS "${configureFile}" AND NOT arg_NO_CONFIG_HEADER_FILE) - qt_feature_module_begin( - LIBRARY "${target}" - PUBLIC_FILE "qt${arg_CONFIG_MODULE_NAME}-config.h" - PRIVATE_FILE "qt${arg_CONFIG_MODULE_NAME}-config_p.h" - PUBLIC_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} - PRIVATE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} - ) - include(${configureFile}) - qt_feature_module_end("${target}") - - set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config.h") - set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config_p.h") - endif() - - 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 - # automatically generated in the build dir (for example qconfig.h, qtcore-config.h, - # qvulkanfunctions.h, etc) - # module_headers_injections come from the qt_read_headers_pri() call. - # extra_library_injections come from the qt_feature_module_end() call. - set(final_injections "") - if(module_headers_injections) - string(APPEND final_injections "${module_headers_injections} ") - endif() - if(extra_library_injections) - string(APPEND final_injections "${extra_library_injections} ") - endif() - - if(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(). - 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(extra_cmake_files) - set(extra_cmake_includes) - if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") - list(APPEND extra_cmake_files "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") - list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") - endif() - if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in") - configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in" - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake" - @ONLY) - list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake") - list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake") - endif() - - foreach(cmake_file IN LISTS arg_EXTRA_CMAKE_FILES) - get_filename_component(basename ${cmake_file} NAME) - file(COPY ${cmake_file} DESTINATION ${config_build_dir}) - list(APPEND extra_cmake_files "${config_build_dir}/${basename}") - endforeach() - list(APPEND extra_cmake_includes ${arg_EXTRA_CMAKE_INCLUDES}) - - set(extra_cmake_code "") - - if(target STREQUAL Core) - # Propagate non-build related variables that are needed for consuming Qt packages. - # Do this in CoreConfig instead of Qt6Config, so that consumers can also use - # find_package(Qt6Core) instead of find_package(Qt6 COMPONENTS Core) - string(APPEND extra_cmake_code " -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} - COMPATIBILITY AnyNewerVersion - ) - qt_install(FILES - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" - ${extra_cmake_files} - DESTINATION "${config_install_dir}" - COMPONENT Devel - ) - - file(COPY ${extra_cmake_files} DESTINATION "${config_build_dir}") - set(exported_targets ${target}) - if(NOT ${arg_NO_PRIVATE_MODULE}) - list(APPEND exported_targets ${target_private}) - endif() - set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") - qt_install(TARGETS ${exported_targets} - EXPORT ${export_name} - 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 - ) - - qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH) - - 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 - QT_ANDROID_MODULE_INSTALL_DIR ${INSTALL_LIBDIR}) - endif() - - qt_install(EXPORT ${export_name} - NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: - DESTINATION ${config_install_dir}) - - qt_internal_export_modern_cmake_config_targets_file( - TARGETS ${exported_targets} - EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} - CONFIG_INSTALL_DIR "${config_install_dir}") - - if (${arg_INTERNAL_MODULE}) - set(arg_INTERNAL_MODULE "INTERNAL_MODULE") - else() - unset(arg_INTERNAL_MODULE) - endif() - - ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins - # that belong to Qt. - if(NOT arg_HEADER_MODULE) - qt_internal_add_link_flags_no_undefined("${target}") - endif() - - set(interface_includes "") - - # 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}>") - - # syncqt.pl does not create a private header directory like 'include/6.0/QtFoo' unless - # the module has foo_p.h header files. For QtZlib, there are no such private headers, so we - # need to make sure not to add such include paths unless the directory exists, otherwise - # consumers of the module will fail at CMake generation time stating that - # INTERFACE_INCLUDE_DIRECTORIES contains a non-existent path. - if(NOT arg_NO_MODULE_HEADERS - AND EXISTS "${module_include_dir}/${PROJECT_VERSION}/${module}") - list(APPEND interface_includes - "$<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}) - target_link_libraries("${target_private}" INTERFACE "${target}") - endif() - - if(is_framework AND NOT is_interface_lib) - qt_finalize_framework_headers_copy(${target}) - endif() - - qt_describe_module(${target}) - qt_add_list_file_finalizer(qt_finalize_module ${target} ${arg_INTERNAL_MODULE} ${header_module}) -endfunction() - -function(qt_finalize_module target) - qt_generate_prl_file(${target} "${INSTALL_LIBDIR}") - qt_generate_module_pri_file("${target}" ${ARGN}) -endfunction() - -# Add libraries to variable ${out_libs_var} in a way that duplicates -# are added at the end. This ensures the library order needed for the -# linker. -function(qt_merge_libs out_libs_var) - foreach(dep ${ARGN}) - list(REMOVE_ITEM ${out_libs_var} ${dep}) - list(APPEND ${out_libs_var} ${dep}) - endforeach() - set(${out_libs_var} ${${out_libs_var}} PARENT_SCOPE) -endfunction() - -# Collects the library dependencies of a target. -# This takes into account transitive usage requirements. -function(qt_collect_libs target out_var) - qt_internal_walk_libs("${target}" "${out_var}" "qt_collect_libs_dict" "collect_libs") - set("${out_var}" "${${out_var}}" PARENT_SCOPE) -endfunction() - -# Walks a target's link libraries recursively, and performs some actions (poor man's polypmorphism) -# -# out_var is the name of the variable where the result will be assigned. The result is a list of -# libraries, mostly in generator expression form. -# dict_name is used for caching the result, and preventing the same target from being processed -# twice -# operation is a string to tell the function what to do -function(qt_internal_walk_libs target out_var dict_name operation) - set(collected ${ARGN}) - if(target IN_LIST collected) - return() - endif() - list(APPEND collected ${target}) - if(NOT TARGET ${dict_name}) - add_library(${dict_name} INTERFACE IMPORTED GLOBAL) - endif() - get_target_property(libs ${dict_name} INTERFACE_${target}) - if(NOT libs) - unset(libs) - get_target_property(target_libs ${target} INTERFACE_LINK_LIBRARIES) - if(NOT target_libs) - unset(target_libs) - endif() - get_target_property(target_type ${target} TYPE) - if(target_type STREQUAL "STATIC_LIBRARY") - get_target_property(link_libs ${target} LINK_LIBRARIES) - if(link_libs) - list(APPEND target_libs ${link_libs}) - endif() - endif() - foreach(lib ${target_libs}) - # Cannot use $<TARGET_POLICY:...> in add_custom_command. - # Check the policy now, and replace the generator expression with the value. - while(lib MATCHES "\\$<TARGET_POLICY:([^>]+)>") - cmake_policy(GET ${CMAKE_MATCH_1} value) - if(value STREQUAL "NEW") - set(value "TRUE") - else() - set(value "FALSE") - endif() - string(REPLACE "${CMAKE_MATCH_0}" "${value}" lib "${lib}") - endwhile() - - # Fix up $<TARGET_PROPERTY:FOO> expressions that refer to the "current" target. - # Those cannot be used with add_custom_command. - while(lib MATCHES "\\$<TARGET_PROPERTY:([^,>]+)>") - string(REPLACE "${CMAKE_MATCH_0}" "$<TARGET_PROPERTY:${target},${CMAKE_MATCH_1}>" - lib "${lib}") - endwhile() - - # Skip static plugins. - set(_is_plugin_marker_genex "\\$<BOOL:QT_IS_PLUGIN_GENEX>") - if(lib MATCHES "${_is_plugin_marker_genex}") - continue() - endif() - - # Strip any directory scope tokens. - qt_internal_strip_target_directory_scope_token("${lib}" lib) - - if(lib MATCHES "^\\$<TARGET_OBJECTS:") - # Skip object files. - continue() - elseif(lib MATCHES "^\\$<LINK_ONLY:(.*)>$") - set(lib_target ${CMAKE_MATCH_1}) - else() - set(lib_target ${lib}) - endif() - - # Skip CMAKE_DIRECTORY_ID_SEP. If a target_link_libraries is applied to a target - # that was defined in a different scope, CMake appends and prepends a special directory - # id separator. Filter those out. - if(lib_target MATCHES "^::@") - continue() - elseif(TARGET ${lib_target}) - if ("${lib_target}" MATCHES "^Qt::(.*)") - # If both, Qt::Foo and Foo targets exist, prefer the target name without - # namespace. Which one is preferred doesn't really matter. This code exists to - # avoid ending up with both, Qt::Foo and Foo in our dependencies. - set(namespaceless_lib_target "${CMAKE_MATCH_1}") - if(TARGET namespaceless_lib_target) - set(lib_target ${namespaceless_lib_target}) - endif() - endif() - get_target_property(lib_target_type ${lib_target} TYPE) - if(lib_target_type STREQUAL "INTERFACE_LIBRARY") - qt_internal_walk_libs( - ${lib_target} lib_libs "${dict_name}" "${operation}" ${collected}) - if(lib_libs) - qt_merge_libs(libs ${lib_libs}) - set(is_module 0) - endif() - else() - qt_merge_libs(libs "$<TARGET_FILE:${lib_target}>") - qt_internal_walk_libs( - ${lib_target} lib_libs "${dict_name}" "${operation}" ${collected}) - if(lib_libs) - qt_merge_libs(libs ${lib_libs}) - endif() - endif() - if(operation STREQUAL "promote_global") - set(lib_target_unaliased "${lib_target}") - get_target_property(aliased_target ${lib_target} ALIASED_TARGET) - if(aliased_target) - set(lib_target_unaliased ${aliased_target}) - endif() - - get_property(is_imported TARGET ${lib_target_unaliased} PROPERTY IMPORTED) - get_property(is_global TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL) - - # Allow opting out of promotion. This is useful in certain corner cases - # like with WrapLibClang and Threads in qttools. - qt_internal_should_not_promote_package_target_to_global( - "${lib_target_unaliased}" should_not_promote) - if(NOT is_global AND is_imported AND NOT should_not_promote) - set_property(TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL TRUE) - endif() - endif() - else() - set(final_lib_name_to_merge "${lib_target}") - if(lib_target MATCHES "/([^/]+).framework$") - set(final_lib_name_to_merge "-framework ${CMAKE_MATCH_1}") - endif() - qt_merge_libs(libs "${final_lib_name_to_merge}") - endif() - endforeach() - set_target_properties(${dict_name} PROPERTIES INTERFACE_${target} "${libs}") - endif() - set(${out_var} ${libs} PARENT_SCOPE) -endfunction() - -# Generate a qmake .prl file for the given target. -# The install_dir argument is a relative path, for example "lib". -function(qt_generate_prl_file target install_dir) - get_target_property(target_type ${target} TYPE) - if(target_type STREQUAL "INTERFACE_LIBRARY") - return() - endif() - - get_target_property(rcc_objects ${target} QT_RCC_OBJECTS) - if(rcc_objects) - if(QT_WILL_INSTALL) - list(TRANSFORM rcc_objects PREPEND "$$[QT_INSTALL_LIBS]/") - endif() - else() - unset(rcc_objects) - endif() - - unset(prl_config) - set(is_static FALSE) - if(target_type STREQUAL "STATIC_LIBRARY") - list(APPEND prl_config static) - set(is_static TRUE) - elseif(target_type STREQUAL "SHARED_LIBRARY") - list(APPEND prl_config shared) - endif() - if (NOT target_type STREQUAL "INTERFACE_LIBRARY") - get_target_property(is_fw ${target} FRAMEWORK) - if(is_fw) - list(APPEND prl_config lib_bundle) - endif() - endif() - list(JOIN prl_config " " prl_config) - - # Generate a preliminary .prl file that contains absolute paths to all libraries - if(MINGW) - # For MinGW, qmake doesn't have a lib prefix in prl files. - set(prefix_for_final_prl_name "") - else() - set(prefix_for_final_prl_name "$<TARGET_FILE_PREFIX:${target}>") - endif() - - # For frameworks, the prl file should be placed under the Resources subdir. - get_target_property(is_framework ${target} FRAMEWORK) - if(is_framework) - get_target_property(fw_version ${target} FRAMEWORK_VERSION) - string(APPEND prefix_for_final_prl_name "Versions/${fw_version}/Resources/") - endif() - - # What follows is a complicated setup for generating configuration-specific - # prl files. It has to be this way, because add_custom_command doesn't support - # generator expressions in OUTPUT or DEPENDS. - # To circumvent that, we create well known file names with file(GENERATE) - # with configuration specific content, which are then fed to add_custom_command - # that uses these genex-less file names. The actual command will extract the info - # from the configuration-specific files, and create a properly named final prl file. - - # The file is named according to a pattern, that is then used in the - # add_custom_command. - set(prl_step1_name_prefix "preliminary_prl_for_${target}_step1_") - set(prl_step1_name_suffix ".prl" ) - qt_path_join(prl_step1_path - "${CMAKE_CURRENT_BINARY_DIR}" - "${prl_step1_name_prefix}$<CONFIG>${prl_step1_name_suffix}") - - # Same, except instead of containing the prl contents, it will contain the final prl file - # name computed via a generator expression. - set(prl_meta_info_name_prefix "preliminary_prl_meta_info_for_${target}_") - set(prl_meta_info_name_suffix ".txt") - qt_path_join(prl_meta_info_path - "${CMAKE_CURRENT_BINARY_DIR}" - "${prl_meta_info_name_prefix}$<CONFIG>${prl_meta_info_name_suffix}") - - # The final prl file name that will be embedded in the file above. - set(final_prl_file_name "${prefix_for_final_prl_name}$<TARGET_FILE_BASE_NAME:${target}>.prl") - qt_path_join(final_prl_file_path "${QT_BUILD_DIR}/${install_dir}" "${final_prl_file_name}") - - # Generate the prl content and its final file name into configuration specific files - # whose names we know, and can be used in add_custom_command. - set(prl_step1_content - "RCC_OBJECTS = ${rcc_objects} -QMAKE_PRL_BUILD_DIR = ${CMAKE_CURRENT_BINARY_DIR} -QMAKE_PRL_TARGET = $<TARGET_FILE_NAME:${target}> -QMAKE_PRL_CONFIG = ${prl_config} -QMAKE_PRL_VERSION = ${PROJECT_VERSION} -") - if(NOT is_static AND WIN32) - # Do nothing. Prl files for shared libraries on Windows shouldn't have the libs listed, - # as per qt_build_config.prf and the conditional CONFIG+=explicitlib assignment. - else() - set(prl_libs "") - qt_collect_libs(${target} prl_libs) - string(APPEND prl_step1_content "QMAKE_PRL_LIBS_FOR_CMAKE = ${prl_libs}\n") - endif() - - file(GENERATE - OUTPUT "${prl_step1_path}" - CONTENT "${prl_step1_content}") - file(GENERATE - OUTPUT "${prl_meta_info_path}" - CONTENT - "FINAL_PRL_FILE_PATH = ${final_prl_file_path}") - - set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX}) - set(library_suffixes - ${CMAKE_SHARED_LIBRARY_SUFFIX} - ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES} - ${CMAKE_STATIC_LIBRARY_SUFFIX}) - - if(QT_GENERATOR_IS_MULTI_CONFIG) - set(configs ${CMAKE_CONFIGURATION_TYPES}) - else() - set(configs ${CMAKE_BUILD_TYPE}) - endif() - - foreach(config ${configs}) - # Output file for dependency tracking, and which will contain the final content. - qt_path_join(prl_step2_path - "${CMAKE_CURRENT_BINARY_DIR}" "preliminary_prl_for_${target}_step2_${config}.prl") - - # Input dependency names that are constructed for each config manually - # (no genexes allowed). - qt_path_join(prl_step1_path - "${CMAKE_CURRENT_BINARY_DIR}" - "${prl_step1_name_prefix}${config}${prl_step1_name_suffix}") - qt_path_join(prl_meta_info_path - "${CMAKE_CURRENT_BINARY_DIR}" - "${prl_meta_info_name_prefix}${config}${prl_meta_info_name_suffix}") - add_custom_command( - OUTPUT "${prl_step2_path}" - DEPENDS "${prl_step1_path}" - "${prl_meta_info_path}" - "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake" - "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake" - COMMAND ${CMAKE_COMMAND} - "-DIN_FILE=${prl_step1_path}" - "-DIN_META_FILE=${prl_meta_info_path}" - "-DOUT_FILE=${prl_step2_path}" - "-DLIBRARY_PREFIXES=${library_prefixes}" - "-DLIBRARY_SUFFIXES=${library_suffixes}" - "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}" - "-DQT_BUILD_LIBDIR=${QT_BUILD_DIR}/${INSTALL_LIBDIR}" - -P "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake" - VERBATIM - COMMENT "Generating prl file for target ${target}" - ) - - # Tell the target to depend on the preliminary prl file, to ensure the custom command - # is executed. As a side-effect, this will also create the final prl file that - # is named appropriately. It should not be specified as a BYPRODUCT. - # This allows proper per-file dependency tracking, without having to resort on a POST_BUILD - # step, which means that relinking would happen as well as transitive rebuilding of any - # dependees. - # This is inspired by https://gitlab.kitware.com/cmake/cmake/-/issues/20842 - target_sources(${target} PRIVATE "${prl_step2_path}") - endforeach() - - # Installation of the .prl file happens globally elsewhere, - # because we have no clue here what the actual file name is. - # What we know however, is the directory where the prl file is created. - # Save that for later, to install all prl files from that directory. - get_property(prl_install_dirs GLOBAL PROPERTY QT_PRL_INSTALL_DIRS) - if(NOT install_dir IN_LIST prl_install_dirs) - set_property(GLOBAL APPEND PROPERTY QT_PRL_INSTALL_DIRS "${install_dir}") - endif() -endfunction() - -function(qt_export_tools module_name) - # Bail out when cross-compiling, unless QT_BUILD_TOOLS_WHEN_CROSSCOMPILING is on. - if(CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - return() - endif() - - # If no tools were defined belonging to this module, don't create a config and targets file. - if(NOT "${module_name}" IN_LIST QT_KNOWN_MODULES_WITH_TOOLS) - return() - endif() - - # The tools target name. For example: CoreTools - set(target "${module_name}Tools") - - 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}) - - # Add the extra cmake statements to make the tool targets global, so it doesn't matter where - # find_package is called. - # 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() - - if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - string(REGEX REPLACE "_native$" "" tool_name ${tool_name}) - 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) - if(NOT is_global) - set_property(TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL TRUE) - endif() -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" - INSTALL_DESTINATION "${config_install_dir}" - ) - write_basic_package_version_file( - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY AnyNewerVersion - ARCH_INDEPENDENT - ) - - qt_install(FILES - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" - DESTINATION "${config_install_dir}" - COMPONENT Devel - ) - - set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") - qt_install(EXPORT "${export_name}" - NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::" - DESTINATION "${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) - if (TARGET "${main_target_name}") - 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}") - endif() -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 "qt_internal_add_plugin called without setting either TYPE or ${name}.") - endif() - set(${result_var} "${default}" PARENT_SCOPE) - else() - set(${result_var} "${dir}" PARENT_SCOPE) - endif() -endfunction() - -# Utility function to find the module to which a plug-in belongs. -# 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 - # name, because the current one would be invalid for interface libraries. - if(module_type STREQUAL "INTERFACE_LIBRARY") - continue() - endif() - - get_target_property(plugin_types - "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" - MODULE_PLUGIN_TYPES) - if(plugin_types) - foreach(plugin_type ${plugin_types}) - if("${target_type}" STREQUAL "${plugin_type}") - set_target_properties("${target}" PROPERTIES QT_MODULE "${qt_module}") - return() - endif() - endforeach() - endif() - endforeach() - message(AUTHOR_WARNING "The plug-in '${target}' does not belong to any Qt module.") -endfunction() - - # Collection of qt_add_plugin arguments so they can be shared across different # plugin type wrappers set(__qt_add_plugin_optional_args @@ -3711,351 +403,6 @@ set(__qt_add_plugin_single_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(qt_internal_add_plugin target) - qt_internal_module_info(module "${target}") - - qt_internal_set_qt_known_plugins("${QT_KNOWN_PLUGINS}" "${target}") - - qt_parse_all_arguments(arg "qt_internal_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}" plugin_type_escaped) - - set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${arg_TYPE}") - set(install_directory_default "${INSTALL_PLUGINSDIR}/${arg_TYPE}") - - if (arg_QML_TARGET_PATH) - set(target_path "${arg_QML_TARGET_PATH}") - set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${target_path}") - set(install_directory_default "${INSTALL_QMLDIR}/${target_path}") - endif() - - # 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 "${plugin_type_escaped}" STREQUAL "qml_plugin") - if (NOT arg_CLASS_NAME) - set(plugin_class_name "${target}") - else() - set(plugin_class_name "${arg_CLASS_NAME}") - endif() - endif() - - qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${arg_TYPE}" - "${output_directory_default}" output_directory) - if (NOT arg_SKIP_INSTALL) - qt_internal_check_directory_or_type(INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}" "${arg_TYPE}" - "${install_directory_default}" install_directory) - set(archive_install_directory ${arg_ARCHIVE_INSTALL_DIRECTORY}) - if (NOT archive_install_directory AND install_directory) - set(archive_install_directory "${install_directory}") - endif() - endif() - - if(arg_STATIC OR NOT BUILD_SHARED_LIBS) - add_library("${target}" STATIC) - else() - add_library("${target}" MODULE) - 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() - qt_internal_apply_win_prefix_and_suffix("${target}") - endif() - - qt_set_common_target_properties(${target}) - qt_set_target_info_properties(${target} ${ARGN} TARGET_VERSION "${arg_VERSION}") - - # 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}") - _qt_internal_apply_strict_cpp("${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_TYPE "${plugin_type_escaped}" - # Save the non-sanitized plugin type values for qmake consumption via .pri files. - QT_QMAKE_PLUGIN_TYPE "${arg_TYPE}" - QT_PLUGIN_CLASS_NAME "${plugin_class_name}") - qt_handle_multi_config_output_dirs("${target}") - - qt_internal_library_deprecation_level(deprecation_define) - - qt_autogen_tools_initial_setup(${target}) - - set(static_plugin_define "") - if (arg_STATIC OR NOT QT_BUILD_SHARED_LIBS) - set(static_plugin_define "QT_STATICPLUGIN") - endif() - - # Save the Qt module in the plug-in's properties - if(NOT plugin_type_escaped STREQUAL "qml_plugin") - qt_get_module_for_plugin("${target}" "${plugin_type_escaped}") - get_target_property(qt_module "${target}" QT_MODULE) - set(plugin_install_package_suffix "${qt_module}") - endif() - - # Add the plug-in to the list of plug-ins of this module - if(TARGET "${qt_module}") - set_property(TARGET "${qt_module}" APPEND PROPERTY QT_PLUGINS "${target}") - endif() - - # Change the configuration file install location for qml plugins into the Qml package location. - if(plugin_type_escaped STREQUAL "qml_plugin" AND TARGET "${INSTALL_CMAKE_NAMESPACE}::Qml") - set(plugin_install_package_suffix "Qml/QmlPlugins") - endif() - - # Save the install package suffix as a property, so that the Dependencies file is placed - # in the current location. - if(plugin_install_package_suffix) - set_target_properties("${target}" PROPERTIES - _qt_plugin_install_package_suffix "${plugin_install_package_suffix}") - endif() - - set(_default_plugin 1) - if (DEFINED arg_DEFAULT_IF) - if (NOT ${arg_DEFAULT_IF}) - set(_default_plugin 0) - endif() - endif() - - set_property(TARGET "${target}" PROPERTY QT_DEFAULT_PLUGIN "${_default_plugin}") - set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_PLUGIN_CLASS_NAME;QT_PLUGIN_TYPE;QT_MODULE;QT_DEFAULT_PLUGIN") - - set(private_includes - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}" - # For the syncqt headers - "$<BUILD_INTERFACE:${module_repo_include_dir}>" - ${arg_INCLUDE_DIRECTORIES} - ) - - set(public_includes - ${arg_PUBLIC_INCLUDE_DIRECTORIES} - ) - - qt_extend_target("${target}" - SOURCES ${arg_SOURCES} - INCLUDE_DIRECTORIES - ${private_includes} - PUBLIC_INCLUDE_DIRECTORIES - ${public_includes} - LIBRARIES ${arg_LIBRARIES} Qt::PlatformPluginInternal - PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} - DEFINES - ${arg_DEFINES} - QT_DEPRECATED_WARNINGS - "${deprecation_define}" - "${static_plugin_define}" - QT_PLUGIN - PUBLIC_DEFINES - QT_${module_define}_LIB - ${arg_PUBLIC_DEFINES} - FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} - DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}" - DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}" - DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}" - DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}" - 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} - ) - if(NOT ${arg_EXCEPTIONS}) - qt_internal_set_no_exceptions_flags("${target}") - endif() - - - set(qt_libs_private "") - qt_internal_get_qt_all_known_modules(known_modules) - foreach(it ${known_modules}) - list(FIND arg_LIBRARIES "Qt::${it}Private" pos) - if(pos GREATER -1) - list(APPEND qt_libs_private "Qt::${it}Private") - endif() - endforeach() - - qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}") - qt_generate_plugin_pri_file("${target}" pri_file) - - if (NOT arg_SKIP_INSTALL) - # Handle creation of cmake files for consumers of find_package(). - # If we are part of a Qt module, the plugin cmake files are installed as part of that - # module. - # For qml plugins, they are all installed into the QtQml package location for automatic - # discovery. - if(plugin_install_package_suffix) - set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${plugin_install_package_suffix}") - else() - set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}") - endif() - - 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_package_config_file( - "${QT_CMAKE_DIR}/QtPluginConfig.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(FILES - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" - DESTINATION "${config_install_dir}" - COMPONENT Devel - ) - qt_install(FILES - "${pri_file}" - DESTINATION "${INSTALL_MKSPECSDIR}/modules" - ) - - # Make the export name of plugins be consistent with modules, so that - # 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} - RUNTIME DESTINATION "${install_directory}" - LIBRARY DESTINATION "${install_directory}" - ARCHIVE DESTINATION "${archive_install_directory}" - ) - qt_install(EXPORT ${export_name} - NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: - DESTINATION "${config_install_dir}" - ) - qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH) - endif() - - 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() - - qt_internal_add_linker_version_script(${target}) - qt_add_list_file_finalizer(qt_finalize_plugin ${target} "${install_directory}") -endfunction() - -function(qt_finalize_plugin target install_directory) - # Generate .prl files for plugins of static Qt builds. - if(NOT BUILD_SHARED_LIBS) - qt_generate_prl_file(${target} "${install_directory}") - endif() -endfunction() - -function(qt_install_qml_files target) - - qt_parse_all_arguments(arg "qt_install_qml_files" - "" "" "FILES" ${ARGN} - ) - - if (NOT arg_FILES) - message(FATAL_ERROR "No files specified for qt_install_qml_files. Please specify them using the FILES parameter.") - endif() - - get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH) - if (NOT target_path) - message(FATAL_ERROR "Target ${target} is not a qml module.") - endif() - - qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${target_path}") - qt_copy_or_install(FILES ${arg_FILES} - DESTINATION ${qml_module_install_dir} - ) - -endfunction() - - -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) - if(is_imported) - return() - endif() - - qt_parse_all_arguments(arg "qt_add_resource" "" "PREFIX;LANG;BASE" "FILES" ${ARGN}) - - QT6_PROCESS_RESOURCE(${target} ${resourceName} - PREFIX "${arg_PREFIX}" - LANG "${arg_LANG}" - BASE "${arg_BASE}" - FILES ${arg_FILES} - OUTPUT_TARGETS out_targets - ) - - if (out_targets) - qt_install(TARGETS ${out_targets} - EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets" - DESTINATION ${INSTALL_LIBDIR} - ) - foreach(out_target ${out_targets}) - get_target_property(resource_name ${out_target} QT_RESOURCE_NAME) - if(NOT resource_name) - continue() - endif() - if(QT_WILL_INSTALL) - # Compute the install location of the rcc object file. - # This is the relative path below the install destination (install_prefix/lib). - # See CMake's computeInstallObjectDir function. - set(object_file_name "qrc_${resource_name}.cpp${CMAKE_CXX_OUTPUT_EXTENSION}") - qt_path_join(rcc_object_file_path - "objects-$<CONFIG>" ${out_target} .rcc "${object_file_name}") - else() - # In a non-prefix build we use the object file paths right away. - set(rcc_object_file_path $<TARGET_OBJECTS:$<TARGET_NAME:${out_target}>>) - endif() - set_property(TARGET ${target} APPEND PROPERTY QT_RCC_OBJECTS "${rcc_object_file_path}") - - # Make sure that the target cpp files are compiled with the regular Qt internal compile - # flags, needed for building iOS apps with qmake where bitcode is involved. - target_link_libraries("${out_target}" PRIVATE Qt::PlatformModuleInternal) - endforeach() - endif() - -endfunction() # Collection of qt_add_executable arguments so they can be shared across qt_add_executable # and qt_add_test_helper. @@ -4070,2153 +417,37 @@ 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 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 "${QT_BUILD_DIR}/${INSTALL_BINDIR}") - endif() - - get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" - ABSOLUTE BASE_DIR "${QT_BUILD_DIR}") - - if ("x${arg_INSTALL_DIRECTORY}" STREQUAL "x") - set(arg_INSTALL_DIRECTORY "${INSTALL_BINDIR}") - endif() - - 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() - - if (arg_VERSION) - - if(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+") - # nothing to do - elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") - set(arg_VERSION "${arg_VERSION}.0") - elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+") - set(arg_VERSION "${arg_VERSION}.0.0") - elseif (arg_VERSION MATCHES "[0-9]+") - set(arg_VERSION "${arg_VERSION}.0.0.0") - else() - message(FATAL_ERROR "Invalid version format") - endif() - endif() - - if(arg_DELAY_TARGET_INFO) - # Delay the setting of target info properties if requested. Needed for scope finalization - # of Qt apps. - set_target_properties("${name}" PROPERTIES - QT_DELAYED_TARGET_VERSION "${arg_VERSION}" - QT_DELAYED_TARGET_PRODUCT "${arg_TARGET_PRODUCT}" - QT_DELAYED_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" - QT_DELAYED_TARGET_COMPANY "${arg_TARGET_COMPANY}" - QT_DELAYED_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}" - ) - else() - if("${arg_TARGET_DESCRIPTION}" STREQUAL "") - set(arg_TARGET_DESCRIPTION "Qt ${name}") - endif() - qt_set_target_info_properties(${name} ${ARGN} - TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" - TARGET_VERSION "${arg_VERSION}") - endif() - - - if (WIN32 AND NOT arg_DELAY_RC) - qt6_generate_win32_rc_file(${name}) - endif() - - qt_set_common_target_properties(${name}) - 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) - set(extra_libraries "Qt::Core") - endif() - - set(private_includes - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}" - ${arg_INCLUDE_DIRECTORIES} - ) - - qt_extend_target("${name}" - SOURCES ${arg_SOURCES} - INCLUDE_DIRECTORIES ${private_includes} - DEFINES ${arg_DEFINES} - LIBRARIES ${arg_LIBRARIES} Qt::PlatformCommonInternal - PUBLIC_LIBRARIES ${extra_libraries} ${arg_PUBLIC_LIBRARIES} - DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}" - DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}" - DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}" - DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}" - COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} - LINK_OPTIONS ${arg_LINK_OPTIONS} - MOC_OPTIONS ${arg_MOC_OPTIONS} - ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} - DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} - ) - 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}" - ) - if(NOT ${arg_EXCEPTIONS}) - qt_internal_set_no_exceptions_flags("${name}") - endif() - - # Check if target needs to be excluded from all target. Also affects qt_install. - # Set by qt_exclude_tool_directories_from_default_target. - set(exclude_from_all FALSE) - if(__qt_exclude_tool_directories) - foreach(absolute_dir ${__qt_exclude_tool_directories}) - string(FIND "${CMAKE_CURRENT_SOURCE_DIR}" "${absolute_dir}" dir_starting_pos) - if(dir_starting_pos EQUAL 0) - set(exclude_from_all TRUE) - set_target_properties("${name}" PROPERTIES EXCLUDE_FROM_ALL TRUE) - break() - endif() - endforeach() - endif() - - if(NOT arg_NO_INSTALL) - set(additional_install_args "") - if(exclude_from_all) - list(APPEND additional_install_args EXCLUDE_FROM_ALL COMPONENT "ExcludedExecutables") - endif() - - qt_get_cmake_configurations(cmake_configs) - foreach(cmake_config ${cmake_configs}) - qt_get_install_target_default_args( - OUT_VAR install_targets_default_args - CMAKE_CONFIG "${cmake_config}" - ALL_CMAKE_CONFIGS "${cmake_configs}" - RUNTIME "${arg_INSTALL_DIRECTORY}" - LIBRARY "${arg_INSTALL_DIRECTORY}" - BUNDLE "${arg_INSTALL_DIRECTORY}") - qt_install(TARGETS "${name}" - ${additional_install_args} # Needs to be before the DESTINATIONS. - CONFIGURATIONS ${cmake_config} - ${install_targets_default_args}) - endforeach() - 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} - ) - - if(NOT arg_OUTPUT_DIRECTORY) - set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - endif() - - qt_add_executable(${target} - NO_INSTALL # we don't install benchmarks - OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # 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} - ) - - if(NOT arg_OUTPUT_DIRECTORY) - set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - endif() - - qt_add_executable(${target} - NO_INSTALL # we don't install benchmarks - OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # avoid polluting bin directory - ${exec_args} - ) - -endfunction() - - -# This function creates a CMake test target with the specified name for use with CTest. -function(qt_add_test name) - qt_parse_all_arguments(arg "qt_add_test" - "RUN_SERIAL;EXCEPTIONS;GUI;QMLTEST;CATCH;LOWDPI" - "OUTPUT_DIRECTORY;WORKING_DIRECTORY;TIMEOUT;VERSION" - "QML_IMPORTPATH;TESTDATA;${__default_private_args};${__default_public_args}" ${ARGN} - ) - - if (NOT arg_OUTPUT_DIRECTORY) - set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") - endif() - - if (${arg_EXCEPTIONS}) - set(exceptions_text "EXCEPTIONS") - endif() - - if (${arg_GUI}) - set(gui_text "GUI") - endif() - - if (arg_VERSION) - set(version_arg VERSION "${arg_VERSION}") - endif() - - # Handle cases where we have a qml test without source files - if (arg_SOURCES) - set(private_includes - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}" - "$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>" - ${arg_INCLUDE_DIRECTORIES} - ) - - qt_add_executable("${name}" - ${exceptions_text} - ${gui_text} - ${version_arg} - NO_INSTALL - OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" - SOURCES "${arg_SOURCES}" - INCLUDE_DIRECTORIES - ${private_includes} - DEFINES - QT_TESTCASE_BUILDDIR="${CMAKE_CURRENT_BINARY_DIR}" - QT_TESTCASE_SOURCEDIR="${CMAKE_CURRENT_SOURCE_DIR}" - ${arg_DEFINES} - PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Test ${arg_PUBLIC_LIBRARIES} - LIBRARIES ${arg_LIBRARIES} - COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} - LINK_OPTIONS ${arg_LINK_OPTIONS} - MOC_OPTIONS ${arg_MOC_OPTIONS} - ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} - DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} - ) - - # Tests should not be bundles on macOS even if arg_GUI is true, because some tests make - # assumptions about the location of helper processes, and those paths would be different - # if a test is built as a bundle. - set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE FALSE) - # The same goes for WIN32_EXECUTABLE, but because it will detach from the console window - # and not print anything. - set_property(TARGET "${name}" PROPERTY WIN32_EXECUTABLE FALSE) - - # QMLTest specifics - - qt_extend_target("${name}" CONDITION arg_QMLTEST - PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest - ) - - qt_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID - DEFINES - QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" - ) - - qt_extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID - DEFINES - QUICK_TEST_SOURCE_DIR=":/" - ) - endif() - - foreach(path IN LISTS arg_QML_IMPORTPATH) - list(APPEND extra_test_args "-import" "${path}") - endforeach() - - # Generate a label in the form tests/auto/foo/bar/tst_baz - # and use it also for XML output - file(RELATIVE_PATH label "${PROJECT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}") - - if (arg_LOWDPI) - target_compile_definitions("${name}" PUBLIC TESTCASE_LOWDPI) - if (MACOS) - set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE_INFO_PLIST "${QT_MKSPECS_DIR}/macx-clang/Info.plist.disable_highdpi") - set_property(TARGET "${name}" PROPERTY PROPERTY MACOSX_BUNDLE TRUE) - endif() - endif() - - if (ANDROID) - qt_android_add_test("${name}") - else() - 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}") - elseif(arg_OUTPUT_DIRECTORY) - set(test_working_dir "${arg_OUTPUT_DIRECTORY}") - else() - set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}") - endif() - set(test_executable "${name}") - endif() - - if (NOT arg_CATCH) - list(APPEND test_outputs "-o" "${name}.xml,xml" "-o" "-,txt") - endif() - - add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args} ${test_outputs} 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() - - # Add a ${target}/check makefile target, to more easily test one test. - if(TEST "${name}") - add_custom_target("${name}_check" - VERBATIM - COMMENT "Running ${CMAKE_CTEST_COMMAND} -V -R \"^${name}$\"" - COMMAND "${CMAKE_CTEST_COMMAND}" -V -R "^${name}$" - ) - if(TARGET "${name}") - add_dependencies("${name}_check" "${name}") - endif() - endif() - - # Get path to <qt_relocatable_install_prefix>/bin, as well as CMAKE_INSTALL_PREFIX/bin, then - # prepend them to the PATH environment variable. - # It's needed on Windows to find the shared libraries and plugins. - # qt_relocatable_install_prefix is dynamically computed from the location of where the Qt CMake - # package is found. - # The regular CMAKE_INSTALL_PREFIX can be different for example when building standalone tests. - # Any given CMAKE_INSTALL_PREFIX takes priority over qt_relocatable_install_prefix for the - # PATH environment variable. - set(install_prefixes "${CMAKE_INSTALL_PREFIX}") - if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX) - list(APPEND install_prefixes "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}") - endif() - - set(test_env_path "PATH=${CMAKE_CURRENT_BINARY_DIR}") - foreach(install_prefix ${install_prefixes}) - set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}${install_prefix}/${INSTALL_BINDIR}") - endforeach() - set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}$ENV{PATH}") - string(REPLACE ";" "\;" test_env_path "${test_env_path}") - set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "${test_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) - foreach(install_prefix ${install_prefixes}) - list(APPEND plugin_paths "${install_prefix}/${INSTALL_PLUGINSDIR}") - endforeach() - endif() - - #TODO: Collect all paths from known repositories when performing a super - # build. - list(APPEND plugin_paths "${PROJECT_BINARY_DIR}/${INSTALL_PLUGINSDIR}") - list(JOIN plugin_paths "${QT_PATH_SEPARATOR}" plugin_paths_joined) - set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_PLUGIN_PATH=${plugin_paths_joined}") - - if(ANDROID OR IOS OR WINRT) - set(builtin_testdata TRUE) - endif() - - if(builtin_testdata) - # Safe guard against qml only tests, no source files == no target - if (TARGET "${name}") - target_compile_definitions("${name}" PRIVATE BUILTIN_TESTDATA) - - foreach(testdata IN LISTS arg_TESTDATA) - list(APPEND builtin_files ${testdata}) - endforeach() - - set(blacklist_path "BLACKLIST") - if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}") - list(APPEND builtin_files ${blacklist_path}) - endif() - - list(REMOVE_DUPLICATES builtin_files) - - # Skip Qt quick compiler when embedding test resources - foreach(file IN LISTS builtin_files) - set_source_files_properties(${file} - PROPERTIES QT_SKIP_QUICKCOMPILER TRUE - ) - endforeach() - - if (builtin_files) - qt_add_resource(${name} "${name}_testdata_builtin" - PREFIX "/" - FILES ${builtin_files} - BASE ${CMAKE_CURRENT_SOURCE_DIR}) - endif() - endif() - else() - # Install test data - file(RELATIVE_PATH relative_path_to_test_project - "${QT_TOP_LEVEL_SOURCE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}") - qt_path_join(testdata_install_dir ${QT_INSTALL_DIR} - "${relative_path_to_test_project}") - foreach(testdata IN LISTS arg_TESTDATA) - set(testdata "${CMAKE_CURRENT_SOURCE_DIR}/${testdata}") - if (IS_DIRECTORY "${testdata}") - qt_install( - DIRECTORY "${testdata}" - DESTINATION "${testdata_install_dir}") - else() - qt_install( - FILES "${testdata}" - DESTINATION "${testdata_install_dir}") - endif() - endforeach() - endif() - -endfunction() - - -# This function creates an executable for use as a helper program with tests. Some -# 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(qt_add_test_helper name) - - set(qt_add_test_helper_optional_args - "OVERRIDE_OUTPUT_DIRECTORY" - ) - - 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}" - ${qt_add_test_helper_optional_args} - ALL_ARGS - ${qt_add_test_helper_optional_args} - ${__qt_add_executable_optional_args} - ${__qt_add_executable_single_args} - ${__qt_add_executable_multi_args} - ARGS - ${ARGV} - ) - - set(extra_args_to_pass) - if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY) - set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..") - endif() - - qt_add_executable("${name}" NO_INSTALL ${extra_args_to_pass} ${forward_args}) -endfunction() - -# Sets QT_WILL_BUILD_TOOLS if tools will be built. -function(qt_check_if_tools_will_be_built) - if(QT_FORCE_FIND_TOOLS OR (CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)) - set(will_build_tools FALSE) - else() - set(will_build_tools TRUE) - endif() - set(QT_WILL_BUILD_TOOLS ${will_build_tools} CACHE INTERNAL "Are tools going to be built" FORCE) -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(qt_add_cmake_library target) - # Process arguments: - 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}" - ${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) - qt_internal_apply_win_prefix_and_suffix("${target}") - 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) - set_property(TARGET ${name} PROPERTY OBJC_VISIBILITY_PRESET default) - set_property(TARGET ${name} PROPERTY OBJCXX_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() - qt_internal_apply_win_prefix_and_suffix("${target}") - else() - add_library("${target}") - endif() - - if (NOT arg_ARCHIVE_INSTALL_DIRECTORY AND arg_INSTALL_DIRECTORY) - set(arg_ARCHIVE_INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}") - endif() - - 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 - ARCHIVE_INSTALL_DIRECTORY ${arg_ARCHIVE_INSTALL_DIRECTORY} - INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY} - ) - endif() - - if (arg_OUTPUT_DIRECTORY) - set_target_properties(${target} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} - RUNTIME_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} - LIBRARY_OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} - ) - 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} Qt::PlatformCommonInternal - 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} - ) - -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;INSTALL;SKIP_AUTOMOC" - "OUTPUT_DIRECTORY;QMAKE_LIB_NAME" - "${__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) - set_property(TARGET ${name} PROPERTY OBJC_VISIBILITY_PRESET default) - set_property(TARGET ${name} PROPERTY OBJCXX_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_INTERFACE) - qt_set_common_target_properties(${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}) - _qt_internal_apply_strict_cpp(${target}) - - if (ANDROID) - qt_android_apply_arch_suffix("${target}") - endif() - - qt_skip_warnings_are_errors_when_repo_unclean("${target}") - - 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_MODULE_SKIP_DEPENDS_INCLUDE TRUE - ) - qt_handle_multi_config_output_dirs("${target}") - - set_target_properties(${target} PROPERTIES - OUTPUT_NAME "${INSTALL_CMAKE_NAMESPACE}${target}" - ) - - if(NOT arg_SKIP_AUTOMOC) - qt_autogen_tools_initial_setup(${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_generate_3rdparty_lib_pri_file("${target}" "${arg_QMAKE_LIB_NAME}" pri_file) - if(pri_file) - qt_install(FILES "${pri_file}" DESTINATION "${INSTALL_MKSPECSDIR}/modules") - 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} Qt::PlatformModuleInternal - 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_INSTALL) - 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(FILES - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" - "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" - DESTINATION "${config_install_dir}" - COMPONENT Devel - ) - - qt_install(TARGETS ${target} - EXPORT "${export_name}" - RUNTIME DESTINATION ${INSTALL_BINDIR} - LIBRARY DESTINATION ${INSTALL_LIBDIR} - ARCHIVE DESTINATION ${INSTALL_LIBDIR} - ) - - 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_install_3rdparty_library_wrap_config_extra_file target) - if(TARGET "${target}") - set(use_bundled "ON") - else() - set(use_bundled "OFF") - endif() - - set(QT_USE_BUNDLED_${target} "${use_bundled}" CACHE BOOL "" FORCE) - set(extra_cmake_code "set(QT_USE_BUNDLED_${target} ${use_bundled} CACHE BOOL \"\" FORCE)") - configure_file( - "${QT_CMAKE_DIR}/QtFindWrapConfigExtra.cmake.in" - "${QT_CONFIG_BUILD_DIR}/${INSTALL_CMAKE_NAMESPACE}/FindWrap${target}ConfigExtra.cmake" - @ONLY - ) - - qt_install(FILES - "${QT_CONFIG_BUILD_DIR}/${INSTALL_CMAKE_NAMESPACE}/FindWrap${target}ConfigExtra.cmake" - DESTINATION "${QT_CONFIG_INSTALL_DIR}/${INSTALL_CMAKE_NAMESPACE}" - COMPONENT Devel - ) -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() - -# Returns the target name for the tool with the given name. -# -# In most cases, the target name is the same as the tool name. -# If the user specifies to build tools when cross-compiling, then the -# suffix "_native" is appended. -function(qt_get_tool_target_name out_var name) - if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - set(${out_var} ${name}_native PARENT_SCOPE) - else() - set(${out_var} ${name} PARENT_SCOPE) - endif() -endfunction() - -# Returns the tool name for a given tool target. -# This is the inverse of qt_get_tool_target_name. -function(qt_tool_target_to_name out_var target) - set(name ${target}) - if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - string(REGEX REPLACE "_native$" "" name ${target}) - endif() - set(${out_var} ${name} 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. -# -# We must pass this function a target name obtained from -# qt_get_tool_target_name like this: -# qt_get_tool_target_name(target_name my_tool) -# qt_add_tool(${target_name}) -# -function(qt_add_tool target_name) - qt_tool_target_to_name(name ${target_name}) - qt_parse_all_arguments(arg "qt_add_tool" "BOOTSTRAP;NO_QT;NO_INSTALL" - "TOOLS_TARGET;${__default_target_info_args}" - "${__default_private_args}" ${ARGN}) - - # Handle case when a tool does not belong to a module and it can't be built either (like - # during a cross-compile). - if(NOT arg_TOOLS_TARGET AND NOT QT_WILL_BUILD_TOOLS) - message(FATAL_ERROR "The tool \"${name}\" has not been assigned to a module via" - " TOOLS_TARGET (so it can't be found) and it can't be built" - " (QT_WILL_BUILD_TOOLS is ${QT_WILL_BUILD_TOOLS}).") - endif() - - if(CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING AND (name STREQUAL target_name)) - message(FATAL_ERROR - "qt_add_tool must be passed a target obtained from qt_get_tool_target_name.") - endif() - - set(full_name "${QT_CMAKE_EXPORT_NAMESPACE}::${name}") - set(imported_tool_target_found FALSE) - if(TARGET ${full_name}) - get_property(path TARGET ${full_name} PROPERTY LOCATION) - message(STATUS "Tool '${full_name}' was found at ${path}.") - set(imported_tool_target_found TRUE) - if(CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - return() - endif() - endif() - - if(arg_TOOLS_TARGET AND (NOT QT_WILL_BUILD_TOOLS OR QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - AND NOT imported_tool_target_found) - set(tools_package_name "Qt6${arg_TOOLS_TARGET}Tools") - message(STATUS "Searching for tool '${full_name}' in package ${tools_package_name}.") - - # Only search in path provided by QT_HOST_PATH. We need to do it with CMAKE_PREFIX_PATH - # instead of PATHS option, because any find_dependency call inside a Tools package would - # not get the proper prefix when using PATHS. - set(BACKUP_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) - set(CMAKE_PREFIX_PATH "${QT_HOST_PATH}") - - # Search both with sysroots prepended as well as in the host system. When cross compiling - # the mode_package might be set to ONLY only, and the Qt6 tools packages are actually - # in the host system. - set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH") - find_package( - ${tools_package_name} - ${PROJECT_VERSION} - NO_PACKAGE_ROOT_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_PACKAGE_REGISTRY - NO_CMAKE_SYSTEM_PATH - NO_CMAKE_SYSTEM_PACKAGE_REGISTRY) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}") - set(CMAKE_PREFIX_PATH "${BACKUP_CMAKE_PREFIX_PATH}") - - if(${${tools_package_name}_FOUND} AND TARGET ${full_name}) - # Even if the tool is already visible, make sure that our modules remain associated - # with the tools. - qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}") - get_property(path TARGET ${full_name} PROPERTY LOCATION) - message(STATUS "${full_name} was found at ${path} using package ${tools_package_name}.") - if (NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - return() - endif() - endif() - endif() - - if(NOT QT_WILL_BUILD_TOOLS) - message(FATAL_ERROR "The tool \"${full_name}\" was not found in the " - "${tools_package_name} package. " - "Package found: ${${tools_package_name}_FOUND}") - else() - if(QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) - message(STATUS "Tool '${target_name}' will be cross-built from source.") - else() - message(STATUS "Tool '${full_name}' will be built from source.") - endif() - endif() - - set(disable_autogen_tools "${arg_DISABLE_AUTOGEN_TOOLS}") - if (arg_NO_QT) - # FIXME: Remove NO_QT again once qmake can use a "normal" Qt! - if (arg_BOOTSTRAP) - message(FATAL_ERROR "Tool can not be NO_QT and BOOTSTRAP at the same time!") - endif() - set(corelib "") - else() - if (arg_BOOTSTRAP) - set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Bootstrap) - list(APPEND disable_autogen_tools "uic" "moc" "rcc") - else() - set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Core) - endif() - endif() - - set(bootstrap "") - if(arg_BOOTSTRAP) - set(bootstrap BOOTSTRAP) - endif() - - set(no_qt "") - if(arg_NO_QT) - set(no_qt NO_QT) - endif() - - qt_add_executable("${target_name}" OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" - ${bootstrap} - ${no_qt} - NO_INSTALL - SOURCES ${arg_SOURCES} - INCLUDE_DIRECTORIES - ${arg_INCLUDE_DIRECTORIES} - DEFINES - QT_USE_QSTRINGBUILDER - ${arg_DEFINES} - PUBLIC_LIBRARIES ${corelib} - LIBRARIES ${arg_LIBRARIES} Qt::PlatformToolInternal - COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} - LINK_OPTIONS ${arg_LINK_OPTIONS} - MOC_OPTIONS ${arg_MOC_OPTIONS} - DISABLE_AUTOGEN_TOOLS ${disable_autogen_tools} - TARGET_VERSION "${arg_TARGET_VERSION}" - TARGET_PRODUCT "${arg_TARGET_PRODUCT}" - TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" - TARGET_COMPANY "${arg_TARGET_COMPANY}" - TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}" - ) - qt_internal_add_target_aliases("${target_name}") - _qt_internal_apply_strict_cpp("${target_name}") - - if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.19.0" AND QT_FEATURE_debug_and_release) - set_property(TARGET "${target_name}" - PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:${QT_MULTI_CONFIG_FIRST_CONFIG}>>") - endif() - - if (NOT target_name STREQUAL name) - set_target_properties(${target_name} PROPERTIES - OUTPUT_NAME ${name} - EXPORT_NAME ${name} - ) - endif() - - if(TARGET host_tools) - add_dependencies(host_tools "${target_name}") - if(bootstrap OR no_qt) - add_dependencies(bootstrap_tools "${target_name}") - endif() - endif() - - # 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("${target_name}" PROPERTIES - RUNTIME_OUTPUT_DIRECTORY_${tool_cmake_configuration} "${QT_BUILD_DIR}/${INSTALL_BINDIR}" - ) - - if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET) - # Assign a tool to an export set, and mark the module to which the tool belongs. - qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}") - - # Also append the tool to the module list. - qt_internal_append_known_module_tool("${arg_TOOLS_TARGET}" "${target_name}") - - qt_get_cmake_configurations(cmake_configs) - - set(install_initial_call_args - EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_TOOLS_TARGET}ToolsTargets") - - foreach(cmake_config ${cmake_configs}) - qt_get_install_target_default_args( - OUT_VAR install_targets_default_args - CMAKE_CONFIG "${cmake_config}" - ALL_CMAKE_CONFIGS "${cmake_configs}") - qt_install(TARGETS "${target_name}" - ${install_initial_call_args} - CONFIGURATIONS ${cmake_config} - ${install_targets_default_args}) - unset(install_initial_call_args) - endforeach() - - qt_apply_rpaths(TARGET "${target_name}" INSTALL_PATH "${INSTALL_BINDIR}" RELATIVE_RPATH) - - endif() - - if(QT_FEATURE_separate_debug_info AND (UNIX OR MINGW)) - qt_enable_separate_debug_info(${target_name} ${INSTALL_BINDIR}) - endif() -endfunction() - -function(qt_create_tracepoints name tracePointsFile) - #### TODO - string(TOLOWER "${name}" name) - - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qt${name}_tracepoints_p.h" CONTENT - "#include <private/qtrace_p.h>") -endfunction() - -# Handle files that need special SIMD-related flags. -# This creates an object library and makes target link -# to it (privately). -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 "qt_add_simd_part needs a SIMD type to be set.") - endif() - - set(condition "QT_FEATURE_${arg_SIMD}") - string(TOUPPER "QT_CFLAGS_${arg_SIMD}" simd_flags_var_name) - set(simd_flags_expanded "") - - # As per mkspecs/features/simd.prf, the arch_haswell SIMD compiler is enabled when - # qmake's CONFIG contains "avx2", which maps to CMake's QT_FEATURE_avx2. - # The list of dependencies 'avx2 bmi bmi2 f16c fma lzcnt popcnt' only influences whether - # the 'arch_haswell' SIMD flags need to be added explicitly to the compiler invocation. - # If the compiler adds them implicitly, they must be present in qmake's QT_CPU_FEATURES as - # detected by the architecture test, and thus they are present in TEST_subarch_result. - if("${arg_SIMD}" STREQUAL arch_haswell) - set(condition "QT_FEATURE_avx2") - - # Use avx2 flags as per simd.prf, if there are no specific arch_haswell flags specified in - # QtCompilerOptimization.cmake. - if("${simd_flags_var_name}" STREQUAL "") - set(simd_flags_var_name "QT_CFLAGS_AVX2") - endif() - - # The avx512 profiles dependencies DO influence if the SIMD compiler will be executed, - # so each of the profile dependencies have to be in qmake's CONFIG for the compiler to be - # enabled, which means the CMake features have to evaluate to true. - # Also the profile flags to be used are a combination of arch_haswell, avx512f and each of the - # dependencies. - elseif("${arg_SIMD}" STREQUAL avx512common) - set(condition "QT_FEATURE_avx512cd") - list(APPEND simd_flags_expanded "${QT_CFLAGS_ARCH_HASWELL}") - list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512F}") - list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512CD}") - list(REMOVE_DUPLICATES simd_flags_expanded) - elseif("${arg_SIMD}" STREQUAL avx512core) - set(condition "QT_FEATURE_avx512cd AND QT_FEATURE_avx512bw AND QT_FEATURE_avx512dq AND QT_FEATURE_avx512vl") - list(APPEND simd_flags_expanded "${QT_CFLAGS_ARCH_HASWELL}") - list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512F}") - list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512CD}") - list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512BW}") - list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512DQ}") - list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512VL}") - list(REMOVE_DUPLICATES simd_flags_expanded) - endif() - - set(name "${arg_NAME}") - if("x${name}" STREQUAL x) - set(name "${target}_simd_${arg_SIMD}") - endif() - - qt_evaluate_config_expression(result ${condition}) - if(${result}) - if(QT_CMAKE_DEBUG_EXTEND_TARGET) - message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Evaluated") - endif() - - if(NOT simd_flags_expanded) - set(simd_flags_expanded "${${simd_flags_var_name}}") - endif() - - foreach(source IN LISTS arg_SOURCES) - set_property(SOURCE "${source}" APPEND - PROPERTY COMPILE_OPTIONS - ${simd_flags_expanded} - ${arg_COMPILE_FLAGS} - ) - endforeach() - set_source_files_properties(${arg_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE) - target_sources(${target} PRIVATE ${arg_SOURCES}) - else() - if(QT_CMAKE_DEBUG_EXTEND_TARGET) - message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped") - endif() - endif() -endfunction() - -# From Qt6CoreMacros -# Function used to create the names of output files preserving relative dirs -function(qt_make_output_file infile prefix suffix source_dir binary_dir result) - get_filename_component(outfilename "${infile}" NAME_WE) - - set(base_dir "${source_dir}") - string(FIND "${infile}" "${binary_dir}/" in_binary) - if (in_binary EQUAL 0) - set(base_dir "${binary_dir}") - endif() - - get_filename_component(abs_infile "${infile}" ABSOLUTE BASE_DIR "${base_dir}") - file(RELATIVE_PATH rel_infile "${base_dir}" "${abs_infile}") - string(REPLACE "../" "__/" mapped_infile "${rel_infile}") - - get_filename_component(abs_mapped_infile "${mapped_infile}" ABSOLUTE BASE_DIR "${binary_dir}") - get_filename_component(outpath "${abs_mapped_infile}" PATH) - - file(MAKE_DIRECTORY "${outpath}") - set("${result}" "${outpath}/${prefix}${outfilename}${suffix}" PARENT_SCOPE) -endfunction() - - -# Complete manual moc invocation with full control. -# Use AUTOMOC whenever possible. -function(qt_manual_moc result) - 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) - list(APPEND moc_files "${outfile}") - - 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}" ${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() - - -# helper to set up a qdbusxml2cpp rule -function(qt_create_qdbusxml2cpp_command target infile) - qt_parse_all_arguments(arg "qt_create_qdbusxml2cpp_command" "ADAPTOR;INTERFACE" "BASENAME" "FLAGS" ${ARGN}) - if((arg_ADAPTOR AND arg_INTERFACE) OR (NOT arg_ADAPTOR AND NOT arg_INTERFACE)) - message(FATAL_ERROR "qt_create_dbusxml2cpp_command needs either ADAPTOR or INTERFACE.") - endif() - - set(option "-a") - set(type "adaptor") - if (arg_INTERFACE) - set(option "-p") - set(type "interface") - endif() - - if ("${arg_BASENAME}" STREQUAL "") - get_filename_component(file_dir "${infile}" DIRECTORY) - get_filename_component(file_name "${infile}" NAME_WLE) - get_filename_component(file_ext "${infile}" LAST_EXT) - - if("${file_ext}" STREQUAL ".xml") - else() - message(FATAL_ERROR "DBUS ${type} input file is not xml.") - endif() - - # use last part of io.qt.something.xml! - get_filename_component(file_ext "${file_name}" LAST_EXT) - if("x${file_ext}" STREQUAL "x") - else() - string(SUBSTRING "${file_ext}" 1 -1 file_name) # cut of leading '.' - endif() - - string(TOLOWER "${file_name}" file_name) - set(file_name "${file_name}_${type}") - else() - set(file_name ${arg_BASENAME}) - endif() - - # Use absolute file path for the source file and set the current working directory to the - # current binary directory, because setting an absolute path for the header:source combo option - # does not work. Splitting on ":" breaks inside the dbus tool when running on Windows - # due to ":" being contained in the drive path (e.g C:\foo.h:C:\foo.cpp). - get_filename_component(absolute_in_file_path "${infile}" ABSOLUTE) - - set(header_file "${file_name}.h") - set(source_file "${file_name}.cpp") - - 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}" ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - VERBATIM) - - target_sources("${target}" PRIVATE "${header_file}" "${source_file}") -endfunction() - -function(qt_compute_injection_forwarding_header target) - qt_parse_all_arguments(arg "qt_compute_injection_forwarding_header" - "PRIVATE" "SOURCE;OUT_VAR" "" ${ARGN}) - qt_internal_module_info(module "${target}") - get_filename_component(file_name "${arg_SOURCE}" NAME) - - set(source_absolute_path "${CMAKE_CURRENT_BINARY_DIR}/${arg_SOURCE}") - file(RELATIVE_PATH relpath "${PROJECT_BINARY_DIR}" "${source_absolute_path}") - - if (arg_PRIVATE) - set(fwd "${PROJECT_VERSION}/${module}/private/${file_name}") - else() - set(fwd "${file_name}") - endif() - - string(APPEND ${arg_OUT_VAR} " ${relpath}:${fwd}") - set(${arg_OUT_VAR} ${${arg_OUT_VAR}} PARENT_SCOPE) -endfunction() - - -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 "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}) - - # If a target is not built (which can happen for tools when crosscompiling, we shouldn't try - # to generate docs. - if(NOT TARGET "${target}") - return() - endif() - - if (NOT QT_SUPERBUILD OR QT_WILL_INSTALL) - set(qdoc_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qdoc") - set(qtattributionsscanner_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qtattributionsscanner") - set(qhelpgenerator_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qhelpgenerator") - else() - set(qdoc_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qdoc") - set(qtattributionsscanner_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qtattributionsscanner") - set(qhelpgenerator_bin "${QT_BUILD_INTERNALS_RELOCATABLE_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 "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}/${doc_target}") - set(index_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}") - else() - set(qdoc_output_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}") - set(index_dir "${QT_BUILD_INTERNALS_RELOCATABLE_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_WILL_INSTALL) - set(qt_install_docs_env "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}") - elseif (QT_SUPERBUILD) - set(qt_install_docs_env "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}") - else() - set(qt_install_docs_env "${QT_BUILD_INTERNALS_RELOCATABLE_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_custom_target(docs_${target}) - add_dependencies(docs_${target} html_docs_${target}) - add_dependencies(docs_${target} 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_target_name} 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() - -# This function recursively walks transitive link libraries of the given target -# and promotes those targets to be IMPORTED_GLOBAL if they are not. -# -# This is required for .prl file generation in top-level builds, to make sure that imported 3rd -# party library targets in any repo are made global, so there are no scoping issues. -# -# Only works if called from qt_find_package(), because the promotion needs to happen in the same -# directory scope where the imported target is first created. -# -# Uses qt_internal_walk_libs. -function(qt_find_package_promote_targets_to_global_scope target) - qt_internal_walk_libs("${target}" _discared_out_var - "qt_find_package_targets_dict" "promote_global") -endfunction() - -macro(qt_find_package) - # Get the target names we expect to be provided by the package. - set(options CONFIG NO_MODULE MODULE REQUIRED) - set(oneValueArgs MODULE_NAME QMAKE_LIB) - set(multiValueArgs PROVIDED_TARGETS COMPONENTS) - cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # If some Qt internal project calls qt_find_package(WrapFreeType), but WrapFreeType was already - # found as part of a find_dependency() call from a ModuleDependencies.cmake file (or similar), - # and the provided target is also found, that means this might have been an unnecessary - # qt_find_package() call, because the dependency was already found via some other transitive - # dependency. Return early, so that CMake doesn't fail wiht an error with trying to promote the - # targets to be global. This behavior is not enabled by default, because there are cases - # when a regular find_package() (non qt_) can find a package (Freetype -> PNG), and a subsequent - # qt_find_package(PNG PROVIDED_TARGET PNG::PNG) still needs to succeed and register the provided - # targets. To enable the debugging behavior, set QT_DEBUG_QT_FIND_PACKAGE to 1. - set(_qt_find_package_skip_find_package FALSE) - if(QT_DEBUG_QT_FIND_PACKAGE AND ${ARGV0}_FOUND AND arg_PROVIDED_TARGETS) - set(_qt_find_package_skip_find_package TRUE) - foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS}) - if(NOT TARGET ${qt_find_package_target_name}) - set(_qt_find_package_skip_find_package FALSE) - endif() - endforeach() - - if(_qt_find_package_skip_find_package) - message(AUTHOR_WARNING "qt_find_package(${ARGV0}) called even though the package " - "was already found. Consider removing the call.") - endif() - endif() - - # Get the version if specified. - set(package_version "") - if(${ARGC} GREATER_EQUAL 2) - if(${ARGV1} MATCHES "^[0-9\.]+$") - set(package_version "${ARGV1}") - endif() - endif() - - if(arg_COMPONENTS) - # Re-append components to forward them. - list(APPEND arg_UNPARSED_ARGUMENTS "COMPONENTS;${arg_COMPONENTS}") - endif() - - # Don't look for packages in PATH if requested to. - if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH) - set(_qt_find_package_use_system_env_backup "${CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH}") - set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH "OFF") - endif() - - if(NOT (arg_CONFIG OR arg_NO_MODULE OR arg_MODULE) AND NOT _qt_find_package_skip_find_package) - # Try to find a config package first in quiet mode - set(config_package_arg ${arg_UNPARSED_ARGUMENTS}) - list(APPEND config_package_arg "CONFIG;QUIET") - find_package(${config_package_arg}) - - # Double check that in config mode the targets become visible. Sometimes - # only the module mode creates the targets. For example with vcpkg, the sqlite - # package provides sqlite3-config.cmake, which offers multi-config targets but - # in their own way. CMake has FindSQLite3.cmake and with the original - # qt_find_package(SQLite3) call it is our intention to use the cmake package - # in module mode. - if (${ARGV0}_FOUND AND arg_PROVIDED_TARGETS) - unset(any_target_found) - foreach(expected_target ${arg_PROVIDED_TARGETS}) - if (TARGET ${expected_target}) - set(any_target_found TRUE) - break() - endif() - endforeach() - if(NOT any_target_found) - unset(${ARGV0}_FOUND) - endif() - endif() - endif() - - # Ensure the options are back in the original unparsed arguments - foreach(opt IN LISTS options) - if(arg_${opt}) - list(APPEND arg_UNPARSED_ARGUMENTS ${opt}) - endif() - endforeach() - - if (NOT ${ARGV0}_FOUND AND NOT _qt_find_package_skip_find_package) - # Unset the NOTFOUND ${package}_DIR var that might have been set by the previous - # find_package call, to get rid of "not found" messagees in the feature summary - # if the package is found by the next find_package call. - if(DEFINED CACHE{${ARGV0}_DIR} AND NOT ${ARGV0}_DIR) - unset(${ARGV0}_DIR CACHE) - endif() - - # Call original function without our custom arguments. - find_package(${arg_UNPARSED_ARGUMENTS}) - endif() - - if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH) - if("${_qt_find_package_use_system_env_backup}" STREQUAL "") - unset(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH) - else() - set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH "${_qt_find_package_use_system_env_backup}") - endif() - endif() - - if(${ARGV0}_FOUND AND arg_PROVIDED_TARGETS AND NOT _qt_find_package_skip_find_package) - # If package was found, associate each target with its package name. This will be used - # later when creating Config files for Qt libraries, to generate correct find_dependency() - # calls. Also make the provided targets global, so that the properties can be read in - # all scopes. - foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS}) - if(TARGET ${qt_find_package_target_name}) - # Allow usage of aliased targets by setting properties on the actual target - get_target_property(aliased_target ${qt_find_package_target_name} ALIASED_TARGET) - if(aliased_target) - set(qt_find_package_target_name ${aliased_target}) - endif() - - set_target_properties(${qt_find_package_target_name} - PROPERTIES INTERFACE_QT_PACKAGE_NAME ${ARGV0}) - if(package_version) - set_target_properties(${qt_find_package_target_name} - PROPERTIES INTERFACE_QT_PACKAGE_VERSION ${ARGV1}) - endif() - - if(arg_COMPONENTS) - string(REPLACE ";" " " components_as_string "${arg_COMPONENTS}") - set_property(TARGET ${qt_find_package_target_name} - PROPERTY INTERFACE_QT_PACKAGE_COMPONENTS ${components_as_string}) - endif() - - get_property(is_global TARGET ${qt_find_package_target_name} PROPERTY - IMPORTED_GLOBAL) - qt_internal_should_not_promote_package_target_to_global( - "${qt_find_package_target_name}" should_not_promote) - if(NOT is_global AND NOT should_not_promote) - set_property(TARGET ${qt_find_package_target_name} PROPERTY - IMPORTED_GLOBAL TRUE) - qt_find_package_promote_targets_to_global_scope( - "${qt_find_package_target_name}") - endif() - endif() - - endforeach() - - if(arg_MODULE_NAME AND arg_QMAKE_LIB - AND (NOT arg_QMAKE_LIB IN_LIST QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME})) - set(QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME} - ${QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME}};${arg_QMAKE_LIB} CACHE INTERNAL "") - set(QT_QMAKE_LIB_TARGETS_${arg_QMAKE_LIB} ${arg_PROVIDED_TARGETS} CACHE INTERNAL "") - endif() - endif() -endmacro() - -macro(qt_add_qmake_lib_dependency lib dep) - string(REPLACE "-" "_" dep ${dep}) - string(TOUPPER "${dep}" ucdep) - list(APPEND QT_QMAKE_LIB_DEPS_${lib} ${ucdep}) -endmacro() - -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) - find_library(FWFoundation Foundation) - find_library(FWIOBluetooth IOBluetooth) - find_library(FWIOKit IOKit) - find_library(FWIOSurface IOSurface) - find_library(FWImageIO ImageIO) - find_library(FWMetal Metal) - find_library(FWMobileCoreServices MobileCoreServices) - find_library(FWQuartzCore QuartzCore) - find_library(FWSecurity Security) - find_library(FWSystemConfiguration SystemConfiguration) - find_library(FWUIKit UIKit) - find_library(FWWatchKit WatchKit) - find_library(FWGameController GameController) - endif() -endmacro() - -# Match the pattern 'regex' in 'input_line', replace the match with 'replacement' -# and set that result in 'out_var' in the parent scope. -function(qt_regex_match_and_get input_line regex replacement out_var) - string(REGEX MATCH "${regex}" match "${input_line}") - if(match) - string(REGEX REPLACE "${regex}" "${replacement}" match "${input_line}") - string(STRIP ${match} match) - set(${out_var} "${match}" PARENT_SCOPE) - endif() -endfunction() - -# Match 'regex' in a list of lines. When found, set the value to 'out_var' and break early. -function(qt_qlalr_find_option_in_list input_list regex out_var) - foreach(line ${input_list}) - qt_regex_match_and_get("${line}" "${regex}" "\\1" option) - if(option) - string(TOLOWER ${option} option) - set(${out_var} "${option}" PARENT_SCOPE) - return() - endif() - endforeach() - message(FATAL_ERROR "qt_qlalr_find_option_in_list: Could not extract ${out_var}") -endfunction() - -# Generate a few output files using qlalr, and assign those to 'consuming_target'. -# 'input_file_list' is a list of 'foo.g' file paths. -# 'flags' are extra flags to be passed to qlalr. -function(qt_process_qlalr consuming_target input_file_list flags) - # Don't try to extend_target when cross compiling an imported host target (like a tool). - qt_is_imported_target("${consuming_target}" is_imported) - if(is_imported) - return() - endif() - - foreach(input_file ${input_file_list}) - file(STRINGS ${input_file} input_file_lines) - qt_qlalr_find_option_in_list("${input_file_lines}" "^%parser(.+)" "parser") - qt_qlalr_find_option_in_list("${input_file_lines}" "^%decl(.+)" "decl") - qt_qlalr_find_option_in_list("${input_file_lines}" "^%impl(.+)" "impl") - get_filename_component(base_file_name ${input_file} NAME_WE) - - set(cpp_file "${parser}.cpp") - set(private_file "${parser}_p.h") - set(decl_file "${decl}") - set(impl_file "${impl}") - 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}) - endforeach() -endfunction() - - -# qt_configure_file(OUTPUT output-file <INPUT input-file | CONTENT content>) -# input-file is relative to ${CMAKE_CURRENT_SOURCE_DIR} -# output-file is relative to ${CMAKE_CURRENT_BINARY_DIR} -# -# This function is similar to file(GENERATE OUTPUT) except it writes the content -# to the file at configure time, rather than at generate time. Once CMake 3.18 is released, it can use file(CONFIGURE) in its implmenetation. Until then, it -# uses configure_file() with a generic input file as source, when used with the CONTENT signature. -function(qt_configure_file) - qt_parse_all_arguments(arg "qt_configure_file" "" "OUTPUT;INPUT;CONTENT" "" ${ARGN}) - - if(NOT arg_OUTPUT) - message(FATAL_ERROR "No output file provided to qt_configure_file.") - endif() - - if(arg_CONTENT) - set(template_name "QtFileConfigure.txt.in") - # When building qtbase, use the source template file. - # Otherwise use the installed file. - # This should work for non-prefix and superbuilds as well. - if(QtBase_SOURCE_DIR) - set(input_file "${QtBase_SOURCE_DIR}/cmake/${template_name}") - else() - set(input_file "${Qt6_DIR}/${template_name}") - endif() - set(__qt_file_configure_content "${arg_CONTENT}") - elseif(arg_INPUT) - set(input_file "${arg_INPUT}") - else() - message(FATAL_ERROR "No input value provided to qt_configure_file.") - endif() - - configure_file("${input_file}" "${arg_OUTPUT}" @ONLY) -endfunction() - -macro(qt_add_string_to_qconfig_cpp str) - string(LENGTH "${str}" length) - string(APPEND QT_CONFIG_STRS " \"${str}\\0\"\n") - string(APPEND QT_CONFIG_STR_OFFSETS " ${QT_CONFIG_STR_OFFSET},\n") - math(EXPR QT_CONFIG_STR_OFFSET "${QT_CONFIG_STR_OFFSET}+${length}+1") -endmacro() - -function(qt_generate_qconfig_cpp) - set(QT_CONFIG_STR_OFFSET "0") - set(QT_CONFIG_STR_OFFSETS "") - set(QT_CONFIG_STRS "") - - # Start first part. - qt_add_string_to_qconfig_cpp("${INSTALL_DOCDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_INCLUDEDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_LIBDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_LIBEXECDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_BINDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_PLUGINSDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_QMLDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_ARCHDATADIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_DATADIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_TRANSLATIONSDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_EXAMPLESDIR}") - qt_add_string_to_qconfig_cpp("${INSTALL_TESTSDIR}") - - # Save first part. - set(QT_CONFIG_STR_OFFSETS_FIRST "${QT_CONFIG_STR_OFFSETS}") - set(QT_CONFIG_STRS_FIRST "${QT_CONFIG_STRS}") - - # Start second part. - set(QT_CONFIG_STR_OFFSETS "") - set(QT_CONFIG_STRS "") - - qt_add_string_to_qconfig_cpp("") # config.input.sysroot - qt_add_string_to_qconfig_cpp("false") # qmake_sysrootify - qt_add_string_to_qconfig_cpp("${INSTALL_BINDIR}") # TODO: Host-specific - qt_add_string_to_qconfig_cpp("${INSTALL_LIBDIR}") # TODO: Host-specific - qt_add_string_to_qconfig_cpp("${INSTALL_DATADIR}") # TODO: Host-specific - qt_add_string_to_qconfig_cpp("${QT_QMAKE_TARGET_MKSPEC}") - qt_add_string_to_qconfig_cpp("${QT_QMAKE_HOST_MKSPEC}") - - # Save second part. - set(QT_CONFIG_STR_OFFSETS_SECOND "${QT_CONFIG_STR_OFFSETS}") - set(QT_CONFIG_STRS_SECOND "${QT_CONFIG_STRS}") - - # Settings path / sysconf dir. - set(QT_SYS_CONF_DIR "${INSTALL_SYSCONFDIR}") - - # Compute and set relocation prefixes. - # TODO: Clean this up, there's a bunch of unrealistic assumptions here. - # See qtConfOutput_preparePaths in qtbase/configure.pri. - if(WIN32) - set(lib_location_absolute_path - "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}") - else() - set(lib_location_absolute_path - "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") - endif() - file(RELATIVE_PATH from_lib_location_to_prefix - "${lib_location_absolute_path}" "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}") - set(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH "${from_lib_location_to_prefix}") - - # The QT_CONFIGURE_HOSTBINDIR_TO_*PREFIX_PATH defines are exclusively used by qmake to determine - # the prefix from the location of the qmake executable. In our build of qmake host_prefix is - # always the same as ext_prefix, and we can just use CMAKE_INSTALL_PREFIX for the calculation of - # the relative path between <ext_prefix>/bin and <ext_prefix>. - set(bin_dir_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") - file(RELATIVE_PATH from_bin_dir_to_prefix "${bin_dir_absolute_path}" "${CMAKE_INSTALL_PREFIX}") - set(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH "${from_bin_dir_to_prefix}") - set(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH "${from_bin_dir_to_prefix}") - - 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) - else() - set(CMAKE_CXX_STANDARD 17 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() - -function(qt_set_language_standards_interface_compile_features target) - # Regardless of which C++ standard is used to build Qt itself, require C++17 when building - # Qt applications using CMake (because the Qt header files use C++17 features). - set(cpp_feature "cxx_std_17") - target_compile_features("${target}" INTERFACE ${cpp_feature}) -endfunction() - -function(qt_enable_msvc_cplusplus_define target visibility) - # For MSVC we need to explicitly pass -Zc:__cplusplus to get correct __cplusplus. - # Check qt_config_compile_test for more info. - if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1913) - target_compile_options("${target}" ${visibility} "-Zc:__cplusplus") - endif() -endfunction() - -function(qt_enable_utf8_sources target) - set(utf8_flags "") - if(MSVC) - list(APPEND utf8_flags "-utf-8") - elseif(WIN32 AND ICC) - list(APPEND utf8_flags "-Qoption,cpp,--unicode_source_kind,UTF-8") - endif() - - if(utf8_flags) - # Allow opting out by specifying the QT_NO_UTF8_SOURCE target property. - set(genex_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UTF8_SOURCE>>>") - set(utf8_flags "$<${genex_condition}:${utf8_flags}>") - target_compile_options("${target}" INTERFACE "${utf8_flags}") - endif() -endfunction() - -# Equivalent of qmake's qtNomakeTools(directory1 directory2). -# If QT_NO_MAKE_TOOLS is true, then targets within the given directories will be excluded from the -# default 'all' target, as well as from install phase. -# The private variable is checked by qt_add_executable. -function(qt_exclude_tool_directories_from_default_target) - if(QT_NO_MAKE_TOOLS) - set(absolute_path_directories "") - foreach(directory ${ARGV}) - list(APPEND absolute_path_directories "${CMAKE_CURRENT_SOURCE_DIR}/${directory}") - endforeach() - set(__qt_exclude_tool_directories "${absolute_path_directories}" PARENT_SCOPE) - endif() -endfunction() - -function(qt_compute_relative_rpath_base rpath install_location out_var) - set(install_lib_dir_absolute "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") - get_filename_component(rpath_absolute "${rpath}" - ABSOLUTE BASE_DIR "${install_lib_dir_absolute}") - - if(NOT IS_ABSOLUTE) - set(install_location_absolute "${CMAKE_INSTALL_PREFIX}/${install_location}") - endif() - # Compute relative rpath from where the target will be installed, to the place where libraries - # will be placed (INSTALL_LIBDIR). - file(RELATIVE_PATH rpath_relative "${install_location_absolute}" "${rpath_absolute}") - - if("${rpath_relative}" STREQUAL "") - # file(RELATIVE_PATH) returns an empty string if the given absolute paths are equal - set(rpath_relative ".") - endif() - - # Prepend $ORIGIN / @loader_path style tokens (qmake's QMAKE_REL_RPATH_BASE), to make the - # relative rpaths work. qmake does this automatically when generating a project, so it wasn't - # needed in the .prf files, but for CMake we need to prepend them ourselves. - if(APPLE) - set(rpath_rel_base "@loader_path") - elseif(LINUX) - set(rpath_rel_base "$ORIGIN") - else() - message(WARNING "No known RPATH_REL_BASE for target platform.") - set(rpath_rel_base "NO_KNOWN_RPATH_REL_BASE") - endif() - - if(rpath_relative STREQUAL ".") - set(rpath_relative "${rpath_rel_base}") - else() - set(rpath_relative "${rpath_rel_base}/${rpath_relative}") - endif() - - set("${out_var}" "${rpath_relative}" PARENT_SCOPE) -endfunction() - -# Applies necessary rpaths to a target upon target installation. -# No-op when targeting Windows, Android, or non-prefix builds. -# -# If no RELATIVE_RPATH option is given, embeds an absolute path rpath to ${INSTALL_LIBDIR}. -# If RELATIVE_RPATH is given, the INSTALL_PATH value is to compute the relative path from -# ${INSTALL_LIBDIR} to wherever the target will be installed (the value of INSTALL_PATH). -# It's the equivalent of qmake's relative_qt_rpath. -# INSTALL_PATH is used to implement the equivalent of qmake's $$qtRelativeRPathBase(). -# -# A cache variable QT_DISABLE_RPATH can be set to disable embedding any rpaths when installing. -function(qt_apply_rpaths) - # No rpath support for win32 and android. Also no need to apply rpaths when doing a non-prefix - # build. - if(NOT QT_WILL_INSTALL OR WIN32 OR ANDROID) - return() - endif() - - # Rpaths xplicitly disabled (like for uikit), equivalent to qmake's no_qt_rpath. - if(QT_DISABLE_RPATH) - return() - endif() - - qt_parse_all_arguments(arg "qt_apply_rpaths" "RELATIVE_RPATH" "TARGET;INSTALL_PATH" "" ${ARGN}) - if(NOT arg_TARGET) - message(FATAL_ERRO "No target given to qt_apply_rpaths.") - else() - set(target "${arg_TARGET}") - endif() - - # If a target is not built (which can happen for tools when crosscompiling, we shouldn't try - # to apply properties. - if(NOT TARGET "${target}") - return() - endif() - - # Protect against interface libraries. - get_target_property(target_type "${target}" TYPE) - if (target_type STREQUAL "INTERFACE_LIBRARY") - return() - endif() - - if(NOT arg_INSTALL_PATH) - message(FATAL_ERROR "No INSTALL_PATH given to qt_apply_rpaths.") - endif() - - set(rpaths "") - - # Modify the install path to contain the nested structure of a framework. - get_target_property(is_framework "${target}" FRAMEWORK) - if(is_framework) - if(UIKIT) - # Shallow framework - string(APPEND arg_INSTALL_PATH "/Qt${target}.framework") - else() - # Full framework - string(APPEND arg_INSTALL_PATH "/Qt${target}.framework/Versions/Current") - endif() - endif() - - # Same but for an app bundle. - get_target_property(is_bundle "${target}" MACOSX_BUNDLE) - if(is_bundle AND NOT is_framework) - if(UIKIT) - # Shallow bundle - string(APPEND arg_INSTALL_PATH "/${target}.app") - else() - # Full bundle - string(APPEND arg_INSTALL_PATH "/${target}.app/Contents/MacOS") - endif() - endif() - - # Somewhat similar to mkspecs/features/qt.prf - if(arg_RELATIVE_RPATH) - qt_compute_relative_rpath_base( - "${_default_install_rpath}" "${arg_INSTALL_PATH}" relative_rpath) - list(APPEND rpaths "${relative_rpath}") - else() - list(APPEND rpaths "${_default_install_rpath}") - endif() - - # Somewhat similar to mkspecs/features/qt_build_extra.prf. - foreach(rpath ${QT_EXTRA_RPATHS}) - if(IS_ABSOLUTE) - list(APPEND rpaths "${rpath}") - else() - qt_compute_relative_rpath_base("${rpath}" "${arg_INSTALL_PATH}" relative_rpath) - list(APPEND rpaths "${relative_rpath}") - endif() - endforeach() - - if(rpaths) - list(REMOVE_DUPLICATES rpaths) - set_property(TARGET "${target}" APPEND PROPERTY INSTALL_RPATH ${rpaths}) - endif() -endfunction() - -function(qt_internal_set_up_sanitizer_features) - set(ECM_ENABLE_SANITIZERS "" CACHE STRING "Enable sanitizers") - set_property(CACHE ECM_ENABLE_SANITIZERS PROPERTY STRINGS "address;memory;thread;undefined") - - # If FEATURE_sanitize_foo is set on the command line, make sure to set the appropriate - # ECM_ENABLE_SANITIZERS value. Also the other way around. This basically allows setting either - # the feature or ECM_ENABLE_SANITIZERS directly. - # - # TODO: Decide which one of these should be the source of truth, because reconfiguration with - # different options might not work as expected when ECM_ENABLE_SANITIZERS is provided instead of - # the features. - set(enabled_sanitizer_features "") - foreach(sanitizer_type address memory thread undefined) - if(FEATURE_sanitize_${sanitizer_type}) - list(APPEND enabled_sanitizer_features "${sanitizer_type}") - endif() - endforeach() - if(enabled_sanitizer_features) - set(ECM_ENABLE_SANITIZERS - "${enabled_sanitizer_features}" CACHE STRING "Enable sanitizers" FORCE) - endif() - - if(ECM_ENABLE_SANITIZERS) - foreach(sanitizer_type ${ECM_ENABLE_SANITIZERS}) - message(STATUS "Enabling sanitizer: ${sanitizer_type}") - set(feature_name "FEATURE_sanitize_${sanitizer_type}") - set(${feature_name} "ON" CACHE BOOL "Enable ${sanitizer_type} sanitizer" FORCE) - set(QT_${feature_name} "ON" CACHE BOOL "Enable ${sanitizer_type} sanitizer" FORCE) - endforeach() - endif() -endfunction() - -function(qt_internal_apply_win_prefix_and_suffix target) - if(WIN32) - # Table of prefix / suffixes for MSVC libraries as qmake expects them to be created. - # static - Qt6EdidSupport.lib (platform support libraries / or static QtCore, etc) - # shared - Qt6Core.dll - # shared import library - Qt6Core.lib - # module aka Qt plugin - qwindows.dll - # module import library - qwindows.lib - # - # The CMake defaults are fine for us. - - # Table of prefix / suffixes for MinGW libraries as qmake expects them to be created. - # static - libQt6EdidSupport.a (platform support libraries / or static QtCore, etc) - # shared - Qt6Core.dll - # shared import library - libQt6Core.a - # module aka Qt plugin - qwindows.dll - # module import library - libqwindows.a - # - # CMake for Windows-GNU platforms defaults the prefix to "lib". - # CMake for Windows-GNU platforms defaults the import suffix to ".dll.a". - # These CMake defaults are not ok for us. - - # This should cover both MINGW with GCC and CLANG. - if(NOT MSVC) - set_property(TARGET "${target}" PROPERTY IMPORT_SUFFIX ".a") - - get_target_property(target_type ${target} TYPE) - if(target_type STREQUAL "STATIC_LIBRARY") - set_property(TARGET "${target}" PROPERTY PREFIX "lib") - else() - set_property(TARGET "${target}" PROPERTY PREFIX "") - set_property(TARGET "${target}" PROPERTY IMPORT_PREFIX "lib") - endif() - endif() - endif() -endfunction() - -function(qt_internal_strip_target_directory_scope_token target out_var) - # In CMake versions earlier than CMake 3.18, a subdirectory scope id is appended to the - # target name if the target is referenced in a target_link_libraries command from a - # different directory scope than where the target was created. - # Strip it. - # - # For informational purposes, in CMake 3.18, the target name looks as follows: - # ::@(0x5604cb3f6b50);Threads::Threads;::@ - # This case doesn't have to be stripped (at least for now), because when we iterate over - # link libraries, the tokens appear as separate target names. - # - # Example: Threads::Threads::@<0x5604cb3f6b50> - # Output: Threads::Threads - string(REGEX REPLACE "::@<.+>$" "" target "${target}") - set("${out_var}" "${target}" PARENT_SCOPE) -endfunction() - -# Sets out_var to to TRUE if the target was marked to not be promoted to global scope. -function(qt_internal_should_not_promote_package_target_to_global target out_var) - get_property(should_not_promote TARGET "${target}" PROPERTY _qt_no_promote_global) - set("${out_var}" "${should_not_promote}" PARENT_SCOPE) -endfunction() - -function(qt_internal_disable_find_package_global_promotion target) - set_target_properties("${target}" PROPERTIES _qt_no_promote_global TRUE) -endfunction() - -include(QtApp) - -# 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() +option(QT_CMAKE_DEBUG_EXTEND_TARGET "Debug extend_target calls in Qt's build system" OFF) -function(add_cmake_library) - qt_add_cmake_library(${ARGV}) -endfunction() +include(Qt3rdPartyLibraryHelpers) +include(QtAppHelpers) +include(QtAutogenHelpers) +include(QtCMakeHelpers) +include(QtCompatibilityHelpers) +include(QtDbusHelpers) +include(QtDocsHelpers) +include(QtExecutableHelpers) +include(QtFindPackageHelpers) +include(QtFlagHandlingHelpers) +include(QtFrameworkHelpers) +include(QtInstallHelpers) +include(QtLalrHelpers) +include(QtModuleHelpers) +include(QtNoLinkTargetHelpers) +include(QtPluginHelpers) +include(QtPrecompiledHeadersHelpers) +include(QtPriHelpers) +include(QtPrlHelpers) +include(QtQmakeHelpers) +include(QtResourceHelpers) +include(QtRpathHelpers) +include(QtSanitizerHelpers) +include(QtScopeFinalizerHelpers) +include(QtSimdHelpers) +include(QtSyncQtHelpers) +include(QtTargetHelpers) +include(QtTestHelpers) +include(QtToolHelpers) + +# This sets up the scope finalizer mechanism. +variable_watch(CMAKE_CURRENT_LIST_DIR qt_watch_current_list_dir) diff --git a/cmake/QtCMakeHelpers.cmake b/cmake/QtCMakeHelpers.cmake new file mode 100644 index 0000000000..261e9cc457 --- /dev/null +++ b/cmake/QtCMakeHelpers.cmake @@ -0,0 +1,151 @@ +# qt_configure_file(OUTPUT output-file <INPUT input-file | CONTENT content>) +# input-file is relative to ${CMAKE_CURRENT_SOURCE_DIR} +# output-file is relative to ${CMAKE_CURRENT_BINARY_DIR} +# +# This function is similar to file(GENERATE OUTPUT) except it writes the content +# to the file at configure time, rather than at generate time. Once CMake 3.18 is released, it can use file(CONFIGURE) in its implmenetation. Until then, it +# uses configure_file() with a generic input file as source, when used with the CONTENT signature. +function(qt_configure_file) + qt_parse_all_arguments(arg "qt_configure_file" "" "OUTPUT;INPUT;CONTENT" "" ${ARGN}) + + if(NOT arg_OUTPUT) + message(FATAL_ERROR "No output file provided to qt_configure_file.") + endif() + + if(arg_CONTENT) + set(template_name "QtFileConfigure.txt.in") + # When building qtbase, use the source template file. + # Otherwise use the installed file. + # This should work for non-prefix and superbuilds as well. + if(QtBase_SOURCE_DIR) + set(input_file "${QtBase_SOURCE_DIR}/cmake/${template_name}") + else() + set(input_file "${Qt6_DIR}/${template_name}") + endif() + set(__qt_file_configure_content "${arg_CONTENT}") + elseif(arg_INPUT) + set(input_file "${arg_INPUT}") + else() + message(FATAL_ERROR "No input value provided to qt_configure_file.") + endif() + + configure_file("${input_file}" "${arg_OUTPUT}" @ONLY) +endfunction() + +# A version of cmake_parse_arguments that makes sure all arguments are processed and errors out +# with a message about ${type} having received unknown arguments. +macro(qt_parse_all_arguments result type flags options multiopts) + cmake_parse_arguments(${result} "${flags}" "${options}" "${multiopts}" ${ARGN}) + if(DEFINED ${result}_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown arguments were passed to ${type} (${${result}_UNPARSED_ARGUMENTS}).") + endif() +endmacro() + +# Print all variables defined in the current scope. +macro(qt_debug_print_variables) + cmake_parse_arguments(__arg "DEDUP" "" "MATCH;IGNORE" ${ARGN}) + message("Known Variables:") + get_cmake_property(__variableNames VARIABLES) + list (SORT __variableNames) + if (__arg_DEDUP) + list(REMOVE_DUPLICATES __variableNames) + endif() + + foreach(__var ${__variableNames}) + set(__ignore OFF) + foreach(__i ${__arg_IGNORE}) + if(__var MATCHES "${__i}") + set(__ignore ON) + break() + endif() + endforeach() + + if (__ignore) + continue() + endif() + + set(__show OFF) + foreach(__i ${__arg_MATCH}) + if(__var MATCHES "${__i}") + set(__show ON) + break() + endif() + endforeach() + + if (__show) + message(" ${__var}=${${__var}}.") + endif() + endforeach() +endmacro() + +macro(assert) + if (${ARGN}) + else() + message(FATAL_ERROR "ASSERT: ${ARGN}.") + endif() +endmacro() + +# Takes a list of path components and joins them into one path separated by forward slashes "/", +# and saves the path in out_var. +function(qt_path_join out_var) + string(JOIN "/" path ${ARGN}) + set(${out_var} ${path} PARENT_SCOPE) +endfunction() + +# qt_remove_args can remove arguments from an existing list of function +# arguments in order to pass a filtered list of arguments to a different function. +# Parameters: +# out_var: result of remove all arguments specified by ARGS_TO_REMOVE from ALL_ARGS +# ARGS_TO_REMOVE: Arguments to remove. +# ALL_ARGS: All arguments supplied to cmake_parse_arguments or +# qt_parse_all_arguments +# from which ARGS_TO_REMOVE should be removed from. We require all the +# arguments or we can't properly identify the range of the arguments detailed +# in ARGS_TO_REMOVE. +# ARGS: Arguments passed into the function, usually ${ARGV} +# +# E.g.: +# We want to forward all arguments from foo to bar, execpt ZZZ since it will +# trigger an error in bar. +# +# foo(target BAR .... ZZZ .... WWW ...) +# bar(target BAR.... WWW...) +# +# function(foo target) +# qt_parse_all_arguments(arg "" "" "BAR;ZZZ;WWW ${ARGV}) +# qt_remove_args(forward_args +# ARGS_TO_REMOVE ${target} ZZZ +# ALL_ARGS ${target} BAR ZZZ WWW +# ARGS ${ARGV} +# ) +# bar(${target} ${forward_args}) +# endfunction() +# +function(qt_remove_args out_var) + cmake_parse_arguments(arg "" "" "ARGS_TO_REMOVE;ALL_ARGS;ARGS" ${ARGN}) + set(result ${arg_ARGS}) + foreach(arg IN LISTS arg_ARGS_TO_REMOVE) + # find arg + list(FIND result ${arg} find_result) + if (NOT find_result EQUAL -1) + # remove arg + list(REMOVE_AT result ${find_result}) + list(LENGTH result result_len) + list(GET result ${find_result} arg_current) + # remove values until we hit another arg + while(NOT ${arg_current} IN_LIST arg_ALL_ARGS AND find_result LESS result_len) + list(REMOVE_AT result ${find_result}) + list(GET result ${find_result} arg_current) + list(LENGTH result result_len) + endwhile() + endif() + endforeach() + set(${out_var} "${result}" PARENT_SCOPE) +endfunction() + +# Creates a regular expression that exactly matches the given string +# Found in https://gitlab.kitware.com/cmake/cmake/issues/18580 +function(qt_re_escape out_var str) + string(REGEX REPLACE "([][+.*()^])" "\\\\\\1" regex "${str}") + set(${out_var} ${regex} PARENT_SCOPE) +endfunction() diff --git a/cmake/QtCompatibilityHelpers.cmake b/cmake/QtCompatibilityHelpers.cmake new file mode 100644 index 0000000000..bee2b2cda6 --- /dev/null +++ b/cmake/QtCompatibilityHelpers.cmake @@ -0,0 +1,52 @@ +# 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/QtDbusHelpers.cmake b/cmake/QtDbusHelpers.cmake new file mode 100644 index 0000000000..8b972adc92 --- /dev/null +++ b/cmake/QtDbusHelpers.cmake @@ -0,0 +1,55 @@ +# helper to set up a qdbusxml2cpp rule +function(qt_create_qdbusxml2cpp_command target infile) + qt_parse_all_arguments(arg "qt_create_qdbusxml2cpp_command" "ADAPTOR;INTERFACE" "BASENAME" "FLAGS" ${ARGN}) + if((arg_ADAPTOR AND arg_INTERFACE) OR (NOT arg_ADAPTOR AND NOT arg_INTERFACE)) + message(FATAL_ERROR "qt_create_dbusxml2cpp_command needs either ADAPTOR or INTERFACE.") + endif() + + set(option "-a") + set(type "adaptor") + if (arg_INTERFACE) + set(option "-p") + set(type "interface") + endif() + + if ("${arg_BASENAME}" STREQUAL "") + get_filename_component(file_dir "${infile}" DIRECTORY) + get_filename_component(file_name "${infile}" NAME_WLE) + get_filename_component(file_ext "${infile}" LAST_EXT) + + if("${file_ext}" STREQUAL ".xml") + else() + message(FATAL_ERROR "DBUS ${type} input file is not xml.") + endif() + + # use last part of io.qt.something.xml! + get_filename_component(file_ext "${file_name}" LAST_EXT) + if("x${file_ext}" STREQUAL "x") + else() + string(SUBSTRING "${file_ext}" 1 -1 file_name) # cut of leading '.' + endif() + + string(TOLOWER "${file_name}" file_name) + set(file_name "${file_name}_${type}") + else() + set(file_name ${arg_BASENAME}) + endif() + + # Use absolute file path for the source file and set the current working directory to the + # current binary directory, because setting an absolute path for the header:source combo option + # does not work. Splitting on ":" breaks inside the dbus tool when running on Windows + # due to ":" being contained in the drive path (e.g C:\foo.h:C:\foo.cpp). + get_filename_component(absolute_in_file_path "${infile}" ABSOLUTE) + + set(header_file "${file_name}.h") + set(source_file "${file_name}.cpp") + + 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}" ${QT_CMAKE_EXPORT_NAMESPACE}::qdbusxml2cpp + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + VERBATIM) + + target_sources("${target}" PRIVATE "${header_file}" "${source_file}") +endfunction() diff --git a/cmake/QtDocsHelpers.cmake b/cmake/QtDocsHelpers.cmake new file mode 100644 index 0000000000..e65448846c --- /dev/null +++ b/cmake/QtDocsHelpers.cmake @@ -0,0 +1,198 @@ +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 "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}) + + # If a target is not built (which can happen for tools when crosscompiling, we shouldn't try + # to generate docs. + if(NOT TARGET "${target}") + return() + endif() + + if (NOT QT_SUPERBUILD OR QT_WILL_INSTALL) + set(qdoc_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qdoc") + set(qtattributionsscanner_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qtattributionsscanner") + set(qhelpgenerator_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}/qhelpgenerator") + else() + set(qdoc_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qdoc") + set(qtattributionsscanner_bin "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_BINDIR}/qtattributionsscanner") + set(qhelpgenerator_bin "${QT_BUILD_INTERNALS_RELOCATABLE_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 "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}/${doc_target}") + set(index_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}") + else() + set(qdoc_output_dir "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_DOCDIR}/${doc_target}") + set(index_dir "${QT_BUILD_INTERNALS_RELOCATABLE_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_WILL_INSTALL) + set(qt_install_docs_env "${CMAKE_INSTALL_PREFIX}/${INSTALL_DOCDIR}") + elseif (QT_SUPERBUILD) + set(qt_install_docs_env "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/qtbase/${INSTALL_DOCDIR}") + else() + set(qt_install_docs_env "${QT_BUILD_INTERNALS_RELOCATABLE_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_custom_target(docs_${target}) + add_dependencies(docs_${target} html_docs_${target}) + add_dependencies(docs_${target} 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_target_name} 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() diff --git a/cmake/QtExecutableHelpers.cmake b/cmake/QtExecutableHelpers.cmake new file mode 100644 index 0000000000..3914fe36e6 --- /dev/null +++ b/cmake/QtExecutableHelpers.cmake @@ -0,0 +1,150 @@ +# 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 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 "${QT_BUILD_DIR}/${INSTALL_BINDIR}") + endif() + + get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + ABSOLUTE BASE_DIR "${QT_BUILD_DIR}") + + if ("x${arg_INSTALL_DIRECTORY}" STREQUAL "x") + set(arg_INSTALL_DIRECTORY "${INSTALL_BINDIR}") + endif() + + 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() + + if (arg_VERSION) + if(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+") + # nothing to do + elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") + set(arg_VERSION "${arg_VERSION}.0") + elseif(arg_VERSION MATCHES "[0-9]+\\.[0-9]+") + set(arg_VERSION "${arg_VERSION}.0.0") + elseif (arg_VERSION MATCHES "[0-9]+") + set(arg_VERSION "${arg_VERSION}.0.0.0") + else() + message(FATAL_ERROR "Invalid version format") + endif() + endif() + + if(arg_DELAY_TARGET_INFO) + # Delay the setting of target info properties if requested. Needed for scope finalization + # of Qt apps. + set_target_properties("${name}" PROPERTIES + QT_DELAYED_TARGET_VERSION "${arg_VERSION}" + QT_DELAYED_TARGET_PRODUCT "${arg_TARGET_PRODUCT}" + QT_DELAYED_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" + QT_DELAYED_TARGET_COMPANY "${arg_TARGET_COMPANY}" + QT_DELAYED_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}" + ) + else() + if("${arg_TARGET_DESCRIPTION}" STREQUAL "") + set(arg_TARGET_DESCRIPTION "Qt ${name}") + endif() + qt_set_target_info_properties(${name} ${ARGN} + TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" + TARGET_VERSION "${arg_VERSION}") + endif() + + if (WIN32 AND NOT arg_DELAY_RC) + qt6_generate_win32_rc_file(${name}) + endif() + + qt_set_common_target_properties(${name}) + 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) + set(extra_libraries "Qt::Core") + endif() + + set(private_includes + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + ${arg_INCLUDE_DIRECTORIES} + ) + + qt_extend_target("${name}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES ${private_includes} + DEFINES ${arg_DEFINES} + LIBRARIES ${arg_LIBRARIES} Qt::PlatformCommonInternal + PUBLIC_LIBRARIES ${extra_libraries} ${arg_PUBLIC_LIBRARIES} + DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}" + DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}" + DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}" + DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}" + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + 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}" + ) + if(NOT ${arg_EXCEPTIONS}) + qt_internal_set_no_exceptions_flags("${name}") + endif() + + # Check if target needs to be excluded from all target. Also affects qt_install. + # Set by qt_exclude_tool_directories_from_default_target. + set(exclude_from_all FALSE) + if(__qt_exclude_tool_directories) + foreach(absolute_dir ${__qt_exclude_tool_directories}) + string(FIND "${CMAKE_CURRENT_SOURCE_DIR}" "${absolute_dir}" dir_starting_pos) + if(dir_starting_pos EQUAL 0) + set(exclude_from_all TRUE) + set_target_properties("${name}" PROPERTIES EXCLUDE_FROM_ALL TRUE) + break() + endif() + endforeach() + endif() + + if(NOT arg_NO_INSTALL) + set(additional_install_args "") + if(exclude_from_all) + list(APPEND additional_install_args EXCLUDE_FROM_ALL COMPONENT "ExcludedExecutables") + endif() + + qt_get_cmake_configurations(cmake_configs) + foreach(cmake_config ${cmake_configs}) + qt_get_install_target_default_args( + OUT_VAR install_targets_default_args + CMAKE_CONFIG "${cmake_config}" + ALL_CMAKE_CONFIGS "${cmake_configs}" + RUNTIME "${arg_INSTALL_DIRECTORY}" + LIBRARY "${arg_INSTALL_DIRECTORY}" + BUNDLE "${arg_INSTALL_DIRECTORY}") + qt_install(TARGETS "${name}" + ${additional_install_args} # Needs to be before the DESTINATIONS. + CONFIGURATIONS ${cmake_config} + ${install_targets_default_args}) + endforeach() + endif() +endfunction() diff --git a/cmake/QtFindPackageHelpers.cmake b/cmake/QtFindPackageHelpers.cmake new file mode 100644 index 0000000000..f5d84f0456 --- /dev/null +++ b/cmake/QtFindPackageHelpers.cmake @@ -0,0 +1,246 @@ +# This function recursively walks transitive link libraries of the given target +# and promotes those targets to be IMPORTED_GLOBAL if they are not. +# +# This is required for .prl file generation in top-level builds, to make sure that imported 3rd +# party library targets in any repo are made global, so there are no scoping issues. +# +# Only works if called from qt_find_package(), because the promotion needs to happen in the same +# directory scope where the imported target is first created. +# +# Uses qt_internal_walk_libs. +function(qt_find_package_promote_targets_to_global_scope target) + qt_internal_walk_libs("${target}" _discared_out_var + "qt_find_package_targets_dict" "promote_global") +endfunction() + +macro(qt_find_package) + # Get the target names we expect to be provided by the package. + set(options CONFIG NO_MODULE MODULE REQUIRED) + set(oneValueArgs MODULE_NAME QMAKE_LIB) + set(multiValueArgs PROVIDED_TARGETS COMPONENTS) + cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # If some Qt internal project calls qt_find_package(WrapFreeType), but WrapFreeType was already + # found as part of a find_dependency() call from a ModuleDependencies.cmake file (or similar), + # and the provided target is also found, that means this might have been an unnecessary + # qt_find_package() call, because the dependency was already found via some other transitive + # dependency. Return early, so that CMake doesn't fail wiht an error with trying to promote the + # targets to be global. This behavior is not enabled by default, because there are cases + # when a regular find_package() (non qt_) can find a package (Freetype -> PNG), and a subsequent + # qt_find_package(PNG PROVIDED_TARGET PNG::PNG) still needs to succeed and register the provided + # targets. To enable the debugging behavior, set QT_DEBUG_QT_FIND_PACKAGE to 1. + set(_qt_find_package_skip_find_package FALSE) + if(QT_DEBUG_QT_FIND_PACKAGE AND ${ARGV0}_FOUND AND arg_PROVIDED_TARGETS) + set(_qt_find_package_skip_find_package TRUE) + foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS}) + if(NOT TARGET ${qt_find_package_target_name}) + set(_qt_find_package_skip_find_package FALSE) + endif() + endforeach() + + if(_qt_find_package_skip_find_package) + message(AUTHOR_WARNING "qt_find_package(${ARGV0}) called even though the package " + "was already found. Consider removing the call.") + endif() + endif() + + # Get the version if specified. + set(package_version "") + if(${ARGC} GREATER_EQUAL 2) + if(${ARGV1} MATCHES "^[0-9\.]+$") + set(package_version "${ARGV1}") + endif() + endif() + + if(arg_COMPONENTS) + # Re-append components to forward them. + list(APPEND arg_UNPARSED_ARGUMENTS "COMPONENTS;${arg_COMPONENTS}") + endif() + + # Don't look for packages in PATH if requested to. + if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH) + set(_qt_find_package_use_system_env_backup "${CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH}") + set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH "OFF") + endif() + + if(NOT (arg_CONFIG OR arg_NO_MODULE OR arg_MODULE) AND NOT _qt_find_package_skip_find_package) + # Try to find a config package first in quiet mode + set(config_package_arg ${arg_UNPARSED_ARGUMENTS}) + list(APPEND config_package_arg "CONFIG;QUIET") + find_package(${config_package_arg}) + + # Double check that in config mode the targets become visible. Sometimes + # only the module mode creates the targets. For example with vcpkg, the sqlite + # package provides sqlite3-config.cmake, which offers multi-config targets but + # in their own way. CMake has FindSQLite3.cmake and with the original + # qt_find_package(SQLite3) call it is our intention to use the cmake package + # in module mode. + if (${ARGV0}_FOUND AND arg_PROVIDED_TARGETS) + unset(any_target_found) + foreach(expected_target ${arg_PROVIDED_TARGETS}) + if (TARGET ${expected_target}) + set(any_target_found TRUE) + break() + endif() + endforeach() + if(NOT any_target_found) + unset(${ARGV0}_FOUND) + endif() + endif() + endif() + + # Ensure the options are back in the original unparsed arguments + foreach(opt IN LISTS options) + if(arg_${opt}) + list(APPEND arg_UNPARSED_ARGUMENTS ${opt}) + endif() + endforeach() + + if (NOT ${ARGV0}_FOUND AND NOT _qt_find_package_skip_find_package) + # Unset the NOTFOUND ${package}_DIR var that might have been set by the previous + # find_package call, to get rid of "not found" messagees in the feature summary + # if the package is found by the next find_package call. + if(DEFINED CACHE{${ARGV0}_DIR} AND NOT ${ARGV0}_DIR) + unset(${ARGV0}_DIR CACHE) + endif() + + # Call original function without our custom arguments. + find_package(${arg_UNPARSED_ARGUMENTS}) + endif() + + if(QT_NO_USE_FIND_PACKAGE_SYSTEM_ENVIRONMENT_PATH) + if("${_qt_find_package_use_system_env_backup}" STREQUAL "") + unset(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH) + else() + set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH "${_qt_find_package_use_system_env_backup}") + endif() + endif() + + if(${ARGV0}_FOUND AND arg_PROVIDED_TARGETS AND NOT _qt_find_package_skip_find_package) + # If package was found, associate each target with its package name. This will be used + # later when creating Config files for Qt libraries, to generate correct find_dependency() + # calls. Also make the provided targets global, so that the properties can be read in + # all scopes. + foreach(qt_find_package_target_name ${arg_PROVIDED_TARGETS}) + if(TARGET ${qt_find_package_target_name}) + # Allow usage of aliased targets by setting properties on the actual target + get_target_property(aliased_target ${qt_find_package_target_name} ALIASED_TARGET) + if(aliased_target) + set(qt_find_package_target_name ${aliased_target}) + endif() + + set_target_properties(${qt_find_package_target_name} + PROPERTIES INTERFACE_QT_PACKAGE_NAME ${ARGV0}) + if(package_version) + set_target_properties(${qt_find_package_target_name} + PROPERTIES INTERFACE_QT_PACKAGE_VERSION ${ARGV1}) + endif() + + if(arg_COMPONENTS) + string(REPLACE ";" " " components_as_string "${arg_COMPONENTS}") + set_property(TARGET ${qt_find_package_target_name} + PROPERTY INTERFACE_QT_PACKAGE_COMPONENTS ${components_as_string}) + endif() + + get_property(is_global TARGET ${qt_find_package_target_name} PROPERTY + IMPORTED_GLOBAL) + qt_internal_should_not_promote_package_target_to_global( + "${qt_find_package_target_name}" should_not_promote) + if(NOT is_global AND NOT should_not_promote) + set_property(TARGET ${qt_find_package_target_name} PROPERTY + IMPORTED_GLOBAL TRUE) + qt_find_package_promote_targets_to_global_scope( + "${qt_find_package_target_name}") + endif() + endif() + + endforeach() + + if(arg_MODULE_NAME AND arg_QMAKE_LIB + AND (NOT arg_QMAKE_LIB IN_LIST QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME})) + set(QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME} + ${QT_QMAKE_LIBS_FOR_${arg_MODULE_NAME}};${arg_QMAKE_LIB} CACHE INTERNAL "") + set(QT_QMAKE_LIB_TARGETS_${arg_QMAKE_LIB} ${arg_PROVIDED_TARGETS} CACHE INTERNAL "") + endif() + endif() +endmacro() + +# 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) + if (TARGET "${main_target_name}") + 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}") + endif() +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() + +# This function stores the list of Qt modules a library depend on, +# along with their version info, for usage in ${target}Depends.cmake file +function(qt_register_target_dependencies target public_libs private_libs) + get_target_property(target_deps "${target}" _qt_target_deps) + if(NOT target_deps) + set(target_deps "") + endif() + + # 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 + OR lib STREQUAL GlobalConfig + OR lib STREQUAL GlobalConfigPrivate + OR lib STREQUAL PlatformModuleInternal + OR lib STREQUAL PlatformPluginInternal + OR lib STREQUAL PlatformToolInternal) + list(APPEND target_deps "Qt6\;${PROJECT_VERSION}") + elseif ("${lib}" MATCHES "(.*)Private") + list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${CMAKE_MATCH_1}\;${PROJECT_VERSION}") + else() + list(APPEND target_deps "${INSTALL_CMAKE_NAMESPACE}${lib}\;${PROJECT_VERSION}") + endif() + endif() + endforeach() + + set_target_properties("${target}" PROPERTIES _qt_target_deps "${target_deps}") +endfunction() + +# Sets out_var to to TRUE if the target was marked to not be promoted to global scope. +function(qt_internal_should_not_promote_package_target_to_global target out_var) + get_property(should_not_promote TARGET "${target}" PROPERTY _qt_no_promote_global) + set("${out_var}" "${should_not_promote}" PARENT_SCOPE) +endfunction() + +function(qt_internal_disable_find_package_global_promotion target) + set_target_properties("${target}" PROPERTIES _qt_no_promote_global TRUE) +endfunction() diff --git a/cmake/QtFlagHandlingHelpers.cmake b/cmake/QtFlagHandlingHelpers.cmake new file mode 100644 index 0000000000..ea06a24865 --- /dev/null +++ b/cmake/QtFlagHandlingHelpers.cmake @@ -0,0 +1,243 @@ +function(qt_internal_add_linker_version_script target) + qt_parse_all_arguments(arg "qt_internal_add_linker" "INTERNAL" "" "PRIVATE_HEADERS" ${ARGN}) + + if (TEST_ld_version_script) + if (arg_INTERNAL) + set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API { *; };") + else() + set(contents "Qt_${PROJECT_VERSION_MAJOR}_PRIVATE_API {\n qt_private_api_tag*;\n") + foreach(ph ${arg_PRIVATE_HEADERS}) + string(APPEND contents " @FILE:${ph}@\n") + endforeach() + string(APPEND contents "};\n") + set(current "Qt_${PROJECT_VERSION_MAJOR}") + if (QT_NAMESPACE STREQUAL "") + set(tag_symbol "qt_version_tag") + else() + set(tag_symbol "qt_version_tag_${QT_NAMESPACE}") + endif() + string(APPEND contents "${current} { *; };\n") + + foreach(minor_version RANGE ${PROJECT_VERSION_MINOR}) + set(previous "${current}") + set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}") + if (minor_version EQUAL ${PROJECT_VERSION_MINOR}) + string(APPEND contents "${current} { ${tag_symbol}; } ${previous};\n") + else() + string(APPEND contents "${current} {} ${previous};\n") + endif() + endforeach() + + set(infile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version.in") + set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${target}.version") + + file(GENERATE OUTPUT "${infile}" CONTENT "${contents}") + + qt_ensure_perl() + + add_custom_command(TARGET "${target}" PRE_LINK + 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" + ) + target_link_options("${target}" PRIVATE "-Wl,--version-script,${outfile}") + endif() + endif() +endfunction() + +function(qt_internal_add_link_flags_no_undefined target) + if (NOT QT_BUILD_SHARED_LIBS) + return() + endif() + if (GCC OR CLANG) + 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_SYMBOLS) + if(HAVE_DASH_UNDEFINED_SYMBOLS) + set(no_undefined_flag "-Wl,-undefined,error") + 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") + endif() + + set(CMAKE_REQUIRED_LINK_OPTIONS ${previous_CMAKE_REQUIRED_LINK_OPTIONS}) + + if (NOT HAVE_DASH_UNDEFINED_SYMBOLS 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}") + endif() +endfunction() + +function(qt_internal_apply_gc_binaries_conditional target visibility) + # Should only be applied when the feature is enabled, aka for static builds. + if(NOT QT_FEATURE_gc_binaries) + return() + endif() + qt_internal_apply_gc_binaries("${target}" "${visibility}") +endfunction() + +function(qt_internal_apply_gc_binaries target visibility) + set(possible_visibilities PRIVATE INTERFACE PUBLIC) + list(FIND possible_visibilities "${visibility}" known_visibility) + if (known_visibility EQUAL "-1") + message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.") + endif() + + if ((GCC OR CLANG) AND NOT EMSCRIPTEN AND NOT UIKIT) + if(APPLE) + set(gc_sections_flag "-Wl,-dead_strip") + elseif(SOLARIS) + set(gc_sections_flag "-Wl,-z,ignore") + elseif(LINUX OR BSD OR WIN32 OR ANDROID) + set(gc_sections_flag "-Wl,--gc-sections") + endif() + endif() + if(gc_sections_flag) + target_link_options("${target}" ${visibility} "${gc_sections_flag}") + endif() + + if((GCC OR CLANG OR ICC) AND NOT EMSCRIPTEN AND NOT UIKIT) + set(split_sections_flags "-ffunction-sections" "-fdata-sections") + endif() + if(split_sections_flags) + target_compile_options("${target}" ${visibility} ${split_sections_flags}) + endif() +endfunction() + +function(qt_internal_apply_intel_cet target visibility) + if(NOT QT_FEATURE_intelcet) + return() + endif() + + set(possible_visibilities PRIVATE INTERFACE PUBLIC) + list(FIND possible_visibilities "${visibility}" known_visibility) + if (known_visibility EQUAL "-1") + message(FATAL_ERROR "Visibitily setting must be one of PRIVATE, INTERFACE or PUBLIC.") + endif() + + if(GCC) + set(flags "-mshstk") + endif() + if(flags) + target_compile_options("${target}" ${visibility} "${flags}") + endif() +endfunction() + +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 + 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 + list(APPEND deprecations "QT_DISABLE_DEPRECATED_BEFORE=0x050000") + endif() + list(APPEND deprecations "QT_DEPRECATED_WARNINGS_SINCE=0x060000") + set("${result}" deprecations PARENT_SCOPE) +endfunction() + +# Sets the exceptions flags for the given target +function(qt_internal_set_no_exceptions_flags target) + target_compile_definitions("${target}" PRIVATE "QT_NO_EXCEPTIONS") + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + target_compile_options("${target}" PRIVATE "/wd4530" "/wd4577") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + target_compile_options("${target}" PRIVATE "-fno-exceptions") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + target_compile_options("${target}" PRIVATE "-fno-exceptions") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + target_compile_options("${target}" PRIVATE "-fno-exceptions") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") + target_compile_options("${target}" PRIVATE "-fno-exceptions") + 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_disable_warnings target) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + set_target_properties("${target}" PROPERTIES QT_COMPILE_OPTIONS_DISABLE_WARNINGS ON) +endfunction() + +function(qt_set_symbol_visibility_preset target value) + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + + set_target_properties("${target}" PROPERTIES C_VISIBILITY_PRESET "${value}") + set_target_properties("${target}" PROPERTIES CXX_VISIBILITY_PRESET "${value}") + set_target_properties("${target}" PROPERTIES OBJC_VISIBILITY_PRESET "${value}") + set_target_properties("${target}" PROPERTIES OBJCXX_VISIBILITY_PRESET "${value}") +endfunction() + +function(qt_set_symbol_visibility_hidden target) + qt_set_symbol_visibility_preset("${target}" "hidden") +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) + else() + set(CMAKE_CXX_STANDARD 17 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() + +function(qt_set_language_standards_interface_compile_features target) + # Regardless of which C++ standard is used to build Qt itself, require C++17 when building + # Qt applications using CMake (because the Qt header files use C++17 features). + set(cpp_feature "cxx_std_17") + target_compile_features("${target}" INTERFACE ${cpp_feature}) +endfunction() + +function(qt_enable_msvc_cplusplus_define target visibility) + # For MSVC we need to explicitly pass -Zc:__cplusplus to get correct __cplusplus. + # Check qt_config_compile_test for more info. + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1913) + target_compile_options("${target}" ${visibility} "-Zc:__cplusplus") + endif() +endfunction() + +function(qt_enable_utf8_sources target) + set(utf8_flags "") + if(MSVC) + list(APPEND utf8_flags "-utf-8") + elseif(WIN32 AND ICC) + list(APPEND utf8_flags "-Qoption,cpp,--unicode_source_kind,UTF-8") + endif() + + if(utf8_flags) + # Allow opting out by specifying the QT_NO_UTF8_SOURCE target property. + set(genex_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:QT_NO_UTF8_SOURCE>>>") + set(utf8_flags "$<${genex_condition}:${utf8_flags}>") + target_compile_options("${target}" INTERFACE "${utf8_flags}") + endif() +endfunction() diff --git a/cmake/QtFrameworkHelpers.cmake b/cmake/QtFrameworkHelpers.cmake new file mode 100644 index 0000000000..4760dbed32 --- /dev/null +++ b/cmake/QtFrameworkHelpers.cmake @@ -0,0 +1,106 @@ +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) + find_library(FWFoundation Foundation) + find_library(FWIOBluetooth IOBluetooth) + find_library(FWIOKit IOKit) + find_library(FWIOSurface IOSurface) + find_library(FWImageIO ImageIO) + find_library(FWMetal Metal) + find_library(FWMobileCoreServices MobileCoreServices) + find_library(FWQuartzCore QuartzCore) + find_library(FWSecurity Security) + find_library(FWSystemConfiguration SystemConfiguration) + find_library(FWUIKit UIKit) + find_library(FWWatchKit WatchKit) + find_library(FWGameController GameController) + endif() +endmacro() + +# 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() diff --git a/cmake/QtGlobalStateHelpers.cmake b/cmake/QtGlobalStateHelpers.cmake new file mode 100644 index 0000000000..bb5a289c85 --- /dev/null +++ b/cmake/QtGlobalStateHelpers.cmake @@ -0,0 +1,65 @@ +function(qt_internal_clear_qt_repo_known_modules) + set(QT_REPO_KNOWN_MODULES "" CACHE INTERNAL "Known current repo Qt modules" FORCE) +endfunction() + +function(qt_internal_add_qt_repo_known_module) + set(QT_REPO_KNOWN_MODULES ${QT_REPO_KNOWN_MODULES} ${ARGN} + CACHE INTERNAL "Known current repo Qt modules" FORCE) +endfunction() + +function(qt_internal_get_qt_repo_known_modules out_var) + set("${out_var}" "${QT_REPO_KNOWN_MODULES}" PARENT_SCOPE) +endfunction() + +# Gets the list of all known Qt modules both found and that were built as part of the +# current project. +function(qt_internal_get_qt_all_known_modules out_var) + qt_internal_get_qt_repo_known_modules(repo_known_modules) + set(known_modules ${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE} ${repo_known_modules}) + list(REMOVE_DUPLICATES known_modules) + set("${out_var}" "${known_modules}" PARENT_SCOPE) +endfunction() + +macro(qt_internal_set_qt_known_plugins) + set(QT_KNOWN_PLUGINS ${ARGN} CACHE INTERNAL "Known Qt plugins" FORCE) +endmacro() + +### Global plug-in types handling ### +# QT_REPO_KNOWN_PLUGIN_TYPES and QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE +# hold a list of plug-in types (e.G. "imageformats;bearer") +function(qt_internal_clear_qt_repo_known_plugin_types) + set(QT_REPO_KNOWN_PLUGIN_TYPES "" CACHE INTERNAL "Known current repo Qt plug-in types" FORCE) +endfunction() + +function(qt_internal_add_qt_repo_known_plugin_types) + set(QT_REPO_KNOWN_PLUGIN_TYPES ${QT_REPO_KNOWN_PLUGIN_TYPES} ${ARGN} + CACHE INTERNAL "Known current repo Qt plug-in types" FORCE) +endfunction() + +function(qt_internal_get_qt_repo_known_plugin_types out_var) + set("${out_var}" "${QT_REPO_KNOWN_PLUGIN_TYPES}" PARENT_SCOPE) +endfunction() + +function(qt_internal_get_qt_all_known_plugin_types out_var) + qt_internal_get_qt_repo_known_plugin_types(repo_known_plugin_types) + set(known ${QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE} ${repo_known_plugin_types}) + list(REMOVE_DUPLICATES known) + set("${out_var}" "${known}" PARENT_SCOPE) +endfunction() + +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() + +macro(qt_internal_append_known_module_tool module tool) + if(NOT ${tool} IN_LIST QT_KNOWN_MODULE_${module}_TOOLS) + list(APPEND QT_KNOWN_MODULE_${module}_TOOLS "${tool}") + set(QT_KNOWN_MODULE_${module}_TOOLS "${QT_KNOWN_MODULE_${module}_TOOLS}" + CACHE INTERNAL "Known Qt module ${module} tools" FORCE) + endif() +endmacro() diff --git a/cmake/QtInstallHelpers.cmake b/cmake/QtInstallHelpers.cmake new file mode 100644 index 0000000000..5832df144c --- /dev/null +++ b/cmake/QtInstallHelpers.cmake @@ -0,0 +1,127 @@ +# Wraps install() command. In a prefix build, simply passes along arguments to install(). +# In a non-prefix build, handles association of targets to export names, and also calls export(). +function(qt_install) + set(flags) + set(options EXPORT DESTINATION NAMESPACE) + set(multiopts TARGETS) + cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) + + if(arg_TARGETS) + set(is_install_targets TRUE) + endif() + + # In a prefix build, always invoke install() without modification. + # In a non-prefix build, pass install(TARGETS) commands to allow + # association of targets to export names, so we can later use the export names + # in export() commands. + if(QT_WILL_INSTALL OR is_install_targets) + install(${ARGV}) + endif() + + # Exit early if this is a prefix build. + if(QT_WILL_INSTALL) + return() + endif() + + # In a non-prefix build, when install(EXPORT) is called, + # also call export(EXPORT) to generate build tree target files. + if(NOT is_install_targets AND arg_EXPORT) + set(namespace_option "") + if(arg_NAMESPACE) + set(namespace_option NAMESPACE ${arg_NAMESPACE}) + endif() + export(EXPORT ${arg_EXPORT} + ${namespace_option} + FILE "${arg_DESTINATION}/${arg_EXPORT}.cmake") + endif() +endfunction() + +# Copies files using file(COPY) signature in non-prefix builds. +function(qt_non_prefix_copy) + if(NOT QT_WILL_INSTALL) + file(${ARGV}) + endif() +endfunction() + +# Retrieve the permissions that are set by install(PROGRAMS). +function(qt_get_install_executable_permissions out_var) + set(default_permissions ${CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS}) + if(NOT default_permissions) + set(default_permissions OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + endif() + set(executable_permissions ${default_permissions} OWNER_EXECUTE) + if(GROUP_READ IN_LIST default_permissions) + list(APPEND executable_permissions GROUP_EXECUTE) + endif() + if(WORLD_READ IN_LIST default_permissions) + list(APPEND executable_permissions WORLD_EXECUTE) + endif() + set(${out_var} ${executable_permissions} PARENT_SCOPE) +endfunction() + +# Use case is installing files in a prefix build, or copying them to the correct build dir +# in a non-prefix build. +# Pass along arguments as you would pass them to install(). +# Only supports FILES, PROGRAMS and DIRECTORY signature, and without fancy things +# like OPTIONAL or RENAME or COMPONENT. +function(qt_copy_or_install) + set(flags FILES PROGRAMS DIRECTORY) + set(options) + set(multiopts) + cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) + + # Remember which option has to be passed to the install command. + set(copy_arguments "") + set(argv_copy ${ARGV}) + if(arg_FILES) + set(install_option "FILES") + elseif(arg_PROGRAMS) + set(install_option "PROGRAMS") + qt_get_install_executable_permissions(executable_permissions) + list(APPEND copy_arguments FILE_PERMISSIONS ${executable_permissions}) + elseif(arg_DIRECTORY) + set(install_option "DIRECTORY") + endif() + + list(REMOVE_AT argv_copy 0) + qt_install(${install_option} ${argv_copy}) + qt_non_prefix_copy(COPY ${argv_copy} ${copy_arguments}) +endfunction() + +# Hacky way to remove the install target in non-prefix builds. +# We need to associate targets with export names, and that is only possible to do with the +# install(TARGETS) command. But in a non-prefix build, we don't want to install anything. +# To make sure that developers don't accidentally run make install, replace the generated +# cmake_install.cmake file with an empty file. To do this, always create a new temporary file +# 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(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") + file(WRITE ${file_in} "") + + add_custom_command(OUTPUT ${file_generated} + COMMAND ${CMAKE_COMMAND} -E copy ${file_in} ${file_generated} + COMMAND ${CMAKE_COMMAND} -E remove ${cmake_install_file} + COMMAND ${CMAKE_COMMAND} -E touch ${cmake_install_file} + COMMENT "Removing cmake_install.cmake" + MAIN_DEPENDENCY ${file_in}) + + add_custom_target(remove_cmake_install ALL DEPENDS ${file_generated}) +endfunction() + +function(qt_set_up_nonprefix_build) + if(NOT QT_WILL_INSTALL) + qt_remove_install_target() + endif() +endfunction() diff --git a/cmake/QtLalrHelpers.cmake b/cmake/QtLalrHelpers.cmake new file mode 100644 index 0000000000..ce6f07007e --- /dev/null +++ b/cmake/QtLalrHelpers.cmake @@ -0,0 +1,54 @@ +# Match the pattern 'regex' in 'input_line', replace the match with 'replacement' +# and set that result in 'out_var' in the parent scope. +function(qt_regex_match_and_get input_line regex replacement out_var) + string(REGEX MATCH "${regex}" match "${input_line}") + if(match) + string(REGEX REPLACE "${regex}" "${replacement}" match "${input_line}") + string(STRIP ${match} match) + set(${out_var} "${match}" PARENT_SCOPE) + endif() +endfunction() + +# Match 'regex' in a list of lines. When found, set the value to 'out_var' and break early. +function(qt_qlalr_find_option_in_list input_list regex out_var) + foreach(line ${input_list}) + qt_regex_match_and_get("${line}" "${regex}" "\\1" option) + if(option) + string(TOLOWER ${option} option) + set(${out_var} "${option}" PARENT_SCOPE) + return() + endif() + endforeach() + message(FATAL_ERROR "qt_qlalr_find_option_in_list: Could not extract ${out_var}") +endfunction() + +# Generate a few output files using qlalr, and assign those to 'consuming_target'. +# 'input_file_list' is a list of 'foo.g' file paths. +# 'flags' are extra flags to be passed to qlalr. +function(qt_process_qlalr consuming_target input_file_list flags) + # Don't try to extend_target when cross compiling an imported host target (like a tool). + qt_is_imported_target("${consuming_target}" is_imported) + if(is_imported) + return() + endif() + + foreach(input_file ${input_file_list}) + file(STRINGS ${input_file} input_file_lines) + qt_qlalr_find_option_in_list("${input_file_lines}" "^%parser(.+)" "parser") + qt_qlalr_find_option_in_list("${input_file_lines}" "^%decl(.+)" "decl") + qt_qlalr_find_option_in_list("${input_file_lines}" "^%impl(.+)" "impl") + get_filename_component(base_file_name ${input_file} NAME_WE) + + set(cpp_file "${parser}.cpp") + set(private_file "${parser}_p.h") + set(decl_file "${decl}") + set(impl_file "${impl}") + 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}) + endforeach() +endfunction() diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake new file mode 100644 index 0000000000..6a4f49dc76 --- /dev/null +++ b/cmake/QtModuleHelpers.cmake @@ -0,0 +1,624 @@ +# 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. +# +# A CMake target with the specified target parameter is created. If the current source +# directory has a configure.cmake file, then that is also processed for feature definition +# and testing. Any features defined as well as any features coming from dependencies to +# 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(qt_add_module target) + qt_internal_module_info(module "${target}") + + # Process arguments: + 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;NO_CONFIG_HEADER_FILE;SKIP_DEPENDS_INCLUDE" + "MODULE_INCLUDE_NAME;CONFIG_MODULE_NAME;PRECOMPILED_HEADER;CONFIGURE_FILE_PATH;${__default_target_info_args}" + "${__default_private_args};${__default_public_args};${__default_private_module_args};QMAKE_MODULE_CONFIG;EXTRA_CMAKE_FILES;EXTRA_CMAKE_INCLUDES;NO_PCH_SOURCES" ${ARGN}) + + qt_internal_add_qt_repo_known_module("${target}") + + if(NOT DEFINED arg_CONFIG_MODULE_NAME) + set(arg_CONFIG_MODULE_NAME "${module_lower}") + endif() + + ### Define Targets: + set(is_interface_lib 0) + set(is_shared_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}) + add_library("${target}" SHARED) + set(is_shared_lib 1) + else() + add_library("${target}" STATIC) + endif() + + set(property_prefix "INTERFACE_") + if(NOT arg_HEADER_MODULE) + qt_set_common_target_properties(${target}) + set(property_prefix "") + endif() + + set_target_properties(${target} PROPERTIES + _qt_config_module_name "${arg_CONFIG_MODULE_NAME}" + ${property_prefix}QT_QMAKE_MODULE_CONFIG "${arg_QMAKE_MODULE_CONFIG}") + set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES _qt_config_module_name) + + 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(QT_FEATURE_reduce_relocations AND UNIX AND NOT is_interface_lib) + # On x86 and x86-64 systems with ELF binaries (especially Linux), due to + # a new optimization in GCC 5.x in combination with a recent version of + # GNU binutils, compiling Qt applications with -fPIE is no longer + # enough. + # Applications now need to be compiled with the -fPIC option if the Qt option + # \"reduce relocations\" is active. + target_compile_options(${target} INTERFACE -fPIC) + if(GCC AND is_shared_lib) + target_link_options(${target} PRIVATE LINKER:-Bsymbolic-functions) + endif() + endif() + + if(QT_FEATURE_separate_debug_info AND is_shared_lib AND (UNIX OR MINGW)) + qt_enable_separate_debug_info(${target} ${INSTALL_LIBDIR}) + 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}") + _qt_internal_apply_strict_cpp("${target}") + + # Add _private target to link against the private headers: + if(NOT ${arg_NO_PRIVATE_MODULE}) + set(target_private "${target}Private") + add_library("${target_private}" INTERFACE) + qt_internal_add_target_aliases("${target_private}") + set_target_properties(${target_private} PROPERTIES + _qt_config_module_name ${arg_CONFIG_MODULE_NAME}_private) + set_property(TARGET "${target_private}" APPEND PROPERTY + EXPORT_PROPERTIES _qt_config_module_name) + 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_set_target_info_properties(${target} ${ARGN}) + qt_handle_multi_config_output_dirs("${target}") + + if(NOT BUILD_SHARED_LIBS AND LINUX) + # Horrible workaround for static build failures due to incorrect static library link + # order. By increasing the multiplicity to 3, each library cycle will be repeated + # 3 times on the link line, reducing the probability of undefined symbols at + # link time. + # These failures are only observed on Linux with the ld linker (not sure about + # ld.gold). + # Allow opting out and modifying the value via cache value, in case if we urgently + # need to increase it without waiting for the qtbase change to propagate to + # other dependent repos. + # The proper fix will be to get rid of the cycles in the future. + # See QTBUG-83498 for details. + set(default_link_cycle_multiplicity "3") + if(DEFINED QT_LINK_CYCLE_MULTIPLICITY) + set(default_link_cycle_multiplicity "${QT_LINK_CYCLE_MULTIPLICITY}") + endif() + if(default_link_cycle_multiplicity) + set_property(TARGET "${target}" + PROPERTY + LINK_INTERFACE_MULTIPLICITY "${default_link_cycle_multiplicity}") + endif() + endif() + + if (arg_SKIP_DEPENDS_INCLUDE) + set_target_properties(${target} PROPERTIES QT_MODULE_SKIP_DEPENDS_INCLUDE TRUE) + endif() + 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() + + qt_internal_apply_win_prefix_and_suffix("${target}") + + if (WIN32 AND BUILD_SHARED_LIBS) + qt6_generate_win32_rc_file(${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) + else() + if(arg_MODULE_INCLUDE_NAME) + set(module_include_name ${arg_MODULE_INCLUDE_NAME}) + else() + set(module_include_name ${module}) + endif() + set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_INCLUDE_NAME "${module_include_name}") + + # Use QT_BUILD_DIR for the syncqt call. + # So we either write the generated files into the qtbase non-prefix build root, or the + # module specific build root. + qt_ensure_sync_qt() + set(syncqt_full_command "${HOST_PERL}" -w "${QT_SYNCQT}" + -quiet + -check-includes + -module "${module_include_name}" + -version "${PROJECT_VERSION}" + -outdir "${QT_BUILD_DIR}" + -builddir "${PROJECT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}") + message(STATUS "Running syncqt for module: '${module_include_name}' ") + execute_process(COMMAND ${syncqt_full_command}) + + set_target_properties("${target}" PROPERTIES INTERFACE_MODULE_HAS_HEADERS ON) + + ### FIXME: Can we replace headers.pri? + set(module_include_dir "${QT_BUILD_DIR}/include/${module_include_name}") + qt_read_headers_pri("${module_include_dir}" "module_headers") + 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_include_name}") + endif() + + if(module_headers_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_include_name}/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}) + 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() + + # Save the non-sanitized plugin type values for qmake consumption via .pri files. + set_property(TARGET "${target}" + PROPERTY QMAKE_MODULE_PLUGIN_TYPES "${arg_PLUGIN_TYPES}") + endif() + endif() + + qt_internal_library_deprecation_level(deprecation_define) + + if(NOT arg_HEADER_MODULE) + qt_autogen_tools_initial_setup(${target}) + endif() + + set(private_includes + "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>" + "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>" + ${arg_INCLUDE_DIRECTORIES} + ) + + set(public_includes "") + set(public_headers_list "public_includes") + if(is_framework) + set(public_headers_list "private_includes") + endif() + + # Make sure the BUILD_INTERFACE include paths come before the framework headers, so that the + # the compiler prefers the build dir includes. + # + # Make sure to add non-framework "build_dir/include" as an include path for moc to find the + # currently built module headers. qmake does this too. + # Framework-style include paths are found by moc when cmQtAutoMocUic.cxx detects frameworks by + # looking at an include path and detecting a "QtFoo.framework/Headers" path. + # Make sure to create such paths for both the the BUILD_INTERFACE and the INSTALL_INTERFACE. + # + # Only add syncqt headers if they exist. + # This handles cases like QmlDevTools which do not have their own headers, but borrow them + # from another module. + if(NOT arg_NO_SYNC_QT AND NOT arg_NO_MODULE_HEADERS) + # 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 + # For the syncqt headers + "$<BUILD_INTERFACE:${module_repo_include_dir}>" + "$<BUILD_INTERFACE:${module_include_dir}>") + endif() + + if(is_framework) + set(fw_bundle_subdir "${INSTALL_LIBDIR}/Qt${target}.framework") + list(APPEND public_includes + # Add the lib/Foo.framework dir as include path to let CMake generate + # the -F compiler flag for framework-style includes to work. + "$<INSTALL_INTERFACE:${fw_bundle_subdir}>" + + # Add the framework Headers subdir, so that non-framework-style includes work. The + # BUILD_INTERFACE Headers symlink was previously claimed not to exist at the relevant + # time, and a fully specified Header path was used instead. This doesn't seem to be a + # problem anymore. + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/${fw_bundle_subdir}/Headers>" + "$<INSTALL_INTERFACE:${fw_bundle_subdir}/Headers>" + ) + endif() + + if(NOT arg_NO_MODULE_HEADERS AND NOT arg_NO_SYNC_QT) + # For the syncqt headers + list(APPEND ${public_headers_list} "$<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${module}>") + endif() + list(APPEND ${public_headers_list} ${arg_PUBLIC_INCLUDE_DIRECTORIES}) + + set(header_module) + if(arg_HEADER_MODULE) + set(header_module "HEADER_MODULE") + + # Provide a *_timestamp target that can be used to trigger the build of custom_commands. + set(timestamp_file "${CMAKE_CURRENT_BINARY_DIR}/timestamp") + add_custom_command(OUTPUT "${timestamp_file}" + COMMAND ${CMAKE_COMMAND} -E touch "${timestamp_file}" + DEPENDS ${module_headers_public} + VERBATIM) + add_custom_target(${target}_timestamp ALL DEPENDS "${timestamp_file}") + endif() + + set(defines_for_extend_target "") + + if(NOT arg_HEADER_MODULE) + list(APPEND defines_for_extend_target + QT_NO_CAST_TO_ASCII QT_ASCII_CAST_WARNINGS + QT_MOC_COMPAT #we don't need warnings from calling moc code in our generated code + QT_USE_QSTRINGBUILDER + QT_DEPRECATED_WARNINGS + QT_BUILDING_QT + QT_BUILD_${module_define}_LIB ### FIXME: use QT_BUILD_ADDON for Add-ons or remove if we don't have add-ons anymore + "${deprecation_define}" + ) + endif() + + qt_extend_target("${target}" + ${header_module} + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${private_includes} + PUBLIC_INCLUDE_DIRECTORIES + ${public_includes} + PUBLIC_DEFINES + ${arg_PUBLIC_DEFINES} + QT_${module_define}_LIB + DEFINES + ${arg_DEFINES} + ${defines_for_extend_target} + 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} + DBUS_INTERFACE_SOURCES ${arg_DBUS_INTERFACE_SOURCES} + DBUS_INTERFACE_FLAGS ${arg_DBUS_INTERFACE_FLAGS} + 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} + PRECOMPILED_HEADER ${arg_PRECOMPILED_HEADER} + NO_PCH_SOURCES ${arg_NO_PCH_SOURCES} + ) + + if(NOT ${arg_EXCEPTIONS} AND NOT ${arg_HEADER_MODULE}) + qt_internal_set_no_exceptions_flags("${target}") + endif() + + set(configureFile "${CMAKE_CURRENT_SOURCE_DIR}/configure.cmake") + if(arg_CONFIGURE_FILE_PATH) + set(configureFile "${arg_CONFIGURE_FILE_PATH}") + endif() + if(EXISTS "${configureFile}" AND NOT arg_NO_CONFIG_HEADER_FILE) + qt_feature_module_begin( + LIBRARY "${target}" + PUBLIC_FILE "qt${arg_CONFIG_MODULE_NAME}-config.h" + PRIVATE_FILE "qt${arg_CONFIG_MODULE_NAME}-config_p.h" + PUBLIC_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} + PRIVATE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} + ) + include(${configureFile}) + qt_feature_module_end("${target}") + + set_property(TARGET "${target}" APPEND PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config.h") + set_property(TARGET "${target}" APPEND PROPERTY PRIVATE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/qt${arg_CONFIG_MODULE_NAME}-config_p.h") + endif() + + 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 + # automatically generated in the build dir (for example qconfig.h, qtcore-config.h, + # qvulkanfunctions.h, etc) + # module_headers_injections come from the qt_read_headers_pri() call. + # extra_library_injections come from the qt_feature_module_end() call. + set(final_injections "") + if(module_headers_injections) + string(APPEND final_injections "${module_headers_injections} ") + endif() + if(extra_library_injections) + string(APPEND final_injections "${extra_library_injections} ") + endif() + + if(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(). + 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(extra_cmake_files) + set(extra_cmake_includes) + if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") + list(APPEND extra_cmake_files "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") + list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}Macros.cmake") + endif() + if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in") + configure_file("${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake.in" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake" + @ONLY) + list(APPEND extra_cmake_files "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake") + list(APPEND extra_cmake_includes "${INSTALL_CMAKE_NAMESPACE}${target}ConfigExtras.cmake") + endif() + + foreach(cmake_file IN LISTS arg_EXTRA_CMAKE_FILES) + get_filename_component(basename ${cmake_file} NAME) + file(COPY ${cmake_file} DESTINATION ${config_build_dir}) + list(APPEND extra_cmake_files "${config_build_dir}/${basename}") + endforeach() + list(APPEND extra_cmake_includes ${arg_EXTRA_CMAKE_INCLUDES}) + + set(extra_cmake_code "") + + if(target STREQUAL Core) + # Propagate non-build related variables that are needed for consuming Qt packages. + # Do this in CoreConfig instead of Qt6Config, so that consumers can also use + # find_package(Qt6Core) instead of find_package(Qt6 COMPONENTS Core) + string(APPEND extra_cmake_code " +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} + COMPATIBILITY AnyNewerVersion + ) + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + ${extra_cmake_files} + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + file(COPY ${extra_cmake_files} DESTINATION "${config_build_dir}") + set(exported_targets ${target}) + if(NOT ${arg_NO_PRIVATE_MODULE}) + list(APPEND exported_targets ${target_private}) + endif() + set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") + qt_install(TARGETS ${exported_targets} + EXPORT ${export_name} + 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 + ) + + qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH) + + 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 + QT_ANDROID_MODULE_INSTALL_DIR ${INSTALL_LIBDIR}) + endif() + + qt_install(EXPORT ${export_name} + NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: + DESTINATION ${config_install_dir}) + + qt_internal_export_modern_cmake_config_targets_file( + TARGETS ${exported_targets} + EXPORT_NAME_PREFIX ${INSTALL_CMAKE_NAMESPACE}${target} + CONFIG_INSTALL_DIR "${config_install_dir}") + + if (${arg_INTERNAL_MODULE}) + set(arg_INTERNAL_MODULE "INTERNAL_MODULE") + else() + unset(arg_INTERNAL_MODULE) + endif() + + ### fixme: cmake is missing a built-in variable for this. We want to apply it only to modules and plugins + # that belong to Qt. + if(NOT arg_HEADER_MODULE) + qt_internal_add_link_flags_no_undefined("${target}") + endif() + + set(interface_includes "") + + # 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}>") + + # syncqt.pl does not create a private header directory like 'include/6.0/QtFoo' unless + # the module has foo_p.h header files. For QtZlib, there are no such private headers, so we + # need to make sure not to add such include paths unless the directory exists, otherwise + # consumers of the module will fail at CMake generation time stating that + # INTERFACE_INCLUDE_DIRECTORIES contains a non-existent path. + if(NOT arg_NO_MODULE_HEADERS + AND EXISTS "${module_include_dir}/${PROJECT_VERSION}/${module}") + list(APPEND interface_includes + "$<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}) + target_link_libraries("${target_private}" INTERFACE "${target}") + endif() + + if(is_framework AND NOT is_interface_lib) + qt_finalize_framework_headers_copy(${target}) + endif() + + qt_describe_module(${target}) + qt_add_list_file_finalizer(qt_finalize_module ${target} ${arg_INTERNAL_MODULE} ${header_module}) +endfunction() + +function(qt_finalize_module target) + qt_generate_prl_file(${target} "${INSTALL_LIBDIR}") + qt_generate_module_pri_file("${target}" ${ARGN}) +endfunction() + +# Get a set of Qt module related values based on the target name. +# When doing qt_internal_module_info(foo Core) this method will set +# the following variables in the caller's scope: +# * foo with the value "QtCore" +# * foo_versioned with the value "Qt6Core" (based on major Qt version) +# * foo_upper with the value "CORE" +# * foo_lower with the value "core" +# * foo_repo_include_dir with the module's include directory +# e.g for QtQuick it would be qtdeclarative_build_dir/include for a prefix build or +# qtbase_build_dir/include for a non-prefix build +# * foo_include_dir with the module's include directory +# e.g for QtQuick it would be qtdeclarative_build_dir/include/QtQuick for a prefix build or +# qtbase_build_dir/include/QtQuick for a non-prefix build +# * foo_define same as foo_uper but with - replaced as _ +function(qt_internal_module_info result target) + set(module "Qt${target}") + set("${result}" "${module}" PARENT_SCOPE) + set("${result}_versioned" "Qt${PROJECT_VERSION_MAJOR}${target}" PARENT_SCOPE) + string(TOUPPER "${target}" upper) + string(TOLOWER "${target}" lower)# * foo_upper with the value "CORE" + string(REPLACE "-" "_" define "${upper}") + 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}_define" "${define}" PARENT_SCOPE) +endfunction() + +# 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_CROSSCOMPILING) + set(cross_compilation "true") + endif() + configure_file("${descfile_in}" "${descfile_out}") + + qt_install(FILES "${descfile_out}" DESTINATION "${install_dir}") +endfunction() diff --git a/cmake/QtNoLinkTargetHelpers.cmake b/cmake/QtNoLinkTargetHelpers.cmake new file mode 100644 index 0000000000..debf1eb3cd --- /dev/null +++ b/cmake/QtNoLinkTargetHelpers.cmake @@ -0,0 +1,55 @@ +function(qt_create_nolink_target target dependee_target) + if(NOT TARGET "${target}") + message(FATAL_ERROR "${target} does not exist when trying to build a nolink target.") + endif() + get_target_property(type "${target}" TYPE) + if(type STREQUAL EXECUTABLE) + message(FATAL_ERROR "${target} must be a library of some kind.") + endif() + if(type STREQUAL OBJECT_LIBRARY) + message(FATAL_ERROR "${target} must not be an object library.") + endif() + + # Strip off the namespace prefix, so from Vulkan::Vulkan to Vulkan, and then append _nolink. + string(REGEX REPLACE "^.*::" "" non_prefixed_target ${target}) + set(nolink_target "${non_prefixed_target}_nolink") + + # 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 + # 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") + + # Whe configuring an example with qmake, if QtGui is built with Vulkan support but the + # user's machine where Qt is installed doesn't have Vulkan, qmake doesn't fail saying + # that vulkan is not installed. Instead it silently configures and just doesn't add + # the include headers. + # To mimic that in CMake, if the Vulkan CMake package is not found, we shouldn't fail + # at generation time saying that the Vulkan target does not exist. Instead check with a + # genex that the target exists to query the properties, otherwise just silently continue. + # FIXME: If we figure out that such behavior should only be applied to Vulkan, and not the + # other _nolink targets, we'll have to modify this to be configurable. + set(target_exists_genex "$<TARGET_EXISTS:${target}>") + set(props_to_set INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS + INTERFACE_COMPILE_FEATURES) + foreach(prop ${props_to_set}) + set_target_properties( + "${nolink_target}" PROPERTIES + ${prop} $<${target_exists_genex}:$<TARGET_PROPERTY:${target},${prop}>> + ) + endforeach() + + 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}) + endif() +endfunction() diff --git a/cmake/QtPluginHelpers.cmake b/cmake/QtPluginHelpers.cmake new file mode 100644 index 0000000000..06399bcc19 --- /dev/null +++ b/cmake/QtPluginHelpers.cmake @@ -0,0 +1,308 @@ +# 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(qt_internal_add_plugin target) + qt_internal_module_info(module "${target}") + + qt_internal_set_qt_known_plugins("${QT_KNOWN_PLUGINS}" "${target}") + + qt_parse_all_arguments(arg "qt_internal_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}" plugin_type_escaped) + + set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}/${arg_TYPE}") + set(install_directory_default "${INSTALL_PLUGINSDIR}/${arg_TYPE}") + + if (arg_QML_TARGET_PATH) + set(target_path "${arg_QML_TARGET_PATH}") + set(output_directory_default "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${target_path}") + set(install_directory_default "${INSTALL_QMLDIR}/${target_path}") + endif() + + # 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 "${plugin_type_escaped}" STREQUAL "qml_plugin") + if (NOT arg_CLASS_NAME) + set(plugin_class_name "${target}") + else() + set(plugin_class_name "${arg_CLASS_NAME}") + endif() + endif() + + qt_internal_check_directory_or_type(OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" "${arg_TYPE}" + "${output_directory_default}" output_directory) + if (NOT arg_SKIP_INSTALL) + qt_internal_check_directory_or_type(INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}" "${arg_TYPE}" + "${install_directory_default}" install_directory) + set(archive_install_directory ${arg_ARCHIVE_INSTALL_DIRECTORY}) + if (NOT archive_install_directory AND install_directory) + set(archive_install_directory "${install_directory}") + endif() + endif() + + if(arg_STATIC OR NOT BUILD_SHARED_LIBS) + add_library("${target}" STATIC) + else() + add_library("${target}" MODULE) + 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() + qt_internal_apply_win_prefix_and_suffix("${target}") + endif() + + qt_set_common_target_properties(${target}) + qt_set_target_info_properties(${target} ${ARGN} TARGET_VERSION "${arg_VERSION}") + + # 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}") + _qt_internal_apply_strict_cpp("${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_TYPE "${plugin_type_escaped}" + # Save the non-sanitized plugin type values for qmake consumption via .pri files. + QT_QMAKE_PLUGIN_TYPE "${arg_TYPE}" + QT_PLUGIN_CLASS_NAME "${plugin_class_name}") + qt_handle_multi_config_output_dirs("${target}") + + qt_internal_library_deprecation_level(deprecation_define) + + qt_autogen_tools_initial_setup(${target}) + + set(static_plugin_define "") + if (arg_STATIC OR NOT QT_BUILD_SHARED_LIBS) + set(static_plugin_define "QT_STATICPLUGIN") + endif() + + # Save the Qt module in the plug-in's properties + if(NOT plugin_type_escaped STREQUAL "qml_plugin") + qt_get_module_for_plugin("${target}" "${plugin_type_escaped}") + get_target_property(qt_module "${target}" QT_MODULE) + set(plugin_install_package_suffix "${qt_module}") + endif() + + # Add the plug-in to the list of plug-ins of this module + if(TARGET "${qt_module}") + set_property(TARGET "${qt_module}" APPEND PROPERTY QT_PLUGINS "${target}") + endif() + + # Change the configuration file install location for qml plugins into the Qml package location. + if(plugin_type_escaped STREQUAL "qml_plugin" AND TARGET "${INSTALL_CMAKE_NAMESPACE}::Qml") + set(plugin_install_package_suffix "Qml/QmlPlugins") + endif() + + # Save the install package suffix as a property, so that the Dependencies file is placed + # in the current location. + if(plugin_install_package_suffix) + set_target_properties("${target}" PROPERTIES + _qt_plugin_install_package_suffix "${plugin_install_package_suffix}") + endif() + + set(_default_plugin 1) + if (DEFINED arg_DEFAULT_IF) + if (NOT ${arg_DEFAULT_IF}) + set(_default_plugin 0) + endif() + endif() + + set_property(TARGET "${target}" PROPERTY QT_DEFAULT_PLUGIN "${_default_plugin}") + set_property(TARGET "${target}" APPEND PROPERTY EXPORT_PROPERTIES "QT_PLUGIN_CLASS_NAME;QT_PLUGIN_TYPE;QT_MODULE;QT_DEFAULT_PLUGIN") + + set(private_includes + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + # For the syncqt headers + "$<BUILD_INTERFACE:${module_repo_include_dir}>" + ${arg_INCLUDE_DIRECTORIES} + ) + + set(public_includes + ${arg_PUBLIC_INCLUDE_DIRECTORIES} + ) + + qt_extend_target("${target}" + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${private_includes} + PUBLIC_INCLUDE_DIRECTORIES + ${public_includes} + LIBRARIES ${arg_LIBRARIES} Qt::PlatformPluginInternal + PUBLIC_LIBRARIES ${arg_PUBLIC_LIBRARIES} + DEFINES + ${arg_DEFINES} + QT_DEPRECATED_WARNINGS + "${deprecation_define}" + "${static_plugin_define}" + QT_PLUGIN + PUBLIC_DEFINES + QT_${module_define}_LIB + ${arg_PUBLIC_DEFINES} + FEATURE_DEPENDENCIES ${arg_FEATURE_DEPENDENCIES} + DBUS_ADAPTOR_SOURCES "${arg_DBUS_ADAPTOR_SOURCES}" + DBUS_ADAPTOR_FLAGS "${arg_DBUS_ADAPTOR_FLAGS}" + DBUS_INTERFACE_SOURCES "${arg_DBUS_INTERFACE_SOURCES}" + DBUS_INTERFACE_FLAGS "${arg_DBUS_INTERFACE_FLAGS}" + 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} + ) + if(NOT ${arg_EXCEPTIONS}) + qt_internal_set_no_exceptions_flags("${target}") + endif() + + + set(qt_libs_private "") + qt_internal_get_qt_all_known_modules(known_modules) + foreach(it ${known_modules}) + list(FIND arg_LIBRARIES "Qt::${it}Private" pos) + if(pos GREATER -1) + list(APPEND qt_libs_private "Qt::${it}Private") + endif() + endforeach() + + qt_register_target_dependencies("${target}" "${arg_PUBLIC_LIBRARIES}" "${qt_libs_private}") + qt_generate_plugin_pri_file("${target}" pri_file) + + if (NOT arg_SKIP_INSTALL) + # Handle creation of cmake files for consumers of find_package(). + # If we are part of a Qt module, the plugin cmake files are installed as part of that + # module. + # For qml plugins, they are all installed into the QtQml package location for automatic + # discovery. + if(plugin_install_package_suffix) + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${plugin_install_package_suffix}") + else() + set(path_suffix "${INSTALL_CMAKE_NAMESPACE}${target}") + endif() + + 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_package_config_file( + "${QT_CMAKE_DIR}/QtPluginConfig.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(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + qt_install(FILES + "${pri_file}" + DESTINATION "${INSTALL_MKSPECSDIR}/modules" + ) + + # Make the export name of plugins be consistent with modules, so that + # 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} + RUNTIME DESTINATION "${install_directory}" + LIBRARY DESTINATION "${install_directory}" + ARCHIVE DESTINATION "${archive_install_directory}" + ) + qt_install(EXPORT ${export_name} + NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}:: + DESTINATION "${config_install_dir}" + ) + qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH) + endif() + + 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() + + qt_internal_add_linker_version_script(${target}) + qt_add_list_file_finalizer(qt_finalize_plugin ${target} "${install_directory}") +endfunction() + +function(qt_finalize_plugin target install_directory) + # Generate .prl files for plugins of static Qt builds. + if(NOT BUILD_SHARED_LIBS) + qt_generate_prl_file(${target} "${install_directory}") + 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() + +# Utility function to find the module to which a plug-in belongs. +# 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 + # name, because the current one would be invalid for interface libraries. + if(module_type STREQUAL "INTERFACE_LIBRARY") + continue() + endif() + + get_target_property(plugin_types + "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_module}" + MODULE_PLUGIN_TYPES) + if(plugin_types) + foreach(plugin_type ${plugin_types}) + if("${target_type}" STREQUAL "${plugin_type}") + set_target_properties("${target}" PROPERTIES QT_MODULE "${qt_module}") + return() + endif() + endforeach() + endif() + endforeach() + message(AUTHOR_WARNING "The plug-in '${target}' does not belong to any Qt module.") +endfunction() diff --git a/cmake/QtPrecompiledHeadersHelpers.cmake b/cmake/QtPrecompiledHeadersHelpers.cmake new file mode 100644 index 0000000000..b9735cd52a --- /dev/null +++ b/cmake/QtPrecompiledHeadersHelpers.cmake @@ -0,0 +1,29 @@ +function(qt_update_precompiled_header target precompiled_header) + if (precompiled_header AND BUILD_WITH_PCH) + set_property(TARGET "${target}" APPEND PROPERTY "PRECOMPILE_HEADERS" "$<$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:OBJCXX>>:${precompiled_header}>") + endif() +endfunction() + +function(qt_update_precompiled_header_with_library target library) + if (TARGET "${library}") + get_target_property(TARGET_TYPE "${library}" TYPE) + if (NOT TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") + get_target_property(HEADER "${library}" MODULE_HEADER) + qt_update_precompiled_header("${target}" "${HEADER}") + endif() + endif() +endfunction() + +function(qt_update_ignore_pch_source target sources) + if (sources) + set_source_files_properties(${sources} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) + endif() +endfunction() + +function(qt_ignore_pch_obj_c_sources target sources) + # No obj-cxx PCH support for versions lower than 3.16. + if(CMAKE_VERSION VERSION_LESS 3.16.0) + list(FILTER sources INCLUDE REGEX "\\.mm$") + qt_update_ignore_pch_source("${target}" "${sources}") + endif() +endfunction() diff --git a/cmake/QtPriHelpers.cmake b/cmake/QtPriHelpers.cmake new file mode 100644 index 0000000000..a82e3bb227 --- /dev/null +++ b/cmake/QtPriHelpers.cmake @@ -0,0 +1,728 @@ +# Extracts the 3rdparty libraries for the module ${module_name} +# and stores the information in cmake language in +# ${output_root_dir}/$<CONFIG>/${output_file_name}. +# +# This function "follows" INTERFACE_LIBRARY targets to "real" targets +# and collects defines, include dirs and lib dirs on the way. +function(qt_generate_qmake_libraries_pri_content module_name output_root_dir output_file_name) + set(content "") + + # Set up a regular expression that matches all implicit include dirs + set(implicit_include_dirs_regex "") + foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) + qt_re_escape(regex "${dir}") + list(APPEND implicit_include_dirs_regex ${regex}) + endforeach() + list(JOIN implicit_include_dirs_regex "|" implicit_include_dirs_regex) + + foreach(lib ${QT_QMAKE_LIBS_FOR_${module_name}}) + set(lib_targets ${QT_QMAKE_LIB_TARGETS_${lib}}) + string(TOUPPER ${lib} uclib) + set(lib_defines "") + set(lib_incdir "") + set(lib_libdir "") + set(lib_libs "") + while(lib_targets) + list(POP_BACK lib_targets lib_target) + if(TARGET ${lib_target}) + get_target_property(lib_target_type ${lib_target} TYPE) + if(lib_target_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(iface_libs ${lib_target} INTERFACE_LINK_LIBRARIES) + if(iface_libs) + list(PREPEND lib_targets ${iface_libs}) + endif() + else() + list(APPEND lib_libs "$<TARGET_LINKER_FILE:${lib_target}>") + endif() + list(APPEND lib_libdir "$<TARGET_PROPERTY:${lib_target},INTERFACE_LINK_DIRECTORIES>") + list(APPEND lib_incdir "$<TARGET_PROPERTY:${lib_target},INTERFACE_INCLUDE_DIRECTORIES>") + list(APPEND lib_defines "$<TARGET_PROPERTY:${lib_target},INTERFACE_COMPILE_DEFINITIONS>") + else() + if(lib_target MATCHES "/([^/]+).framework$") + list(APPEND lib_libs "-framework" "${CMAKE_MATCH_1}") + else() + list(APPEND lib_libs "${lib_target}") + endif() + endif() + endwhile() + + # Wrap in $<REMOVE_DUPLICATES:...> but not the libs, because + # we would have to preserve the right order for the linker. + foreach(sfx libdir incdir defines) + string(PREPEND lib_${sfx} "$<REMOVE_DUPLICATES:") + string(APPEND lib_${sfx} ">") + endforeach() + + # Filter out implicit include directories + string(PREPEND lib_incdir "$<FILTER:") + string(APPEND lib_incdir ",EXCLUDE,${implicit_include_dirs_regex}>") + + set(uccfg $<UPPER_CASE:$<CONFIG>>) + string(APPEND content "list(APPEND known_libs ${uclib}) +set(QMAKE_LIBS_${uclib}_${uccfg} \"${lib_libs}\") +set(QMAKE_LIBDIR_${uclib}_${uccfg} \"${lib_libdir}\") +set(QMAKE_INCDIR_${uclib}_${uccfg} \"${lib_incdir}\") +set(QMAKE_DEFINES_${uclib}_${uccfg} \"${lib_defines}\") +") + if(QT_QMAKE_LIB_DEPS_${lib}) + string(APPEND content "set(QMAKE_DEPENDS_${uclib}_CC, ${deps}) +set(QMAKE_DEPENDS_${uclib}_LD, ${deps}) +") + endif() + endforeach() + + file(GENERATE + OUTPUT "${output_root_dir}/$<CONFIG>/${output_file_name}" + CONTENT "${content}" + ) +endfunction() + +# Retrieves the public Qt module dependencies of the given Qt module or Qt Private module. +function(qt_get_direct_module_dependencies target out_var) + set(dependencies "") + get_target_property(libs ${target} INTERFACE_LINK_LIBRARIES) + if(NOT libs) + set(libs "") + endif() + get_target_property(target_type ${target} TYPE) + while(libs) + list(POP_FRONT libs lib) + string(GENEX_STRIP "${lib}" lib) + if(NOT lib OR NOT TARGET "${lib}") + continue() + endif() + get_target_property(lib_type ${lib} TYPE) + get_target_property(is_versionless_target ${lib} _qt_is_versionless_target) + if (lib_type STREQUAL "INTERFACE_LIBRARY" AND is_versionless_target) + # Found a version-less target like Qt::Core outside of qtbase. + # Skip this one and use what this target points to, e.g. Qt6::Core. + # Make sure to process Private interface libraries as-is. + get_target_property(ifacelibs ${lib} INTERFACE_LINK_LIBRARIES) + list(PREPEND libs ${ifacelibs}) + continue() + endif() + if(lib_type STREQUAL "OBJECT_LIBRARY") + # Skip object libraries, because they're already part of ${target}. + continue() + elseif(lib_type STREQUAL "STATIC_LIBRARY" AND target_type STREQUAL "SHARED_LIBRARY") + # Skip static libraries if ${target} is a shared library. + continue() + endif() + get_target_property(lib_config_module_name ${lib} "_qt_config_module_name") + if(lib_config_module_name) + list(APPEND dependencies ${lib_config_module_name}) + endif() + endwhile() + set(${out_var} ${dependencies} PARENT_SCOPE) +endfunction() + +# Generates module .pri files for consumption by qmake +function(qt_generate_module_pri_file target) + set(flags INTERNAL_MODULE HEADER_MODULE) + set(options) + set(multiopts) + cmake_parse_arguments(arg "${flags}" "${options}" "${multiopts}" ${ARGN}) + + qt_internal_module_info(module "${target}") + set(pri_files) + + set(property_prefix) + if(arg_HEADER_MODULE) + set(property_prefix "INTERFACE_") + endif() + + get_target_property(enabled_features "${target}" + "${property_prefix}QT_ENABLED_PUBLIC_FEATURES") + get_target_property(disabled_features "${target}" + "${property_prefix}QT_DISABLED_PUBLIC_FEATURES") + get_target_property(enabled_private_features "${target}" + "${property_prefix}QT_ENABLED_PRIVATE_FEATURES") + get_target_property(disabled_private_features "${target}" + "${property_prefix}QT_DISABLED_PRIVATE_FEATURES") + qt_correct_features(enabled_features "${enabled_features}") + qt_correct_features(disabled_features "${disabled_features}") + qt_correct_features(enabled_private_features "${enabled_private_features}") + qt_correct_features(disabled_private_features "${disabled_private_features}") + + foreach(var enabled_features disabled_features enabled_private_features disabled_private_features) + if(${var} STREQUAL "${var}-NOTFOUND") + set(${var} "") + else() + string (REPLACE ";" " " ${var} "${${var}}") + endif() + endforeach() + + set(module_internal_config v2) + if(NOT QT_FEATURE_shared) + list(APPEND module_internal_config staticlib) + endif() + if(arg_INTERNAL_MODULE) + list(APPEND module_internal_config internal_module) + endif() + + get_target_property(target_type ${target} TYPE) + if (NOT target_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(is_fw ${target} FRAMEWORK) + if(is_fw) + list(APPEND module_internal_config lib_bundle) + endif() + endif() + + # TODO: Add the value 'ltcg' to module_internal_config if LTCG is turned on. + + list(JOIN module_internal_config " " joined_module_internal_config) + + get_target_property(config_module_name ${target} _qt_config_module_name) + get_target_property(qmake_module_config ${target} ${property_prefix}QT_QMAKE_MODULE_CONFIG) + if(qmake_module_config) + string(REPLACE ";" " " module_build_config "${qmake_module_config}") + set(module_build_config "\nQT.${config_module_name}.CONFIG = ${module_build_config}") + else() + set(module_build_config "") + endif() + + if(is_fw) + set(framework_base_path "$$QT_MODULE_LIB_BASE/${module}.framework/Headers") + set(public_module_includes "${framework_base_path}") + set(public_module_frameworks "$$QT_MODULE_LIB_BASE") + set(private_module_includes "${framework_base_path}/${PROJECT_VERSION} ${framework_base_path}/${PROJECT_VERSION}/${module}") + set(module_name_in_pri "${module}") + else() + set(public_module_includes "$$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/${module}") + set(public_module_frameworks "") + set(private_module_includes "$$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION} $$QT_MODULE_INCLUDE_BASE/${module}/${PROJECT_VERSION}/${module}") + set(module_name_in_pri "${module_versioned}") + endif() + + qt_path_join(target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules) + if (arg_INTERNAL_MODULE) + string(PREPEND private_module_includes "${public_module_includes} ") + set(private_module_frameworks ${public_module_frameworks}) + else() + unset(private_module_frameworks) + if(arg_HEADER_MODULE) + set(module_plugin_types "") + else() + get_target_property(module_plugin_types ${target} QMAKE_MODULE_PLUGIN_TYPES) + if(module_plugin_types) + list(JOIN module_plugin_types " " module_plugin_types) + else() + set(module_plugin_types "") + endif() + endif() + + qt_get_direct_module_dependencies(${target} public_module_dependencies) + list(JOIN public_module_dependencies " " public_module_dependencies) + + qt_path_join(pri_file_name "${target_path}" "qt_lib_${config_module_name}.pri") + list(APPEND pri_files "${pri_file_name}") + + # Don't use $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS> genex because that + # will compute the transitive list of all defines for a module (so Gui would get Core + #defines too). Instead query just the public defines on the target. + get_target_property(target_defines "${target}" INTERFACE_COMPILE_DEFINITIONS) + + # We must filter out expressions of the form $<TARGET_PROPERTY:name>, because + # 1. They cannot be used in file(GENERATE) content. + # 2. They refer to the consuming target we have no access to here. + list(FILTER target_defines EXCLUDE REGEX "\\$<TARGET_PROPERTY:[^,>]+>") + list(JOIN target_defines " " joined_target_defines) + + file(GENERATE + OUTPUT "${pri_file_name}" + CONTENT + "QT.${config_module_name}.VERSION = ${PROJECT_VERSION} +QT.${config_module_name}.name = ${module} +QT.${config_module_name}.module = ${module_name_in_pri} +QT.${config_module_name}.libs = $$QT_MODULE_LIB_BASE +QT.${config_module_name}.includes = ${public_module_includes} +QT.${config_module_name}.frameworks = ${public_module_frameworks} +QT.${config_module_name}.bins = $$QT_MODULE_BIN_BASE +QT.${config_module_name}.plugin_types = ${module_plugin_types} +QT.${config_module_name}.depends = ${public_module_dependencies} +QT.${config_module_name}.uses = +QT.${config_module_name}.module_config = ${joined_module_internal_config} +QT.${config_module_name}.DEFINES = ${joined_target_defines} +QT.${config_module_name}.enabled_features = ${enabled_features} +QT.${config_module_name}.disabled_features = ${disabled_features}${module_build_config} +QT_CONFIG += ${enabled_features} +QT_MODULES += ${config_module_name} +" + ) + endif() + + set(pri_data_cmake_file "qt_lib_${config_module_name}_private.cmake") + qt_generate_qmake_libraries_pri_content(${config_module_name} "${CMAKE_CURRENT_BINARY_DIR}" + ${pri_data_cmake_file}) + + set(private_pri_file_name "qt_lib_${config_module_name}_private.pri") + + set(private_module_dependencies "") + if(NOT arg_HEADER_MODULE) + qt_get_direct_module_dependencies(${target}Private private_module_dependencies) + endif() + list(JOIN private_module_dependencies " " private_module_dependencies) + + # Generate a preliminary qt_lib_XXX_private.pri file + file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}" + CONTENT + "QT.${config_module_name}_private.VERSION = ${PROJECT_VERSION} +QT.${config_module_name}_private.name = ${module} +QT.${config_module_name}_private.module = +QT.${config_module_name}_private.libs = $$QT_MODULE_LIB_BASE +QT.${config_module_name}_private.includes = ${private_module_includes} +QT.${config_module_name}_private.frameworks = ${private_module_frameworks} +QT.${config_module_name}_private.depends = ${private_module_dependencies} +QT.${config_module_name}_private.uses = +QT.${config_module_name}_private.module_config = ${joined_module_internal_config} +QT.${config_module_name}_private.enabled_features = ${enabled_private_features} +QT.${config_module_name}_private.disabled_features = ${disabled_private_features}" + ) + + if(QT_GENERATOR_IS_MULTI_CONFIG) + set(configs ${CMAKE_CONFIGURATION_TYPES}) + else() + set(configs ${CMAKE_BUILD_TYPE}) + endif() + set(inputs "${CMAKE_CURRENT_BINARY_DIR}/${private_pri_file_name}") + foreach(cfg ${configs}) + list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/${pri_data_cmake_file}") + endforeach() + + qt_path_join(private_pri_file_path "${target_path}" "${private_pri_file_name}") + list(APPEND pri_files "${private_pri_file_path}") + + set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX}) + set(library_suffixes + ${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES} + ${CMAKE_STATIC_LIBRARY_SUFFIX}) + add_custom_command( + OUTPUT "${private_pri_file_path}" + DEPENDS ${inputs} + "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake" + "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake" + COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${private_pri_file_path}" + "-DLIBRARY_PREFIXES=${library_prefixes}" + "-DLIBRARY_SUFFIXES=${library_suffixes}" + "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}" + "-DCONFIGS=${configs}" + -P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake" + VERBATIM) + add_custom_target(${target}_lib_pri DEPENDS "${private_pri_file_path}") + if(arg_HEADER_MODULE) + add_dependencies(${target}_timestamp ${target}_lib_pri) + else() + add_dependencies(${target} ${target}_lib_pri) + endif() + qt_install(FILES "${pri_files}" DESTINATION ${INSTALL_MKSPECSDIR}/modules) +endfunction() + +# Generates qt_ext_XXX.pri files for consumption by qmake +function(qt_generate_3rdparty_lib_pri_file target lib pri_file_var) + if(NOT lib) + # Don't write a pri file for projects that don't set QMAKE_LIB_NAME yet. + return() + endif() + + if(QT_GENERATOR_IS_MULTI_CONFIG) + set(configs ${CMAKE_CONFIGURATION_TYPES}) + else() + set(configs ${CMAKE_BUILD_TYPE}) + endif() + + file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/qt_ext_${lib}.cmake" + CONTENT "set(cfg $<CONFIG>) +set(incdir $<TARGET_PROPERTY:${target},INTERFACE_INCLUDE_DIRECTORIES>) +set(defines $<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS>) +set(libs $<TARGET_FILE:${target}>) +") + + set(inputs "") + foreach(cfg ${configs}) + list(APPEND inputs "${CMAKE_CURRENT_BINARY_DIR}/${cfg}/qt_ext_${lib}.cmake") + endforeach() + + qt_path_join(pri_target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules) + qt_path_join(pri_file "${pri_target_path}" "qt_ext_${lib}.pri") + qt_path_join(qt_build_libdir ${QT_BUILD_DIR} ${INSTALL_LIBDIR}) + add_custom_command( + OUTPUT "${pri_file}" + DEPENDS ${inputs} "${QT_CMAKE_DIR}/QtGenerateExtPri.cmake" + COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${pri_file}" -DLIB=${lib} + "-DCONFIGS=${configs}" + "-DQT_BUILD_LIBDIR=${qt_build_libdir}" + -P "${QT_CMAKE_DIR}/QtGenerateExtPri.cmake" + VERBATIM) + add_custom_target(${target}_ext_pri DEPENDS "${pri_file}") + add_dependencies(${target} ${target}_ext_pri) + set(${pri_file_var} ${pri_file} PARENT_SCOPE) +endfunction() + +# Generates qt_plugin_XXX.pri files for consumption by qmake +# +# QT_PLUGIN.XXX.EXTENDS is set to "-" for the following plugin types: +# - generic +# - platform, if the plugin is not the default QPA plugin +# Otherwise, this variable is empty. +function(qt_generate_plugin_pri_file target pri_file_var) + get_target_property(plugin_name ${target} OUTPUT_NAME) + get_target_property(plugin_type ${target} QT_PLUGIN_TYPE) + get_target_property(qmake_plugin_type ${target} QT_QMAKE_PLUGIN_TYPE) + get_target_property(default_plugin ${target} QT_DEFAULT_PLUGIN) + get_target_property(plugin_class_name ${target} QT_PLUGIN_CLASS_NAME) + + set(plugin_extends "") + if(NOT default_plugin AND (plugin_type STREQUAL "generic" OR plugin_type STREQUAL "platforms")) + set(plugin_extends "-") + endif() + + set(plugin_deps "") + get_target_property(target_deps ${target} _qt_target_deps) + foreach(dep ${target_deps}) + list(GET dep 0 dep_name) + qt_get_qmake_module_name(dep_name ${dep_name}) + list(APPEND plugin_deps ${dep_name}) + endforeach() + list(REMOVE_DUPLICATES plugin_deps) + list(JOIN plugin_deps " " plugin_deps) + + qt_path_join(pri_target_path ${QT_BUILD_DIR} ${INSTALL_MKSPECSDIR}/modules) + qt_path_join(pri_file "${pri_target_path}" "qt_plugin_${plugin_name}.pri") + qt_configure_file(OUTPUT "${pri_file}" + CONTENT "QT_PLUGIN.${plugin_name}.TYPE = ${qmake_plugin_type} +QT_PLUGIN.${plugin_name}.EXTENDS = ${plugin_extends} +QT_PLUGIN.${plugin_name}.DEPENDS = ${plugin_deps} +QT_PLUGIN.${plugin_name}.CLASS_NAME = ${plugin_class_name} +QT_PLUGINS += ${plugin_name} +") + set(${pri_file_var} "${pri_file}" PARENT_SCOPE) +endfunction() + +# Creates mkspecs/qconfig.pri which contains public global features among other things. +function(qt_generate_global_config_pri_file) + 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) + get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PUBLIC_FEATURES) + + qt_correct_features(corrected_enabled_features "${enabled_features}") + qt_correct_features(corrected_disabled_features "${disabled_features}") + + string (REPLACE ";" " " corrected_enabled_features "${corrected_enabled_features}") + string (REPLACE ";" " " corrected_disabled_features "${corrected_disabled_features}") + + # Add some required CONFIG entries. + set(config_entries "") + if(CMAKE_BUILD_TYPE STREQUAL Debug) + list(APPEND config_entries "debug") + elseif(CMAKE_BUILD_TYPE STREQUAL Release) + list(APPEND config_entries "release") + endif() + list(APPEND config_entries "${qt_build_config_type}") + string (REPLACE ";" " " config_entries "${config_entries}") + + get_target_property(public_config GlobalConfig INTERFACE_QT_QMAKE_PUBLIC_CONFIG) + get_target_property(qt_public_config GlobalConfig INTERFACE_QT_QMAKE_PUBLIC_QT_CONFIG) + qt_correct_config(corrected_public_config "${public_config}") + qt_correct_config(corrected_qt_public_config "${qt_public_config}") + qt_guess_qmake_build_config(qmake_build_config) + list(APPEND corrected_qt_public_config ${qmake_build_config}) + + list(JOIN corrected_public_config " " public_config_joined) + list(JOIN corrected_qt_public_config " " qt_public_config_joined) + + set(content "") + if(GCC OR CLANG AND NOT "${CMAKE_SYSROOT}" STREQUAL "") + string(APPEND content "!host_build { + QMAKE_CFLAGS += --sysroot=\$\$[QT_SYSROOT] + QMAKE_CXXFLAGS += --sysroot=\$\$[QT_SYSROOT] + QMAKE_LFLAGS += --sysroot=\$\$[QT_SYSROOT] +} +") + endif() + + if(CMAKE_CROSSCOMPILING) + string(APPEND content "host_build { + QT_ARCH = ${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_ARCH} + QT_BUILDABI = ${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BUILDABI} + QT_TARGET_ARCH = ${TEST_architecture_arch} + QT_TARGET_BUILDABI = ${TEST_buildAbi} +} else { + QT_ARCH = ${TEST_architecture_arch} + QT_BUILDABI = ${TEST_buildAbi} + QT_LIBCPP_ABI_TAG = ${TEST_libcppabiTag} +} +") + else() + string(APPEND content "QT_ARCH = ${TEST_architecture_arch} +QT_BUILDABI = ${TEST_buildAbi} +QT_LIBCPP_ABI_TAG = ${TEST_libcppabiTag} +") + endif() + + string(APPEND content "QT.global.enabled_features = ${corrected_enabled_features} +QT.global.disabled_features = ${corrected_disabled_features} +QT.global.disabled_features += release build_all +QT_CONFIG += ${qt_public_config_joined} +CONFIG += ${config_entries} ${public_config_joined} +QT_VERSION = ${PROJECT_VERSION} +QT_MAJOR_VERSION = ${PROJECT_VERSION_MAJOR} +QT_MINOR_VERSION = ${PROJECT_VERSION_MINOR} +QT_PATCH_VERSION = ${PROJECT_VERSION_PATCH} +") + + set(extra_statements "") + if(QT_NAMESPACE) + list(APPEND extra_statements "QT_NAMESPACE = ${QT_NAMESPACE}") + endif() + # TODO: Add libinfix support. + + # TODO: Add QT_EMCC_VERSION when WASM is ported over. + if(APPLECLANG) + set(compiler_version_major_var_name "QT_APPLE_CLANG_MAJOR_VERSION") + set(compiler_version_minor_var_name "QT_APPLE_CLANG_MINOR_VERSION") + set(compiler_version_patch_var_name "QT_APPLE_CLANG_PATCH_VERSION") + elseif(CLANG) + set(compiler_version_major_var_name "QT_CLANG_MAJOR_VERSION") + set(compiler_version_minor_var_name "QT_CLANG_MINOR_VERSION") + set(compiler_version_patch_var_name "QT_CLANG_PATCH_VERSION") + elseif(GCC) + set(compiler_version_major_var_name "QT_GCC_MAJOR_VERSION") + set(compiler_version_minor_var_name "QT_GCC_MINOR_VERSION") + set(compiler_version_patch_var_name "QT_GCC_PATCH_VERSION") + elseif(ICC) + set(compiler_version_major_var_name "QT_ICC_MAJOR_VERSION") + set(compiler_version_minor_var_name "QT_ICC_MINOR_VERSION") + set(compiler_version_patch_var_name "QT_ICC_PATCH_VERSION") + elseif(MSVC) + set(compiler_version_major_var_name "QT_MSVC_MAJOR_VERSION") + set(compiler_version_minor_var_name "QT_MSVC_MINOR_VERSION") + set(compiler_version_patch_var_name "QT_MSVC_PATCH_VERSION") + endif() + + if(compiler_version_major_var_name) + list(APPEND extra_statements + "${compiler_version_major_var_name} = ${QT_COMPILER_VERSION_MAJOR}") + list(APPEND extra_statements + "${compiler_version_minor_var_name} = ${QT_COMPILER_VERSION_MINOR}") + list(APPEND extra_statements + "${compiler_version_patch_var_name} = ${QT_COMPILER_VERSION_PATCH}") + endif() + + if(APPLE) + list(APPEND extra_statements "QT_MAC_SDK_VERSION = ${QT_MAC_SDK_VERSION}") + list(APPEND extra_statements + "QMAKE_MACOSX_DEPLOYMENT_TARGET = ${CMAKE_OSX_DEPLOYMENT_TARGET}") + endif() + + list(APPEND extra_statements "QT_EDITION = Open Source") + + if(extra_statements) + string(REPLACE ";" "\n" extra_statements "${extra_statements}") + string(APPEND content "\n${extra_statements}\n") + endif() + + file(GENERATE + OUTPUT "${qconfig_pri_target_path}" + CONTENT "${content}" + ) + qt_install(FILES "${qconfig_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR}) +endfunction() + +# Creates mkspecs/qdevice.pri which contains target device information for cross-builds. +# The content of QT_QMAKE_DEVICE_OPTIONS is written verbatim into qdevice.pri. +function(qt_generate_global_device_pri_file) + if(NOT CMAKE_CROSSCOMPILING) + return() + endif() + + qt_path_join(qdevice_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR} "qdevice.pri") + + set(content "") + foreach(opt ${QT_QMAKE_DEVICE_OPTIONS}) + string(APPEND content "${opt}\n") + endforeach() + + # Write android specific device info. + if(ANDROID) + string(APPEND content "DEFAULT_ANDROID_SDK_ROOT = ${ANDROID_SDK_ROOT}\n") + string(APPEND content "DEFAULT_ANDROID_NDK_ROOT = ${ANDROID_NDK}\n") + + set(android_platform "android-23") + if(ANDROID_NATIVE_API_LEVEL) + set(android_platform "android-${ANDROID_NATIVE_API_LEVEL}") + endif() + string(APPEND content "DEFAULT_ANDROID_PLATFORM = ${android_platform}\n") + + string(APPEND content "DEFAULT_ANDROID_NDK_HOST = ${ANDROID_HOST_TAG}\n") + + # TODO: QTBUG-80943 When we eventually support Android multi-abi, this should be changed. + string(APPEND content "DEFAULT_ANDROID_ABIS = ${ANDROID_ABI}\n") + endif() + + set(gcc_machine_dump "") + if(TEST_machine_tuple) + set(gcc_machine_dump "${TEST_machine_tuple}") + endif() + string(APPEND content "GCC_MACHINE_DUMP = ${gcc_machine_dump}\n") + + file(GENERATE OUTPUT "${qdevice_pri_target_path}" CONTENT "${content}") + qt_install(FILES "${qdevice_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR}) +endfunction() + +function(qt_get_build_parts out_var) + set(parts "libs") + + if(BUILD_EXAMPLES AND NOT QT_NO_MAKE_EXAMPLES) + list(APPEND parts "examples") + endif() + + if(BUILD_TESTING AND NOT QT_NO_MAKE_TESTS) + list(APPEND parts "tests") + endif() + + if(NOT CMAKE_CROSSCOMPILING OR QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + list(APPEND parts "tools") + endif() + + set(${out_var} ${parts} PARENT_SCOPE) +endfunction() + +# Creates mkspecs/qmodule.pri which contains private global features among other things. +function(qt_generate_global_module_pri_file) + qt_path_join(qmodule_pri_target_path ${PROJECT_BINARY_DIR} ${INSTALL_MKSPECSDIR}) + qt_path_join(qmodule_pri_target_path "${qmodule_pri_target_path}" "qmodule.pri") + + get_target_property(enabled_features GlobalConfig INTERFACE_QT_ENABLED_PRIVATE_FEATURES) + get_target_property(disabled_features GlobalConfig INTERFACE_QT_DISABLED_PRIVATE_FEATURES) + + qt_correct_features(corrected_enabled_features "${enabled_features}") + qt_correct_features(corrected_disabled_features "${disabled_features}") + + string (REPLACE ";" " " corrected_enabled_features "${corrected_enabled_features}") + string (REPLACE ";" " " corrected_disabled_features "${corrected_disabled_features}") + + set(corrected_private_config "") + get_target_property(private_config GlobalConfig INTERFACE_QT_QMAKE_PRIVATE_CONFIG) + qt_correct_config(corrected_private_config "${private_config}") + list(JOIN corrected_private_config " " private_config_joined) + + set(content "") + set(arch "${TEST_architecture_arch}") + list(JOIN TEST_subarch_result " " subarchs) + if(CMAKE_CROSSCOMPILING) + set(host_arch "${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_ARCH}") + list(JOIN QT${PROJECT_VERSION_MAJOR}_HOST_INFO_SUBARCHS " " host_subarchs) + string(APPEND content "host_build { + QT_CPU_FEATURES.${host_arch} = ${host_subarchs} +} else { + QT_CPU_FEATURES.${arch} = ${subarchs} +} +") + else() + string(APPEND content "QT_CPU_FEATURES.${arch} = ${subarchs}\n") + endif() + + string(APPEND content "QT.global_private.enabled_features = ${corrected_enabled_features} +QT.global_private.disabled_features = ${corrected_disabled_features} +CONFIG += ${private_config_joined} +") + if(PKG_CONFIG_FOUND) + string(APPEND content "PKG_CONFIG_EXECUTABLE = ${PKG_CONFIG_EXECUTABLE}\n") + endif() + + # TODO: Write QT_COORD_TYPE once we support setting it. + + qt_get_build_parts(build_parts) + string(REPLACE ";" " " build_parts "${build_parts}") + string(APPEND content "QT_BUILD_PARTS = ${build_parts}\n") + + if(QT_EXTRA_RPATHS) + list(JOIN QT_EXTRA_RPATHS " " extra_rpaths) + string(APPEND content "EXTRA_RPATHS += ${extra_rpaths}") + endif() + + set(preliminary_pri_root "${CMAKE_CURRENT_BINARY_DIR}/mkspecs/preliminary") + set(pri_data_cmake_file "qmodule.cmake") + qt_generate_qmake_libraries_pri_content(global ${preliminary_pri_root} ${pri_data_cmake_file}) + + # Generate a preliminary qmodule.pri file + set(preliminary_pri_file_path "${preliminary_pri_root}/qmodule.pri") + file(GENERATE + OUTPUT ${preliminary_pri_file_path} + CONTENT "${content}" + ) + + if(QT_GENERATOR_IS_MULTI_CONFIG) + set(configs ${CMAKE_CONFIGURATION_TYPES}) + else() + set(configs ${CMAKE_BUILD_TYPE}) + endif() + set(inputs ${preliminary_pri_file_path}) + foreach(cfg ${configs}) + list(APPEND inputs "${preliminary_pri_root}/${cfg}/${pri_data_cmake_file}") + endforeach() + + set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX}) + set(library_suffixes + ${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES} + ${CMAKE_STATIC_LIBRARY_SUFFIX}) + add_custom_command( + OUTPUT "${qmodule_pri_target_path}" + DEPENDS ${inputs} + "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake" + "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake" + COMMAND ${CMAKE_COMMAND} "-DIN_FILES=${inputs}" "-DOUT_FILE=${qmodule_pri_target_path}" + "-DLIBRARY_PREFIXES=${library_prefixes}" + "-DLIBRARY_SUFFIXES=${library_suffixes}" + "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}" + "-DCONFIGS=${configs}" + -P "${QT_CMAKE_DIR}/QtGenerateLibPri.cmake" + VERBATIM) + add_custom_target(qmodule_pri DEPENDS "${qmodule_pri_target_path}") + qt_install(FILES "${qmodule_pri_target_path}" DESTINATION ${INSTALL_MKSPECSDIR}) +endfunction() + +function(qt_correct_features out_var features) + set(corrected_features "") + foreach(feature ${features}) + get_property(feature_original_name GLOBAL PROPERTY "QT_FEATURE_ORIGINAL_NAME_${feature}") + list(APPEND corrected_features "${feature_original_name}") + endforeach() + set(${out_var} ${corrected_features} PARENT_SCOPE) +endfunction() + +# Get original names for config values (which correspond to feature names) and use them if they +# exist, otherwise just use the config value (which might be the case when a config value has +# a custom name). +function(qt_correct_config out_var config) + set(corrected_config "") + foreach(name ${config}) + # Is the config value a known feature? + get_property(feature_original_name GLOBAL PROPERTY "QT_FEATURE_ORIGINAL_NAME_${name}") + if(feature_original_name) + list(APPEND corrected_config "${feature_original_name}") + continue() + endif() + + # Is the config value a negated known feature, e.g. no_foo? + # Then add the config value no-foo. + if(name MATCHES "^no_(.*)") + get_property(feature_original_name GLOBAL PROPERTY + "QT_FEATURE_ORIGINAL_NAME_${CMAKE_MATCH_1}") + if(feature_original_name) + list(APPEND corrected_config "no-${feature_original_name}") + continue() + endif() + endif() + + # The config value is no known feature. Add the value as is. + list(APPEND corrected_config "${name}") + endforeach() + set(${out_var} ${corrected_config} PARENT_SCOPE) +endfunction() diff --git a/cmake/QtPrlHelpers.cmake b/cmake/QtPrlHelpers.cmake new file mode 100644 index 0000000000..7977afd030 --- /dev/null +++ b/cmake/QtPrlHelpers.cmake @@ -0,0 +1,313 @@ +# Add libraries to variable ${out_libs_var} in a way that duplicates +# are added at the end. This ensures the library order needed for the +# linker. +function(qt_merge_libs out_libs_var) + foreach(dep ${ARGN}) + list(REMOVE_ITEM ${out_libs_var} ${dep}) + list(APPEND ${out_libs_var} ${dep}) + endforeach() + set(${out_libs_var} ${${out_libs_var}} PARENT_SCOPE) +endfunction() + +# Collects the library dependencies of a target. +# This takes into account transitive usage requirements. +function(qt_collect_libs target out_var) + qt_internal_walk_libs("${target}" "${out_var}" "qt_collect_libs_dict" "collect_libs") + set("${out_var}" "${${out_var}}" PARENT_SCOPE) +endfunction() + +# Walks a target's link libraries recursively, and performs some actions (poor man's polypmorphism) +# +# out_var is the name of the variable where the result will be assigned. The result is a list of +# libraries, mostly in generator expression form. +# dict_name is used for caching the result, and preventing the same target from being processed +# twice +# operation is a string to tell the function what to do +function(qt_internal_walk_libs target out_var dict_name operation) + set(collected ${ARGN}) + if(target IN_LIST collected) + return() + endif() + list(APPEND collected ${target}) + if(NOT TARGET ${dict_name}) + add_library(${dict_name} INTERFACE IMPORTED GLOBAL) + endif() + get_target_property(libs ${dict_name} INTERFACE_${target}) + if(NOT libs) + unset(libs) + get_target_property(target_libs ${target} INTERFACE_LINK_LIBRARIES) + if(NOT target_libs) + unset(target_libs) + endif() + get_target_property(target_type ${target} TYPE) + if(target_type STREQUAL "STATIC_LIBRARY") + get_target_property(link_libs ${target} LINK_LIBRARIES) + if(link_libs) + list(APPEND target_libs ${link_libs}) + endif() + endif() + foreach(lib ${target_libs}) + # Cannot use $<TARGET_POLICY:...> in add_custom_command. + # Check the policy now, and replace the generator expression with the value. + while(lib MATCHES "\\$<TARGET_POLICY:([^>]+)>") + cmake_policy(GET ${CMAKE_MATCH_1} value) + if(value STREQUAL "NEW") + set(value "TRUE") + else() + set(value "FALSE") + endif() + string(REPLACE "${CMAKE_MATCH_0}" "${value}" lib "${lib}") + endwhile() + + # Fix up $<TARGET_PROPERTY:FOO> expressions that refer to the "current" target. + # Those cannot be used with add_custom_command. + while(lib MATCHES "\\$<TARGET_PROPERTY:([^,>]+)>") + string(REPLACE "${CMAKE_MATCH_0}" "$<TARGET_PROPERTY:${target},${CMAKE_MATCH_1}>" + lib "${lib}") + endwhile() + + # Skip static plugins. + set(_is_plugin_marker_genex "\\$<BOOL:QT_IS_PLUGIN_GENEX>") + if(lib MATCHES "${_is_plugin_marker_genex}") + continue() + endif() + + # Strip any directory scope tokens. + qt_internal_strip_target_directory_scope_token("${lib}" lib) + + if(lib MATCHES "^\\$<TARGET_OBJECTS:") + # Skip object files. + continue() + elseif(lib MATCHES "^\\$<LINK_ONLY:(.*)>$") + set(lib_target ${CMAKE_MATCH_1}) + else() + set(lib_target ${lib}) + endif() + + # Skip CMAKE_DIRECTORY_ID_SEP. If a target_link_libraries is applied to a target + # that was defined in a different scope, CMake appends and prepends a special directory + # id separator. Filter those out. + if(lib_target MATCHES "^::@") + continue() + elseif(TARGET ${lib_target}) + if ("${lib_target}" MATCHES "^Qt::(.*)") + # If both, Qt::Foo and Foo targets exist, prefer the target name without + # namespace. Which one is preferred doesn't really matter. This code exists to + # avoid ending up with both, Qt::Foo and Foo in our dependencies. + set(namespaceless_lib_target "${CMAKE_MATCH_1}") + if(TARGET namespaceless_lib_target) + set(lib_target ${namespaceless_lib_target}) + endif() + endif() + get_target_property(lib_target_type ${lib_target} TYPE) + if(lib_target_type STREQUAL "INTERFACE_LIBRARY") + qt_internal_walk_libs( + ${lib_target} lib_libs "${dict_name}" "${operation}" ${collected}) + if(lib_libs) + qt_merge_libs(libs ${lib_libs}) + set(is_module 0) + endif() + else() + qt_merge_libs(libs "$<TARGET_FILE:${lib_target}>") + qt_internal_walk_libs( + ${lib_target} lib_libs "${dict_name}" "${operation}" ${collected}) + if(lib_libs) + qt_merge_libs(libs ${lib_libs}) + endif() + endif() + if(operation STREQUAL "promote_global") + set(lib_target_unaliased "${lib_target}") + get_target_property(aliased_target ${lib_target} ALIASED_TARGET) + if(aliased_target) + set(lib_target_unaliased ${aliased_target}) + endif() + + get_property(is_imported TARGET ${lib_target_unaliased} PROPERTY IMPORTED) + get_property(is_global TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL) + + # Allow opting out of promotion. This is useful in certain corner cases + # like with WrapLibClang and Threads in qttools. + qt_internal_should_not_promote_package_target_to_global( + "${lib_target_unaliased}" should_not_promote) + if(NOT is_global AND is_imported AND NOT should_not_promote) + set_property(TARGET ${lib_target_unaliased} PROPERTY IMPORTED_GLOBAL TRUE) + endif() + endif() + else() + set(final_lib_name_to_merge "${lib_target}") + if(lib_target MATCHES "/([^/]+).framework$") + set(final_lib_name_to_merge "-framework ${CMAKE_MATCH_1}") + endif() + qt_merge_libs(libs "${final_lib_name_to_merge}") + endif() + endforeach() + set_target_properties(${dict_name} PROPERTIES INTERFACE_${target} "${libs}") + endif() + set(${out_var} ${libs} PARENT_SCOPE) +endfunction() + +# Generate a qmake .prl file for the given target. +# The install_dir argument is a relative path, for example "lib". +function(qt_generate_prl_file target install_dir) + get_target_property(target_type ${target} TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + + get_target_property(rcc_objects ${target} QT_RCC_OBJECTS) + if(rcc_objects) + if(QT_WILL_INSTALL) + list(TRANSFORM rcc_objects PREPEND "$$[QT_INSTALL_LIBS]/") + endif() + else() + unset(rcc_objects) + endif() + + unset(prl_config) + set(is_static FALSE) + if(target_type STREQUAL "STATIC_LIBRARY") + list(APPEND prl_config static) + set(is_static TRUE) + elseif(target_type STREQUAL "SHARED_LIBRARY") + list(APPEND prl_config shared) + endif() + if (NOT target_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(is_fw ${target} FRAMEWORK) + if(is_fw) + list(APPEND prl_config lib_bundle) + endif() + endif() + list(JOIN prl_config " " prl_config) + + # Generate a preliminary .prl file that contains absolute paths to all libraries + if(MINGW) + # For MinGW, qmake doesn't have a lib prefix in prl files. + set(prefix_for_final_prl_name "") + else() + set(prefix_for_final_prl_name "$<TARGET_FILE_PREFIX:${target}>") + endif() + + # For frameworks, the prl file should be placed under the Resources subdir. + get_target_property(is_framework ${target} FRAMEWORK) + if(is_framework) + get_target_property(fw_version ${target} FRAMEWORK_VERSION) + string(APPEND prefix_for_final_prl_name "Versions/${fw_version}/Resources/") + endif() + + # What follows is a complicated setup for generating configuration-specific + # prl files. It has to be this way, because add_custom_command doesn't support + # generator expressions in OUTPUT or DEPENDS. + # To circumvent that, we create well known file names with file(GENERATE) + # with configuration specific content, which are then fed to add_custom_command + # that uses these genex-less file names. The actual command will extract the info + # from the configuration-specific files, and create a properly named final prl file. + + # The file is named according to a pattern, that is then used in the + # add_custom_command. + set(prl_step1_name_prefix "preliminary_prl_for_${target}_step1_") + set(prl_step1_name_suffix ".prl" ) + qt_path_join(prl_step1_path + "${CMAKE_CURRENT_BINARY_DIR}" + "${prl_step1_name_prefix}$<CONFIG>${prl_step1_name_suffix}") + + # Same, except instead of containing the prl contents, it will contain the final prl file + # name computed via a generator expression. + set(prl_meta_info_name_prefix "preliminary_prl_meta_info_for_${target}_") + set(prl_meta_info_name_suffix ".txt") + qt_path_join(prl_meta_info_path + "${CMAKE_CURRENT_BINARY_DIR}" + "${prl_meta_info_name_prefix}$<CONFIG>${prl_meta_info_name_suffix}") + + # The final prl file name that will be embedded in the file above. + set(final_prl_file_name "${prefix_for_final_prl_name}$<TARGET_FILE_BASE_NAME:${target}>.prl") + qt_path_join(final_prl_file_path "${QT_BUILD_DIR}/${install_dir}" "${final_prl_file_name}") + + # Generate the prl content and its final file name into configuration specific files + # whose names we know, and can be used in add_custom_command. + set(prl_step1_content + "RCC_OBJECTS = ${rcc_objects} +QMAKE_PRL_BUILD_DIR = ${CMAKE_CURRENT_BINARY_DIR} +QMAKE_PRL_TARGET = $<TARGET_FILE_NAME:${target}> +QMAKE_PRL_CONFIG = ${prl_config} +QMAKE_PRL_VERSION = ${PROJECT_VERSION} +") + if(NOT is_static AND WIN32) + # Do nothing. Prl files for shared libraries on Windows shouldn't have the libs listed, + # as per qt_build_config.prf and the conditional CONFIG+=explicitlib assignment. + else() + set(prl_libs "") + qt_collect_libs(${target} prl_libs) + string(APPEND prl_step1_content "QMAKE_PRL_LIBS_FOR_CMAKE = ${prl_libs}\n") + endif() + + file(GENERATE + OUTPUT "${prl_step1_path}" + CONTENT "${prl_step1_content}") + file(GENERATE + OUTPUT "${prl_meta_info_path}" + CONTENT + "FINAL_PRL_FILE_PATH = ${final_prl_file_path}") + + set(library_prefixes ${CMAKE_SHARED_LIBRARY_PREFIX} ${CMAKE_STATIC_LIBRARY_PREFIX}) + set(library_suffixes + ${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES} + ${CMAKE_STATIC_LIBRARY_SUFFIX}) + + if(QT_GENERATOR_IS_MULTI_CONFIG) + set(configs ${CMAKE_CONFIGURATION_TYPES}) + else() + set(configs ${CMAKE_BUILD_TYPE}) + endif() + + foreach(config ${configs}) + # Output file for dependency tracking, and which will contain the final content. + qt_path_join(prl_step2_path + "${CMAKE_CURRENT_BINARY_DIR}" "preliminary_prl_for_${target}_step2_${config}.prl") + + # Input dependency names that are constructed for each config manually + # (no genexes allowed). + qt_path_join(prl_step1_path + "${CMAKE_CURRENT_BINARY_DIR}" + "${prl_step1_name_prefix}${config}${prl_step1_name_suffix}") + qt_path_join(prl_meta_info_path + "${CMAKE_CURRENT_BINARY_DIR}" + "${prl_meta_info_name_prefix}${config}${prl_meta_info_name_suffix}") + add_custom_command( + OUTPUT "${prl_step2_path}" + DEPENDS "${prl_step1_path}" + "${prl_meta_info_path}" + "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake" + "${QT_CMAKE_DIR}/QtGenerateLibHelpers.cmake" + COMMAND ${CMAKE_COMMAND} + "-DIN_FILE=${prl_step1_path}" + "-DIN_META_FILE=${prl_meta_info_path}" + "-DOUT_FILE=${prl_step2_path}" + "-DLIBRARY_PREFIXES=${library_prefixes}" + "-DLIBRARY_SUFFIXES=${library_suffixes}" + "-DLINK_LIBRARY_FLAG=${CMAKE_LINK_LIBRARY_FLAG}" + "-DQT_BUILD_LIBDIR=${QT_BUILD_DIR}/${INSTALL_LIBDIR}" + -P "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake" + VERBATIM + COMMENT "Generating prl file for target ${target}" + ) + + # Tell the target to depend on the preliminary prl file, to ensure the custom command + # is executed. As a side-effect, this will also create the final prl file that + # is named appropriately. It should not be specified as a BYPRODUCT. + # This allows proper per-file dependency tracking, without having to resort on a POST_BUILD + # step, which means that relinking would happen as well as transitive rebuilding of any + # dependees. + # This is inspired by https://gitlab.kitware.com/cmake/cmake/-/issues/20842 + target_sources(${target} PRIVATE "${prl_step2_path}") + endforeach() + + # Installation of the .prl file happens globally elsewhere, + # because we have no clue here what the actual file name is. + # What we know however, is the directory where the prl file is created. + # Save that for later, to install all prl files from that directory. + get_property(prl_install_dirs GLOBAL PROPERTY QT_PRL_INSTALL_DIRS) + if(NOT install_dir IN_LIST prl_install_dirs) + set_property(GLOBAL APPEND PROPERTY QT_PRL_INSTALL_DIRS "${install_dir}") + endif() +endfunction() diff --git a/cmake/QtQmakeHelpers.cmake b/cmake/QtQmakeHelpers.cmake new file mode 100644 index 0000000000..ce1f96efd9 --- /dev/null +++ b/cmake/QtQmakeHelpers.cmake @@ -0,0 +1,208 @@ +macro(qt_add_string_to_qconfig_cpp str) + string(LENGTH "${str}" length) + string(APPEND QT_CONFIG_STRS " \"${str}\\0\"\n") + string(APPEND QT_CONFIG_STR_OFFSETS " ${QT_CONFIG_STR_OFFSET},\n") + math(EXPR QT_CONFIG_STR_OFFSET "${QT_CONFIG_STR_OFFSET}+${length}+1") +endmacro() + +function(qt_generate_qconfig_cpp) + set(QT_CONFIG_STR_OFFSET "0") + set(QT_CONFIG_STR_OFFSETS "") + set(QT_CONFIG_STRS "") + + # Start first part. + qt_add_string_to_qconfig_cpp("${INSTALL_DOCDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_INCLUDEDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_LIBDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_LIBEXECDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_BINDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_PLUGINSDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_QMLDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_ARCHDATADIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_DATADIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_TRANSLATIONSDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_EXAMPLESDIR}") + qt_add_string_to_qconfig_cpp("${INSTALL_TESTSDIR}") + + # Save first part. + set(QT_CONFIG_STR_OFFSETS_FIRST "${QT_CONFIG_STR_OFFSETS}") + set(QT_CONFIG_STRS_FIRST "${QT_CONFIG_STRS}") + + # Start second part. + set(QT_CONFIG_STR_OFFSETS "") + set(QT_CONFIG_STRS "") + + qt_add_string_to_qconfig_cpp("") # config.input.sysroot + qt_add_string_to_qconfig_cpp("false") # qmake_sysrootify + qt_add_string_to_qconfig_cpp("${INSTALL_BINDIR}") # TODO: Host-specific + qt_add_string_to_qconfig_cpp("${INSTALL_LIBDIR}") # TODO: Host-specific + qt_add_string_to_qconfig_cpp("${INSTALL_DATADIR}") # TODO: Host-specific + qt_add_string_to_qconfig_cpp("${QT_QMAKE_TARGET_MKSPEC}") + qt_add_string_to_qconfig_cpp("${QT_QMAKE_HOST_MKSPEC}") + + # Save second part. + set(QT_CONFIG_STR_OFFSETS_SECOND "${QT_CONFIG_STR_OFFSETS}") + set(QT_CONFIG_STRS_SECOND "${QT_CONFIG_STRS}") + + # Settings path / sysconf dir. + set(QT_SYS_CONF_DIR "${INSTALL_SYSCONFDIR}") + + # Compute and set relocation prefixes. + # TODO: Clean this up, there's a bunch of unrealistic assumptions here. + # See qtConfOutput_preparePaths in qtbase/configure.pri. + if(WIN32) + set(lib_location_absolute_path + "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_BINDIR}") + else() + set(lib_location_absolute_path + "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") + endif() + file(RELATIVE_PATH from_lib_location_to_prefix + "${lib_location_absolute_path}" "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}") + set(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH "${from_lib_location_to_prefix}") + + # The QT_CONFIGURE_HOSTBINDIR_TO_*PREFIX_PATH defines are exclusively used by qmake to determine + # the prefix from the location of the qmake executable. In our build of qmake host_prefix is + # always the same as ext_prefix, and we can just use CMAKE_INSTALL_PREFIX for the calculation of + # the relative path between <ext_prefix>/bin and <ext_prefix>. + set(bin_dir_absolute_path "${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}") + file(RELATIVE_PATH from_bin_dir_to_prefix "${bin_dir_absolute_path}" "${CMAKE_INSTALL_PREFIX}") + set(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH "${from_bin_dir_to_prefix}") + set(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH "${from_bin_dir_to_prefix}") + + configure_file(global/qconfig.cpp.in global/qconfig.cpp @ONLY) +endfunction() + +# In the cross-compiling case, creates a wrapper around the host Qt's +# qmake executable. Also creates a qmake configuration file that sets +# up the host qmake's properties for cross-compiling with this Qt +# build. +function(qt_generate_qmake_wrapper_for_target) + if(NOT CMAKE_CROSSCOMPILING) + return() + endif() + + # Call the configuration file something else but qt.conf to avoid + # being picked up by the qmake executable that's created if + # QT_BUILD_TOOLS_WHEN_CROSSCOMPILING is enabled. + qt_path_join(qt_conf_path "${INSTALL_BINDIR}" "target_qt.conf") + + set(prefix "${CMAKE_INSTALL_PREFIX}") + set(ext_prefix "${QT_STAGING_PREFIX}") + set(host_prefix "${QT_HOST_PATH}") + file(RELATIVE_PATH host_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}" + "${host_prefix}") + file(RELATIVE_PATH ext_prefix_relative_to_conf_file "${ext_prefix}/${INSTALL_BINDIR}" + "${ext_prefix}") + file(RELATIVE_PATH ext_prefix_relative_to_host_prefix "${host_prefix}" "${ext_prefix}") + + set(content "") + if(ext_prefix STREQUAL prefix) + set(sysrootify_prefix true) + else() + set(sysrootify_prefix false) + string(APPEND content "[DevicePaths] +Prefix=${prefix} +") + endif() + + if(NOT QT_WILL_INSTALL) + # The shadow build directory of a non-prefix build does not contain a copy of the mkspecs + # directory. Let $$[QT_HOST_DATA/src] point to the qtbase source directory. + string(APPEND content "[EffectiveSourcePaths] +HostData=${CMAKE_CURRENT_SOURCE_DIR} +") + + # Set $$[QT_HOST_DATA/get] to avoid falling back to the source dir where it isn't explicitly + # requested. + # Also make sure to specif the Prefix as well, because it doesn't get inherited from the + # [Paths] section. + string(APPEND content "[EffectivePaths] +HostData=${ext_prefix} +Prefix=${ext_prefix_relative_to_conf_file} +") + endif() + + # On Android CMAKE_SYSROOT is set, but for Qt's purposes it should not be set, because then + # qmake generates incorrect Qt module include flags (among other things). Do the same for darwin + # cross-compilation. + set(sysroot "") + if(CMAKE_SYSROOT AND NOT ANDROID AND NOT UIKIT) + set(sysroot "${CMAKE_SYSROOT}") + endif() + + string(APPEND content + "[Paths] +Prefix=${ext_prefix_relative_to_conf_file} +HostPrefix=${host_prefix_relative_to_conf_file} +HostData=${ext_prefix_relative_to_host_prefix} +Sysroot=${sysroot} +SysrootifyPrefix=${sysrootify_prefix} +TargetSpec=${QT_QMAKE_TARGET_MKSPEC} +HostSpec=${QT_QMAKE_HOST_MKSPEC} +") + file(GENERATE OUTPUT "${qt_conf_path}" CONTENT "${content}") + + qt_path_join(qmake_wrapper_in_file "${CMAKE_CURRENT_SOURCE_DIR}/bin/qmake-wrapper-for-target") + qt_path_join(qmake_wrapper "preliminary" "qmake") + if(QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + # Avoid collisions with the cross-compiled qmake binary. + string(PREPEND qmake_wrapper "host-") + endif() + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + string(APPEND qmake_wrapper_in_file ".bat") + string(APPEND qmake_wrapper ".bat") + endif() + string(APPEND qmake_wrapper_in_file ".in") + + set(host_qt_bindir "${host_prefix}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}") + + configure_file("${qmake_wrapper_in_file}" "${qmake_wrapper}" @ONLY) + qt_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${qt_conf_path}" + DESTINATION "${INSTALL_BINDIR}") + qt_copy_or_install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${qmake_wrapper}" + DESTINATION "${INSTALL_BINDIR}") +endfunction() + +# Transforms a CMake Qt module name to a qmake Qt module name. +# Example: Qt6FooPrivate becomes foo_private +function(qt_get_qmake_module_name result module) + string(REGEX REPLACE "^Qt6" "" module "${module}") + string(REGEX REPLACE "Private$" "_private" module "${module}") + string(REGEX REPLACE "Qpa$" "_qpa_lib_private" module "${module}") + string(TOLOWER "${module}" module) + set(${result} ${module} PARENT_SCOPE) +endfunction() + +function(qt_cmake_build_type_to_qmake_build_config out_var build_type) + if(build_type STREQUAL "Debug") + set(cfg debug) + else() + set(cfg release) + endif() + set(${out_var} ${cfg} PARENT_SCOPE) +endfunction() + +function(qt_guess_qmake_build_config out_var) + if(QT_GENERATOR_IS_MULTI_CONFIG) + unset(cfg) + foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) + qt_cmake_build_type_to_qmake_build_config(tmp ${config_type}) + list(APPEND cfg ${tmp}) + endforeach() + if(cfg) + list(REMOVE_DUPLICATES cfg) + else() + set(cfg debug) + endif() + else() + qt_cmake_build_type_to_qmake_build_config(cfg ${CMAKE_BUILD_TYPE}) + endif() + set(${out_var} ${cfg} PARENT_SCOPE) +endfunction() + +macro(qt_add_qmake_lib_dependency lib dep) + string(REPLACE "-" "_" dep ${dep}) + string(TOUPPER "${dep}" ucdep) + list(APPEND QT_QMAKE_LIB_DEPS_${lib} ${ucdep}) +endmacro() diff --git a/cmake/QtResourceHelpers.cmake b/cmake/QtResourceHelpers.cmake new file mode 100644 index 0000000000..7274186301 --- /dev/null +++ b/cmake/QtResourceHelpers.cmake @@ -0,0 +1,48 @@ +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) + if(is_imported) + return() + endif() + + qt_parse_all_arguments(arg "qt_add_resource" "" "PREFIX;LANG;BASE" "FILES" ${ARGN}) + + QT6_PROCESS_RESOURCE(${target} ${resourceName} + PREFIX "${arg_PREFIX}" + LANG "${arg_LANG}" + BASE "${arg_BASE}" + FILES ${arg_FILES} + OUTPUT_TARGETS out_targets + ) + + if (out_targets) + qt_install(TARGETS ${out_targets} + EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets" + DESTINATION ${INSTALL_LIBDIR} + ) + foreach(out_target ${out_targets}) + get_target_property(resource_name ${out_target} QT_RESOURCE_NAME) + if(NOT resource_name) + continue() + endif() + if(QT_WILL_INSTALL) + # Compute the install location of the rcc object file. + # This is the relative path below the install destination (install_prefix/lib). + # See CMake's computeInstallObjectDir function. + set(object_file_name "qrc_${resource_name}.cpp${CMAKE_CXX_OUTPUT_EXTENSION}") + qt_path_join(rcc_object_file_path + "objects-$<CONFIG>" ${out_target} .rcc "${object_file_name}") + else() + # In a non-prefix build we use the object file paths right away. + set(rcc_object_file_path $<TARGET_OBJECTS:$<TARGET_NAME:${out_target}>>) + endif() + set_property(TARGET ${target} APPEND PROPERTY QT_RCC_OBJECTS "${rcc_object_file_path}") + + # Make sure that the target cpp files are compiled with the regular Qt internal compile + # flags, needed for building iOS apps with qmake where bitcode is involved. + target_link_libraries("${out_target}" PRIVATE Qt::PlatformModuleInternal) + endforeach() + endif() + +endfunction() diff --git a/cmake/QtRpathHelpers.cmake b/cmake/QtRpathHelpers.cmake new file mode 100644 index 0000000000..eeb837df8f --- /dev/null +++ b/cmake/QtRpathHelpers.cmake @@ -0,0 +1,133 @@ +function(qt_compute_relative_rpath_base rpath install_location out_var) + set(install_lib_dir_absolute "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}") + get_filename_component(rpath_absolute "${rpath}" + ABSOLUTE BASE_DIR "${install_lib_dir_absolute}") + + if(NOT IS_ABSOLUTE) + set(install_location_absolute "${CMAKE_INSTALL_PREFIX}/${install_location}") + endif() + # Compute relative rpath from where the target will be installed, to the place where libraries + # will be placed (INSTALL_LIBDIR). + file(RELATIVE_PATH rpath_relative "${install_location_absolute}" "${rpath_absolute}") + + if("${rpath_relative}" STREQUAL "") + # file(RELATIVE_PATH) returns an empty string if the given absolute paths are equal + set(rpath_relative ".") + endif() + + # Prepend $ORIGIN / @loader_path style tokens (qmake's QMAKE_REL_RPATH_BASE), to make the + # relative rpaths work. qmake does this automatically when generating a project, so it wasn't + # needed in the .prf files, but for CMake we need to prepend them ourselves. + if(APPLE) + set(rpath_rel_base "@loader_path") + elseif(LINUX) + set(rpath_rel_base "$ORIGIN") + else() + message(WARNING "No known RPATH_REL_BASE for target platform.") + set(rpath_rel_base "NO_KNOWN_RPATH_REL_BASE") + endif() + + if(rpath_relative STREQUAL ".") + set(rpath_relative "${rpath_rel_base}") + else() + set(rpath_relative "${rpath_rel_base}/${rpath_relative}") + endif() + + set("${out_var}" "${rpath_relative}" PARENT_SCOPE) +endfunction() + +# Applies necessary rpaths to a target upon target installation. +# No-op when targeting Windows, Android, or non-prefix builds. +# +# If no RELATIVE_RPATH option is given, embeds an absolute path rpath to ${INSTALL_LIBDIR}. +# If RELATIVE_RPATH is given, the INSTALL_PATH value is to compute the relative path from +# ${INSTALL_LIBDIR} to wherever the target will be installed (the value of INSTALL_PATH). +# It's the equivalent of qmake's relative_qt_rpath. +# INSTALL_PATH is used to implement the equivalent of qmake's $$qtRelativeRPathBase(). +# +# A cache variable QT_DISABLE_RPATH can be set to disable embedding any rpaths when installing. +function(qt_apply_rpaths) + # No rpath support for win32 and android. Also no need to apply rpaths when doing a non-prefix + # build. + if(NOT QT_WILL_INSTALL OR WIN32 OR ANDROID) + return() + endif() + + # Rpaths xplicitly disabled (like for uikit), equivalent to qmake's no_qt_rpath. + if(QT_DISABLE_RPATH) + return() + endif() + + qt_parse_all_arguments(arg "qt_apply_rpaths" "RELATIVE_RPATH" "TARGET;INSTALL_PATH" "" ${ARGN}) + if(NOT arg_TARGET) + message(FATAL_ERRO "No target given to qt_apply_rpaths.") + else() + set(target "${arg_TARGET}") + endif() + + # If a target is not built (which can happen for tools when crosscompiling, we shouldn't try + # to apply properties. + if(NOT TARGET "${target}") + return() + endif() + + # Protect against interface libraries. + get_target_property(target_type "${target}" TYPE) + if (target_type STREQUAL "INTERFACE_LIBRARY") + return() + endif() + + if(NOT arg_INSTALL_PATH) + message(FATAL_ERROR "No INSTALL_PATH given to qt_apply_rpaths.") + endif() + + set(rpaths "") + + # Modify the install path to contain the nested structure of a framework. + get_target_property(is_framework "${target}" FRAMEWORK) + if(is_framework) + if(UIKIT) + # Shallow framework + string(APPEND arg_INSTALL_PATH "/Qt${target}.framework") + else() + # Full framework + string(APPEND arg_INSTALL_PATH "/Qt${target}.framework/Versions/Current") + endif() + endif() + + # Same but for an app bundle. + get_target_property(is_bundle "${target}" MACOSX_BUNDLE) + if(is_bundle AND NOT is_framework) + if(UIKIT) + # Shallow bundle + string(APPEND arg_INSTALL_PATH "/${target}.app") + else() + # Full bundle + string(APPEND arg_INSTALL_PATH "/${target}.app/Contents/MacOS") + endif() + endif() + + # Somewhat similar to mkspecs/features/qt.prf + if(arg_RELATIVE_RPATH) + qt_compute_relative_rpath_base( + "${_default_install_rpath}" "${arg_INSTALL_PATH}" relative_rpath) + list(APPEND rpaths "${relative_rpath}") + else() + list(APPEND rpaths "${_default_install_rpath}") + endif() + + # Somewhat similar to mkspecs/features/qt_build_extra.prf. + foreach(rpath ${QT_EXTRA_RPATHS}) + if(IS_ABSOLUTE) + list(APPEND rpaths "${rpath}") + else() + qt_compute_relative_rpath_base("${rpath}" "${arg_INSTALL_PATH}" relative_rpath) + list(APPEND rpaths "${relative_rpath}") + endif() + endforeach() + + if(rpaths) + list(REMOVE_DUPLICATES rpaths) + set_property(TARGET "${target}" APPEND PROPERTY INSTALL_RPATH ${rpaths}) + endif() +endfunction() diff --git a/cmake/QtSanitizerHelpers.cmake b/cmake/QtSanitizerHelpers.cmake new file mode 100644 index 0000000000..5514465178 --- /dev/null +++ b/cmake/QtSanitizerHelpers.cmake @@ -0,0 +1,31 @@ +function(qt_internal_set_up_sanitizer_features) + set(ECM_ENABLE_SANITIZERS "" CACHE STRING "Enable sanitizers") + set_property(CACHE ECM_ENABLE_SANITIZERS PROPERTY STRINGS "address;memory;thread;undefined") + + # If FEATURE_sanitize_foo is set on the command line, make sure to set the appropriate + # ECM_ENABLE_SANITIZERS value. Also the other way around. This basically allows setting either + # the feature or ECM_ENABLE_SANITIZERS directly. + # + # TODO: Decide which one of these should be the source of truth, because reconfiguration with + # different options might not work as expected when ECM_ENABLE_SANITIZERS is provided instead of + # the features. + set(enabled_sanitizer_features "") + foreach(sanitizer_type address memory thread undefined) + if(FEATURE_sanitize_${sanitizer_type}) + list(APPEND enabled_sanitizer_features "${sanitizer_type}") + endif() + endforeach() + if(enabled_sanitizer_features) + set(ECM_ENABLE_SANITIZERS + "${enabled_sanitizer_features}" CACHE STRING "Enable sanitizers" FORCE) + endif() + + if(ECM_ENABLE_SANITIZERS) + foreach(sanitizer_type ${ECM_ENABLE_SANITIZERS}) + message(STATUS "Enabling sanitizer: ${sanitizer_type}") + set(feature_name "FEATURE_sanitize_${sanitizer_type}") + set(${feature_name} "ON" CACHE BOOL "Enable ${sanitizer_type} sanitizer" FORCE) + set(QT_${feature_name} "ON" CACHE BOOL "Enable ${sanitizer_type} sanitizer" FORCE) + endforeach() + endif() +endfunction() diff --git a/cmake/QtScopeFinalizerHelpers.cmake b/cmake/QtScopeFinalizerHelpers.cmake new file mode 100644 index 0000000000..bd0775e059 --- /dev/null +++ b/cmake/QtScopeFinalizerHelpers.cmake @@ -0,0 +1,84 @@ +# Add a finalizer function for the current CMake list file. +# +# You may add up to nine arguments that are passed to the finalizer. +# A finalizer that is registered with qt_add_list_file_finalizer(foo bar baz) +# will be called with nine arguments: foo(bar baz IGNORE IGNORE IGNORE...), +# because CMake's handling of empty list elements is a cruel joke. +# +# For CMake < 3.18 the function qt_watch_current_list_dir must know about the finalizer. +function(qt_add_list_file_finalizer func) + set_property(GLOBAL APPEND + PROPERTY QT_LIST_FILE_FINALIZER_FILES "${CMAKE_CURRENT_LIST_FILE}") + set_property(GLOBAL APPEND + PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${func}) + foreach(i RANGE 1 9) + set(arg "${ARGV${i}}") + if(i GREATER_EQUAL ARGC OR "${arg}" STREQUAL "") + set(arg "IGNORE") + endif() + set_property(GLOBAL APPEND + PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${arg}") + endforeach() +endfunction() + +# Watcher function for the variable CMAKE_CURRENT_LIST_DIR. +# This is the driver of the finalizer facility. +function(qt_watch_current_list_dir variable access value current_list_file stack) + if(NOT access STREQUAL "MODIFIED_ACCESS") + # We are only interested in modifications of CMAKE_CURRENT_LIST_DIR. + return() + endif() + list(GET stack -1 stack_top) + if(stack_top STREQUAL current_list_file) + # If the top of the stack equals the current list file then + # we're entering a file. We're not interested in this case. + return() + endif() + get_property(files GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES) + if(NOT files) + return() + endif() + get_property(funcs GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS) + foreach(i RANGE 1 9) + get_property(args${i} GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i}) + endforeach() + list(LENGTH files n) + set(i 0) + while(i LESS n) + list(GET files ${i} file) + if(file STREQUAL stack_top) + list(GET funcs ${i} func) + foreach(k RANGE 1 9) + list(GET args${k} ${i} a${k}) + endforeach() + # We've found a file we're looking for. Call the finalizer. + if(${CMAKE_VERSION} VERSION_LESS "3.18.0") + # Make finalizer known functions here: + if(func STREQUAL "qt_finalize_module") + qt_finalize_module(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) + elseif(func STREQUAL "qt_finalize_plugin") + qt_finalize_plugin(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) + elseif(func STREQUAL "qt_internal_finalize_app") + qt_internal_finalize_app(${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) + else() + message(FATAL_ERROR "qt_watch_current_list_dir doesn't know about ${func}. Consider adding it.") + endif() + else() + cmake_language(CALL ${func} ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9}) + endif() + list(REMOVE_AT files ${i}) + list(REMOVE_AT funcs ${i}) + foreach(k RANGE 1 9) + list(REMOVE_AT args${k} ${i}) + endforeach() + math(EXPR n "${n} - 1") + else() + math(EXPR i "${i} + 1") + endif() + endwhile() + set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FILES ${files}) + set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_FUNCS ${funcs}) + foreach(i RANGE 1 9) + set_property(GLOBAL PROPERTY QT_LIST_FILE_FINALIZER_ARGV${i} "${args${i}}") + endforeach() +endfunction() diff --git a/cmake/QtSimdHelpers.cmake b/cmake/QtSimdHelpers.cmake new file mode 100644 index 0000000000..26a275dc1f --- /dev/null +++ b/cmake/QtSimdHelpers.cmake @@ -0,0 +1,81 @@ +# Handle files that need special SIMD-related flags. +# This creates an object library and makes target link +# to it (privately). +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 "qt_add_simd_part needs a SIMD type to be set.") + endif() + + set(condition "QT_FEATURE_${arg_SIMD}") + string(TOUPPER "QT_CFLAGS_${arg_SIMD}" simd_flags_var_name) + set(simd_flags_expanded "") + + # As per mkspecs/features/simd.prf, the arch_haswell SIMD compiler is enabled when + # qmake's CONFIG contains "avx2", which maps to CMake's QT_FEATURE_avx2. + # The list of dependencies 'avx2 bmi bmi2 f16c fma lzcnt popcnt' only influences whether + # the 'arch_haswell' SIMD flags need to be added explicitly to the compiler invocation. + # If the compiler adds them implicitly, they must be present in qmake's QT_CPU_FEATURES as + # detected by the architecture test, and thus they are present in TEST_subarch_result. + if("${arg_SIMD}" STREQUAL arch_haswell) + set(condition "QT_FEATURE_avx2") + + # Use avx2 flags as per simd.prf, if there are no specific arch_haswell flags specified in + # QtCompilerOptimization.cmake. + if("${simd_flags_var_name}" STREQUAL "") + set(simd_flags_var_name "QT_CFLAGS_AVX2") + endif() + + # The avx512 profiles dependencies DO influence if the SIMD compiler will be executed, + # so each of the profile dependencies have to be in qmake's CONFIG for the compiler to be + # enabled, which means the CMake features have to evaluate to true. + # Also the profile flags to be used are a combination of arch_haswell, avx512f and each of the + # dependencies. + elseif("${arg_SIMD}" STREQUAL avx512common) + set(condition "QT_FEATURE_avx512cd") + list(APPEND simd_flags_expanded "${QT_CFLAGS_ARCH_HASWELL}") + list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512F}") + list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512CD}") + list(REMOVE_DUPLICATES simd_flags_expanded) + elseif("${arg_SIMD}" STREQUAL avx512core) + set(condition "QT_FEATURE_avx512cd AND QT_FEATURE_avx512bw AND QT_FEATURE_avx512dq AND QT_FEATURE_avx512vl") + list(APPEND simd_flags_expanded "${QT_CFLAGS_ARCH_HASWELL}") + list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512F}") + list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512CD}") + list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512BW}") + list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512DQ}") + list(APPEND simd_flags_expanded "${QT_CFLAGS_AVX512VL}") + list(REMOVE_DUPLICATES simd_flags_expanded) + endif() + + set(name "${arg_NAME}") + if("x${name}" STREQUAL x) + set(name "${target}_simd_${arg_SIMD}") + endif() + + qt_evaluate_config_expression(result ${condition}) + if(${result}) + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Evaluated") + endif() + + if(NOT simd_flags_expanded) + set(simd_flags_expanded "${${simd_flags_var_name}}") + endif() + + foreach(source IN LISTS arg_SOURCES) + set_property(SOURCE "${source}" APPEND + PROPERTY COMPILE_OPTIONS + ${simd_flags_expanded} + ${arg_COMPILE_FLAGS} + ) + endforeach() + set_source_files_properties(${arg_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE) + target_sources(${target} PRIVATE ${arg_SOURCES}) + else() + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_add_simd_part(${target} SIMD ${arg_SIMD} ...): Skipped") + endif() + endif() +endfunction() diff --git a/cmake/QtSyncQtHelpers.cmake b/cmake/QtSyncQtHelpers.cmake new file mode 100644 index 0000000000..a161c8ecbe --- /dev/null +++ b/cmake/QtSyncQtHelpers.cmake @@ -0,0 +1,201 @@ +function(qt_ensure_perl) + if(DEFINED HOST_PERL) + return() + endif() + find_program(HOST_PERL "perl" DOC "Perl binary") + if (NOT HOST_PERL) + message(FATAL_ERROR "Perl needs to be available to build Qt.") + endif() +endfunction() + +function(qt_ensure_sync_qt) + qt_ensure_perl() + if(DEFINED QT_SYNCQT) + return() + endif() + + # When building qtbase, use the source syncqt, otherwise use the installed one. + set(SYNCQT_FROM_SOURCE "${QtBase_SOURCE_DIR}/bin/syncqt.pl") + if(NOT ("${QtBase_SOURCE_DIR}" STREQUAL "") AND EXISTS "${SYNCQT_FROM_SOURCE}") + set(QT_SYNCQT "${SYNCQT_FROM_SOURCE}" CACHE FILEPATH "syncqt script") + message(STATUS "Using source syncqt found at: ${QT_SYNCQT}") + + qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_LIBEXECDIR}) + qt_copy_or_install(PROGRAMS "${SYNCQT_FROM_SOURCE}" + DESTINATION "${syncqt_install_dir}") + + qt_path_join(syncqt_install_dir ${QT_INSTALL_DIR} ${INSTALL_BINDIR}) + 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 + "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBEXECDIR}/syncqt.pl" + ABSOLUTE) + set(QT_SYNCQT "${syncqt_absolute_path}" CACHE FILEPATH "syncqt script") + message(STATUS "Using installed syncqt found at: ${QT_SYNCQT}") + endif() +endfunction() + +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 + # The are 3 parts to the assignment, divded by colons ':'. + # The first part contains a path to a generated file in a build folder. + # The second part contains the file name that the forwarding header should have, which points + # to the file in the first part. + # The third part contains multiple UpperCaseFileNames that should be forwarding headers to the + # header specified in the second part. + separate_arguments(injections UNIX_COMMAND "${injections}") + foreach(injection ${injections}) + string(REPLACE ":" ";" injection ${injection}) + # Part 1. + list(GET injection 0 file) + # Part 2. + list(GET injection 1 destination) + string(REGEX REPLACE "^\\^" "" destination "${destination}") + list(REMOVE_AT injection 0 1) + # Part 3. + set(fwd_hdrs ${injection}) + get_filename_component(destinationdir ${destination} DIRECTORY) + get_filename_component(destinationname ${destination} NAME) + get_filename_component(original_file_name ${file} NAME) + + # This describes a concrete example for easier comprehension: + # A file 'qtqml-config.h' is generated by qt_internal_feature_write_file into + # ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h (part 1). + # + # Generate a lower case forwarding header (part 2) 'qtqml-config.h' at the following + # location: + # ${some_prefix}/include/${module}/qtqml-config.h. + # + # Inside this file, we #include the originally generated file, + # ${qtdeclarative_build_dir}/src/{module}/qtqml-config.h. + # + # ${some_prefix}'s value depends on the build type. + # If doing a prefix build, it should point to + # ${current_repo_build_dir} which is ${qtdeclarative_build_dir}. + # If doing a non-prefix build, it should point to + # ${qtbase_build_dir}. + # + # In the code below, ${some_prefix} == ${build_dir}. + set(lower_case_forwarding_header_path "${build_dir}/include/${module}") + if(destinationdir) + string(APPEND lower_case_forwarding_header_path "/${destinationdir}") + endif() + set(current_repo_build_dir "${PROJECT_BINARY_DIR}") + + file(RELATIVE_PATH relpath + "${lower_case_forwarding_header_path}" + "${current_repo_build_dir}/${file}") + set(main_contents "#include \"${relpath}\"") + + qt_configure_file(OUTPUT "${lower_case_forwarding_header_path}/${original_file_name}" + CONTENT "${main_contents}") + + 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}) + set(upper_case_forwarding_header_path "include/${module}") + if(destinationdir) + string(APPEND upper_case_forwarding_header_path "/${destinationdir}") + endif() + + # Generate upper case forwarding header like QVulkanFunctions or QtConfig. + qt_configure_file(OUTPUT "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" + CONTENT "#include \"${destinationname}\"\n") + + 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}" "${INSTALL_INCLUDEDIR}" ${module}) + qt_install(FILES "${build_dir}/${upper_case_forwarding_header_path}/${fwd_hdr}" + DESTINATION ${install_destination} OPTIONAL) + endif() + endforeach() + endforeach() +endfunction() + +function(qt_read_headers_pri module_include_dir resultVarPrefix) + file(STRINGS "${module_include_dir}/headers.pri" headers_pri_contents) + foreach(line ${headers_pri_contents}) + if("${line}" MATCHES "SYNCQT.HEADER_FILES = (.*)") + set(public_module_headers "${CMAKE_MATCH_1}") + separate_arguments(public_module_headers UNIX_COMMAND "${public_module_headers}") + elseif("${line}" MATCHES "SYNCQT.PRIVATE_HEADER_FILES = (.*)") + set(private_module_headers "${CMAKE_MATCH_1}") + separate_arguments(private_module_headers UNIX_COMMAND "${private_module_headers}") + elseif("${line}" MATCHES "SYNCQT.GENERATED_HEADER_FILES = (.*)") + set(generated_module_headers "${CMAKE_MATCH_1}") + separate_arguments(generated_module_headers UNIX_COMMAND "${generated_module_headers}") + foreach(generated_header ${generated_module_headers}) + list(APPEND public_module_headers "${module_include_dir}/${generated_header}") + endforeach() + elseif("${line}" MATCHES "SYNCQT.INJECTIONS = (.*)") + set(injections "${CMAKE_MATCH_1}") + elseif("${line}" MATCHES "SYNCQT.([A-Z_]+)_HEADER_FILES = (.+)") + set(prefix "${CMAKE_MATCH_1}") + string(TOLOWER "${prefix}" prefix) + set(entries "${CMAKE_MATCH_2}") + separate_arguments(entries UNIX_COMMAND "${entries}") + set("${resultVarPrefix}_${prefix}" "${entries}" PARENT_SCOPE) + endif() + endforeach() + set(${resultVarPrefix}_public "${public_module_headers}" PARENT_SCOPE) + set(${resultVarPrefix}_private "${private_module_headers}" PARENT_SCOPE) + set(${resultVarPrefix}_injections "${injections}" PARENT_SCOPE) +endfunction() + +function(qt_compute_injection_forwarding_header target) + qt_parse_all_arguments(arg "qt_compute_injection_forwarding_header" + "PRIVATE" "SOURCE;OUT_VAR" "" ${ARGN}) + qt_internal_module_info(module "${target}") + get_filename_component(file_name "${arg_SOURCE}" NAME) + + set(source_absolute_path "${CMAKE_CURRENT_BINARY_DIR}/${arg_SOURCE}") + file(RELATIVE_PATH relpath "${PROJECT_BINARY_DIR}" "${source_absolute_path}") + + if (arg_PRIVATE) + set(fwd "${PROJECT_VERSION}/${module}/private/${file_name}") + else() + set(fwd "${file_name}") + endif() + + string(APPEND ${arg_OUT_VAR} " ${relpath}:${fwd}") + set(${arg_OUT_VAR} ${${arg_OUT_VAR}} PARENT_SCOPE) +endfunction() diff --git a/cmake/QtTargetHelpers.cmake b/cmake/QtTargetHelpers.cmake new file mode 100644 index 0000000000..c79ce47363 --- /dev/null +++ b/cmake/QtTargetHelpers.cmake @@ -0,0 +1,335 @@ +# This function can be used to add sources/libraries/etc. to the specified CMake target +# if the provided CONDITION evaluates to true. +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) + return() + endif() + + if (NOT TARGET "${target}") + message(FATAL_ERROR "Trying to extend non-existing target \"${target}\".") + endif() + 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() + + qt_evaluate_config_expression(result ${arg_CONDITION}) + if (${result}) + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Evaluated") + endif() + set(dbus_sources "") + foreach(adaptor ${arg_DBUS_ADAPTOR_SOURCES}) + qt_create_qdbusxml2cpp_command("${target}" "${adaptor}" ADAPTOR BASENAME "${arg_DBUS_ADAPTOR_BASENAME}" FLAGS "${arg_DBUS_ADAPTOR_FLAGS}") + list(APPEND dbus_sources "${sources}") + endforeach() + + foreach(interface ${arg_DBUS_INTERFACE_SOURCES}) + qt_create_qdbusxml2cpp_command("${target}" "${interface}" INTERFACE BASENAME "${arg_DBUS_INTERFACE_BASENAME}" FLAGS "${arg_DBUS_INTERFACE_FLAGS}") + list(APPEND dbus_sources "${sources}") + endforeach() + + get_target_property(target_type ${target} TYPE) + set(is_library FALSE) + if (${target_type} STREQUAL "STATIC_LIBRARY" OR ${target_type} STREQUAL "SHARED_LIBRARY") + set(is_library TRUE) + endif() + foreach(lib ${arg_PUBLIC_LIBRARIES} ${arg_LIBRARIES}) + # Automatically generate PCH for 'target' using dependencies + # if 'target' is a library/module! + if (${is_library}) + qt_update_precompiled_header_with_library("${target}" "${lib}") + endif() + + string(REGEX REPLACE "_nolink$" "" base_lib "${lib}") + if(NOT base_lib STREQUAL lib) + qt_create_nolink_target("${base_lib}" ${target}) + endif() + endforeach() + + # Set-up the target + target_sources("${target}" PRIVATE ${arg_SOURCES} ${dbus_sources}) + if (arg_COMPILE_FLAGS) + set_source_files_properties(${arg_SOURCES} PROPERTIES COMPILE_FLAGS "${arg_COMPILE_FLAGS}") + endif() + + set(public_visibility_option "PUBLIC") + set(private_visibility_option "PRIVATE") + if(arg_HEADER_MODULE) + set(public_visibility_option "INTERFACE") + set(private_visibility_option "INTERFACE") + endif() + target_include_directories("${target}" + ${public_visibility_option} ${arg_PUBLIC_INCLUDE_DIRECTORIES} + ${private_visibility_option} ${arg_INCLUDE_DIRECTORIES}) + target_compile_definitions("${target}" + ${public_visibility_option} ${arg_PUBLIC_DEFINES} + ${private_visibility_option} ${arg_DEFINES}) + target_link_libraries("${target}" + ${public_visibility_option} ${arg_PUBLIC_LIBRARIES} + ${private_visibility_option} ${arg_LIBRARIES}) + target_compile_options("${target}" + ${public_visibility_option} ${arg_PUBLIC_COMPILE_OPTIONS} + ${private_visibility_option} ${arg_COMPILE_OPTIONS}) + target_link_options("${target}" + ${public_visibility_option} ${arg_PUBLIC_LINK_OPTIONS} + ${private_visibility_option} ${arg_LINK_OPTIONS}) + + if(NOT arg_HEADER_MODULE) + set_property (TARGET "${target}" APPEND PROPERTY + AUTOMOC_MOC_OPTIONS "${arg_MOC_OPTIONS}" + ) + endif() + + # When computing the private library dependencies, we need to check not only the known + # modules added by this repo's qt_build_repo(), but also all module dependencies that + # were found via find_package(). + qt_internal_get_qt_all_known_modules(known_modules) + + # When a public module depends on a private module (Gui on CorePrivate) + # make its private module depend on the other private module (GuiPrivate will depend on + # CorePrivate). + set(qt_libs_private "") + foreach(it ${known_modules}) + list(FIND arg_LIBRARIES "Qt::${it}Private" pos) + if(pos GREATER -1) + list(APPEND qt_libs_private "Qt::${it}Private") + endif() + endforeach() + + set(target_private "${target}Private") + if(TARGET "${target_private}") + target_link_libraries("${target_private}" + INTERFACE ${arg_PRIVATE_MODULE_INTERFACE}) + endif() + qt_register_target_dependencies("${target}" + "${arg_PUBLIC_LIBRARIES}" + "${qt_libs_private};${arg_LIBRARIES}") + + + qt_autogen_tools(${target} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS}) + + qt_update_precompiled_header("${target}" "${arg_PRECOMPILED_HEADER}") + qt_update_ignore_pch_source("${target}" "${arg_NO_PCH_SOURCES}") + ## Ignore objective-c files for PCH (not supported atm) + qt_ignore_pch_obj_c_sources("${target}" "${arg_SOURCES}") + + else() + if(QT_CMAKE_DEBUG_EXTEND_TARGET) + message("qt_extend_target(${target} CONDITION ${arg_CONDITION} ...): Skipped") + endif() + endif() +endfunction() + +function(qt_is_imported_target target out_var) + if(NOT TARGET "${target}") + set(target "${QT_CMAKE_EXPORT_NAMESPACE}::${target}") + endif() + if(NOT TARGET "${target}") + message(FATAL_ERROR "Invalid target given to qt_is_imported_target: ${target}") + endif() + get_target_property(is_imported "${target}" IMPORTED) + set(${out_var} "${is_imported}" PARENT_SCOPE) +endfunction() + +# Add Qt::target and Qt6::target as aliases for the target +function(qt_internal_add_target_aliases target) + get_target_property(type "${target}" TYPE) + if (type STREQUAL EXECUTABLE) + add_executable("Qt::${target}" ALIAS "${target}") + add_executable("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}") + else() + add_library("Qt::${target}" ALIAS "${target}") + add_library("Qt${PROJECT_VERSION_MAJOR}::${target}" ALIAS "${target}") + endif() +endfunction() + +function(qt_get_cmake_configurations out_var) + set(possible_configs "${CMAKE_BUILD_TYPE}") + if(CMAKE_CONFIGURATION_TYPES) + set(possible_configs "${CMAKE_CONFIGURATION_TYPES}") + endif() + set(${out_var} "${possible_configs}" PARENT_SCOPE) +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) + qt_get_cmake_configurations(possible_configs) + 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() + +# Set target properties that are the same for all modules, plugins, executables +# and 3rdparty libraries. +function(qt_set_common_target_properties target) + if(FEATURE_static_runtime) + if(MSVC) + set_property(TARGET ${target} PROPERTY + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") + elseif(MINGW) + target_link_options(${target} INTERFACE "LINKER:-static") + endif() + endif() +endfunction() + +# Set common, informational target properties. +# +# On Windows, these properties are used to generate the version information resource. +function(qt_set_target_info_properties target) + cmake_parse_arguments(arg "" "${__default_target_info_args}" "" ${ARGN}) + if("${arg_TARGET_VERSION}" STREQUAL "") + set(arg_TARGET_VERSION "${PROJECT_VERSION}.0") + endif() + if("${arg_TARGET_PRODUCT}" STREQUAL "") + set(arg_TARGET_PRODUCT "Qt6") + endif() + if("${arg_TARGET_DESCRIPTION}" STREQUAL "") + set(arg_TARGET_DESCRIPTION "C++ Application Development Framework") + endif() + if("${arg_TARGET_COMPANY}" STREQUAL "") + set(arg_TARGET_COMPANY "The Qt Company Ltd.") + endif() + if("${arg_TARGET_COPYRIGHT}" STREQUAL "") + set(arg_TARGET_COPYRIGHT "Copyright (C) 2020 The Qt Company Ltd.") + endif() + set_target_properties(${target} PROPERTIES + QT_TARGET_VERSION "${arg_TARGET_VERSION}" + QT_TARGET_COMPANY_NAME "${arg_TARGET_COMPANY}" + QT_TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" + QT_TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}" + QT_TARGET_PRODUCT_NAME "${arg_TARGET_PRODUCT}") +endfunction() + +# Uses the QT_DELAYED_TARGET_* property values to set the final QT_TARGET_* properties. +# Needed when doing executable finalization at the end of a subdirectory scope +# (aka scope finalization). +function(qt_internal_set_target_info_properties_from_delayed_properties target) + set(args "") + foreach(prop ${__default_target_info_args}) + get_target_property(prop_value "${target}" "QT_DELAYED_${prop}") + list(APPEND args "${prop}" "${prop_value}") + endforeach() + qt_set_target_info_properties(${target} ${args}) +endfunction() + +# Updates the QT_DELAYED_ properties with values from the QT_ variants, in case if they were +# set in-between a qt_add_* call and before scope finalization. +function(qt_internal_update_delayed_target_info_properties target) + foreach(prop ${__default_target_info_args}) + get_target_property(prop_value "${target}" "QT_${prop}") + get_target_property(delayed_prop_value ${target} "QT_DELAYED_${prop}") + set(final_value "${delayed_prop_value}") + if(prop_value) + set(final_value "${prop_value}") + endif() + set_target_properties(${target} PROPERTIES "QT_DELAYED_${prop}" "${final_value}") + endforeach() +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 "qt_internal_add_plugin called without setting either TYPE or ${name}.") + endif() + set(${result_var} "${default}" PARENT_SCOPE) + else() + set(${result_var} "${dir}" PARENT_SCOPE) + endif() +endfunction() + +function(qt_internal_apply_win_prefix_and_suffix target) + if(WIN32) + # Table of prefix / suffixes for MSVC libraries as qmake expects them to be created. + # static - Qt6EdidSupport.lib (platform support libraries / or static QtCore, etc) + # shared - Qt6Core.dll + # shared import library - Qt6Core.lib + # module aka Qt plugin - qwindows.dll + # module import library - qwindows.lib + # + # The CMake defaults are fine for us. + + # Table of prefix / suffixes for MinGW libraries as qmake expects them to be created. + # static - libQt6EdidSupport.a (platform support libraries / or static QtCore, etc) + # shared - Qt6Core.dll + # shared import library - libQt6Core.a + # module aka Qt plugin - qwindows.dll + # module import library - libqwindows.a + # + # CMake for Windows-GNU platforms defaults the prefix to "lib". + # CMake for Windows-GNU platforms defaults the import suffix to ".dll.a". + # These CMake defaults are not ok for us. + + # This should cover both MINGW with GCC and CLANG. + if(NOT MSVC) + set_property(TARGET "${target}" PROPERTY IMPORT_SUFFIX ".a") + + get_target_property(target_type ${target} TYPE) + if(target_type STREQUAL "STATIC_LIBRARY") + set_property(TARGET "${target}" PROPERTY PREFIX "lib") + else() + set_property(TARGET "${target}" PROPERTY PREFIX "") + set_property(TARGET "${target}" PROPERTY IMPORT_PREFIX "lib") + endif() + endif() + endif() +endfunction() + +function(qt_internal_strip_target_directory_scope_token target out_var) + # In CMake versions earlier than CMake 3.18, a subdirectory scope id is appended to the + # target name if the target is referenced in a target_link_libraries command from a + # different directory scope than where the target was created. + # Strip it. + # + # For informational purposes, in CMake 3.18, the target name looks as follows: + # ::@(0x5604cb3f6b50);Threads::Threads;::@ + # This case doesn't have to be stripped (at least for now), because when we iterate over + # link libraries, the tokens appear as separate target names. + # + # Example: Threads::Threads::@<0x5604cb3f6b50> + # Output: Threads::Threads + string(REGEX REPLACE "::@<.+>$" "" target "${target}") + set("${out_var}" "${target}" PARENT_SCOPE) +endfunction() + +function(qt_internal_export_modern_cmake_config_targets_file) + cmake_parse_arguments(__arg "" "EXPORT_NAME_PREFIX;CONFIG_INSTALL_DIR" "TARGETS" ${ARGN}) + + set(export_name "${__arg_EXPORT_NAME_PREFIX}VersionlessTargets") + foreach(target ${__arg_TARGETS}) + if (TARGET "${target}Versionless") + continue() + endif() + + add_library("${target}Versionless" INTERFACE) + target_link_libraries("${target}Versionless" INTERFACE "${target}") + set_target_properties("${target}Versionless" PROPERTIES + EXPORT_NAME "${target}" + _qt_is_versionless_target "TRUE") + set_property(TARGET "${target}Versionless" + APPEND PROPERTY EXPORT_PROPERTIES _qt_is_versionless_target) + + qt_install(TARGETS "${target}Versionless" EXPORT ${export_name}) + endforeach() + qt_install(EXPORT ${export_name} NAMESPACE Qt:: DESTINATION "${__arg_CONFIG_INSTALL_DIR}") +endfunction() + +function(qt_create_tracepoints name tracePointsFile) + #### TODO + string(TOLOWER "${name}" name) + + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qt${name}_tracepoints_p.h" CONTENT + "#include <private/qtrace_p.h>") +endfunction() diff --git a/cmake/QtTestHelpers.cmake b/cmake/QtTestHelpers.cmake new file mode 100644 index 0000000000..a7d6d9d849 --- /dev/null +++ b/cmake/QtTestHelpers.cmake @@ -0,0 +1,340 @@ +# 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} + ) + + if(NOT arg_OUTPUT_DIRECTORY) + set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() + + qt_add_executable(${target} + NO_INSTALL # we don't install benchmarks + OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # 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} + ) + + if(NOT arg_OUTPUT_DIRECTORY) + set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() + + qt_add_executable(${target} + NO_INSTALL # we don't install benchmarks + OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" # avoid polluting bin directory + ${exec_args} + ) + +endfunction() + + +# This function creates a CMake test target with the specified name for use with CTest. +function(qt_add_test name) + qt_parse_all_arguments(arg "qt_add_test" + "RUN_SERIAL;EXCEPTIONS;GUI;QMLTEST;CATCH;LOWDPI" + "OUTPUT_DIRECTORY;WORKING_DIRECTORY;TIMEOUT;VERSION" + "QML_IMPORTPATH;TESTDATA;${__default_private_args};${__default_public_args}" ${ARGN} + ) + + if (NOT arg_OUTPUT_DIRECTORY) + set(arg_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + endif() + + if (${arg_EXCEPTIONS}) + set(exceptions_text "EXCEPTIONS") + endif() + + if (${arg_GUI}) + set(gui_text "GUI") + endif() + + if (arg_VERSION) + set(version_arg VERSION "${arg_VERSION}") + endif() + + # Handle cases where we have a qml test without source files + if (arg_SOURCES) + set(private_includes + "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}" + "$<BUILD_INTERFACE:${QT_BUILD_DIR}/include>" + ${arg_INCLUDE_DIRECTORIES} + ) + + qt_add_executable("${name}" + ${exceptions_text} + ${gui_text} + ${version_arg} + NO_INSTALL + OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + SOURCES "${arg_SOURCES}" + INCLUDE_DIRECTORIES + ${private_includes} + DEFINES + QT_TESTCASE_BUILDDIR="${CMAKE_CURRENT_BINARY_DIR}" + QT_TESTCASE_SOURCEDIR="${CMAKE_CURRENT_SOURCE_DIR}" + ${arg_DEFINES} + PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::Core ${QT_CMAKE_EXPORT_NAMESPACE}::Test ${arg_PUBLIC_LIBRARIES} + LIBRARIES ${arg_LIBRARIES} + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + ENABLE_AUTOGEN_TOOLS ${arg_ENABLE_AUTOGEN_TOOLS} + DISABLE_AUTOGEN_TOOLS ${arg_DISABLE_AUTOGEN_TOOLS} + ) + + # Tests should not be bundles on macOS even if arg_GUI is true, because some tests make + # assumptions about the location of helper processes, and those paths would be different + # if a test is built as a bundle. + set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE FALSE) + # The same goes for WIN32_EXECUTABLE, but because it will detach from the console window + # and not print anything. + set_property(TARGET "${name}" PROPERTY WIN32_EXECUTABLE FALSE) + + # QMLTest specifics + + qt_extend_target("${name}" CONDITION arg_QMLTEST + PUBLIC_LIBRARIES ${QT_CMAKE_EXPORT_NAMESPACE}::QuickTest + ) + + qt_extend_target("${name}" CONDITION arg_QMLTEST AND NOT ANDROID + DEFINES + QUICK_TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" + ) + + qt_extend_target("${name}" CONDITION arg_QMLTEST AND ANDROID + DEFINES + QUICK_TEST_SOURCE_DIR=":/" + ) + endif() + + foreach(path IN LISTS arg_QML_IMPORTPATH) + list(APPEND extra_test_args "-import" "${path}") + endforeach() + + # Generate a label in the form tests/auto/foo/bar/tst_baz + # and use it also for XML output + file(RELATIVE_PATH label "${PROJECT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${name}") + + if (arg_LOWDPI) + target_compile_definitions("${name}" PUBLIC TESTCASE_LOWDPI) + if (MACOS) + set_property(TARGET "${name}" PROPERTY MACOSX_BUNDLE_INFO_PLIST "${QT_MKSPECS_DIR}/macx-clang/Info.plist.disable_highdpi") + set_property(TARGET "${name}" PROPERTY PROPERTY MACOSX_BUNDLE TRUE) + endif() + endif() + + if (ANDROID) + qt_android_add_test("${name}") + else() + 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}") + elseif(arg_OUTPUT_DIRECTORY) + set(test_working_dir "${arg_OUTPUT_DIRECTORY}") + else() + set(test_working_dir "${CMAKE_CURRENT_BINARY_DIR}") + endif() + set(test_executable "${name}") + endif() + + if (NOT arg_CATCH) + list(APPEND test_outputs "-o" "${name}.xml,xml" "-o" "-,txt") + endif() + + add_test(NAME "${name}" COMMAND ${test_executable} ${extra_test_args} ${test_outputs} 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() + + # Add a ${target}/check makefile target, to more easily test one test. + if(TEST "${name}") + add_custom_target("${name}_check" + VERBATIM + COMMENT "Running ${CMAKE_CTEST_COMMAND} -V -R \"^${name}$\"" + COMMAND "${CMAKE_CTEST_COMMAND}" -V -R "^${name}$" + ) + if(TARGET "${name}") + add_dependencies("${name}_check" "${name}") + endif() + endif() + + # Get path to <qt_relocatable_install_prefix>/bin, as well as CMAKE_INSTALL_PREFIX/bin, then + # prepend them to the PATH environment variable. + # It's needed on Windows to find the shared libraries and plugins. + # qt_relocatable_install_prefix is dynamically computed from the location of where the Qt CMake + # package is found. + # The regular CMAKE_INSTALL_PREFIX can be different for example when building standalone tests. + # Any given CMAKE_INSTALL_PREFIX takes priority over qt_relocatable_install_prefix for the + # PATH environment variable. + set(install_prefixes "${CMAKE_INSTALL_PREFIX}") + if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX) + list(APPEND install_prefixes "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}") + endif() + + set(test_env_path "PATH=${CMAKE_CURRENT_BINARY_DIR}") + foreach(install_prefix ${install_prefixes}) + set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}${install_prefix}/${INSTALL_BINDIR}") + endforeach() + set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}$ENV{PATH}") + string(REPLACE ";" "\;" test_env_path "${test_env_path}") + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "${test_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) + foreach(install_prefix ${install_prefixes}) + list(APPEND plugin_paths "${install_prefix}/${INSTALL_PLUGINSDIR}") + endforeach() + endif() + + #TODO: Collect all paths from known repositories when performing a super + # build. + list(APPEND plugin_paths "${PROJECT_BINARY_DIR}/${INSTALL_PLUGINSDIR}") + list(JOIN plugin_paths "${QT_PATH_SEPARATOR}" plugin_paths_joined) + set_property(TEST "${name}" APPEND PROPERTY ENVIRONMENT "QT_PLUGIN_PATH=${plugin_paths_joined}") + + if(ANDROID OR IOS OR WINRT) + set(builtin_testdata TRUE) + endif() + + if(builtin_testdata) + # Safe guard against qml only tests, no source files == no target + if (TARGET "${name}") + target_compile_definitions("${name}" PRIVATE BUILTIN_TESTDATA) + + foreach(testdata IN LISTS arg_TESTDATA) + list(APPEND builtin_files ${testdata}) + endforeach() + + set(blacklist_path "BLACKLIST") + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${blacklist_path}") + list(APPEND builtin_files ${blacklist_path}) + endif() + + list(REMOVE_DUPLICATES builtin_files) + + # Skip Qt quick compiler when embedding test resources + foreach(file IN LISTS builtin_files) + set_source_files_properties(${file} + PROPERTIES QT_SKIP_QUICKCOMPILER TRUE + ) + endforeach() + + if (builtin_files) + qt_add_resource(${name} "${name}_testdata_builtin" + PREFIX "/" + FILES ${builtin_files} + BASE ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + endif() + else() + # Install test data + file(RELATIVE_PATH relative_path_to_test_project + "${QT_TOP_LEVEL_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}") + qt_path_join(testdata_install_dir ${QT_INSTALL_DIR} + "${relative_path_to_test_project}") + foreach(testdata IN LISTS arg_TESTDATA) + set(testdata "${CMAKE_CURRENT_SOURCE_DIR}/${testdata}") + if (IS_DIRECTORY "${testdata}") + qt_install( + DIRECTORY "${testdata}" + DESTINATION "${testdata_install_dir}") + else() + qt_install( + FILES "${testdata}" + DESTINATION "${testdata_install_dir}") + endif() + endforeach() + endif() + +endfunction() + + +# This function creates an executable for use as a helper program with tests. Some +# 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(qt_add_test_helper name) + + set(qt_add_test_helper_optional_args + "OVERRIDE_OUTPUT_DIRECTORY" + ) + + 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}" + ${qt_add_test_helper_optional_args} + ALL_ARGS + ${qt_add_test_helper_optional_args} + ${__qt_add_executable_optional_args} + ${__qt_add_executable_single_args} + ${__qt_add_executable_multi_args} + ARGS + ${ARGV} + ) + + set(extra_args_to_pass) + if(NOT arg_OVERRIDE_OUTPUT_DIRECTORY) + set(extra_args_to_pass OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/..") + endif() + + qt_add_executable("${name}" NO_INSTALL ${extra_args_to_pass} ${forward_args}) +endfunction() diff --git a/cmake/QtToolHelpers.cmake b/cmake/QtToolHelpers.cmake new file mode 100644 index 0000000000..56dcddb310 --- /dev/null +++ b/cmake/QtToolHelpers.cmake @@ -0,0 +1,380 @@ +# 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. +# +# We must pass this function a target name obtained from +# qt_get_tool_target_name like this: +# qt_get_tool_target_name(target_name my_tool) +# qt_add_tool(${target_name}) +# +function(qt_add_tool target_name) + qt_tool_target_to_name(name ${target_name}) + qt_parse_all_arguments(arg "qt_add_tool" "BOOTSTRAP;NO_QT;NO_INSTALL" + "TOOLS_TARGET;${__default_target_info_args}" + "${__default_private_args}" ${ARGN}) + + # Handle case when a tool does not belong to a module and it can't be built either (like + # during a cross-compile). + if(NOT arg_TOOLS_TARGET AND NOT QT_WILL_BUILD_TOOLS) + message(FATAL_ERROR "The tool \"${name}\" has not been assigned to a module via" + " TOOLS_TARGET (so it can't be found) and it can't be built" + " (QT_WILL_BUILD_TOOLS is ${QT_WILL_BUILD_TOOLS}).") + endif() + + if(CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING AND (name STREQUAL target_name)) + message(FATAL_ERROR + "qt_add_tool must be passed a target obtained from qt_get_tool_target_name.") + endif() + + set(full_name "${QT_CMAKE_EXPORT_NAMESPACE}::${name}") + set(imported_tool_target_found FALSE) + if(TARGET ${full_name}) + get_property(path TARGET ${full_name} PROPERTY LOCATION) + message(STATUS "Tool '${full_name}' was found at ${path}.") + set(imported_tool_target_found TRUE) + if(CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + return() + endif() + endif() + + if(arg_TOOLS_TARGET AND (NOT QT_WILL_BUILD_TOOLS OR QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + AND NOT imported_tool_target_found) + set(tools_package_name "Qt6${arg_TOOLS_TARGET}Tools") + message(STATUS "Searching for tool '${full_name}' in package ${tools_package_name}.") + + # Only search in path provided by QT_HOST_PATH. We need to do it with CMAKE_PREFIX_PATH + # instead of PATHS option, because any find_dependency call inside a Tools package would + # not get the proper prefix when using PATHS. + set(BACKUP_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) + set(CMAKE_PREFIX_PATH "${QT_HOST_PATH}") + + # Search both with sysroots prepended as well as in the host system. When cross compiling + # the mode_package might be set to ONLY only, and the Qt6 tools packages are actually + # in the host system. + set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH") + find_package( + ${tools_package_name} + ${PROJECT_VERSION} + NO_PACKAGE_ROOT_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_PACKAGE_REGISTRY + NO_CMAKE_SYSTEM_PATH + NO_CMAKE_SYSTEM_PACKAGE_REGISTRY) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "${BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}") + set(CMAKE_PREFIX_PATH "${BACKUP_CMAKE_PREFIX_PATH}") + + if(${${tools_package_name}_FOUND} AND TARGET ${full_name}) + # Even if the tool is already visible, make sure that our modules remain associated + # with the tools. + qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}") + get_property(path TARGET ${full_name} PROPERTY LOCATION) + message(STATUS "${full_name} was found at ${path} using package ${tools_package_name}.") + if (NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + return() + endif() + endif() + endif() + + if(NOT QT_WILL_BUILD_TOOLS) + message(FATAL_ERROR "The tool \"${full_name}\" was not found in the " + "${tools_package_name} package. " + "Package found: ${${tools_package_name}_FOUND}") + else() + if(QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + message(STATUS "Tool '${target_name}' will be cross-built from source.") + else() + message(STATUS "Tool '${full_name}' will be built from source.") + endif() + endif() + + set(disable_autogen_tools "${arg_DISABLE_AUTOGEN_TOOLS}") + if (arg_NO_QT) + # FIXME: Remove NO_QT again once qmake can use a "normal" Qt! + if (arg_BOOTSTRAP) + message(FATAL_ERROR "Tool can not be NO_QT and BOOTSTRAP at the same time!") + endif() + set(corelib "") + else() + if (arg_BOOTSTRAP) + set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Bootstrap) + list(APPEND disable_autogen_tools "uic" "moc" "rcc") + else() + set(corelib ${QT_CMAKE_EXPORT_NAMESPACE}::Core) + endif() + endif() + + set(bootstrap "") + if(arg_BOOTSTRAP) + set(bootstrap BOOTSTRAP) + endif() + + set(no_qt "") + if(arg_NO_QT) + set(no_qt NO_QT) + endif() + + qt_add_executable("${target_name}" OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ${bootstrap} + ${no_qt} + NO_INSTALL + SOURCES ${arg_SOURCES} + INCLUDE_DIRECTORIES + ${arg_INCLUDE_DIRECTORIES} + DEFINES + QT_USE_QSTRINGBUILDER + ${arg_DEFINES} + PUBLIC_LIBRARIES ${corelib} + LIBRARIES ${arg_LIBRARIES} Qt::PlatformToolInternal + COMPILE_OPTIONS ${arg_COMPILE_OPTIONS} + LINK_OPTIONS ${arg_LINK_OPTIONS} + MOC_OPTIONS ${arg_MOC_OPTIONS} + DISABLE_AUTOGEN_TOOLS ${disable_autogen_tools} + TARGET_VERSION "${arg_TARGET_VERSION}" + TARGET_PRODUCT "${arg_TARGET_PRODUCT}" + TARGET_DESCRIPTION "${arg_TARGET_DESCRIPTION}" + TARGET_COMPANY "${arg_TARGET_COMPANY}" + TARGET_COPYRIGHT "${arg_TARGET_COPYRIGHT}" + ) + qt_internal_add_target_aliases("${target_name}") + _qt_internal_apply_strict_cpp("${target_name}") + + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.19.0" AND QT_FEATURE_debug_and_release) + set_property(TARGET "${target_name}" + PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:${QT_MULTI_CONFIG_FIRST_CONFIG}>>") + endif() + + if (NOT target_name STREQUAL name) + set_target_properties(${target_name} PROPERTIES + OUTPUT_NAME ${name} + EXPORT_NAME ${name} + ) + endif() + + if(TARGET host_tools) + add_dependencies(host_tools "${target_name}") + if(bootstrap OR no_qt) + add_dependencies(bootstrap_tools "${target_name}") + endif() + endif() + + # 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("${target_name}" PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_${tool_cmake_configuration} "${QT_BUILD_DIR}/${INSTALL_BINDIR}" + ) + + if(NOT arg_NO_INSTALL AND arg_TOOLS_TARGET) + # Assign a tool to an export set, and mark the module to which the tool belongs. + qt_internal_append_known_modules_with_tools("${arg_TOOLS_TARGET}") + + # Also append the tool to the module list. + qt_internal_append_known_module_tool("${arg_TOOLS_TARGET}" "${target_name}") + + qt_get_cmake_configurations(cmake_configs) + + set(install_initial_call_args + EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_TOOLS_TARGET}ToolsTargets") + + foreach(cmake_config ${cmake_configs}) + qt_get_install_target_default_args( + OUT_VAR install_targets_default_args + CMAKE_CONFIG "${cmake_config}" + ALL_CMAKE_CONFIGS "${cmake_configs}") + qt_install(TARGETS "${target_name}" + ${install_initial_call_args} + CONFIGURATIONS ${cmake_config} + ${install_targets_default_args}) + unset(install_initial_call_args) + endforeach() + + qt_apply_rpaths(TARGET "${target_name}" INSTALL_PATH "${INSTALL_BINDIR}" RELATIVE_RPATH) + + endif() + + if(QT_FEATURE_separate_debug_info AND (UNIX OR MINGW)) + qt_enable_separate_debug_info(${target_name} ${INSTALL_BINDIR}) + endif() +endfunction() + +function(qt_export_tools module_name) + # Bail out when cross-compiling, unless QT_BUILD_TOOLS_WHEN_CROSSCOMPILING is on. + if(CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + return() + endif() + + # If no tools were defined belonging to this module, don't create a config and targets file. + if(NOT "${module_name}" IN_LIST QT_KNOWN_MODULES_WITH_TOOLS) + return() + endif() + + # The tools target name. For example: CoreTools + set(target "${module_name}Tools") + + 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}) + + # Add the extra cmake statements to make the tool targets global, so it doesn't matter where + # find_package is called. + # 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() + + if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + string(REGEX REPLACE "_native$" "" tool_name ${tool_name}) + 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) + if(NOT is_global) + set_property(TARGET ${INSTALL_CMAKE_NAMESPACE}::${tool_name} PROPERTY IMPORTED_GLOBAL TRUE) + endif() +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" + INSTALL_DESTINATION "${config_install_dir}" + ) + write_basic_package_version_file( + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion + ARCH_INDEPENDENT + ) + + qt_install(FILES + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" + "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}ConfigVersion.cmake" + DESTINATION "${config_install_dir}" + COMPONENT Devel + ) + + set(export_name "${INSTALL_CMAKE_NAMESPACE}${target}Targets") + qt_install(EXPORT "${export_name}" + NAMESPACE "${QT_CMAKE_EXPORT_NAMESPACE}::" + DESTINATION "${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() + +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() + +# Returns the target name for the tool with the given name. +# +# In most cases, the target name is the same as the tool name. +# If the user specifies to build tools when cross-compiling, then the +# suffix "_native" is appended. +function(qt_get_tool_target_name out_var name) + if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + set(${out_var} ${name}_native PARENT_SCOPE) + else() + set(${out_var} ${name} PARENT_SCOPE) + endif() +endfunction() + +# Returns the tool name for a given tool target. +# This is the inverse of qt_get_tool_target_name. +function(qt_tool_target_to_name out_var target) + set(name ${target}) + if (CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING) + string(REGEX REPLACE "_native$" "" name ${target}) + endif() + set(${out_var} ${name} PARENT_SCOPE) +endfunction() + +# Sets QT_WILL_BUILD_TOOLS if tools will be built. +function(qt_check_if_tools_will_be_built) + if(QT_FORCE_FIND_TOOLS OR (CMAKE_CROSSCOMPILING AND NOT QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)) + set(will_build_tools FALSE) + else() + set(will_build_tools TRUE) + endif() + set(QT_WILL_BUILD_TOOLS ${will_build_tools} CACHE INTERNAL "Are tools going to be built" FORCE) +endfunction() + +# Equivalent of qmake's qtNomakeTools(directory1 directory2). +# If QT_NO_MAKE_TOOLS is true, then targets within the given directories will be excluded from the +# default 'all' target, as well as from install phase. +# The private variable is checked by qt_add_executable. +function(qt_exclude_tool_directories_from_default_target) + if(QT_NO_MAKE_TOOLS) + set(absolute_path_directories "") + foreach(directory ${ARGV}) + list(APPEND absolute_path_directories "${CMAKE_CURRENT_SOURCE_DIR}/${directory}") + endforeach() + set(__qt_exclude_tool_directories "${absolute_path_directories}" PARENT_SCOPE) + endif() +endfunction() |