summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/QtAutoDetect.cmake5
-rw-r--r--cmake/QtBuild.cmake152
-rw-r--r--cmake/QtBuildInternals/QtBuildInternalsConfig.cmake7
-rw-r--r--cmake/QtPostProcess.cmake12
-rw-r--r--configure.cmake7
-rwxr-xr-xutil/cmake/configurejson2cmake.py16
6 files changed, 189 insertions, 10 deletions
diff --git a/cmake/QtAutoDetect.cmake b/cmake/QtAutoDetect.cmake
index d5d93007ba..dd5d8a6bd6 100644
--- a/cmake/QtAutoDetect.cmake
+++ b/cmake/QtAutoDetect.cmake
@@ -153,6 +153,11 @@ function(qt_auto_detect_ios)
message(FATAL_ERROR
"Building Qt for ${CMAKE_SYSTEM_NAME} as shared libraries is not supported.")
endif()
+
+ # Disable qt rpaths for iOS, just like mkspecs/common/uikit.conf does, due to those
+ # bundles not being able to use paths outside the app bundle. Not sure this is strictly
+ # needed though.
+ set(QT_DISABLE_RPATH "OFF" CACHE BOOL "Disable automatic Qt rpath handling." FORCE)
endif()
endfunction()
diff --git a/cmake/QtBuild.cmake b/cmake/QtBuild.cmake
index 765b5fb961..d4b7924646 100644
--- a/cmake/QtBuild.cmake
+++ b/cmake/QtBuild.cmake
@@ -106,13 +106,12 @@ if("${isSystemDir}" STREQUAL "-1")
set(_default_install_rpath "${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}")
endif("${isSystemDir}" STREQUAL "-1")
-# Default rpath settings: Use rpath for build tree as well as a full path for the installed binaries.
-# For origin builds, one needs to override CMAKE_INSTALL_RPATH for example with $ORIGIN/../lib
-# Example: -DCMAKE_INSTALL_RPATH=\$ORIGIN/../lib (backslash to escape the $ in the shell)
-# Implementation note: the cache var must be STRING and not PATH or FILEPATH, otherwise CMake will
-# transform the value into an absolute path, getting rid of '$ORIGIN'.
-set(CMAKE_INSTALL_RPATH "${_default_install_rpath}" CACHE STRING "RPATH for installed binaries")
-message(STATUS "Install RPATH set to: ${CMAKE_INSTALL_RPATH}")
+# The default rpath settings for installed targets is empty.
+# The rpaths will instead be computed for each target separately using qt_apply_rpaths().
+# Additional rpaths can be passed via QT_EXTRA_RPATHS.
+# By default this will include $ORIGIN / @loader_path, so the installation is relocatable.
+# Bottom line: No need to pass anything to CMAKE_INSTALL_RPATH.
+set(CMAKE_INSTALL_RPATH "" CACHE STRING "RPATH for installed binaries")
# add the automatically determined parts of the RPATH
# which point to directories outside the build tree to the install RPATH
@@ -1976,6 +1975,8 @@ set(QT_CMAKE_EXPORT_NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE})")
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.
@@ -2478,6 +2479,7 @@ function(qt_add_plugin target)
NAMESPACE ${QT_CMAKE_EXPORT_NAMESPACE}::
DESTINATION "${config_install_dir}"
)
+ qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH)
endif()
# Store the plug-in type in the target property
@@ -3378,6 +3380,8 @@ function(qt_add_tool name)
qt_install(TARGETS "${name}"
EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_TOOLS_TARGET}ToolsTargets"
DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS})
+ qt_apply_rpaths(TARGET "${name}" INSTALL_PATH "${INSTALL_BINDIR}" RELATIVE_RPATH)
+
endif()
if(QT_FEATURE_separate_debug_info AND (UNIX OR MINGW))
@@ -4150,6 +4154,140 @@ function(qt_exclude_tool_directories_from_default_target)
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()
+
# Compatibility macros that should be removed once all their usages are removed.
function(extend_target)
qt_extend_target(${ARGV})
diff --git a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
index 5648326ca2..a8c2cc6c65 100644
--- a/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
+++ b/cmake/QtBuildInternals/QtBuildInternalsConfig.cmake
@@ -259,6 +259,13 @@ macro(qt_examples_build_begin)
set(QT_NO_CREATE_TARGETS TRUE)
set(BACKUP_CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE})
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH")
+
+ # Because CMAKE_INSTALL_RPATH is empty by default in the repo project, examples need to have
+ # it set here, so they can run when installed.
+ # This means that installed examples are not relocatable at the moment. We would need to
+ # annotate where each example is installed to, to be able to derive a relative rpath, and it
+ # seems there's no way to query such information from CMake itself.
+ set(CMAKE_INSTALL_RPATH "${_default_install_rpath}")
endmacro()
macro(qt_examples_build_end)
diff --git a/cmake/QtPostProcess.cmake b/cmake/QtPostProcess.cmake
index 9b1769455d..798fd947f1 100644
--- a/cmake/QtPostProcess.cmake
+++ b/cmake/QtPostProcess.cmake
@@ -366,6 +366,18 @@ function(qt_generate_build_internals_extra_cmake_code)
"set(BUILD_WITH_PCH \"${BUILD_WITH_PCH}\" CACHE STRING \"\")\n")
endif()
+ # Rpath related things that need to be re-used when building other repos.
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(CMAKE_INSTALL_RPATH \"${CMAKE_INSTALL_RPATH}\" CACHE STRING \"\")\n")
+ if(DEFINED QT_DISABLE_RPATH)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_DISABLE_RPATH \"${QT_DISABLE_RPATH}\" CACHE STRING \"\")\n")
+ endif()
+ if(DEFINED QT_EXTRA_RPATHS)
+ string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS
+ "set(QT_EXTRA_RPATHS \"${QT_EXTRA_RPATHS}\" CACHE STRING \"\")\n")
+ endif()
+
qt_generate_install_prefixes(install_prefix_content)
string(APPEND QT_EXTRA_BUILD_INTERNALS_VARS "${install_prefix_content}")
diff --git a/configure.cmake b/configure.cmake
index 3976362d6e..f773e28f52 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -397,7 +397,7 @@ qt_feature_config("simulator_and_device" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("rpath" PUBLIC
LABEL "Build with RPATH"
AUTODETECT 1
- CONDITION BUILD_SHARED_LIBS AND UNIX AND NOT WIN32 AND NOT ANDROID AND NOT APPLE
+ CONDITION BUILD_SHARED_LIBS AND UNIX AND NOT WIN32 AND NOT ANDROID
)
qt_feature_config("rpath" QMAKE_PUBLIC_QT_CONFIG)
qt_feature("force_asserts" PUBLIC
@@ -921,6 +921,11 @@ qt_configure_add_report_entry(
)
qt_configure_add_report_entry(
TYPE ERROR
+ MESSAGE "Static builds don't support RPATH"
+ CONDITION ( QT_FEATURE_rpath OR QT_EXTRA_RPATHS ) AND NOT QT_FEATURE_shared
+)
+qt_configure_add_report_entry(
+ TYPE ERROR
MESSAGE "Command line option -coverage is only supported with clang compilers."
CONDITION QT_FEATURE_coverage AND NOT CLANG
)
diff --git a/util/cmake/configurejson2cmake.py b/util/cmake/configurejson2cmake.py
index 85ac26ec2b..f004e732f6 100755
--- a/util/cmake/configurejson2cmake.py
+++ b/util/cmake/configurejson2cmake.py
@@ -876,10 +876,9 @@ def get_feature_mapping():
"qpa_default_platform": None, # Not a bool!
"release": None,
"release_tools": None,
- "rpath_dir": None, # merely used to fill the qmake variable EXTRA_RPATHS
"rpath": {
"autoDetect": "1",
- "condition": "BUILD_SHARED_LIBS AND UNIX AND NOT WIN32 AND NOT ANDROID AND NOT APPLE",
+ "condition": "BUILD_SHARED_LIBS AND UNIX AND NOT WIN32 AND NOT ANDROID",
},
"sanitize_address": None, # sanitizer
"sanitize_memory": None,
@@ -1222,6 +1221,12 @@ def processSummaryHelper(ctx, entries, cm_fh):
print(f" XXXX UNHANDLED SUMMARY TYPE {entry}.")
+report_condition_mapping = {
+ "(features.rpath || features.rpath_dir) && !features.shared": "(features.rpath || QT_EXTRA_RPATHS) && !features.shared",
+ "(features.rpath || features.rpath_dir) && var.QMAKE_LFLAGS_RPATH == ''": None
+}
+
+
def processReportHelper(ctx, entries, cm_fh):
feature_mapping = get_feature_mapping()
@@ -1265,6 +1270,13 @@ def processReportHelper(ctx, entries, cm_fh):
if unhandled_condition:
print(f" XXXX UNHANDLED CONDITION in REPORT TYPE {entry}.")
continue
+
+ if isinstance(condition, str) and condition in report_condition_mapping:
+ new_condition = report_condition_mapping[condition]
+ if new_condition is None:
+ continue
+ else:
+ condition = new_condition
condition = map_condition(condition)
entry_args.append(lineify("CONDITION", condition, quote=False))
entry_args_string = "".join(entry_args)