diff options
Diffstat (limited to 'cmake/QtFinishPrlFile.cmake')
-rw-r--r-- | cmake/QtFinishPrlFile.cmake | 130 |
1 files changed, 108 insertions, 22 deletions
diff --git a/cmake/QtFinishPrlFile.cmake b/cmake/QtFinishPrlFile.cmake index 4927761674..1cf9377e6c 100644 --- a/cmake/QtFinishPrlFile.cmake +++ b/cmake/QtFinishPrlFile.cmake @@ -1,56 +1,127 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + # Finish a preliminary .prl file. # # - Replaces occurrences of the build libdir with $$[QT_INSTALL_LIBDIR]. # - Strips version number suffixes from absolute paths, because qmake's lflag # merging does not handle them correctly. +# - Transforms absolute library paths into link flags +# aka from "/usr/lib/x86_64-linux-gnu/libcups.so" to "-lcups" +# - Replaces Qt absolute framework paths into a combination of -F$$[QT_INSTALL_LIBS] and +# -framework QtFoo +# - Prepends '-l' to values that are not absolute paths, and don't start with a dash +# aka, '-lfoo', '-framework', '-pthread'. +# +# The path to the final .prl file is stored in the input file as assignment to FINAL_PRL_FILE_PATH. # # This file is to be used in CMake script mode with the following variables set: -# IN_FILE: path to the preliminary .prl file -# OUT_FILE: path to the final .prl file that's going to be installed -# QT_BUILD_LIBDIR: path to Qt's libdir when building (those paths get replaced) +# IN_FILE: path to the step 1 preliminary .prl file +# OUT_FILE: path to the step 2 preliminary .prl file that is going to be created +# QT_LIB_DIRS: list of paths where Qt libraries are located. +# This includes the install prefix and the current repo build dir. +# These paths get replaced with relocatable paths or linker / framework flags. # LIBRARY_SUFFIXES: list of known library extensions, e.g. .so;.a on Linux +# LIBRARY_PREFIXES: list of known library prefies, e.g. the "lib" in "libz" on on Linux +# LINK_LIBRARY_FLAG: flag used to link a shared library to an executable, e.g. -l on UNIX +# IMPLICIT_LINK_DIRECTORIES: list of implicit linker search paths -function(strip_library_version_suffix out_var file_path) - get_filename_component(dir "${file_path}" DIRECTORY) - get_filename_component(basename "${file_path}" NAME_WE) - get_filename_component(ext "${file_path}" EXT) - foreach(libsuffix ${LIBRARY_SUFFIXES}) - if(ext MATCHES "^${libsuffix}(\\.[0-9]+)+") - set(ext ${libsuffix}) - break() - endif() - endforeach() - set(${out_var} "${dir}/${basename}${ext}" PARENT_SCOPE) -endfunction() +cmake_policy(SET CMP0007 NEW) +include("${CMAKE_CURRENT_LIST_DIR}/QtGenerateLibHelpers.cmake") file(STRINGS "${IN_FILE}" lines) set(content "") +set(qt_framework_search_path_inserted FALSE) foreach(line ${lines}) if(line MATCHES "^RCC_OBJECTS = (.*)") set(rcc_objects ${CMAKE_MATCH_1}) + elseif(line MATCHES "^QMAKE_PRL_TARGET_PATH_FOR_CMAKE = (.*)") + set(target_library_path "${CMAKE_MATCH_1}") elseif(line MATCHES "^QMAKE_PRL_LIBS_FOR_CMAKE = (.*)") unset(adjusted_libs) foreach(lib ${CMAKE_MATCH_1}) if("${lib}" STREQUAL "") continue() endif() + + # Check if the absolute path represents a Qt module located either in Qt's + # $prefix/lib dir, or in the build dir of the repo. if(IS_ABSOLUTE "${lib}") - strip_library_version_suffix(lib "${lib}") - file(RELATIVE_PATH relative_lib "${QT_BUILD_LIBDIR}" "${lib}") - if(IS_ABSOLUTE "${relative_lib}" OR (relative_lib MATCHES "^\\.\\.")) - list(APPEND adjusted_libs "${lib}") + qt_internal_path_is_relative_to_qt_lib_path( + "${lib}" "${QT_LIB_DIRS}" lib_is_a_qt_module relative_lib) + if(NOT lib_is_a_qt_module) + # It's not a Qt module, extract the library name and prepend an -l to make + # it relocatable. + qt_transform_absolute_library_paths_to_link_flags(lib_with_link_flag "${lib}") + list(APPEND adjusted_libs "${lib_with_link_flag}") else() - list(APPEND adjusted_libs "$$[QT_INSTALL_LIBS]/${relative_lib}") + # Is a Qt module. + # Transform Qt framework paths into -framework flags. + if(relative_lib MATCHES "^(Qt(.+))\\.framework/") + if(NOT qt_framework_search_path_inserted) + set(qt_framework_search_path_inserted TRUE) + list(APPEND adjusted_libs "-F$$[QT_INSTALL_LIBS]") + endif() + list(APPEND adjusted_libs "-framework" "${CMAKE_MATCH_1}") + else() + # Not a framework, transform the Qt module into relocatable relative path. + qt_strip_library_version_suffix(relative_lib "${relative_lib}") + list(APPEND adjusted_libs "$$[QT_INSTALL_LIBS]/${relative_lib}") + endif() endif() else() - if(NOT lib MATCHES "^-l" AND NOT lib MATCHES "^-framework") + # Not absolute path, most likely a library name or a linker flag. + # If linker flag (like -framework, -lfoo, -pthread, keep it as-is). + if(NOT lib MATCHES "^-") string(PREPEND lib "-l") endif() list(APPEND adjusted_libs "${lib}") endif() endforeach() if(rcc_objects) - list(APPEND adjusted_libs ${rcc_objects}) + set(libs_to_prepend ${rcc_objects}) + + # By default, when qmake processes prl files, it first puts the processed library + # on the link line, followed by all values specified in QMAKE_PRL_LIBS. + # Because we add the resource object files into QMAKE_PRL_LIBS, this means they will + # also appear on the link line after the library. + # This causes issues on Linux because the linker may discard unreferenced symbols from + # the library, which are referenced by the resource object files. + # We can't control the placement of the library in relation to QMAKE_PRL_LIBS, but we + # can add the library one more time in QMAKE_PRL_LIBS, after the object files. + # qmake's UnixMakefileGenerator::findLibraries then takes care of deduplication, which + # keeps the last occurrence of the library on the link line, the one after the object + # files. + qt_internal_path_is_relative_to_qt_lib_path( + "${target_library_path}" "${QT_LIB_DIRS}" lib_is_a_qt_module relative_lib) + if(NOT lib_is_a_qt_module) + qt_internal_path_is_relative_to_qt_lib_path( + "${target_library_path}" "${QT_PLUGIN_DIRS}" lib_is_a_qt_plugin relative_lib) + endif() + if(NOT lib_is_a_qt_module AND NOT lib_is_a_qt_plugin) + qt_internal_path_is_relative_to_qt_lib_path( + "${target_library_path}" "${QT_QML_DIRS}" lib_is_a_qt_qml_plugin relative_lib) + endif() + if(NOT lib_is_a_qt_module AND NOT lib_is_a_qt_plugin AND NOT lib_is_a_qt_qml_plugin) + message(AUTHOR_WARNING + "Could not determine relative path for library ${target_library_path} when " + "generating prl file contents. An absolute path will be embedded, which " + "will cause issues if the Qt installation is relocated.") + list(APPEND libs_to_prepend "${target_library_path}") + else() + set(qmake_lib_path_prefix "$$[QT_PRL_INVALID_QMAKE_VARIABLE]") + if(lib_is_a_qt_module) + set(qmake_lib_path_prefix "$$[QT_INSTALL_LIBS]") + elseif(lib_is_a_qt_plugin) + set(qmake_lib_path_prefix "$$[QT_INSTALL_PLUGINS]") + elseif(lib_is_a_qt_qml_plugin) + set(qmake_lib_path_prefix "$$[QT_INSTALL_QML]") + endif() + qt_strip_library_version_suffix(relative_lib "${relative_lib}") + list(APPEND libs_to_prepend "${qmake_lib_path_prefix}/${relative_lib}") + endif() + + list(PREPEND adjusted_libs ${libs_to_prepend}) endif() list(JOIN adjusted_libs " " adjusted_libs_for_qmake) string(APPEND content "QMAKE_PRL_LIBS = ${adjusted_libs_for_qmake}\n") @@ -60,3 +131,18 @@ foreach(line ${lines}) endif() endforeach() file(WRITE "${OUT_FILE}" "${content}") + +# Read the prl meta file to find out where should the final prl file be placed, +# Copy it there, if the contents hasn't changed. +file(STRINGS "${IN_META_FILE}" lines) + +foreach(line ${lines}) + if(line MATCHES "^FINAL_PRL_FILE_PATH = (.*)") + set(final_prl_file_path "${CMAKE_MATCH_1}") + configure_file( + "${OUT_FILE}" + "${final_prl_file_path}" + COPYONLY + ) + endif() +endforeach() |