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
This commit is contained in:
Alex Lapenkou
2022-11-29 15:04:31 -06:00
committed by Brad King
parent 4aa3149c67
commit 136622a2b2
7 changed files with 90 additions and 2 deletions

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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 ".*"
)
]])

View File

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

View File

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

View File

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

View File

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