Просмотр исходного кода

file(GET_RUNTIME_DEPENDENCIES): propagate transitive parent's rpath

This fixes incorrect runtime dependency resolution when the dependency
is located in rpaths of a transitive parent.  Instead of supplying only
the rpaths of the immediate parent, it combines the rpaths of all
transitive parents and passes them down.

Fixes: #24172
Alex Lapenkou 2 лет назад
Родитель
Сommit
136622a2b2

+ 7 - 2
Source/cmBinUtilsLinuxELFLinker.cxx

@@ -154,8 +154,13 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
         if (!this->Archive->IsPostExcluded(path)) {
           bool unique;
           this->Archive->AddResolvedPath(dep, path, unique);
-          if (unique && !this->ScanDependencies(path, rpaths)) {
-            return false;
+          if (unique) {
+            std::vector<std::string> combinedParentRpaths = parentRpaths;
+            combinedParentRpaths.insert(combinedParentRpaths.end(),
+                                        rpaths.begin(), rpaths.end());
+            if (!this->ScanDependencies(path, combinedParentRpaths)) {
+              return false;
+            }
           }
         }
       } else {

+ 1 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake

@@ -61,6 +61,7 @@ elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
 
   if(NOT CMAKE_C_COMPILER_ID MATCHES "^XL")
     run_install_test(linux)
+    run_install_test(linux-parent-rpath-propagation)
     run_install_test(file-filter)
   endif()
   run_install_test(linux-unresolved)

+ 54 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-parent-rpath-propagation.cmake

@@ -0,0 +1,54 @@
+enable_language(C)
+cmake_policy(SET CMP0095 NEW)
+
+# Force linker to set RPATH instead of RUNPATH
+add_link_options("-Wl,--disable-new-dtags")
+
+# bin/exe (RPATH = "lib1:lib2:lib3")
+# ^
+# |
+# lib1/libone.so (RPATH erased)
+# ^
+# |
+# lib2/libtwo.so (RPATH erased)
+# ^
+# |
+# lib3/libthree.so (RPATH erased)
+# GET_RUNTIME_DEPENDENCIES(bin/exe) should resolve all three libraries
+
+set(TEST_SOURCE_DIR "linux/parent-rpath-propagation")
+
+add_library(three SHARED "${TEST_SOURCE_DIR}/three.c")
+
+add_library(two SHARED "${TEST_SOURCE_DIR}/two.c")
+target_link_libraries(two PUBLIC three)
+
+add_library(one SHARED "${TEST_SOURCE_DIR}/one.c")
+target_link_libraries(one PUBLIC two)
+
+add_executable(exe "${TEST_SOURCE_DIR}/main.c")
+target_link_libraries(exe PUBLIC one)
+
+set_property(TARGET exe PROPERTY INSTALL_RPATH
+  $ORIGIN/../lib1
+  $ORIGIN/../lib2
+  $ORIGIN/../lib3
+)
+
+install(TARGETS exe DESTINATION bin)
+install(TARGETS one DESTINATION lib1)
+install(TARGETS two DESTINATION lib2)
+install(TARGETS three DESTINATION lib3)
+
+install(CODE [[
+  file(GET_RUNTIME_DEPENDENCIES
+    EXECUTABLES
+      "${CMAKE_INSTALL_PREFIX}/bin/$<TARGET_FILE_NAME:exe>"
+    PRE_INCLUDE_REGEXES
+      "^lib(one|two|three)\\.so$"
+      "^libc\\.so"
+    PRE_EXCLUDE_REGEXES ".*"
+    POST_INCLUDE_REGEXES "^.*/lib(one|two|three)\\.so$"
+    POST_EXCLUDE_REGEXES ".*"
+    )
+  ]])

+ 12 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/main.c

@@ -0,0 +1,12 @@
+extern void one(void);
+extern void two(void);
+extern void three(void);
+
+int main(void)
+{
+  one();
+  two();
+  three();
+
+  return 0;
+}

+ 7 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/one.c

@@ -0,0 +1,7 @@
+extern void two(void);
+extern void three(void);
+
+void one(void)
+{
+  two();
+}

+ 3 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/three.c

@@ -0,0 +1,3 @@
+void three(void)
+{
+}

+ 6 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux/parent-rpath-propagation/two.c

@@ -0,0 +1,6 @@
+extern void three(void);
+
+void two(void)
+{
+  three();
+}