summaryrefslogtreecommitdiffstats
path: root/cmake/QtFindPackageHelpers.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtFindPackageHelpers.cmake')
-rw-r--r--cmake/QtFindPackageHelpers.cmake246
1 files changed, 246 insertions, 0 deletions
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()