mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
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
This commit is contained in:
@@ -157,6 +157,7 @@ Signatures
|
||||
|
||||
install(TARGETS <target>... [EXPORT <export-name>]
|
||||
[RUNTIME_DEPENDENCIES <arg>...|RUNTIME_DEPENDENCY_SET <set-name>]
|
||||
[RUNTIME_DEPENDENCY_TARGETS]
|
||||
[<artifact-option>...]
|
||||
[<artifact-kind> <artifact-option>...]...
|
||||
[INCLUDES DESTINATION [<dir> ...]]
|
||||
@@ -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 ``<target>...`` 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
|
||||
|
||||
@@ -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.
|
||||
+210
-17
@@ -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<std::string> const& rootNames,
|
||||
std::set<cmTarget*>& out, std::string const& config)
|
||||
{
|
||||
std::set<cmGeneratorTarget const*> visited;
|
||||
std::vector<cmGeneratorTarget const*> stack;
|
||||
std::set<std::string> 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<cmGeneratorTarget const*> 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<std::vector<std::string>> 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<std::vector<std::string>> configurations = {})
|
||||
cm::optional<std::vector<std::string>> 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<cmInstallCxxModuleBmiGenerator>(
|
||||
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<std::string, std::set<cmTarget*>> const& byConfig,
|
||||
std::vector<std::string> const& configs)
|
||||
{
|
||||
std::map<cmTarget*, std::size_t> hits;
|
||||
for (std::pair<std::string const, std::set<cmTarget*>> const& e : byConfig) {
|
||||
for (cmTarget* t : e.second) {
|
||||
++hits[t];
|
||||
}
|
||||
}
|
||||
std::set<cmTarget*> common;
|
||||
std::size_t const n = configs.size();
|
||||
for (std::pair<cmTarget* const, std::size_t> const& h : hits) {
|
||||
if (h.second == n) {
|
||||
common.insert(h.first);
|
||||
}
|
||||
}
|
||||
|
||||
auto installDep =
|
||||
[&](cmTarget& dep,
|
||||
cm::optional<std::vector<std::string>> 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<cmTarget*, std::vector<std::string>> 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<cmTarget* const, std::vector<std::string>> 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<std::string> const& args,
|
||||
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
|
||||
runtimeDependenciesArgVector;
|
||||
std::string runtimeDependencySetArg;
|
||||
bool installTransitiveDependencies = false;
|
||||
std::vector<std::string> unknownArgs;
|
||||
cmInstallCommandArguments genericArgs(helper.DefaultComponentName,
|
||||
*helper.Makefile);
|
||||
@@ -1052,6 +1201,8 @@ bool HandleTargetsMode(std::vector<std::string> 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<std::string> 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<std::string> const& args,
|
||||
ctx->RuntimeDependencySet = runtimeDependencySet;
|
||||
ctx->BindGenericArguments();
|
||||
|
||||
if (installTransitiveDependencies) {
|
||||
std::vector<std::string> 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<std::string> configs =
|
||||
lg.GetMakefile()->GetGeneratorConfigs(
|
||||
cmMakefile::IncludeEmptyConfig);
|
||||
|
||||
std::map<std::string, std::set<cmTarget*>> 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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -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\)$
|
||||
@@ -0,0 +1,6 @@
|
||||
enable_language(C)
|
||||
|
||||
add_executable(exe main.c)
|
||||
install(TARGETS exe RUNTIME_DEPENDENCY_TARGETS
|
||||
EXPORT e
|
||||
RUNTIME DESTINATION bin)
|
||||
@@ -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}$")
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user