From 53019cd2e640e0d4e871e5a941b9fe652b0681ba Mon Sep 17 00:00:00 2001 From: Stepanov Igor Date: Thu, 10 Sep 2026 08:24:46 +0300 Subject: [PATCH] install(TARGETS): Add option to install runtime deps built as other targets Add a `RUNTIME_DEPENDENCY_TARGETS` option for `install(TARGETS)` to automatically install the necessary runtime shared libraries. Closes: #23505 --- Help/command/install.rst | 34 +++ ...all-TARGETS-RUNTIME_DEPENDENCY_TARGETS.rst | 10 + Source/cmInstallCommand.cxx | 227 ++++++++++++++++-- Tests/RunCMake/install/RunCMakeTest.cmake | 2 + ...NTIME_DEPENDENCY_TARGETS-EXPORT-result.txt | 1 + ...NTIME_DEPENDENCY_TARGETS-EXPORT-stderr.txt | 4 + ...TS-RUNTIME_DEPENDENCY_TARGETS-EXPORT.cmake | 6 + ...RUNTIME_DEPENDENCY_TARGETS-all-check.cmake | 73 ++++++ .../TARGETS-RUNTIME_DEPENDENCY_TARGETS.cmake | 29 +++ 9 files changed, 369 insertions(+), 17 deletions(-) create mode 100644 Help/release/dev/install-TARGETS-RUNTIME_DEPENDENCY_TARGETS.rst create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT-result.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT-stderr.txt create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-all-check.cmake create mode 100644 Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS.cmake diff --git a/Help/command/install.rst b/Help/command/install.rst index cc2b9ecc20..7fa341bc6e 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -157,6 +157,7 @@ Signatures install(TARGETS ... [EXPORT ] [RUNTIME_DEPENDENCIES ...|RUNTIME_DEPENDENCY_SET ] + [RUNTIME_DEPENDENCY_TARGETS] [...] [ ...]... [INCLUDES DESTINATION [ ...]] @@ -477,6 +478,36 @@ Signatures The ``RUNTIME_DEPENDENCIES`` and ``RUNTIME_DEPENDENCY_SET`` keywords are mutually exclusive. + ``RUNTIME_DEPENDENCY_TARGETS`` + .. versionadded:: 4.5 + + This option installs runtime artifacts of non-imported ``SHARED`` + library targets from the same build that appear on the computed + link lines of the listed ``...`` and, recursively, of those + shared libraries. The ``RUNTIME``, ``LIBRARY``, and ``FRAMEWORK`` + destinations and other artifact options from this call apply to + those artifacts (``RUNTIME`` on DLL platforms, ``LIBRARY`` + otherwise, and ``FRAMEWORK`` for macOS frameworks). + + Unlike ``RUNTIME_DEPENDENCIES``, this option does not call + :command:`file(GET_RUNTIME_DEPENDENCIES)` and does not install files + that are not CMake targets of the current build. + + This option may not be used with ``EXPORT``. The call may specify + only runtime artifact groups (``RUNTIME``, ``LIBRARY``, + ``FRAMEWORK``, and ``BUNDLE``). + + .. note:: + + Static, interface, and object libraries on a listed target's + link line are traversed only to discover shared libraries; they + are not themselves installed by this option. Executables and + module libraries are not installed transitively. Imported + targets are skipped. Each :command:`install(TARGETS)` call with + this option installs the collected shared libraries into the + destinations of that call, even if another call already installs + the same target. + :ref:`Interface Libraries` may be listed among the targets to install. They install no artifacts but will be included in an associated ``EXPORT``. If :ref:`Object Libraries` are listed but given no destination for their @@ -1180,6 +1211,9 @@ Signatures Targets built within the build tree will never be installed as runtime dependencies, nor will their own dependencies, unless the targets themselves are installed with :command:`install(TARGETS)`. + Use the ``RUNTIME_DEPENDENCY_TARGETS`` option of + :command:`install(TARGETS)` to install runtime artifacts of + non-imported shared libraries from the same build. The generated install script calls :command:`file(GET_RUNTIME_DEPENDENCIES)` on the build-tree files to calculate the runtime dependencies. The build-tree diff --git a/Help/release/dev/install-TARGETS-RUNTIME_DEPENDENCY_TARGETS.rst b/Help/release/dev/install-TARGETS-RUNTIME_DEPENDENCY_TARGETS.rst new file mode 100644 index 0000000000..3a1b788b0e --- /dev/null +++ b/Help/release/dev/install-TARGETS-RUNTIME_DEPENDENCY_TARGETS.rst @@ -0,0 +1,10 @@ +install-TARGETS-RUNTIME_DEPENDENCY_TARGETS +------------------------------------------ + +* The :command:`install(TARGETS)` command gained a + ``RUNTIME_DEPENDENCY_TARGETS`` option to install runtime artifacts + of non-imported shared libraries from the same build that the named + targets link to. Unlike ``RUNTIME_DEPENDENCIES``, this uses CMake + target graph information rather than + :command:`file(GET_RUNTIME_DEPENDENCIES)`. The option cannot be + used with ``EXPORT`` and may only install runtime artifacts. diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 89167ab544..52b742f2bf 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -19,12 +19,14 @@ #include "cmArgumentParser.h" #include "cmArgumentParserTypes.h" #include "cmCMakePath.h" +#include "cmComputeLinkInformation.h" #include "cmDiagnosticContext.h" #include "cmDiagnostics.h" #include "cmExecutionStatus.h" #include "cmExperimental.h" #include "cmExportSet.h" #include "cmGeneratorExpression.h" +#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmInstallAndroidMKExportGenerator.h" #include "cmInstallCMakeConfigExportGenerator.h" @@ -44,6 +46,7 @@ #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmList.h" +#include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmPackageInfoArguments.h" @@ -60,8 +63,16 @@ #include "cmUnreachable.h" #include "cmValue.h" +class cmListFileBacktrace; + namespace { +enum class RuntimeOnly +{ + No, + Yes, +}; + struct InstallCategoryFlags { bool Archive = false; @@ -121,6 +132,57 @@ struct InstallContext } }; +void CollectEvaluatedTransitiveSharedModuleTargets( + cmLocalGenerator& lg, std::vector const& rootNames, + std::set& out, std::string const& config) +{ + std::set visited; + std::vector stack; + std::set const rootNameSet(rootNames.begin(), rootNames.end()); + + auto consider = [&](cmGeneratorTarget const* dep) { + if (!dep || dep->IsImported()) { + return; + } + if (!visited.insert(dep).second) { + return; + } + cm::TargetType type = dep->GetType(); + if (type == cm::TargetType::SHARED_LIBRARY) { + if (rootNameSet.find(dep->GetName()) == rootNameSet.end()) { + out.insert(dep->Target); + } + stack.push_back(dep); + } + }; + auto enqueue = [&](cmGeneratorTarget const* current) { + cmComputeLinkInformation* linkInfo = current->GetLinkInformation(config); + std::set const& sharedTargets = + linkInfo->GetSharedLibrariesLinked(); + + for (cmGeneratorTarget const* dep : sharedTargets) { + consider(dep); + } + }; + + for (std::string const& name : rootNames) { + cmGeneratorTarget* root = lg.FindGeneratorTargetToUse(name); + if (!root) { + root = lg.GetGlobalGenerator()->FindGeneratorTarget(name); + } + if (!root) { + continue; + } + visited.insert(root); + enqueue(root); + } + while (!stack.empty()) { + cmGeneratorTarget const* current = stack.back(); + stack.pop_back(); + enqueue(current); + } +} + struct RuntimeDependenciesArgs { ArgumentParser::MaybeEmpty> Directories; @@ -417,7 +479,8 @@ void RegisterInstallComponents(cmMakefile* makefile, InstallContext const& ctx, bool CreateInstallGeneratorsForTarget( Helper& helper, cmTarget& target, InstallContext const& ctx, InstallCategoryFlags& flags, std::string& error, - cm::optional> configurations = {}) + cm::optional> configurations = {}, + RuntimeOnly runtimeOnly = RuntimeOnly::No) { cmInstallCommandArguments const& archiveArgs = *ctx.ArchiveArgs; cmInstallCommandArguments const& libraryArgs = *ctx.LibraryArgs; @@ -514,27 +577,32 @@ bool CreateInstallGeneratorsForTarget( // cygwin. Currently no other platform is a DLL platform. if (target.IsDLLPlatform()) { // When in namelink only mode skip all libraries on Windows. - if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { + if (runtimeOnly == RuntimeOnly::No && + namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; return addTargetExport(); } // This is a DLL platform. - if (!archiveArgs.GetDestination().empty()) { + if (runtimeOnly == RuntimeOnly::No && + !archiveArgs.GetDestination().empty()) { // The import library uses the ARCHIVE properties. archiveGenerator = CreateInstallTargetGenerator( target, archiveArgs, true, helper.CaptureContext(), false, false, configurations); artifactsSpecified = true; } - if (!runtimeArgs.GetDestination().empty()) { + if (runtimeOnly == RuntimeOnly::Yes || + !runtimeArgs.GetDestination().empty()) { // The DLL uses the RUNTIME properties. runtimeGenerator = CreateInstallTargetGenerator( - target, runtimeArgs, false, helper.CaptureContext(), false, false, + target, runtimeArgs, false, helper.CaptureContext(), + helper.GetRuntimeDestination(&runtimeArgs), false, false, configurations); artifactsSpecified = true; } - if (!archiveGenerator && !runtimeGenerator) { + if (runtimeOnly == RuntimeOnly::No && !archiveGenerator && + !runtimeGenerator) { archiveGenerator = CreateInstallTargetGenerator( target, archiveArgs, true, helper.CaptureContext(), helper.GetArchiveDestination(nullptr), false, false, @@ -553,7 +621,8 @@ bool CreateInstallGeneratorsForTarget( // INSTALL properties. Otherwise, use the LIBRARY properties. if (target.IsFrameworkOnApple()) { // When in namelink only mode skip frameworks. - if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { + if (runtimeOnly == RuntimeOnly::No && + namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) { namelinkOnly = true; return addTargetExport(); } @@ -574,7 +643,8 @@ bool CreateInstallGeneratorsForTarget( if (!libraryArgs.GetDestination().empty()) { artifactsSpecified = true; } - if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) { + if (runtimeOnly == RuntimeOnly::Yes || + namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) { libraryGenerator = CreateInstallTargetGenerator( target, libraryArgs, false, helper.CaptureContext(), helper.GetLibraryDestination(&libraryArgs), false, false, @@ -582,7 +652,8 @@ bool CreateInstallGeneratorsForTarget( libraryGenerator->SetNamelinkMode( cmInstallTargetGenerator::NamelinkModeSkip); } - if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) { + if (runtimeOnly == RuntimeOnly::No && + namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) { namelinkGenerator = CreateInstallTargetGenerator( target, libraryArgs, false, helper.CaptureContext(), helper.GetLibraryDestination(&libraryArgs), false, true, @@ -590,10 +661,11 @@ bool CreateInstallGeneratorsForTarget( namelinkGenerator->SetNamelinkMode( cmInstallTargetGenerator::NamelinkModeOnly); } - namelinkOnly = + namelinkOnly = runtimeOnly == RuntimeOnly::No && (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); - if (target.GetMakefile()->PlatformSupportsAppleTextStubs() && + if (runtimeOnly == RuntimeOnly::No && + target.GetMakefile()->PlatformSupportsAppleTextStubs() && target.IsSharedLibraryWithExports()) { // Apple .tbd files use the ARCHIVE properties if (!archiveArgs.GetDestination().empty()) { @@ -625,6 +697,9 @@ bool CreateInstallGeneratorsForTarget( } } break; case cm::TargetType::STATIC_LIBRARY: { + if (runtimeOnly == RuntimeOnly::Yes) { + break; + } // If it is marked with FRAMEWORK property use the FRAMEWORK set of // INSTALL properties. Otherwise, use the LIBRARY properties. if (target.IsFrameworkOnApple()) { @@ -671,14 +746,20 @@ bool CreateInstallGeneratorsForTarget( target, libraryArgs, false, helper.CaptureContext(), moduleDest, false, false, configurations); - libraryGenerator->SetNamelinkMode(namelinkMode); - namelinkOnly = + libraryGenerator->SetNamelinkMode( + runtimeOnly == RuntimeOnly::Yes + ? cmInstallTargetGenerator::NamelinkModeNone + : namelinkMode); + namelinkOnly = runtimeOnly == RuntimeOnly::No && (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly); if (runtimeDependencySet) { runtimeDependencySet->AddModule(libraryGenerator.get()); } } break; case cm::TargetType::OBJECT_LIBRARY: { + if (runtimeOnly == RuntimeOnly::Yes) { + break; + } // Objects use OBJECT properties. if (!objectArgs.GetDestination().empty()) { // Verify that we know where the objects are to install them. @@ -699,6 +780,9 @@ bool CreateInstallGeneratorsForTarget( } } break; case cm::TargetType::EXECUTABLE: { + if (runtimeOnly == RuntimeOnly::Yes) { + break; + } if (target.IsAppBundleOnApple()) { // Application bundles use the BUNDLE properties. if (!bundleArgs.GetDestination().empty()) { @@ -760,7 +844,8 @@ bool CreateInstallGeneratorsForTarget( // FRAMEWORK. For other target types or on other platforms, they are not // installed automatically and so we need to create install files // generators for them. - bool createInstallGeneratorsForTargetFileSets = true; + bool createInstallGeneratorsForTargetFileSets = + runtimeOnly == RuntimeOnly::No; if (target.IsFrameworkOnApple()) { createInstallGeneratorsForTargetFileSets = false; @@ -836,7 +921,7 @@ bool CreateInstallGeneratorsForTarget( } } - if (!namelinkOnly) { + if (runtimeOnly == RuntimeOnly::No && !namelinkOnly) { for (std::size_t i = 0; i < fileSetArgs.size(); i++) { fileSetGenerators.push_back(CreateInstallFileSetGenerator( helper, target, fileSetArgs[i], configurations)); @@ -844,7 +929,8 @@ bool CreateInstallGeneratorsForTarget( } } - if (!cxxModuleBmiArgs.GetDestination().empty()) { + if (runtimeOnly == RuntimeOnly::No && + !cxxModuleBmiArgs.GetDestination().empty()) { cxxModuleBmiGenerator = cm::make_unique( target.GetName(), helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs), cxxModuleBmiArgs.GetPermissions(), @@ -857,7 +943,12 @@ bool CreateInstallGeneratorsForTarget( } // Add this install rule to an export if one was specified. - if (!addTargetExport()) { + // Transitive runtime artifacts from RUNTIME_DEPENDENCY_TARGETS are + // included; skip if this call created no runtime install generators. + bool const hasRuntimeArtifact = libraryGenerator || runtimeGenerator || + frameworkGenerator || bundleGenerator; + if ((runtimeOnly == RuntimeOnly::No || hasRuntimeArtifact) && + !addTargetExport()) { return false; } @@ -893,6 +984,63 @@ bool CreateInstallGeneratorsForTarget( return true; } +bool InstallTargetsGroupedByConfig( + Helper& helper, InstallContext const& ctx, InstallCategoryFlags& flags, + cmLocalGenerator& lg, + std::map> const& byConfig, + std::vector const& configs) +{ + std::map hits; + for (std::pair> const& e : byConfig) { + for (cmTarget* t : e.second) { + ++hits[t]; + } + } + std::set common; + std::size_t const n = configs.size(); + for (std::pair const& h : hits) { + if (h.second == n) { + common.insert(h.first); + } + } + + auto installDep = + [&](cmTarget& dep, + cm::optional> configurations) -> bool { + std::string error; + if (!CreateInstallGeneratorsForTarget(helper, dep, ctx, flags, error, + configurations, RuntimeOnly::Yes)) { + lg.IssueMessage(MessageType::FATAL_ERROR, error); + return false; + } + return true; + }; + + for (cmTarget* dep : common) { + if (!installDep(*dep, cm::nullopt)) { + return false; + } + } + + std::map> configSpecific; + for (std::string const& config : configs) { + auto it = byConfig.find(config); + if (it == byConfig.end()) { + continue; + } + for (cmTarget* dep : it->second) { + if (common.find(dep) == common.end()) { + configSpecific[dep].push_back(config); + } + } + } + return std::all_of( + configSpecific.begin(), configSpecific.end(), + [&](std::pair> const& e) { + return installDep(*e.first, e.second); + }); +} + void CheckAbsoluteDestination(Helper& helper, std::string const& destination) { // Check for an absolute destination. @@ -1045,6 +1193,7 @@ bool HandleTargetsMode(std::vector const& args, cm::optional>> runtimeDependenciesArgVector; std::string runtimeDependencySetArg; + bool installTransitiveDependencies = false; std::vector unknownArgs; cmInstallCommandArguments genericArgs(helper.DefaultComponentName, *helper.Makefile); @@ -1052,6 +1201,8 @@ bool HandleTargetsMode(std::vector const& args, genericArgs.Bind("EXPORT"_s, exports); genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector); genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg); + genericArgs.Bind("RUNTIME_DEPENDENCY_TARGETS"_s, + installTransitiveDependencies); genericArgs.Parse(genericArgVector, &unknownArgs); bool success = genericArgs.Finalize(); @@ -1224,6 +1375,14 @@ bool HandleTargetsMode(std::vector const& args, return false; } + if (installTransitiveDependencies) { + if (!exports.empty()) { + status.SetError("TARGETS RUNTIME_DEPENDENCY_TARGETS cannot be used " + "with EXPORT."); + return false; + } + } + cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr; if (runtimeDependenciesArgVector) { if (!runtimeDependencySetArg.empty()) { @@ -1348,6 +1507,40 @@ bool HandleTargetsMode(std::vector const& args, ctx->RuntimeDependencySet = runtimeDependencySet; ctx->BindGenericArguments(); + if (installTransitiveDependencies) { + std::vector rootNames; + rootNames.reserve(targets.size()); + for (cmTarget const* t : targets) { + rootNames.push_back(t->GetName()); + } + + helper.Makefile->AddGeneratorAction( + [ctx, rootNames](cmLocalGenerator& lg, cmListFileBacktrace const&) { + std::vector configs = + lg.GetMakefile()->GetGeneratorConfigs( + cmMakefile::IncludeEmptyConfig); + + std::map> transitiveTargetsByConfig; + for (std::string const& config : configs) { + CollectEvaluatedTransitiveSharedModuleTargets( + lg, rootNames, transitiveTargetsByConfig[config], config); + } + + cmExecutionStatus genStatus(*lg.GetMakefile()); + Helper genHelper(genStatus); + InstallCategoryFlags flags; + + if (!InstallTargetsGroupedByConfig(genHelper, *ctx, flags, lg, + transitiveTargetsByConfig, + configs)) { + return; + } + + RegisterInstallComponents(lg.GetMakefile(), *ctx, flags); + }, + cmMakefile::GeneratorActionWhen::AfterGeneratorTargets); + } + InstallCategoryFlags flags; flags.FileSet.resize(ctx->FileSetArgs.size(), false); diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index 4be7d536b9..8cd1d4e9c5 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/Tests/RunCMake/install/RunCMakeTest.cmake @@ -191,6 +191,8 @@ elseif (CMake_TEST_install_VARIANT STREQUAL "Targets") run_install_test(TARGETS-Defaults) run_install_test(TARGETS-Module-Destination) run_install_test(TARGETS-SymbolicComponent) + run_install_test(TARGETS-RUNTIME_DEPENDENCY_TARGETS) + run_cmake(TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") run_install_test(TARGETS-NAMELINK-No-Tweak) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT-stderr.txt new file mode 100644 index 0000000000..88e87fb166 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT\.cmake:[0-9]+ \(install\): + install TARGETS RUNTIME_DEPENDENCY_TARGETS cannot be used with EXPORT\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT.cmake new file mode 100644 index 0000000000..93541eeaab --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-EXPORT.cmake @@ -0,0 +1,6 @@ +enable_language(C) + +add_executable(exe main.c) +install(TARGETS exe RUNTIME_DEPENDENCY_TARGETS + EXPORT e + RUNTIME DESTINATION bin) diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-all-check.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-all-check.cmake new file mode 100644 index 0000000000..0020521433 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS-all-check.cmake @@ -0,0 +1,73 @@ +if(WIN32) + set(_check_files + [[bin]] + [[bin/first]] + [[bin/first/exe_1\.exe]] + [[bin/first/(lib)?shared_1\.dll]] + [[bin/first/(lib)?shared_2\.dll]] + [[bin/first/(lib)?shared_3\.dll]] + [[bin/second]] + [[bin/second/exe_2\.exe]] + [[bin/second/(lib)?shared_1\.dll]] + [[bin/second/(lib)?shared_2\.dll]] + [[bin/second/(lib)?shared_3\.dll]]) +elseif(MSYS) + set(_check_files + [[bin]] + [[bin/first]] + [[bin/first/exe_1\.exe]] + [[bin/first/msys-shared_1\.dll]] + [[bin/first/msys-shared_2\.dll]] + [[bin/first/msys-shared_3\.dll]] + [[bin/second]] + [[bin/second/exe_2\.exe]] + [[bin/second/msys-shared_1\.dll]] + [[bin/second/msys-shared_2\.dll]] + [[bin/second/msys-shared_3\.dll]]) +elseif(CYGWIN) + set(_check_files + [[bin]] + [[bin/first]] + [[bin/first/cygshared_1\.dll]] + [[bin/first/cygshared_2\.dll]] + [[bin/first/cygshared_3\.dll]] + [[bin/first/exe_1\.exe]] + [[bin/second]] + [[bin/second/cygshared_1\.dll]] + [[bin/second/cygshared_2\.dll]] + [[bin/second/cygshared_3\.dll]] + [[bin/second/exe_2\.exe]]) +elseif(AIX) + set(_check_files + [[bin]] + [[bin/first]] + [[bin/first/exe_1]] + [[bin/second]] + [[bin/second/exe_2]] + [[lib]] + [[lib/first]] + [[lib/first/libshared_1\.a]] + [[lib/first/libshared_2\.a]] + [[lib/first/libshared_3\.a]] + [[lib/second]] + [[lib/second/libshared_1\.a]] + [[lib/second/libshared_2\.a]] + [[lib/second/libshared_3\.a]]) +else() + set(_check_files + [[bin]] + [[bin/first]] + [[bin/first/exe_1]] + [[bin/second]] + [[bin/second/exe_2]] + [[lib]] + [[lib/first]] + [[lib/first/libshared_1\.(dylib|so)]] + [[lib/first/libshared_2\.(dylib|so)]] + [[lib/first/libshared_3\.(dylib|so)]] + [[lib/second]] + [[lib/second/libshared_1\.(dylib|so)]] + [[lib/second/libshared_2\.(dylib|so)]] + [[lib/second/libshared_3\.(dylib|so)]]) +endif() +check_installed("^${_check_files}$") diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS.cmake new file mode 100644 index 0000000000..8f83e5b360 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCY_TARGETS.cmake @@ -0,0 +1,29 @@ +enable_language(C) + +add_executable(exe_1 main.c) + +add_library(static STATIC obj1.c) +add_library(shared_1 SHARED obj5.c) +add_library(shared_2 SHARED obj3.c) +add_library(shared_3 SHARED obj4.c) + +add_executable(exe_2 main.c) +add_library(iface INTERFACE) + +target_link_libraries(exe_1 PRIVATE static shared_1) +target_link_libraries(static PRIVATE shared_2) +target_link_libraries(shared_1 PRIVATE shared_3) + +target_link_libraries(exe_2 PRIVATE iface) +target_link_libraries(iface INTERFACE static shared_1) + +install( + TARGETS exe_1 RUNTIME_DEPENDENCY_TARGETS + COMPONENT exc + LIBRARY DESTINATION lib/first + RUNTIME DESTINATION bin/first) +install( + TARGETS exe_2 RUNTIME_DEPENDENCY_TARGETS + COMPONENT exc + LIBRARY DESTINATION lib/second + RUNTIME DESTINATION bin/second)