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>]
|
install(TARGETS <target>... [EXPORT <export-name>]
|
||||||
[RUNTIME_DEPENDENCIES <arg>...|RUNTIME_DEPENDENCY_SET <set-name>]
|
[RUNTIME_DEPENDENCIES <arg>...|RUNTIME_DEPENDENCY_SET <set-name>]
|
||||||
|
[RUNTIME_DEPENDENCY_TARGETS]
|
||||||
[<artifact-option>...]
|
[<artifact-option>...]
|
||||||
[<artifact-kind> <artifact-option>...]...
|
[<artifact-kind> <artifact-option>...]...
|
||||||
[INCLUDES DESTINATION [<dir> ...]]
|
[INCLUDES DESTINATION [<dir> ...]]
|
||||||
@@ -477,6 +478,36 @@ Signatures
|
|||||||
The ``RUNTIME_DEPENDENCIES`` and ``RUNTIME_DEPENDENCY_SET`` keywords are
|
The ``RUNTIME_DEPENDENCIES`` and ``RUNTIME_DEPENDENCY_SET`` keywords are
|
||||||
mutually exclusive.
|
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.
|
:ref:`Interface Libraries` may be listed among the targets to install.
|
||||||
They install no artifacts but will be included in an associated ``EXPORT``.
|
They install no artifacts but will be included in an associated ``EXPORT``.
|
||||||
If :ref:`Object Libraries` are listed but given no destination for their
|
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
|
Targets built within the build tree will never be installed as runtime
|
||||||
dependencies, nor will their own dependencies, unless the targets themselves
|
dependencies, nor will their own dependencies, unless the targets themselves
|
||||||
are installed with :command:`install(TARGETS)`.
|
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)`
|
The generated install script calls :command:`file(GET_RUNTIME_DEPENDENCIES)`
|
||||||
on the build-tree files to calculate the runtime dependencies. The build-tree
|
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 "cmArgumentParser.h"
|
||||||
#include "cmArgumentParserTypes.h"
|
#include "cmArgumentParserTypes.h"
|
||||||
#include "cmCMakePath.h"
|
#include "cmCMakePath.h"
|
||||||
|
#include "cmComputeLinkInformation.h"
|
||||||
#include "cmDiagnosticContext.h"
|
#include "cmDiagnosticContext.h"
|
||||||
#include "cmDiagnostics.h"
|
#include "cmDiagnostics.h"
|
||||||
#include "cmExecutionStatus.h"
|
#include "cmExecutionStatus.h"
|
||||||
#include "cmExperimental.h"
|
#include "cmExperimental.h"
|
||||||
#include "cmExportSet.h"
|
#include "cmExportSet.h"
|
||||||
#include "cmGeneratorExpression.h"
|
#include "cmGeneratorExpression.h"
|
||||||
|
#include "cmGeneratorTarget.h"
|
||||||
#include "cmGlobalGenerator.h"
|
#include "cmGlobalGenerator.h"
|
||||||
#include "cmInstallAndroidMKExportGenerator.h"
|
#include "cmInstallAndroidMKExportGenerator.h"
|
||||||
#include "cmInstallCMakeConfigExportGenerator.h"
|
#include "cmInstallCMakeConfigExportGenerator.h"
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
#include "cmInstallScriptGenerator.h"
|
#include "cmInstallScriptGenerator.h"
|
||||||
#include "cmInstallTargetGenerator.h"
|
#include "cmInstallTargetGenerator.h"
|
||||||
#include "cmList.h"
|
#include "cmList.h"
|
||||||
|
#include "cmLocalGenerator.h"
|
||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmMessageType.h"
|
#include "cmMessageType.h"
|
||||||
#include "cmPackageInfoArguments.h"
|
#include "cmPackageInfoArguments.h"
|
||||||
@@ -60,8 +63,16 @@
|
|||||||
#include "cmUnreachable.h"
|
#include "cmUnreachable.h"
|
||||||
#include "cmValue.h"
|
#include "cmValue.h"
|
||||||
|
|
||||||
|
class cmListFileBacktrace;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
enum class RuntimeOnly
|
||||||
|
{
|
||||||
|
No,
|
||||||
|
Yes,
|
||||||
|
};
|
||||||
|
|
||||||
struct InstallCategoryFlags
|
struct InstallCategoryFlags
|
||||||
{
|
{
|
||||||
bool Archive = false;
|
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
|
struct RuntimeDependenciesArgs
|
||||||
{
|
{
|
||||||
ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories;
|
ArgumentParser::MaybeEmpty<std::vector<std::string>> Directories;
|
||||||
@@ -417,7 +479,8 @@ void RegisterInstallComponents(cmMakefile* makefile, InstallContext const& ctx,
|
|||||||
bool CreateInstallGeneratorsForTarget(
|
bool CreateInstallGeneratorsForTarget(
|
||||||
Helper& helper, cmTarget& target, InstallContext const& ctx,
|
Helper& helper, cmTarget& target, InstallContext const& ctx,
|
||||||
InstallCategoryFlags& flags, std::string& error,
|
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& archiveArgs = *ctx.ArchiveArgs;
|
||||||
cmInstallCommandArguments const& libraryArgs = *ctx.LibraryArgs;
|
cmInstallCommandArguments const& libraryArgs = *ctx.LibraryArgs;
|
||||||
@@ -514,27 +577,32 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
// cygwin. Currently no other platform is a DLL platform.
|
// cygwin. Currently no other platform is a DLL platform.
|
||||||
if (target.IsDLLPlatform()) {
|
if (target.IsDLLPlatform()) {
|
||||||
// When in namelink only mode skip all libraries on Windows.
|
// When in namelink only mode skip all libraries on Windows.
|
||||||
if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
|
if (runtimeOnly == RuntimeOnly::No &&
|
||||||
|
namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
|
||||||
namelinkOnly = true;
|
namelinkOnly = true;
|
||||||
return addTargetExport();
|
return addTargetExport();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a DLL platform.
|
// This is a DLL platform.
|
||||||
if (!archiveArgs.GetDestination().empty()) {
|
if (runtimeOnly == RuntimeOnly::No &&
|
||||||
|
!archiveArgs.GetDestination().empty()) {
|
||||||
// The import library uses the ARCHIVE properties.
|
// The import library uses the ARCHIVE properties.
|
||||||
archiveGenerator = CreateInstallTargetGenerator(
|
archiveGenerator = CreateInstallTargetGenerator(
|
||||||
target, archiveArgs, true, helper.CaptureContext(), false, false,
|
target, archiveArgs, true, helper.CaptureContext(), false, false,
|
||||||
configurations);
|
configurations);
|
||||||
artifactsSpecified = true;
|
artifactsSpecified = true;
|
||||||
}
|
}
|
||||||
if (!runtimeArgs.GetDestination().empty()) {
|
if (runtimeOnly == RuntimeOnly::Yes ||
|
||||||
|
!runtimeArgs.GetDestination().empty()) {
|
||||||
// The DLL uses the RUNTIME properties.
|
// The DLL uses the RUNTIME properties.
|
||||||
runtimeGenerator = CreateInstallTargetGenerator(
|
runtimeGenerator = CreateInstallTargetGenerator(
|
||||||
target, runtimeArgs, false, helper.CaptureContext(), false, false,
|
target, runtimeArgs, false, helper.CaptureContext(),
|
||||||
|
helper.GetRuntimeDestination(&runtimeArgs), false, false,
|
||||||
configurations);
|
configurations);
|
||||||
artifactsSpecified = true;
|
artifactsSpecified = true;
|
||||||
}
|
}
|
||||||
if (!archiveGenerator && !runtimeGenerator) {
|
if (runtimeOnly == RuntimeOnly::No && !archiveGenerator &&
|
||||||
|
!runtimeGenerator) {
|
||||||
archiveGenerator = CreateInstallTargetGenerator(
|
archiveGenerator = CreateInstallTargetGenerator(
|
||||||
target, archiveArgs, true, helper.CaptureContext(),
|
target, archiveArgs, true, helper.CaptureContext(),
|
||||||
helper.GetArchiveDestination(nullptr), false, false,
|
helper.GetArchiveDestination(nullptr), false, false,
|
||||||
@@ -553,7 +621,8 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
// INSTALL properties. Otherwise, use the LIBRARY properties.
|
// INSTALL properties. Otherwise, use the LIBRARY properties.
|
||||||
if (target.IsFrameworkOnApple()) {
|
if (target.IsFrameworkOnApple()) {
|
||||||
// When in namelink only mode skip frameworks.
|
// When in namelink only mode skip frameworks.
|
||||||
if (namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
|
if (runtimeOnly == RuntimeOnly::No &&
|
||||||
|
namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) {
|
||||||
namelinkOnly = true;
|
namelinkOnly = true;
|
||||||
return addTargetExport();
|
return addTargetExport();
|
||||||
}
|
}
|
||||||
@@ -574,7 +643,8 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
if (!libraryArgs.GetDestination().empty()) {
|
if (!libraryArgs.GetDestination().empty()) {
|
||||||
artifactsSpecified = true;
|
artifactsSpecified = true;
|
||||||
}
|
}
|
||||||
if (namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) {
|
if (runtimeOnly == RuntimeOnly::Yes ||
|
||||||
|
namelinkMode != cmInstallTargetGenerator::NamelinkModeOnly) {
|
||||||
libraryGenerator = CreateInstallTargetGenerator(
|
libraryGenerator = CreateInstallTargetGenerator(
|
||||||
target, libraryArgs, false, helper.CaptureContext(),
|
target, libraryArgs, false, helper.CaptureContext(),
|
||||||
helper.GetLibraryDestination(&libraryArgs), false, false,
|
helper.GetLibraryDestination(&libraryArgs), false, false,
|
||||||
@@ -582,7 +652,8 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
libraryGenerator->SetNamelinkMode(
|
libraryGenerator->SetNamelinkMode(
|
||||||
cmInstallTargetGenerator::NamelinkModeSkip);
|
cmInstallTargetGenerator::NamelinkModeSkip);
|
||||||
}
|
}
|
||||||
if (namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) {
|
if (runtimeOnly == RuntimeOnly::No &&
|
||||||
|
namelinkMode != cmInstallTargetGenerator::NamelinkModeSkip) {
|
||||||
namelinkGenerator = CreateInstallTargetGenerator(
|
namelinkGenerator = CreateInstallTargetGenerator(
|
||||||
target, libraryArgs, false, helper.CaptureContext(),
|
target, libraryArgs, false, helper.CaptureContext(),
|
||||||
helper.GetLibraryDestination(&libraryArgs), false, true,
|
helper.GetLibraryDestination(&libraryArgs), false, true,
|
||||||
@@ -590,10 +661,11 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
namelinkGenerator->SetNamelinkMode(
|
namelinkGenerator->SetNamelinkMode(
|
||||||
cmInstallTargetGenerator::NamelinkModeOnly);
|
cmInstallTargetGenerator::NamelinkModeOnly);
|
||||||
}
|
}
|
||||||
namelinkOnly =
|
namelinkOnly = runtimeOnly == RuntimeOnly::No &&
|
||||||
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
|
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
|
||||||
|
|
||||||
if (target.GetMakefile()->PlatformSupportsAppleTextStubs() &&
|
if (runtimeOnly == RuntimeOnly::No &&
|
||||||
|
target.GetMakefile()->PlatformSupportsAppleTextStubs() &&
|
||||||
target.IsSharedLibraryWithExports()) {
|
target.IsSharedLibraryWithExports()) {
|
||||||
// Apple .tbd files use the ARCHIVE properties
|
// Apple .tbd files use the ARCHIVE properties
|
||||||
if (!archiveArgs.GetDestination().empty()) {
|
if (!archiveArgs.GetDestination().empty()) {
|
||||||
@@ -625,6 +697,9 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case cm::TargetType::STATIC_LIBRARY: {
|
case cm::TargetType::STATIC_LIBRARY: {
|
||||||
|
if (runtimeOnly == RuntimeOnly::Yes) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
// If it is marked with FRAMEWORK property use the FRAMEWORK set of
|
// If it is marked with FRAMEWORK property use the FRAMEWORK set of
|
||||||
// INSTALL properties. Otherwise, use the LIBRARY properties.
|
// INSTALL properties. Otherwise, use the LIBRARY properties.
|
||||||
if (target.IsFrameworkOnApple()) {
|
if (target.IsFrameworkOnApple()) {
|
||||||
@@ -671,14 +746,20 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
target, libraryArgs, false, helper.CaptureContext(), moduleDest, false,
|
target, libraryArgs, false, helper.CaptureContext(), moduleDest, false,
|
||||||
false, configurations);
|
false, configurations);
|
||||||
|
|
||||||
libraryGenerator->SetNamelinkMode(namelinkMode);
|
libraryGenerator->SetNamelinkMode(
|
||||||
namelinkOnly =
|
runtimeOnly == RuntimeOnly::Yes
|
||||||
|
? cmInstallTargetGenerator::NamelinkModeNone
|
||||||
|
: namelinkMode);
|
||||||
|
namelinkOnly = runtimeOnly == RuntimeOnly::No &&
|
||||||
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
|
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
|
||||||
if (runtimeDependencySet) {
|
if (runtimeDependencySet) {
|
||||||
runtimeDependencySet->AddModule(libraryGenerator.get());
|
runtimeDependencySet->AddModule(libraryGenerator.get());
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case cm::TargetType::OBJECT_LIBRARY: {
|
case cm::TargetType::OBJECT_LIBRARY: {
|
||||||
|
if (runtimeOnly == RuntimeOnly::Yes) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Objects use OBJECT properties.
|
// Objects use OBJECT properties.
|
||||||
if (!objectArgs.GetDestination().empty()) {
|
if (!objectArgs.GetDestination().empty()) {
|
||||||
// Verify that we know where the objects are to install them.
|
// Verify that we know where the objects are to install them.
|
||||||
@@ -699,6 +780,9 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case cm::TargetType::EXECUTABLE: {
|
case cm::TargetType::EXECUTABLE: {
|
||||||
|
if (runtimeOnly == RuntimeOnly::Yes) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (target.IsAppBundleOnApple()) {
|
if (target.IsAppBundleOnApple()) {
|
||||||
// Application bundles use the BUNDLE properties.
|
// Application bundles use the BUNDLE properties.
|
||||||
if (!bundleArgs.GetDestination().empty()) {
|
if (!bundleArgs.GetDestination().empty()) {
|
||||||
@@ -760,7 +844,8 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
// FRAMEWORK. For other target types or on other platforms, they are not
|
// FRAMEWORK. For other target types or on other platforms, they are not
|
||||||
// installed automatically and so we need to create install files
|
// installed automatically and so we need to create install files
|
||||||
// generators for them.
|
// generators for them.
|
||||||
bool createInstallGeneratorsForTargetFileSets = true;
|
bool createInstallGeneratorsForTargetFileSets =
|
||||||
|
runtimeOnly == RuntimeOnly::No;
|
||||||
|
|
||||||
if (target.IsFrameworkOnApple()) {
|
if (target.IsFrameworkOnApple()) {
|
||||||
createInstallGeneratorsForTargetFileSets = false;
|
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++) {
|
for (std::size_t i = 0; i < fileSetArgs.size(); i++) {
|
||||||
fileSetGenerators.push_back(CreateInstallFileSetGenerator(
|
fileSetGenerators.push_back(CreateInstallFileSetGenerator(
|
||||||
helper, target, fileSetArgs[i], configurations));
|
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>(
|
cxxModuleBmiGenerator = cm::make_unique<cmInstallCxxModuleBmiGenerator>(
|
||||||
target.GetName(), helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs),
|
target.GetName(), helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs),
|
||||||
cxxModuleBmiArgs.GetPermissions(),
|
cxxModuleBmiArgs.GetPermissions(),
|
||||||
@@ -857,7 +943,12 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add this install rule to an export if one was specified.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -893,6 +984,63 @@ bool CreateInstallGeneratorsForTarget(
|
|||||||
return true;
|
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)
|
void CheckAbsoluteDestination(Helper& helper, std::string const& destination)
|
||||||
{
|
{
|
||||||
// Check for an absolute 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>>>
|
cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>>
|
||||||
runtimeDependenciesArgVector;
|
runtimeDependenciesArgVector;
|
||||||
std::string runtimeDependencySetArg;
|
std::string runtimeDependencySetArg;
|
||||||
|
bool installTransitiveDependencies = false;
|
||||||
std::vector<std::string> unknownArgs;
|
std::vector<std::string> unknownArgs;
|
||||||
cmInstallCommandArguments genericArgs(helper.DefaultComponentName,
|
cmInstallCommandArguments genericArgs(helper.DefaultComponentName,
|
||||||
*helper.Makefile);
|
*helper.Makefile);
|
||||||
@@ -1052,6 +1201,8 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
|
|||||||
genericArgs.Bind("EXPORT"_s, exports);
|
genericArgs.Bind("EXPORT"_s, exports);
|
||||||
genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector);
|
genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector);
|
||||||
genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
|
genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
|
||||||
|
genericArgs.Bind("RUNTIME_DEPENDENCY_TARGETS"_s,
|
||||||
|
installTransitiveDependencies);
|
||||||
genericArgs.Parse(genericArgVector, &unknownArgs);
|
genericArgs.Parse(genericArgVector, &unknownArgs);
|
||||||
bool success = genericArgs.Finalize();
|
bool success = genericArgs.Finalize();
|
||||||
|
|
||||||
@@ -1224,6 +1375,14 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (installTransitiveDependencies) {
|
||||||
|
if (!exports.empty()) {
|
||||||
|
status.SetError("TARGETS RUNTIME_DEPENDENCY_TARGETS cannot be used "
|
||||||
|
"with EXPORT.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
|
cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
|
||||||
if (runtimeDependenciesArgVector) {
|
if (runtimeDependenciesArgVector) {
|
||||||
if (!runtimeDependencySetArg.empty()) {
|
if (!runtimeDependencySetArg.empty()) {
|
||||||
@@ -1348,6 +1507,40 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
|
|||||||
ctx->RuntimeDependencySet = runtimeDependencySet;
|
ctx->RuntimeDependencySet = runtimeDependencySet;
|
||||||
ctx->BindGenericArguments();
|
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;
|
InstallCategoryFlags flags;
|
||||||
flags.FileSet.resize(ctx->FileSetArgs.size(), false);
|
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-Defaults)
|
||||||
run_install_test(TARGETS-Module-Destination)
|
run_install_test(TARGETS-Module-Destination)
|
||||||
run_install_test(TARGETS-SymbolicComponent)
|
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")
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
run_install_test(TARGETS-NAMELINK-No-Tweak)
|
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