summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/FindCUDAToolkit.cmake5
-rw-r--r--Source/cmComputeLinkInformation.cxx12
-rw-r--r--Source/cmGeneratorTarget.cxx14
-rw-r--r--Source/cmGeneratorTarget.h3
-rw-r--r--Tests/RunCMake/CMakeLists.txt7
-rw-r--r--Tests/RunCMake/RuntimePath/RunCMakeTest.cmake41
-rw-r--r--Tests/RunCMake/RuntimePath/Stub-fail-result.txt1
-rw-r--r--Tests/RunCMake/RuntimePath/Stub-fail-stderr.txt1
-rw-r--r--Tests/RunCMake/RuntimePath/Stub.c4
-rw-r--r--Tests/RunCMake/RuntimePath/Stub.cmake25
-rw-r--r--Tests/RunCMake/RuntimePath/StubExe.c5
-rw-r--r--Tests/RunCMake/RuntimePath/StubUse.c5
12 files changed, 112 insertions, 11 deletions
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index 469a7ad..ac72c17 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -1100,7 +1100,10 @@ if(CUDAToolkit_FOUND)
if(CUDA_${lib_name}_LIBRARY MATCHES "/stubs/" AND NOT WIN32)
# Use a SHARED library with IMPORTED_IMPLIB, but not IMPORTED_LOCATION,
# to indicate that the stub is for linkers but not dynamic loaders.
- # It will not contribute any RPATH entry.
+ # It will not contribute any RPATH entry. When encountered as
+ # a private transitive dependency of another shared library,
+ # it will be passed explicitly to linkers so they can find it
+ # even when the runtime library file does not exist on disk.
set(CUDA_IMPORT_PROPERTY IMPORTED_IMPLIB)
set(CUDA_IMPORT_TYPE SHARED)
endif()
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index e7bef68..40eb902 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -1331,7 +1331,17 @@ void cmComputeLinkInformation::AddSharedDepItem(LinkEntry const& entry)
}
// If in linking mode, just link to the shared library.
- if (this->SharedDependencyMode == SharedDepModeLink) {
+ if (this->SharedDependencyMode == SharedDepModeLink ||
+ // For an imported shared library without a known runtime artifact,
+ // such as a CUDA stub, a library file named with the real soname
+ // may not be available at all, so '-rpath-link' cannot help linkers
+ // find it to satisfy '--no-allow-shlib-undefined' recursively.
+ // Pass this dependency to the linker explicitly just in case.
+ // If the linker also uses '--as-needed' behavior, this will not
+ // add an unnecessary direct dependency.
+ (tgt && tgt->IsImported() &&
+ !tgt->HasKnownRuntimeArtifactLocation(this->Config) &&
+ this->Target->LinkerEnforcesNoAllowShLibUndefined(this->Config))) {
this->AddItem(entry);
return;
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 289bb24..11253db 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5596,6 +5596,20 @@ std::string cmGeneratorTarget::GetLinkerTool(const std::string& lang,
return linkerTool;
}
+bool cmGeneratorTarget::LinkerEnforcesNoAllowShLibUndefined(
+ std::string const& config) const
+{
+ // FIXME(#25486): Account for the LINKER_TYPE target property.
+ // Also factor out the hard-coded list below into a platform
+ // information table based on the linker id.
+ std::string ll = this->GetLinkerLanguage(config);
+ std::string linkerIdVar = cmStrCat("CMAKE_", ll, "_COMPILER_LINKER_ID");
+ cmValue linkerId = this->Makefile->GetDefinition(linkerIdVar);
+ // The GNU bfd-based linker may enforce '--no-allow-shlib-undefined'
+ // recursively by default. The Solaris linker has similar behavior.
+ return linkerId && (*linkerId == "GNU" || *linkerId == "Solaris");
+}
+
std::string cmGeneratorTarget::GetPDBOutputName(
const std::string& config) const
{
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index cfb08fa..fb56a0d 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -805,6 +805,9 @@ public:
std::string GetLinkerTool(const std::string& lang,
const std::string& config) const;
+ /** Is the linker known to enforce '--no-allow-shlib-undefined'? */
+ bool LinkerEnforcesNoAllowShLibUndefined(std::string const& config) const;
+
/** Does this target have a GNU implib to convert to MS format? */
bool HasImplibGNUtoMS(std::string const& config) const;
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 324a4da..a4e4800 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -434,8 +434,11 @@ endif()
add_RunCMake_test(ObjectLibrary)
add_RunCMake_test(ParseImplicitIncludeInfo)
add_RunCMake_test(ParseImplicitLinkInfo)
-if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
- add_RunCMake_test(RuntimePath)
+if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG)
+ add_RunCMake_test(RuntimePath
+ -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+ -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT}
+ )
endif()
add_RunCMake_test(ScriptMode)
add_RunCMake_test(Swift -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
diff --git a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
index ad446e9..180a0fe 100644
--- a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
+++ b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
@@ -21,12 +21,39 @@ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
set(cfg_dir /Debug)
endif()
-run_RuntimePath(SymlinkImplicit)
-run_cmake_command(SymlinkImplicitCheck
- ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/SymlinkImplicit-build -Dcfg_dir=${cfg_dir} -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+ run_RuntimePath(SymlinkImplicit)
+ run_cmake_command(SymlinkImplicitCheck
+ ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/SymlinkImplicit-build -Dcfg_dir=${cfg_dir} -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
-run_RuntimePath(Relative)
+ run_RuntimePath(Relative)
-run_RuntimePath(Genex)
-run_cmake_command(GenexCheck
- ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/Genex-build -P ${RunCMake_SOURCE_DIR}/GenexCheck.cmake)
+ run_RuntimePath(Genex)
+ run_cmake_command(GenexCheck
+ ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/Genex-build -P ${RunCMake_SOURCE_DIR}/GenexCheck.cmake)
+endif()
+
+block()
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Stub-build)
+ if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(bin_dir "${RunCMake_TEST_BINARY_DIR}/Debug")
+ set(lib_dir "${RunCMake_TEST_BINARY_DIR}/lib/Debug")
+ else()
+ set(bin_dir "${RunCMake_TEST_BINARY_DIR}")
+ set(lib_dir "${RunCMake_TEST_BINARY_DIR}/lib")
+ endif()
+ run_cmake(Stub)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ run_cmake_command(Stub-build ${CMAKE_COMMAND} --build . --config Debug)
+ if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|SunOS)$|BSD")
+ set(ldpath LD_LIBRARY_PATH)
+ elseif(CMAKE_SYSTEM_NAME MATCHES "^(Darwin)$")
+ set(ldpath DYLD_LIBRARY_PATH)
+ elseif(CMAKE_SYSTEM_NAME MATCHES "^(AIX)$")
+ set(ldpath LIBPATH)
+ endif()
+ if(ldpath)
+ run_cmake_command(Stub-fail ${CMAKE_COMMAND} -E env LANG=C ${bin_dir}/StubExe)
+ run_cmake_command(Stub-pass ${CMAKE_COMMAND} -E env --modify ${ldpath}=path_list_prepend:${lib_dir} ${bin_dir}/StubExe)
+ endif()
+endblock()
diff --git a/Tests/RunCMake/RuntimePath/Stub-fail-result.txt b/Tests/RunCMake/RuntimePath/Stub-fail-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Stub-fail-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/RuntimePath/Stub-fail-stderr.txt b/Tests/RunCMake/RuntimePath/Stub-fail-stderr.txt
new file mode 100644
index 0000000..9c17414
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Stub-fail-stderr.txt
@@ -0,0 +1 @@
+(error while loading shared libraries: libStub\.so\.1|Library not loaded: '?@rpath/libStub\.1\.dylib'?|(Cannot|Could not) load module libStub\.so|fatal: libStub\.so\.1: open failed|Shared object "libStub\.so\.1" not found)
diff --git a/Tests/RunCMake/RuntimePath/Stub.c b/Tests/RunCMake/RuntimePath/Stub.c
new file mode 100644
index 0000000..2ff333a
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Stub.c
@@ -0,0 +1,4 @@
+int Stub(void)
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/RuntimePath/Stub.cmake b/Tests/RunCMake/RuntimePath/Stub.cmake
new file mode 100644
index 0000000..18e99c1
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Stub.cmake
@@ -0,0 +1,25 @@
+enable_language(C)
+
+add_library(Stub SHARED Stub.c)
+set_target_properties(Stub PROPERTIES
+ SOVERSION 1
+ LIBRARY_OUTPUT_DIRECTORY lib
+ )
+
+set(StubDir ${CMAKE_CURRENT_BINARY_DIR}/lib/stubs)
+set(Stub "${StubDir}/${CMAKE_SHARED_LIBRARY_PREFIX}Stub${CMAKE_SHARED_LIBRARY_SUFFIX}")
+add_custom_target(StubCopy
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${StubDir}"
+ COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_SONAME_FILE:Stub>" "${Stub}"
+ BYPRODUCTS ${Stub}
+ )
+add_dependencies(StubCopy Stub)
+add_library(Imp::Stub SHARED IMPORTED)
+set_property(TARGET Imp::Stub PROPERTY IMPORTED_IMPLIB "${Stub}")
+add_dependencies(Imp::Stub StubCopy)
+
+add_library(StubUse SHARED StubUse.c)
+target_link_libraries(StubUse PRIVATE Imp::Stub)
+
+add_executable(StubExe StubExe.c)
+target_link_libraries(StubExe PRIVATE StubUse)
diff --git a/Tests/RunCMake/RuntimePath/StubExe.c b/Tests/RunCMake/RuntimePath/StubExe.c
new file mode 100644
index 0000000..14b3fe4
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/StubExe.c
@@ -0,0 +1,5 @@
+extern int StubUse(void);
+int main(void)
+{
+ return StubUse();
+}
diff --git a/Tests/RunCMake/RuntimePath/StubUse.c b/Tests/RunCMake/RuntimePath/StubUse.c
new file mode 100644
index 0000000..ffdaf6d
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/StubUse.c
@@ -0,0 +1,5 @@
+extern int Stub(void);
+int StubUse(void)
+{
+ return Stub();
+}