summaryrefslogtreecommitdiffstats
path: root/cmake/QtPrlHelpers.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/QtPrlHelpers.cmake')
-rw-r--r--cmake/QtPrlHelpers.cmake229
1 files changed, 66 insertions, 163 deletions
diff --git a/cmake/QtPrlHelpers.cmake b/cmake/QtPrlHelpers.cmake
index 7977afd030..45bfaedcdf 100644
--- a/cmake/QtPrlHelpers.cmake
+++ b/cmake/QtPrlHelpers.cmake
@@ -1,149 +1,16 @@
-# 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()
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
# Collects the library dependencies of a target.
+# As well as rcc object file dependencies.
# 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()
+function(qt_collect_libs target libs_out_var rcc_objects_out_var)
+ __qt_internal_walk_libs("${target}" "${libs_out_var}"
+ "${rcc_objects_out_var}" "qt_collect_libs_dict" "collect_libs")
+ set("${libs_out_var}" "${${libs_out_var}}" PARENT_SCOPE)
- # Strip any directory scope tokens.
- qt_internal_strip_target_directory_scope_token("${lib}" lib)
+ set(${rcc_objects_out_var} "${${rcc_objects_out_var}}" PARENT_SCOPE)
- 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.
@@ -154,15 +21,6 @@ function(qt_generate_prl_file target install_dir)
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")
@@ -179,6 +37,26 @@ function(qt_generate_prl_file target install_dir)
endif()
list(JOIN prl_config " " prl_config)
+ set(rcc_objects "")
+ set(prl_step1_content_libs "")
+ 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 prl_rcc_objects)
+ if(prl_libs)
+ set(prl_step1_content_libs "QMAKE_PRL_LIBS_FOR_CMAKE = ${prl_libs}\n")
+ endif()
+ if(prl_rcc_objects)
+ list(APPEND rcc_objects ${prl_rcc_objects})
+ endif()
+ endif()
+
+ if(rcc_objects AND QT_WILL_INSTALL)
+ list(TRANSFORM rcc_objects PREPEND "$$[QT_INSTALL_PREFIX]/")
+ endif()
+
# 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.
@@ -219,26 +97,23 @@ function(qt_generate_prl_file target install_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")
+ set(final_prl_file_name "${prefix_for_final_prl_name}$<TARGET_FILE_BASE_NAME:${target}>")
+ if(ANDROID)
+ string(APPEND final_prl_file_name "_${CMAKE_ANDROID_ARCH_ABI}")
+ endif()
+ string(APPEND final_prl_file_name ".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_TARGET = $<TARGET_LINKER_FILE_NAME:${target}>
+QMAKE_PRL_TARGET_PATH_FOR_CMAKE = $<TARGET_LINKER_FILE:${target}>
QMAKE_PRL_CONFIG = ${prl_config}
QMAKE_PRL_VERSION = ${PROJECT_VERSION}
+${prl_step1_content_libs}
")
- 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}"
@@ -260,6 +135,24 @@ QMAKE_PRL_VERSION = ${PROJECT_VERSION}
set(configs ${CMAKE_BUILD_TYPE})
endif()
+ set(qt_lib_dirs "${QT_BUILD_DIR}/${INSTALL_LIBDIR}")
+ if(QT_WILL_INSTALL)
+ list(APPEND qt_lib_dirs
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
+ endif()
+
+ set(qt_plugin_dirs "${QT_BUILD_DIR}/${INSTALL_PLUGINSDIR}")
+ if(QT_WILL_INSTALL)
+ list(APPEND qt_plugin_dirs
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_PLUGINSDIR}")
+ endif()
+
+ set(qt_qml_dirs "${QT_BUILD_DIR}/${INSTALL_QMLDIR}")
+ if(QT_WILL_INSTALL)
+ list(APPEND qt_qml_dirs
+ "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${INSTALL_QMLDIR}")
+ endif()
+
foreach(config ${configs})
# Output file for dependency tracking, and which will contain the final content.
qt_path_join(prl_step2_path
@@ -273,6 +166,13 @@ QMAKE_PRL_VERSION = ${PROJECT_VERSION}
qt_path_join(prl_meta_info_path
"${CMAKE_CURRENT_BINARY_DIR}"
"${prl_meta_info_name_prefix}${config}${prl_meta_info_name_suffix}")
+ if(MSVC)
+ set(link_library_flag "-l")
+ file(TO_CMAKE_PATH "$ENV{LIB};${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}" implicit_link_directories)
+ else()
+ set(link_library_flag ${CMAKE_LINK_LIBRARY_FLAG})
+ set(implicit_link_directories ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
+ endif()
add_custom_command(
OUTPUT "${prl_step2_path}"
DEPENDS "${prl_step1_path}"
@@ -285,8 +185,11 @@ QMAKE_PRL_VERSION = ${PROJECT_VERSION}
"-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}"
+ "-DLINK_LIBRARY_FLAG=${link_library_flag}"
+ "-DQT_LIB_DIRS=${qt_lib_dirs}"
+ "-DQT_PLUGIN_DIRS=${qt_plugin_dirs}"
+ "-DQT_QML_DIRS=${qt_qml_dirs}"
+ "-DIMPLICIT_LINK_DIRECTORIES=${implicit_link_directories}"
-P "${QT_CMAKE_DIR}/QtFinishPrlFile.cmake"
VERBATIM
COMMENT "Generating prl file for target ${target}"