diff options
Diffstat (limited to 'cmake/QtPrlHelpers.cmake')
-rw-r--r-- | cmake/QtPrlHelpers.cmake | 229 |
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}" |