summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2021-04-14 14:43:30 (GMT)
committerKyle Edwards <kyle.edwards@kitware.com>2021-06-04 12:52:02 (GMT)
commited3633d88cc5faa6fd7eb68fdd774d6d1f9cfdc9 (patch)
treeb99345e45c9645c178601669ecd5d13c18b8ab1e
parentf2617cf8e6aca6ec0f8c7df6999c1f713c6d7474 (diff)
downloadCMake-ed3633d88cc5faa6fd7eb68fdd774d6d1f9cfdc9.zip
CMake-ed3633d88cc5faa6fd7eb68fdd774d6d1f9cfdc9.tar.gz
CMake-ed3633d88cc5faa6fd7eb68fdd774d6d1f9cfdc9.tar.bz2
install(TARGETS): Add RUNTIME_DEPENDENCIES option
-rw-r--r--Source/CMakeLists.txt4
-rw-r--r--Source/cmFileCommand.cxx5
-rw-r--r--Source/cmInstallCommand.cxx186
-rw-r--r--Source/cmInstallGenerator.cxx51
-rw-r--r--Source/cmInstallGenerator.h3
-rw-r--r--Source/cmInstallGetRuntimeDependenciesGenerator.cxx206
-rw-r--r--Source/cmInstallGetRuntimeDependenciesGenerator.h56
-rw-r--r--Source/cmInstallRuntimeDependencySetGenerator.cxx276
-rw-r--r--Source/cmInstallRuntimeDependencySetGenerator.h74
-rw-r--r--Source/cmRuntimeDependencyArchive.cxx8
-rw-r--r--Source/cmRuntimeDependencyArchive.h2
-rw-r--r--Tests/RunCMake/install/RunCMakeTest.cmake17
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake9
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt4
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake10
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake9
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt1
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt5
-rw-r--r--Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake4
-rwxr-xr-xbootstrap2
29 files changed, 928 insertions, 25 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 5bcf223..9a18184 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -345,6 +345,8 @@ set(SRCS
cmGraphVizWriter.h
cmInstallGenerator.h
cmInstallGenerator.cxx
+ cmInstallGetRuntimeDependenciesGenerator.h
+ cmInstallGetRuntimeDependenciesGenerator.cxx
cmInstallExportGenerator.cxx
cmInstalledFile.h
cmInstalledFile.cxx
@@ -354,6 +356,8 @@ set(SRCS
cmInstallImportedRuntimeArtifactsGenerator.cxx
cmInstallRuntimeDependencySet.h
cmInstallRuntimeDependencySet.cxx
+ cmInstallRuntimeDependencySetGenerator.h
+ cmInstallRuntimeDependencySetGenerator.cxx
cmInstallScriptGenerator.h
cmInstallScriptGenerator.cxx
cmInstallSubdirectoryGenerator.h
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 82546b9..0ad59c7 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -3044,11 +3044,10 @@ bool HandleCreateLinkCommand(std::vector<std::string> const& args,
bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
- static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
- "Darwin" };
std::string platform =
status.GetMakefile().GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
- if (!supportedPlatforms.count(platform)) {
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ platform)) {
status.SetError(
cmStrCat("GET_RUNTIME_DEPENDENCIES is not supported on system \"",
platform, "\""));
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index c9bb467..c36778d 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -2,8 +2,10 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmInstallCommand.h"
+#include <algorithm>
#include <cassert>
#include <cstddef>
+#include <iterator>
#include <set>
#include <sstream>
#include <utility>
@@ -23,7 +25,10 @@
#include "cmInstallExportGenerator.h"
#include "cmInstallFilesGenerator.h"
#include "cmInstallGenerator.h"
+#include "cmInstallGetRuntimeDependenciesGenerator.h"
#include "cmInstallImportedRuntimeArtifactsGenerator.h"
+#include "cmInstallRuntimeDependencySet.h"
+#include "cmInstallRuntimeDependencySetGenerator.h"
#include "cmInstallScriptGenerator.h"
#include "cmInstallTargetGenerator.h"
#include "cmListFileCache.h"
@@ -31,6 +36,7 @@
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmProperty.h"
+#include "cmRuntimeDependencyArchive.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSubcommandTable.h"
@@ -40,6 +46,29 @@
namespace {
+struct RuntimeDependenciesArgs
+{
+ std::vector<std::string> Directories;
+ std::vector<std::string> PreIncludeRegexes;
+ std::vector<std::string> PreExcludeRegexes;
+ std::vector<std::string> PostIncludeRegexes;
+ std::vector<std::string> PostExcludeRegexes;
+ std::vector<std::string> PostIncludeFiles;
+ std::vector<std::string> PostExcludeFiles;
+};
+
+auto const RuntimeDependenciesArgHelper =
+ cmArgumentParser<RuntimeDependenciesArgs>{}
+ .Bind("DIRECTORIES"_s, &RuntimeDependenciesArgs::Directories)
+ .Bind("PRE_INCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreIncludeRegexes)
+ .Bind("PRE_EXCLUDE_REGEXES"_s, &RuntimeDependenciesArgs::PreExcludeRegexes)
+ .Bind("POST_INCLUDE_REGEXES"_s,
+ &RuntimeDependenciesArgs::PostIncludeRegexes)
+ .Bind("POST_EXCLUDE_REGEXES"_s,
+ &RuntimeDependenciesArgs::PostExcludeRegexes)
+ .Bind("POST_INCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostIncludeFiles)
+ .Bind("POST_EXCLUDE_FILES"_s, &RuntimeDependenciesArgs::PostExcludeFiles);
+
class Helper
{
public:
@@ -147,12 +176,106 @@ std::unique_ptr<cmInstallFilesGenerator> CreateInstallFilesGenerator(
args.GetDestination());
}
+void AddInstallRuntimeDependenciesGenerator(
+ Helper& helper, cmInstallRuntimeDependencySet* runtimeDependencySet,
+ const cmInstallCommandArguments& runtimeArgs,
+ const cmInstallCommandArguments& libraryArgs,
+ const cmInstallCommandArguments& frameworkArgs,
+ RuntimeDependenciesArgs runtimeDependenciesArgs, bool& installsRuntime,
+ bool& installsLibrary, bool& installsFramework)
+{
+ bool dllPlatform =
+ !helper.Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty();
+ bool apple =
+ helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") == "Darwin";
+ auto const& runtimeDependenciesArgsRef =
+ dllPlatform ? runtimeArgs : libraryArgs;
+ std::vector<std::string> configurations =
+ runtimeDependenciesArgsRef.GetConfigurations();
+ if (apple) {
+ std::copy(frameworkArgs.GetConfigurations().begin(),
+ frameworkArgs.GetConfigurations().end(),
+ std::back_inserter(configurations));
+ }
+
+ // Create file(GET_RUNTIME_DEPENDENCIES) generator.
+ auto getRuntimeDependenciesGenerator =
+ cm::make_unique<cmInstallGetRuntimeDependenciesGenerator>(
+ runtimeDependencySet, std::move(runtimeDependenciesArgs.Directories),
+ std::move(runtimeDependenciesArgs.PreIncludeRegexes),
+ std::move(runtimeDependenciesArgs.PreExcludeRegexes),
+ std::move(runtimeDependenciesArgs.PostIncludeRegexes),
+ std::move(runtimeDependenciesArgs.PostExcludeRegexes),
+ std::move(runtimeDependenciesArgs.PostIncludeFiles),
+ std::move(runtimeDependenciesArgs.PostExcludeFiles),
+ runtimeDependenciesArgsRef.GetComponent(),
+ apple ? frameworkArgs.GetComponent() : "", true, "_CMAKE_DEPS",
+ "_CMAKE_RPATH", configurations,
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile),
+ runtimeDependenciesArgsRef.GetExcludeFromAll() &&
+ (apple ? frameworkArgs.GetExcludeFromAll() : true),
+ helper.Makefile->GetBacktrace());
+ helper.Makefile->AddInstallGenerator(
+ std::move(getRuntimeDependenciesGenerator));
+
+ // Create the library dependencies generator.
+ auto libraryRuntimeDependenciesGenerator =
+ cm::make_unique<cmInstallRuntimeDependencySetGenerator>(
+ cmInstallRuntimeDependencySetGenerator::DependencyType::Library,
+ runtimeDependencySet, std::vector<std::string>{}, true, std::string{},
+ true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP",
+ dllPlatform ? helper.GetRuntimeDestination(&runtimeArgs)
+ : helper.GetLibraryDestination(&libraryArgs),
+ runtimeDependenciesArgsRef.GetConfigurations(),
+ runtimeDependenciesArgsRef.GetComponent(),
+ runtimeDependenciesArgsRef.GetPermissions(),
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile),
+ runtimeDependenciesArgsRef.GetExcludeFromAll(),
+ helper.Makefile->GetBacktrace());
+ helper.Makefile->AddInstallGenerator(
+ std::move(libraryRuntimeDependenciesGenerator));
+ if (dllPlatform) {
+ installsRuntime = true;
+ } else {
+ installsLibrary = true;
+ }
+
+ if (apple) {
+ // Create the framework dependencies generator.
+ auto frameworkRuntimeDependenciesGenerator =
+ cm::make_unique<cmInstallRuntimeDependencySetGenerator>(
+ cmInstallRuntimeDependencySetGenerator::DependencyType::Framework,
+ runtimeDependencySet, std::vector<std::string>{}, true, std::string{},
+ true, "_CMAKE_DEPS", "_CMAKE_RPATH", "_CMAKE_TMP",
+ frameworkArgs.GetDestination(), frameworkArgs.GetConfigurations(),
+ frameworkArgs.GetComponent(), frameworkArgs.GetPermissions(),
+ cmInstallGenerator::SelectMessageLevel(helper.Makefile),
+ frameworkArgs.GetExcludeFromAll(), helper.Makefile->GetBacktrace());
+ helper.Makefile->AddInstallGenerator(
+ std::move(frameworkRuntimeDependenciesGenerator));
+ installsFramework = true;
+ }
+}
+
std::set<std::string> const allowedTypes{
"BIN", "SBIN", "LIB", "INCLUDE", "SYSCONF",
"SHAREDSTATE", "LOCALSTATE", "RUNSTATE", "DATA", "INFO",
"LOCALE", "MAN", "DOC",
};
+template <typename T>
+bool AddBundleExecutable(Helper& helper,
+ cmInstallRuntimeDependencySet* runtimeDependencySet,
+ T&& bundleExecutable)
+{
+ if (!runtimeDependencySet->AddBundleExecutable(bundleExecutable)) {
+ helper.SetError(
+ "A runtime dependency set may only have one bundle executable.");
+ return false;
+ }
+ return true;
+}
+
bool HandleScriptMode(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@@ -289,13 +412,23 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
// These generic args also contain the targets and the export stuff
std::vector<std::string> targetList;
std::string exports;
+ std::vector<std::string> runtimeDependenciesArgVector;
std::vector<std::string> unknownArgs;
+ std::vector<std::string> parsedArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
genericArgs.Bind("TARGETS"_s, targetList);
genericArgs.Bind("EXPORT"_s, exports);
- genericArgs.Parse(genericArgVector, &unknownArgs);
+ genericArgs.Bind("RUNTIME_DEPENDENCIES"_s, runtimeDependenciesArgVector);
+ genericArgs.Parse(genericArgVector, &unknownArgs, nullptr, &parsedArgs);
bool success = genericArgs.Finalize();
+ bool withRuntimeDependencies =
+ std::find(parsedArgs.begin(), parsedArgs.end(), "RUNTIME_DEPENDENCIES") !=
+ parsedArgs.end();
+ RuntimeDependenciesArgs runtimeDependenciesArgs =
+ RuntimeDependenciesArgHelper.Parse(runtimeDependenciesArgVector,
+ &unknownArgs);
+
cmInstallCommandArguments archiveArgs(helper.DefaultComponentName);
cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
@@ -402,6 +535,32 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
return false;
}
+ cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
+ if (withRuntimeDependencies) {
+ auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ system)) {
+ status.SetError(
+ cmStrCat("TARGETS RUNTIME_DEPENDENCIES is not supported on system \"",
+ system, '"'));
+ return false;
+ }
+ if (helper.Makefile->IsOn("CMAKE_CROSSCOMPILING")) {
+ status.SetError("TARGETS RUNTIME_DEPENDENCIES is not supported "
+ "when cross-compiling.");
+ return false;
+ }
+ if (helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME") ==
+ "Darwin" &&
+ frameworkArgs.GetDestination().empty()) {
+ status.SetError(
+ "TARGETS RUNTIME_DEPENDENCIES given no FRAMEWORK DESTINATION");
+ return false;
+ }
+ runtimeDependencySet = helper.Makefile->GetGlobalGenerator()
+ ->CreateAnonymousRuntimeDependencySet();
+ }
+
// Select the mode for installing symlinks to versioned shared libraries.
cmInstallTargetGenerator::NamelinkModeType namelinkMode =
cmInstallTargetGenerator::NamelinkModeNone;
@@ -546,6 +705,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
helper.GetRuntimeDestination(nullptr));
}
+ if (runtimeDependencySet && runtimeGenerator) {
+ runtimeDependencySet->AddLibrary(runtimeGenerator.get());
+ }
} else {
// This is a non-DLL platform.
// If it is marked with FRAMEWORK property use the FRAMEWORK set of
@@ -591,6 +753,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
namelinkOnly =
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
}
+ if (runtimeDependencySet && libraryGenerator) {
+ runtimeDependencySet->AddLibrary(libraryGenerator.get());
+ }
}
} break;
case cmStateEnums::STATIC_LIBRARY: {
@@ -633,6 +798,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
libraryGenerator->SetNamelinkMode(namelinkMode);
namelinkOnly =
(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly);
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddModule(libraryGenerator.get());
+ }
} else {
status.SetError(
cmStrCat("TARGETS given no LIBRARY DESTINATION for module "
@@ -685,6 +853,12 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
target.GetName(), "\"."));
return false;
}
+ if (runtimeDependencySet) {
+ if (!AddBundleExecutable(helper, runtimeDependencySet,
+ bundleGenerator.get())) {
+ return false;
+ }
+ }
} else {
// Executables use the RUNTIME properties.
if (!runtimeArgs.GetDestination().empty()) {
@@ -693,6 +867,9 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
runtimeGenerator = CreateInstallTargetGenerator(
target, runtimeArgs, false, helper.Makefile->GetBacktrace(),
helper.GetRuntimeDestination(&runtimeArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddExecutable(runtimeGenerator.get());
+ }
}
// On DLL platforms an executable may also have an import
@@ -821,6 +998,13 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
helper.Makefile->AddInstallGenerator(std::move(resourceGenerator));
}
+ if (withRuntimeDependencies && !runtimeDependencySet->Empty()) {
+ AddInstallRuntimeDependenciesGenerator(
+ helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs,
+ std::move(runtimeDependenciesArgs), installsRuntime, installsLibrary,
+ installsFramework);
+ }
+
// Tell the global generator about any installation component names
// specified
if (installsArchive) {
diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index 9f0d119..4cfeb47 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -43,7 +43,8 @@ void cmInstallGenerator::AddInstallRule(
std::vector<std::string> const& files, bool optional /* = false */,
const char* permissions_file /* = 0 */,
const char* permissions_dir /* = 0 */, const char* rename /* = 0 */,
- const char* literal_args /* = 0 */, Indent indent)
+ const char* literal_args /* = 0 */, Indent indent,
+ const char* files_var /* = 0 */)
{
// Use the FILE command to install the file.
std::string stype;
@@ -70,37 +71,46 @@ void cmInstallGenerator::AddInstallRule(
stype = "FILE";
break;
}
- os << indent;
if (cmSystemTools::FileIsFullPath(dest)) {
- os << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
- os << indent << " \"";
- bool firstIteration = true;
- for (std::string const& file : files) {
- if (!firstIteration) {
- os << ";";
+ if (!files.empty()) {
+ os << indent << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
+ os << indent << " \"";
+ bool firstIteration = true;
+ for (std::string const& file : files) {
+ if (!firstIteration) {
+ os << ";";
+ }
+ os << dest << "/";
+ if (rename && *rename) {
+ os << rename;
+ } else {
+ os << cmSystemTools::GetFilenameName(file);
+ }
+ firstIteration = false;
}
- os << dest << "/";
- if (rename && *rename) {
- os << rename;
- } else {
- os << cmSystemTools::GetFilenameName(file);
- }
- firstIteration = false;
+ os << "\")\n";
+ }
+ if (files_var) {
+ os << indent << "foreach(_f IN LISTS " << files_var << ")\n";
+ os << indent.Next() << "get_filename_component(_fn \"${_f}\" NAME)\n";
+ os << indent.Next() << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES \""
+ << dest << "/${_fn}\")\n";
+ os << indent << "endforeach()\n";
}
- os << "\")\n";
os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
- os << indent << indent << "message(WARNING \"ABSOLUTE path INSTALL "
+ os << indent.Next() << "message(WARNING \"ABSOLUTE path INSTALL "
<< "DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
os << indent << "endif()\n";
os << indent << "if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
- os << indent << indent << "message(FATAL_ERROR \"ABSOLUTE path INSTALL "
+ os << indent.Next() << "message(FATAL_ERROR \"ABSOLUTE path INSTALL "
<< "DESTINATION forbidden (by caller): "
<< "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
os << indent << "endif()\n";
}
std::string absDest = ConvertToAbsoluteDestination(dest);
- os << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE " << stype;
+ os << indent << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE "
+ << stype;
if (optional) {
os << " OPTIONAL";
}
@@ -133,6 +143,9 @@ void cmInstallGenerator::AddInstallRule(
for (std::string const& f : files) {
os << "\n" << indent << " \"" << f << "\"";
}
+ if (files_var) {
+ os << " ${" << files_var << "}";
+ }
os << "\n" << indent << " ";
if (!(literal_args && *literal_args)) {
os << " ";
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index 97acb88..d342c99 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -50,7 +50,8 @@ public:
std::vector<std::string> const& files, bool optional = false,
const char* permissions_file = nullptr,
const char* permissions_dir = nullptr, const char* rename = nullptr,
- const char* literal_args = nullptr, Indent indent = Indent());
+ const char* literal_args = nullptr, Indent indent = Indent(),
+ const char* files_var = nullptr);
/** Get the install destination as it should appear in the
installation script. */
diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.cxx b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
new file mode 100644
index 0000000..4d585ce
--- /dev/null
+++ b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
@@ -0,0 +1,206 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallGetRuntimeDependenciesGenerator.h"
+
+#include <memory>
+#include <ostream>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmGeneratorExpression.h"
+#include "cmInstallRuntimeDependencySet.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmStringAlgorithms.h"
+
+namespace {
+template <typename T, typename F>
+void WriteMultiArgument(std::ostream& os, const cm::string_view& keyword,
+ const std::vector<T>& list,
+ cmScriptGeneratorIndent indent, F transform)
+{
+ bool first = true;
+ for (auto const& item : list) {
+ cm::optional<std::string> result = transform(item);
+ if (result) {
+ if (first) {
+ os << indent << " " << keyword << "\n";
+ first = false;
+ }
+ os << indent << " " << *result << "\n";
+ }
+ }
+}
+
+void WriteFilesArgument(
+ std::ostream& os, const cm::string_view& keyword,
+ const std::vector<std::unique_ptr<cmInstallRuntimeDependencySet::Item>>&
+ items,
+ const std::string& config, cmScriptGeneratorIndent indent)
+{
+ WriteMultiArgument(
+ os, keyword, items, indent,
+ [config](const std::unique_ptr<cmInstallRuntimeDependencySet::Item>& i)
+ -> std::string { return cmStrCat('"', i->GetItemPath(config), '"'); });
+}
+
+void WriteGenexEvaluatorArgument(std::ostream& os,
+ const cm::string_view& keyword,
+ const std::vector<std::string>& genexes,
+ const std::string& config,
+ cmLocalGenerator* lg,
+ cmScriptGeneratorIndent indent)
+{
+ WriteMultiArgument(
+ os, keyword, genexes, indent,
+ [config, lg](const std::string& genex) -> cm::optional<std::string> {
+ std::string result = cmGeneratorExpression::Evaluate(genex, lg, config);
+ if (result.empty()) {
+ return cm::nullopt;
+ }
+ return cmOutputConverter::EscapeForCMake(result);
+ });
+}
+}
+
+cmInstallGetRuntimeDependenciesGenerator::
+ cmInstallGetRuntimeDependenciesGenerator(
+ cmInstallRuntimeDependencySet* runtimeDependencySet,
+ std::vector<std::string> directories,
+ std::vector<std::string> preIncludeRegexes,
+ std::vector<std::string> preExcludeRegexes,
+ std::vector<std::string> postIncludeRegexes,
+ std::vector<std::string> postExcludeRegexes,
+ std::vector<std::string> postIncludeFiles,
+ std::vector<std::string> postExcludeFiles, std::string libraryComponent,
+ std::string frameworkComponent, bool noInstallRPath, const char* depsVar,
+ const char* rpathPrefix, std::vector<std::string> const& configurations,
+ MessageLevel message, bool exclude_from_all, cmListFileBacktrace backtrace)
+ : cmInstallGenerator("", configurations, "", message, exclude_from_all,
+ false, std::move(backtrace))
+ , RuntimeDependencySet(runtimeDependencySet)
+ , Directories(std::move(directories))
+ , PreIncludeRegexes(std::move(preIncludeRegexes))
+ , PreExcludeRegexes(std::move(preExcludeRegexes))
+ , PostIncludeRegexes(std::move(postIncludeRegexes))
+ , PostExcludeRegexes(std::move(postExcludeRegexes))
+ , PostIncludeFiles(std::move(postIncludeFiles))
+ , PostExcludeFiles(std::move(postExcludeFiles))
+ , LibraryComponent(std::move(libraryComponent))
+ , FrameworkComponent(std::move(frameworkComponent))
+ , NoInstallRPath(noInstallRPath)
+ , DepsVar(depsVar)
+ , RPathPrefix(rpathPrefix)
+{
+ this->ActionsPerConfig = true;
+}
+
+bool cmInstallGetRuntimeDependenciesGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ return true;
+}
+
+void cmInstallGetRuntimeDependenciesGenerator::GenerateScript(std::ostream& os)
+{
+ // Track indentation.
+ Indent indent;
+
+ // Begin this block of installation.
+ os << indent << "if(";
+ if (this->FrameworkComponent.empty() ||
+ this->FrameworkComponent == this->LibraryComponent) {
+ os << this->CreateComponentTest(this->LibraryComponent,
+ this->ExcludeFromAll);
+ } else {
+ os << this->CreateComponentTest(this->LibraryComponent, true) << " OR "
+ << this->CreateComponentTest(this->FrameworkComponent,
+ this->ExcludeFromAll);
+ }
+ os << ")\n";
+
+ // Generate the script possibly with per-configuration code.
+ this->GenerateScriptConfigs(os, indent.Next());
+
+ // End this block of installation.
+ os << indent << "endif()\n\n";
+}
+
+void cmInstallGetRuntimeDependenciesGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ std::string installNameTool =
+ this->LocalGenerator->GetMakefile()->GetSafeDefinition(
+ "CMAKE_INSTALL_NAME_TOOL");
+
+ os << indent << "file(GET_RUNTIME_DEPENDENCIES\n"
+ << indent << " RESOLVED_DEPENDENCIES_VAR " << this->DepsVar << '\n';
+ WriteFilesArgument(os, "EXECUTABLES"_s,
+ this->RuntimeDependencySet->GetExecutables(), config,
+ indent);
+ WriteFilesArgument(os, "LIBRARIES"_s,
+ this->RuntimeDependencySet->GetLibraries(), config,
+ indent);
+ WriteFilesArgument(os, "MODULES"_s, this->RuntimeDependencySet->GetModules(),
+ config, indent);
+ if (this->RuntimeDependencySet->GetBundleExecutable()) {
+ os << indent << " BUNDLE_EXECUTABLE \""
+ << this->RuntimeDependencySet->GetBundleExecutable()->GetItemPath(
+ config)
+ << "\"\n";
+ }
+ WriteGenexEvaluatorArgument(os, "DIRECTORIES"_s, this->Directories, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "PRE_INCLUDE_REGEXES"_s,
+ this->PreIncludeRegexes, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "PRE_EXCLUDE_REGEXES"_s,
+ this->PreExcludeRegexes, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "POST_INCLUDE_REGEXES"_s,
+ this->PostIncludeRegexes, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "POST_EXCLUDE_REGEXES"_s,
+ this->PostExcludeRegexes, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "POST_INCLUDE_FILES"_s,
+ this->PostIncludeFiles, config,
+ this->LocalGenerator, indent);
+ WriteGenexEvaluatorArgument(os, "POST_EXCLUDE_FILES"_s,
+ this->PostExcludeFiles, config,
+ this->LocalGenerator, indent);
+
+ std::set<std::string> postExcludeFiles;
+ auto const addPostExclude =
+ [config, &postExcludeFiles, this](
+ const std::vector<std::unique_ptr<cmInstallRuntimeDependencySet::Item>>&
+ tgts) {
+ for (auto const& item : tgts) {
+ item->AddPostExcludeFiles(config, postExcludeFiles,
+ this->RuntimeDependencySet);
+ }
+ };
+ addPostExclude(this->RuntimeDependencySet->GetExecutables());
+ addPostExclude(this->RuntimeDependencySet->GetLibraries());
+ addPostExclude(this->RuntimeDependencySet->GetModules());
+ bool first = true;
+ for (auto const& file : postExcludeFiles) {
+ if (first) {
+ os << indent << " POST_EXCLUDE_FILES_STRICT\n";
+ first = false;
+ }
+ os << indent << " \"" << file << "\"\n";
+ }
+
+ if (!installNameTool.empty() && !this->NoInstallRPath) {
+ os << indent << " RPATH_PREFIX " << this->RPathPrefix << '\n';
+ }
+ os << indent << " )\n";
+}
diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.h b/Source/cmInstallGetRuntimeDependenciesGenerator.h
new file mode 100644
index 0000000..19f6cc6
--- /dev/null
+++ b/Source/cmInstallGetRuntimeDependenciesGenerator.h
@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmLocalGenerator;
+class cmInstallRuntimeDependencySet;
+
+class cmInstallGetRuntimeDependenciesGenerator : public cmInstallGenerator
+{
+public:
+ cmInstallGetRuntimeDependenciesGenerator(
+ cmInstallRuntimeDependencySet* runtimeDependencySet,
+ std::vector<std::string> directories,
+ std::vector<std::string> preIncludeRegexes,
+ std::vector<std::string> preExcludeRegexes,
+ std::vector<std::string> postIncludeRegexes,
+ std::vector<std::string> postExcludeRegexes,
+ std::vector<std::string> postIncludeFiles,
+ std::vector<std::string> postExcludeFiles, std::string libraryComponent,
+ std::string frameworkComponent, bool noInstallRPath, const char* depsVar,
+ const char* rpathPrefix, std::vector<std::string> const& configurations,
+ MessageLevel message, bool exclude_from_all,
+ cmListFileBacktrace backtrace);
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+protected:
+ void GenerateScript(std::ostream& os) override;
+
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+private:
+ cmInstallRuntimeDependencySet* RuntimeDependencySet;
+ std::vector<std::string> Directories;
+ std::vector<std::string> PreIncludeRegexes;
+ std::vector<std::string> PreExcludeRegexes;
+ std::vector<std::string> PostIncludeRegexes;
+ std::vector<std::string> PostExcludeRegexes;
+ std::vector<std::string> PostIncludeFiles;
+ std::vector<std::string> PostExcludeFiles;
+ std::string LibraryComponent;
+ std::string FrameworkComponent;
+ bool NoInstallRPath;
+ const char* DepsVar;
+ const char* RPathPrefix;
+ cmLocalGenerator* LocalGenerator = nullptr;
+};
diff --git a/Source/cmInstallRuntimeDependencySetGenerator.cxx b/Source/cmInstallRuntimeDependencySetGenerator.cxx
new file mode 100644
index 0000000..44f03e1
--- /dev/null
+++ b/Source/cmInstallRuntimeDependencySetGenerator.cxx
@@ -0,0 +1,276 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallRuntimeDependencySetGenerator.h"
+
+#include <ostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorExpression.h"
+#include "cmInstallGenerator.h"
+#include "cmInstallType.h"
+#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
+#include "cmScriptGenerator.h"
+#include "cmStringAlgorithms.h"
+#include "cmake.h"
+
+cmInstallRuntimeDependencySetGenerator::cmInstallRuntimeDependencySetGenerator(
+ DependencyType type, cmInstallRuntimeDependencySet* dependencySet,
+ std::vector<std::string> installRPaths, bool noInstallRPath,
+ std::string installNameDir, bool noInstallName, const char* depsVar,
+ const char* rpathPrefix, const char* tmpVarPrefix, std::string destination,
+ std::vector<std::string> const& configurations, std::string component,
+ std::string permissions, MessageLevel message, bool exclude_from_all,
+ cmListFileBacktrace backtrace)
+ : cmInstallGenerator(std::move(destination), configurations,
+ std::move(component), message, exclude_from_all, false,
+ std::move(backtrace))
+ , Type(type)
+ , DependencySet(dependencySet)
+ , InstallRPaths(std::move(installRPaths))
+ , NoInstallRPath(noInstallRPath)
+ , InstallNameDir(std::move(installNameDir))
+ , NoInstallName(noInstallName)
+ , Permissions(std::move(permissions))
+ , DepsVar(depsVar)
+ , RPathPrefix(rpathPrefix)
+ , TmpVarPrefix(tmpVarPrefix)
+{
+ this->ActionsPerConfig = true;
+}
+
+bool cmInstallRuntimeDependencySetGenerator::Compute(cmLocalGenerator* lg)
+{
+ this->LocalGenerator = lg;
+ return true;
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateScriptForConfig(
+ std::ostream& os, const std::string& config, Indent indent)
+{
+ if (!this->LocalGenerator->GetMakefile()
+ ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL")
+ .empty() &&
+ !this->NoInstallName) {
+ std::string installNameDir = "@rpath/";
+ if (!this->InstallNameDir.empty()) {
+ installNameDir = this->InstallNameDir;
+ cmGeneratorExpression::ReplaceInstallPrefix(installNameDir,
+ "${CMAKE_INSTALL_PREFIX}");
+ installNameDir = cmGeneratorExpression::Evaluate(
+ installNameDir, this->LocalGenerator, config);
+ if (installNameDir.empty()) {
+ this->LocalGenerator->GetMakefile()->GetCMakeInstance()->IssueMessage(
+ MessageType::FATAL_ERROR,
+ "INSTALL_NAME_DIR argument must not evaluate to an "
+ "empty string",
+ this->Backtrace);
+ return;
+ }
+ if (installNameDir.back() != '/') {
+ installNameDir += '/';
+ }
+ }
+ os << indent << "set(" << this->TmpVarPrefix << "_install_name_dir \""
+ << installNameDir << "\")\n";
+ }
+
+ os << indent << "foreach(" << this->TmpVarPrefix << "_dep IN LISTS "
+ << this->DepsVar << ")\n";
+
+ if (!this->LocalGenerator->GetMakefile()
+ ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL")
+ .empty()) {
+ std::vector<std::string> evaluatedRPaths;
+ for (auto const& rpath : this->InstallRPaths) {
+ std::string result =
+ cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config);
+ if (!result.empty()) {
+ evaluatedRPaths.push_back(std::move(result));
+ }
+ }
+
+ switch (this->Type) {
+ case DependencyType::Library:
+ this->GenerateAppleLibraryScript(os, config, evaluatedRPaths,
+ indent.Next());
+ break;
+ case DependencyType::Framework:
+ this->GenerateAppleFrameworkScript(os, config, evaluatedRPaths,
+ indent.Next());
+ break;
+ }
+ } else {
+ std::string depVar = cmStrCat(this->TmpVarPrefix, "_dep");
+
+ this->AddInstallRule(
+ os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {},
+ false, this->Permissions.c_str(), nullptr, nullptr,
+ " FOLLOW_SYMLINK_CHAIN", indent.Next(), depVar.c_str());
+
+ if (this->LocalGenerator->GetMakefile()->GetSafeDefinition(
+ "CMAKE_SYSTEM_NAME") == "Linux" &&
+ !this->NoInstallRPath) {
+ std::string evaluatedRPath;
+ for (auto const& rpath : this->InstallRPaths) {
+ std::string result =
+ cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config);
+ if (!result.empty()) {
+ if (evaluatedRPath.empty()) {
+ evaluatedRPath = std::move(result);
+ } else {
+ evaluatedRPath += ':';
+ evaluatedRPath += result;
+ }
+ }
+ }
+
+ os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix
+ << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n";
+ if (evaluatedRPath.empty()) {
+ os << indent.Next() << "file(RPATH_REMOVE FILE \""
+ << GetDestDirPath(
+ ConvertToAbsoluteDestination(this->GetDestination(config)))
+ << "/${" << this->TmpVarPrefix << "_dep_name}\")\n";
+ } else {
+ os << indent.Next() << "file(RPATH_SET FILE \""
+ << GetDestDirPath(
+ ConvertToAbsoluteDestination(this->GetDestination(config)))
+ << "/${" << this->TmpVarPrefix << "_dep_name}\" NEW_RPATH "
+ << cmOutputConverter::EscapeForCMake(evaluatedRPath) << ")\n";
+ }
+ }
+ }
+
+ os << indent << "endforeach()\n";
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateAppleLibraryScript(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, Indent indent)
+{
+ os << indent << "if(NOT " << this->TmpVarPrefix
+ << "_dep MATCHES \"\\\\.framework/\")\n";
+
+ auto depName = cmStrCat(this->TmpVarPrefix, "_dep");
+ this->AddInstallRule(
+ os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, false,
+ this->Permissions.c_str(), nullptr, nullptr, " FOLLOW_SYMLINK_CHAIN",
+ indent.Next(), depName.c_str());
+
+ os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix
+ << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n";
+ auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_dep_name}");
+ this->GenerateInstallNameFixup(os, config, evaluatedRPaths,
+ cmStrCat("${", this->TmpVarPrefix, "_dep}"),
+ depNameVar, indent.Next());
+
+ os << indent << "endif()\n";
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateAppleFrameworkScript(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, Indent indent)
+{
+ os << indent << "if(" << this->TmpVarPrefix
+ << "_dep MATCHES \"^(.*/)?([^/]*\\\\.framework)/(.*)$\")\n"
+ << indent.Next() << "set(" << this->TmpVarPrefix
+ << "_dir \"${CMAKE_MATCH_1}\")\n"
+ << indent.Next() << "set(" << this->TmpVarPrefix
+ << "_name \"${CMAKE_MATCH_2}\")\n"
+ << indent.Next() << "set(" << this->TmpVarPrefix
+ << "_file \"${CMAKE_MATCH_3}\")\n"
+ << indent.Next() << "set(" << this->TmpVarPrefix << "_path \"${"
+ << this->TmpVarPrefix << "_dir}${" << this->TmpVarPrefix << "_name}\")\n";
+
+ auto depName = cmStrCat(this->TmpVarPrefix, "_path");
+ this->AddInstallRule(
+ os, this->GetDestination(config), cmInstallType_DIRECTORY, {}, false,
+ this->Permissions.c_str(), nullptr, nullptr, " USE_SOURCE_PERMISSIONS",
+ indent.Next(), depName.c_str());
+
+ auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_name}/${",
+ this->TmpVarPrefix, "_file}");
+ this->GenerateInstallNameFixup(os, config, evaluatedRPaths,
+ cmStrCat("${", this->TmpVarPrefix, "_dep}"),
+ depNameVar, indent.Next());
+
+ os << indent << "endif()\n";
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateInstallNameFixup(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, const std::string& filename,
+ const std::string& depName, Indent indent)
+{
+ if (!(this->NoInstallRPath && this->NoInstallName)) {
+ auto indent2 = indent;
+ if (evaluatedRPaths.empty() && this->NoInstallName) {
+ indent2 = indent2.Next();
+ os << indent << "if(" << this->RPathPrefix << "_" << filename << ")\n";
+ }
+ os << indent2 << "set(" << this->TmpVarPrefix << "_rpath_args)\n";
+ if (!this->NoInstallRPath) {
+ os << indent2 << "foreach(" << this->TmpVarPrefix << "_rpath IN LISTS "
+ << this->RPathPrefix << '_' << filename << ")\n"
+ << indent2.Next() << "list(APPEND " << this->TmpVarPrefix
+ << "_rpath_args -delete_rpath \"${" << this->TmpVarPrefix
+ << "_rpath}\")\n"
+ << indent2 << "endforeach()\n";
+ }
+ os << indent2 << "execute_process(COMMAND \""
+ << this->LocalGenerator->GetMakefile()->GetSafeDefinition(
+ "CMAKE_INSTALL_NAME_TOOL")
+ << "\" ${" << this->TmpVarPrefix << "_rpath_args}\n";
+ if (!this->NoInstallRPath) {
+ for (auto const& rpath : evaluatedRPaths) {
+ os << indent2 << " -add_rpath "
+ << cmOutputConverter::EscapeForCMake(rpath) << "\n";
+ }
+ }
+ if (!this->NoInstallName) {
+ os << indent2 << " -id \"${" << this->TmpVarPrefix
+ << "_install_name_dir}" << depName << "\"\n";
+ }
+ os << indent2 << " \""
+ << GetDestDirPath(
+ ConvertToAbsoluteDestination(this->GetDestination(config)))
+ << "/" << depName << "\")\n";
+ if (evaluatedRPaths.empty() && this->NoInstallName) {
+ os << indent << "endif()\n";
+ }
+ }
+}
+
+void cmInstallRuntimeDependencySetGenerator::GenerateStripFixup(
+ std::ostream& os, const std::string& config, const std::string& depName,
+ Indent indent)
+{
+ std::string strip =
+ this->LocalGenerator->GetMakefile()->GetSafeDefinition("CMAKE_STRIP");
+ if (!strip.empty()) {
+ os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n"
+ << indent.Next() << "execute_process(COMMAND \"" << strip << "\" ";
+ if (this->LocalGenerator->GetMakefile()->GetSafeDefinition(
+ "CMAKE_HOST_SYSTEM_NAME") == "Darwin") {
+ os << "-x ";
+ }
+ os << "\""
+ << GetDestDirPath(
+ ConvertToAbsoluteDestination(this->GetDestination(config)))
+ << "/" << depName << "\")\n"
+ << indent << "endif()\n";
+ }
+}
+
+std::string cmInstallRuntimeDependencySetGenerator::GetDestination(
+ std::string const& config) const
+{
+ return cmGeneratorExpression::Evaluate(this->Destination,
+ this->LocalGenerator, config);
+}
diff --git a/Source/cmInstallRuntimeDependencySetGenerator.h b/Source/cmInstallRuntimeDependencySetGenerator.h
new file mode 100644
index 0000000..8e98b57
--- /dev/null
+++ b/Source/cmInstallRuntimeDependencySetGenerator.h
@@ -0,0 +1,74 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "cmInstallGenerator.h"
+#include "cmListFileCache.h"
+#include "cmScriptGenerator.h"
+
+class cmInstallRuntimeDependencySet;
+class cmLocalGenerator;
+
+class cmInstallRuntimeDependencySetGenerator : public cmInstallGenerator
+{
+public:
+ enum class DependencyType
+ {
+ Library,
+ Framework,
+ };
+
+ cmInstallRuntimeDependencySetGenerator(
+ DependencyType type, cmInstallRuntimeDependencySet* dependencySet,
+ std::vector<std::string> installRPaths, bool noInstallRPath,
+ std::string installNameDir, bool noInstallName, const char* depsVar,
+ const char* rpathPrefix, const char* tmpVarPrefix, std::string destination,
+ std::vector<std::string> const& configurations, std::string component,
+ std::string permissions, MessageLevel message, bool exclude_from_all,
+ cmListFileBacktrace backtrace);
+
+ bool Compute(cmLocalGenerator* lg) override;
+
+ DependencyType GetDependencyType() const { return this->Type; }
+
+ cmInstallRuntimeDependencySet* GetRuntimeDependencySet() const
+ {
+ return this->DependencySet;
+ }
+
+ std::string GetDestination(std::string const& config) const;
+
+protected:
+ void GenerateScriptForConfig(std::ostream& os, const std::string& config,
+ Indent indent) override;
+
+private:
+ DependencyType Type;
+ cmInstallRuntimeDependencySet* DependencySet;
+ std::vector<std::string> InstallRPaths;
+ bool NoInstallRPath;
+ std::string InstallNameDir;
+ bool NoInstallName;
+ std::string Permissions;
+ const char* DepsVar;
+ const char* RPathPrefix;
+ const char* TmpVarPrefix;
+ cmLocalGenerator* LocalGenerator = nullptr;
+
+ void GenerateAppleLibraryScript(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, Indent indent);
+ void GenerateAppleFrameworkScript(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths, Indent indent);
+ void GenerateInstallNameFixup(
+ std::ostream& os, const std::string& config,
+ const std::vector<std::string>& evaluatedRPaths,
+ const std::string& filename, const std::string& depName, Indent indent);
+ void GenerateStripFixup(std::ostream& os, const std::string& config,
+ const std::string& depName, Indent indent);
+};
diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx
index 06246d1..26f255d 100644
--- a/Source/cmRuntimeDependencyArchive.cxx
+++ b/Source/cmRuntimeDependencyArchive.cxx
@@ -397,3 +397,11 @@ cmRuntimeDependencyArchive::GetRPaths() const
{
return this->RPaths;
}
+
+bool cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ const std::string& platform)
+{
+ static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
+ "Darwin" };
+ return supportedPlatforms.count(platform);
+}
diff --git a/Source/cmRuntimeDependencyArchive.h b/Source/cmRuntimeDependencyArchive.h
index 20a38e2..b170815 100644
--- a/Source/cmRuntimeDependencyArchive.h
+++ b/Source/cmRuntimeDependencyArchive.h
@@ -53,6 +53,8 @@ public:
const std::set<std::string>& GetUnresolvedPaths() const;
const std::map<std::string, std::vector<std::string>>& GetRPaths() const;
+ static bool PlatformSupportsRuntimeDependencies(const std::string& platform);
+
private:
cmExecutionStatus& Status;
std::unique_ptr<cmBinUtilsLinker> Linker;
diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake
index 94887a0..0f6ec70 100644
--- a/Tests/RunCMake/install/RunCMakeTest.cmake
+++ b/Tests/RunCMake/install/RunCMakeTest.cmake
@@ -44,7 +44,7 @@ function(check_installed expect)
do not match what we expected:
${expect}
in directory:
- ${CMAKE_INSTALL_PREFIX}" PARENT_SCOPE)
+ ${CMAKE_INSTALL_PREFIX}\n" PARENT_SCOPE)
endif()
endfunction()
@@ -174,6 +174,21 @@ run_install_test(FILES-PERMISSIONS)
run_install_test(TARGETS-RPATH)
run_install_test(InstallRequiredSystemLibraries)
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ run_cmake(TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle)
+ run_cmake(TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework)
+endif()
+
+if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|Darwin|Windows)$")
+ run_install_test(TARGETS-RUNTIME_DEPENDENCIES-nodep)
+ run_install_test(TARGETS-RUNTIME_DEPENDENCIES-empty)
+ set(RunCMake_TEST_OPTIONS "-DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}")
+ run_cmake(TARGETS-RUNTIME_DEPENDENCIES-cross)
+ unset(RunCMake_TEST_OPTIONS)
+else()
+ run_cmake(TARGETS-RUNTIME_DEPENDENCIES-unsupported)
+endif()
+
set(run_install_test_components 1)
run_install_test(FILES-EXCLUDE_FROM_ALL)
run_install_test(TARGETS-EXCLUDE_FROM_ALL)
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt
new file mode 100644
index 0000000..b7bbb55
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-cross\.cmake:[0-9]+ \(install\):
+ install TARGETS RUNTIME_DEPENDENCIES is not supported when cross-compiling\.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake
new file mode 100644
index 0000000..36b2eb7
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-cross.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(exe main.c)
+install(TARGETS exe RUNTIME_DEPENDENCIES)
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake
new file mode 100644
index 0000000..dafc2a4
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty-all-check.cmake
@@ -0,0 +1 @@
+check_installed([[^static;static/(liblib\.a|lib\.lib)$]])
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake
new file mode 100644
index 0000000..e46e1d9
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-empty.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+add_library(lib STATIC obj1.c)
+
+install(TARGETS lib RUNTIME_DEPENDENCIES
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION static
+ FRAMEWORK DESTINATION fw
+ )
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt
new file mode 100644
index 0000000..6ab14f6
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework\.cmake:[0-9]+ \(install\):
+ install TARGETS RUNTIME_DEPENDENCIES given no FRAMEWORK DESTINATION
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake
new file mode 100644
index 0000000..36b2eb7
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(exe main.c)
+install(TARGETS exe RUNTIME_DEPENDENCIES)
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt
new file mode 100644
index 0000000..c7b49c7
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle\.cmake:[0-9]+ \(install\):
+ install A runtime dependency set may only have one bundle executable\.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake
new file mode 100644
index 0000000..a848a24
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_executable(exe1 MACOSX_BUNDLE main.c)
+add_executable(exe2 MACOSX_BUNDLE main.c)
+
+install(TARGETS exe1 exe2
+ RUNTIME_DEPENDENCIES
+ BUNDLE DESTINATION bundles
+ FRAMEWORK DESTINATION fw
+ )
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake
new file mode 100644
index 0000000..9f455b1
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep-all-check.cmake
@@ -0,0 +1 @@
+check_installed([[^bin;bin/exe(\.exe)?$]])
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake
new file mode 100644
index 0000000..02466561
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-nodep.cmake
@@ -0,0 +1,9 @@
+enable_language(C)
+
+add_executable(exe main.c)
+
+install(TARGETS exe
+ RUNTIME_DEPENDENCIES
+ PRE_EXCLUDE_REGEXES ".*"
+ FRAMEWORK DESTINATION fw
+ )
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt
new file mode 100644
index 0000000..c098a4c
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at TARGETS-RUNTIME_DEPENDENCIES-unsupported\.cmake:[0-9]+ \(install\):
+ install TARGETS RUNTIME_DEPENDENCIES is not supported on system "[^
+]*"
+Call Stack \(most recent call first\):
+ CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake
new file mode 100644
index 0000000..36b2eb7
--- /dev/null
+++ b/Tests/RunCMake/install/TARGETS-RUNTIME_DEPENDENCIES-unsupported.cmake
@@ -0,0 +1,4 @@
+enable_language(C)
+
+add_executable(exe main.c)
+install(TARGETS exe RUNTIME_DEPENDENCIES)
diff --git a/bootstrap b/bootstrap
index 720fa76..f8d2f69 100755
--- a/bootstrap
+++ b/bootstrap
@@ -387,8 +387,10 @@ CMAKE_CXX_SOURCES="\
cmInstallFilesCommand \
cmInstallFilesGenerator \
cmInstallGenerator \
+ cmInstallGetRuntimeDependenciesGenerator \
cmInstallImportedRuntimeArtifactsGenerator \
cmInstallRuntimeDependencySet \
+ cmInstallRuntimeDependencySetGenerator \
cmInstallScriptGenerator \
cmInstallSubdirectoryGenerator \
cmInstallTargetGenerator \