summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2022-04-14 18:04:41 +0200
committerAlexandru Croitor <alexandru.croitor@qt.io>2022-04-22 14:34:47 +0200
commit251033fb0addb9799f2b308b2fa4f7589e9886ac (patch)
tree009478e74b6e720dc03c0de93d798882568923d3
parent4f2b4e0e5ef021864ceb05299ebf67f9751777d2 (diff)
CMake: Work around build rpath issue when CMAKE_STAGING_PREFIX is set
CMake has logic to rewrite build rpaths that contain CMAKE_STAGING_PREFIX to instead point to CMAKE_INSTALL_PREFIX. This breaks running executables from the build directory, because their build rpath will point to a location where the libraries might not exist yet (we didn't install Qt yet). Work around this by setting CMAKE_STAGING_PREFIX to a fake path, so that CMake does not do the rewriting anymore. CMAKE_STAGING_PREFIX needs to be set at subdirectory scope, not function scope, which is why qt_internal_apply_staging_prefix_build_rpath_workaround() is a macro that is called from within each Qt internal function that creates a target. The workaround can be disabled by configuring with -DQT_NO_STAGING_PREFIX_BUILD_RPATH_WORKAROUND=ON The downside of this workaround is that it breaks per-subdirectory install rules like 'ninja src/gui/install'. Regular global installation like 'ninja install' works fine. This is similar to what we do for tests in qt_set_up_fake_standalone_tests_install_prefix() introduced by 20292250d44e08437306096e9096fc655cc9fb8b The reason it's not as good for other target types is because in contrast to tests, we do want to install them. In case if someone does call `ninja src/gui/install' they will most likely get a permission error, telling them it's not possible to install into /qt_fake_staging_prefix/ check_qt_internal_apply_staging_prefix_build_rpath_workaround Fixes: QTBUG-102592 Change-Id: I6ce78dde1924a8d830ef5c62808ff674c9639d65 Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
-rw-r--r--cmake/QtAppHelpers.cmake1
-rw-r--r--cmake/QtBuildInformation.cmake18
-rw-r--r--cmake/QtModuleHelpers.cmake1
-rw-r--r--cmake/QtPluginHelpers.cmake1
-rw-r--r--cmake/QtRpathHelpers.cmake51
-rw-r--r--cmake/QtToolHelpers.cmake2
6 files changed, 73 insertions, 1 deletions
diff --git a/cmake/QtAppHelpers.cmake b/cmake/QtAppHelpers.cmake
index d0cca849f3..719b9d4793 100644
--- a/cmake/QtAppHelpers.cmake
+++ b/cmake/QtAppHelpers.cmake
@@ -111,4 +111,5 @@ function(qt_internal_finalize_app target)
# Rpaths need to be applied in the finalizer, because the MACOSX_BUNDLE property might be
# set after a qt_internal_add_app call.
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_BINDIR}" RELATIVE_RPATH)
+ qt_internal_apply_staging_prefix_build_rpath_workaround()
endfunction()
diff --git a/cmake/QtBuildInformation.cmake b/cmake/QtBuildInformation.cmake
index 24dd0ab0d1..9676d5db78 100644
--- a/cmake/QtBuildInformation.cmake
+++ b/cmake/QtBuildInformation.cmake
@@ -8,9 +8,27 @@ function(qt_print_feature_summary)
OPTIONAL_PACKAGES_NOT_FOUND
RUNTIME_PACKAGES_NOT_FOUND
FATAL_ON_MISSING_REQUIRED_PACKAGES)
+ qt_internal_run_additional_summary_checks()
qt_configure_print_summary()
endfunction()
+function(qt_internal_run_additional_summary_checks)
+ get_property(
+ rpath_workaround_enabled
+ GLOBAL PROPERTY _qt_internal_staging_prefix_build_rpath_workaround)
+ if(rpath_workaround_enabled)
+ set(message
+ "Due to CMAKE_STAGING_PREFIX usage and an unfixed CMake bug,
+ to ensure correct build time rpaths, directory-level install
+ rules like ninja src/gui/install will not work.
+ Check QTBUG-102592 for further details.")
+ qt_configure_add_report_entry(
+ TYPE NOTE
+ MESSAGE "${message}"
+ )
+ endif()
+endfunction()
+
function(qt_print_build_instructions)
if((NOT PROJECT_NAME STREQUAL "QtBase" AND
NOT PROJECT_NAME STREQUAL "Qt") OR
diff --git a/cmake/QtModuleHelpers.cmake b/cmake/QtModuleHelpers.cmake
index c7ae9590f2..ea1bf9cdfe 100644
--- a/cmake/QtModuleHelpers.cmake
+++ b/cmake/QtModuleHelpers.cmake
@@ -726,6 +726,7 @@ set(QT_LIBINFIX \"${QT_LIBINFIX}\")")
if(BUILD_SHARED_LIBS)
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${INSTALL_LIBDIR}" RELATIVE_RPATH)
+ qt_internal_apply_staging_prefix_build_rpath_workaround()
endif()
if (ANDROID AND NOT arg_HEADER_MODULE)
diff --git a/cmake/QtPluginHelpers.cmake b/cmake/QtPluginHelpers.cmake
index 7023e705e8..49fbe0eed2 100644
--- a/cmake/QtPluginHelpers.cmake
+++ b/cmake/QtPluginHelpers.cmake
@@ -422,6 +422,7 @@ function(qt_internal_add_plugin target)
)
if(BUILD_SHARED_LIBS)
qt_apply_rpaths(TARGET "${target}" INSTALL_PATH "${install_directory}" RELATIVE_RPATH)
+ qt_internal_apply_staging_prefix_build_rpath_workaround()
endif()
endif()
diff --git a/cmake/QtRpathHelpers.cmake b/cmake/QtRpathHelpers.cmake
index 9d65415bde..fc75b8f554 100644
--- a/cmake/QtRpathHelpers.cmake
+++ b/cmake/QtRpathHelpers.cmake
@@ -183,3 +183,54 @@ function(qt_apply_rpaths)
set_property(TARGET "${target}" APPEND PROPERTY "${prop_name}" ${rpaths})
endif()
endfunction()
+
+# Overrides the CMAKE_STAGING_PREFIX in a subdirectory scope, to stop CMake from rewriting build
+# rpaths to point into the original staging prefix, and thus breaking running executables from
+# the build directory.
+# See details at https://bugreports.qt.io/browse/QTBUG-102592
+# and https://gitlab.kitware.com/cmake/cmake/-/issues/23421
+#
+# This macro is only meant to be called in functions like
+# qt_internal_add_module / qt_internal_add_tool to ensure the variable is set in the
+# subdirectory scope of the calling function, and not in the actual function scope (where the
+# variable assignment would have no effect).
+#
+# This is the best workaround we can currently do, but it comes with the disadvantage that calling
+# subdirectory-scoped install targets does not work anymore.
+# e.g. calling ninja src/gui/install will try to install to the fake prefix and fail.
+# A regular ninja install call works fine.
+#
+# Usage of this macro assumes there are no binaries or libraries added in the root CMakeLists.txt
+# of the project because that would mean the macro is called at root level scope, which would
+# break installation.
+#
+# The implementation has to be a macro, so we can propagate the variable into the calling
+# subdirectory scope. The implementation can't use return().
+macro(qt_internal_apply_staging_prefix_build_rpath_workaround)
+ set(__qt_internal_should_apply_staging_prefix_build_rpath_workaround TRUE)
+ # Allow an opt out.
+ if(QT_NO_STAGING_PREFIX_BUILD_RPATH_WORKAROUND)
+ set(__qt_internal_should_apply_staging_prefix_build_rpath_workaround FALSE)
+ endif()
+
+ # No need for workaround if CMAKE_STAGING_PREFIX is not set.
+ if(NOT CMAKE_STAGING_PREFIX)
+ set(__qt_internal_should_apply_staging_prefix_build_rpath_workaround FALSE)
+ endif()
+
+ # No rpath support for win32, android, ios, so nothing to do.
+ if(WIN32 OR ANDROID OR UIKIT)
+ set(__qt_internal_should_apply_staging_prefix_build_rpath_workaround FALSE)
+ endif()
+
+ # Set the staging prefix to a non-existent directory, which is unlikely to have permissions
+ # for installation.
+ # The verbose directory name is chosen to attract the user's attention in case if they end up
+ # calling a subdirectory-scope install file.
+ if(__qt_internal_should_apply_staging_prefix_build_rpath_workaround)
+ set_property(GLOBAL PROPERTY _qt_internal_staging_prefix_build_rpath_workaround TRUE)
+ set(CMAKE_STAGING_PREFIX
+ "/qt_fake_staging_prefix/check_qt_internal_apply_staging_prefix_build_rpath_workaround"
+ PARENT_SCOPE)
+ endif()
+endmacro()
diff --git a/cmake/QtToolHelpers.cmake b/cmake/QtToolHelpers.cmake
index d640f146ae..054680f502 100644
--- a/cmake/QtToolHelpers.cmake
+++ b/cmake/QtToolHelpers.cmake
@@ -306,7 +306,7 @@ function(qt_internal_add_tool target_name)
endif()
qt_apply_rpaths(TARGET "${target_name}" INSTALL_PATH "${install_dir}" RELATIVE_RPATH)
-
+ qt_internal_apply_staging_prefix_build_rpath_workaround()
endif()
qt_enable_separate_debug_info(${target_name} "${install_dir}" QT_EXECUTABLE)