summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2021-06-08 12:08:57 (GMT)
committerKitware Robot <kwrobot@kitware.com>2021-06-08 12:09:04 (GMT)
commitacb25d50d9d37e93cafcbbc4401e1b45029b6461 (patch)
tree078d3f511f584e4f924a9380f9539aa122a2263e /Source
parent3653dc60690e6fc33d9e7bf44186b82587cf21a7 (diff)
parent8d898cb3e10d6ad44bbe542b7b219a0b788b2a0d (diff)
downloadCMake-acb25d50d9d37e93cafcbbc4401e1b45029b6461.zip
CMake-acb25d50d9d37e93cafcbbc4401e1b45029b6461.tar.gz
CMake-acb25d50d9d37e93cafcbbc4401e1b45029b6461.tar.bz2
Merge topic 'install-with-runtime-dependencies'
8d898cb3e1 FileAPI: Add integration for runtime dependency installers 72f2448e82 Help: Add documentation for runtime dependency installation 0c3c6acaff Tests: Add tests for new options 4910132d8c install: Add RUNTIME_DEPENDENCY_SET mode bc8a4a06a4 install(IMPORTED_RUNTIME_ARTIFACTS): Add RUNTIME_DEPENDENCY_SET option 3e7d3c252a install(TARGETS): Add RUNTIME_DEPENDENCY_SET argument ed3633d88c install(TARGETS): Add RUNTIME_DEPENDENCIES option f2617cf8e6 Source: Add cmInstallRuntimeDependencySet ... Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !6186
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt6
-rw-r--r--Source/cmBinUtilsMacOSMachOLinker.cxx22
-rw-r--r--Source/cmBinUtilsMacOSMachOLinker.h2
-rw-r--r--Source/cmFileAPICodemodel.cxx28
-rw-r--r--Source/cmFileCommand.cxx211
-rw-r--r--Source/cmGlobalGenerator.cxx24
-rw-r--r--Source/cmGlobalGenerator.h11
-rw-r--r--Source/cmInstallCommand.cxx361
-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/cmInstallRuntimeDependencySet.cxx95
-rw-r--r--Source/cmInstallRuntimeDependencySet.h163
-rw-r--r--Source/cmInstallRuntimeDependencySetGenerator.cxx276
-rw-r--r--Source/cmInstallRuntimeDependencySetGenerator.h74
-rw-r--r--Source/cmRuntimeDependencyArchive.cxx39
-rw-r--r--Source/cmRuntimeDependencyArchive.h26
-rw-r--r--Source/cmSystemTools.cxx210
-rw-r--r--Source/cmSystemTools.h6
20 files changed, 1665 insertions, 205 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 844a2ee..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
@@ -352,6 +354,10 @@ set(SRCS
cmInstallFilesGenerator.cxx
cmInstallImportedRuntimeArtifactsGenerator.h
cmInstallImportedRuntimeArtifactsGenerator.cxx
+ cmInstallRuntimeDependencySet.h
+ cmInstallRuntimeDependencySet.cxx
+ cmInstallRuntimeDependencySetGenerator.h
+ cmInstallRuntimeDependencySetGenerator.cxx
cmInstallScriptGenerator.h
cmInstallScriptGenerator.cxx
cmInstallSubdirectoryGenerator.h
diff --git a/Source/cmBinUtilsMacOSMachOLinker.cxx b/Source/cmBinUtilsMacOSMachOLinker.cxx
index 0f47146..47f77d8 100644
--- a/Source/cmBinUtilsMacOSMachOLinker.cxx
+++ b/Source/cmBinUtilsMacOSMachOLinker.cxx
@@ -65,18 +65,18 @@ bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
if (!executableFile.empty()) {
executablePath = cmSystemTools::GetFilenamePath(executableFile);
}
- return this->ScanDependencies(file, executablePath);
-}
-
-bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
- std::string const& file, std::string const& executablePath)
-{
std::vector<std::string> libs;
std::vector<std::string> rpaths;
if (!this->Tool->GetFileInfo(file, libs, rpaths)) {
return false;
}
+ return this->ScanDependencies(file, libs, rpaths, executablePath);
+}
+bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
+ std::string const& file, std::vector<std::string> const& libs,
+ std::vector<std::string> const& rpaths, std::string const& executablePath)
+{
std::string loaderPath = cmSystemTools::GetFilenamePath(file);
return this->GetFileDependencies(libs, executablePath, loaderPath, rpaths);
}
@@ -98,8 +98,14 @@ bool cmBinUtilsMacOSMachOLinker::GetFileDependencies(
!IsMissingSystemDylib(path)) {
auto filename = cmSystemTools::GetFilenameName(path);
bool unique;
- this->Archive->AddResolvedPath(filename, path, unique);
- if (unique && !this->ScanDependencies(path, executablePath)) {
+ std::vector<std::string> libs;
+ std::vector<std::string> depRpaths;
+ if (!this->Tool->GetFileInfo(path, libs, depRpaths)) {
+ return false;
+ }
+ this->Archive->AddResolvedPath(filename, path, unique, depRpaths);
+ if (unique &&
+ !this->ScanDependencies(path, libs, depRpaths, executablePath)) {
return false;
}
}
diff --git a/Source/cmBinUtilsMacOSMachOLinker.h b/Source/cmBinUtilsMacOSMachOLinker.h
index 1c4a5fc..eae23cc 100644
--- a/Source/cmBinUtilsMacOSMachOLinker.h
+++ b/Source/cmBinUtilsMacOSMachOLinker.h
@@ -27,6 +27,8 @@ private:
std::unique_ptr<cmBinUtilsMacOSMachOGetRuntimeDependenciesTool> Tool;
bool ScanDependencies(std::string const& file,
+ std::vector<std::string> const& libs,
+ std::vector<std::string> const& rpaths,
std::string const& executablePath);
bool GetFileDependencies(std::vector<std::string> const& names,
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index efe1ab6..2d6745c 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -15,6 +15,7 @@
#include <utility>
#include <vector>
+#include <cm/string_view>
#include <cmext/algorithm>
#include <cm3p/json/value.h>
@@ -29,7 +30,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 "cmInstallSubdirectoryGenerator.h"
#include "cmInstallTargetGenerator.h"
@@ -877,8 +881,10 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
assert(gen);
Json::Value installer = Json::objectValue;
- // Exclude subdirectory installers. They are implementation details.
- if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen)) {
+ // Exclude subdirectory installers and file(GET_RUNTIME_DEPENDENCIES)
+ // installers. They are implementation details.
+ if (dynamic_cast<cmInstallSubdirectoryGenerator*>(gen) ||
+ dynamic_cast<cmInstallGetRuntimeDependenciesGenerator*>(gen)) {
return installer;
}
@@ -1020,6 +1026,24 @@ Json::Value DirectoryObject::DumpInstaller(cmInstallGenerator* gen)
if (installImportedRuntimeArtifacts->GetOptional()) {
installer["isOptional"] = true;
}
+ } else if (auto* installRuntimeDependencySet =
+ dynamic_cast<cmInstallRuntimeDependencySetGenerator*>(gen)) {
+ installer["type"] = "runtimeDependencySet";
+ installer["destination"] =
+ installRuntimeDependencySet->GetDestination(this->Config);
+ std::string name(
+ installRuntimeDependencySet->GetRuntimeDependencySet()->GetName());
+ if (!name.empty()) {
+ installer["runtimeDependencySetName"] = name;
+ }
+ switch (installRuntimeDependencySet->GetDependencyType()) {
+ case cmInstallRuntimeDependencySetGenerator::DependencyType::Framework:
+ installer["runtimeDependencySetType"] = "framework";
+ break;
+ case cmInstallRuntimeDependencySetGenerator::DependencyType::Library:
+ installer["runtimeDependencySetType"] = "library";
+ break;
+ }
}
// Add fields common to all install generators.
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index f2d4cda..0ad59c7 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -990,50 +990,42 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- const char* oldRPath = nullptr;
- const char* newRPath = nullptr;
+ std::string oldRPath;
+ std::string newRPath;
bool removeEnvironmentRPath = false;
- enum Doing
- {
- DoingNone,
- DoingFile,
- DoingOld,
- DoingNew
- };
- Doing doing = DoingNone;
- for (unsigned int i = 1; i < args.size(); ++i) {
- if (args[i] == "OLD_RPATH") {
- doing = DoingOld;
- } else if (args[i] == "NEW_RPATH") {
- doing = DoingNew;
- } else if (args[i] == "FILE") {
- doing = DoingFile;
- } else if (args[i] == "INSTALL_REMOVE_ENVIRONMENT_RPATH") {
- removeEnvironmentRPath = true;
- } else if (doing == DoingFile) {
- file = args[i];
- doing = DoingNone;
- } else if (doing == DoingOld) {
- oldRPath = args[i].c_str();
- doing = DoingNone;
- } else if (doing == DoingNew) {
- newRPath = args[i].c_str();
- doing = DoingNone;
- } else {
- status.SetError(
- cmStrCat("RPATH_CHANGE given unknown argument ", args[i]));
- return false;
- }
+ cmArgumentParser<void> parser;
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> missingArgs;
+ std::vector<std::string> parsedArgs;
+ parser.Bind("FILE"_s, file)
+ .Bind("OLD_RPATH"_s, oldRPath)
+ .Bind("NEW_RPATH"_s, newRPath)
+ .Bind("INSTALL_REMOVE_ENVIRONMENT_RPATH"_s, removeEnvironmentRPath);
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
+ &parsedArgs);
+ if (!unknownArgs.empty()) {
+ status.SetError(
+ cmStrCat("RPATH_CHANGE given unknown argument ", unknownArgs.front()));
+ return false;
+ }
+ if (!missingArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_CHANGE \"", missingArgs.front(),
+ "\" argument not given value."));
+ return false;
}
if (file.empty()) {
status.SetError("RPATH_CHANGE not given FILE option.");
return false;
}
- if (!oldRPath) {
+ if (oldRPath.empty() &&
+ std::find(parsedArgs.begin(), parsedArgs.end(), "OLD_RPATH") ==
+ parsedArgs.end()) {
status.SetError("RPATH_CHANGE not given OLD_RPATH option.");
return false;
}
- if (!newRPath) {
+ if (newRPath.empty() &&
+ std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") ==
+ parsedArgs.end()) {
status.SetError("RPATH_CHANGE not given NEW_RPATH option.");
return false;
}
@@ -1065,28 +1057,85 @@ bool HandleRPathChangeCommand(std::vector<std::string> const& args,
return success;
}
+bool HandleRPathSetCommand(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ // Evaluate arguments.
+ std::string file;
+ std::string newRPath;
+ cmArgumentParser<void> parser;
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> missingArgs;
+ std::vector<std::string> parsedArgs;
+ parser.Bind("FILE"_s, file).Bind("NEW_RPATH"_s, newRPath);
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
+ &parsedArgs);
+ if (!unknownArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_SET given unrecognized argument \"",
+ unknownArgs.front(), "\"."));
+ return false;
+ }
+ if (!missingArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_SET \"", missingArgs.front(),
+ "\" argument not given value."));
+ return false;
+ }
+ if (file.empty()) {
+ status.SetError("RPATH_SET not given FILE option.");
+ return false;
+ }
+ if (newRPath.empty() &&
+ std::find(parsedArgs.begin(), parsedArgs.end(), "NEW_RPATH") ==
+ parsedArgs.end()) {
+ status.SetError("RPATH_SET not given NEW_RPATH option.");
+ return false;
+ }
+ if (!cmSystemTools::FileExists(file, true)) {
+ status.SetError(
+ cmStrCat("RPATH_SET given FILE \"", file, "\" that does not exist."));
+ return false;
+ }
+ bool success = true;
+ cmFileTimes const ft(file);
+ std::string emsg;
+ bool changed;
+
+ if (!cmSystemTools::SetRPath(file, newRPath, &emsg, &changed)) {
+ status.SetError(cmStrCat("RPATH_SET could not write new RPATH:\n ",
+ newRPath, "\nto the file:\n ", file, "\n",
+ emsg));
+ success = false;
+ }
+ if (success) {
+ if (changed) {
+ std::string message =
+ cmStrCat("Set runtime path of \"", file, "\" to \"", newRPath, '"');
+ status.GetMakefile().DisplayStatus(message, -1);
+ }
+ ft.Store(file);
+ }
+ return success;
+}
+
bool HandleRPathRemoveCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
// Evaluate arguments.
std::string file;
- enum Doing
- {
- DoingNone,
- DoingFile
- };
- Doing doing = DoingNone;
- for (unsigned int i = 1; i < args.size(); ++i) {
- if (args[i] == "FILE") {
- doing = DoingFile;
- } else if (doing == DoingFile) {
- file = args[i];
- doing = DoingNone;
- } else {
- status.SetError(
- cmStrCat("RPATH_REMOVE given unknown argument ", args[i]));
- return false;
- }
+ cmArgumentParser<void> parser;
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> missingArgs;
+ parser.Bind("FILE"_s, file);
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs);
+ if (!unknownArgs.empty()) {
+ status.SetError(
+ cmStrCat("RPATH_REMOVE given unknown argument ", unknownArgs.front()));
+ return false;
+ }
+ if (!missingArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_REMOVE \"", missingArgs.front(),
+ "\" argument not given value."));
+ return false;
}
if (file.empty()) {
status.SetError("RPATH_REMOVE not given FILE option.");
@@ -1123,36 +1172,31 @@ bool HandleRPathCheckCommand(std::vector<std::string> const& args,
{
// Evaluate arguments.
std::string file;
- const char* rpath = nullptr;
- enum Doing
- {
- DoingNone,
- DoingFile,
- DoingRPath
- };
- Doing doing = DoingNone;
- for (unsigned int i = 1; i < args.size(); ++i) {
- if (args[i] == "RPATH") {
- doing = DoingRPath;
- } else if (args[i] == "FILE") {
- doing = DoingFile;
- } else if (doing == DoingFile) {
- file = args[i];
- doing = DoingNone;
- } else if (doing == DoingRPath) {
- rpath = args[i].c_str();
- doing = DoingNone;
- } else {
- status.SetError(
- cmStrCat("RPATH_CHECK given unknown argument ", args[i]));
- return false;
- }
+ std::string rpath;
+ cmArgumentParser<void> parser;
+ std::vector<std::string> unknownArgs;
+ std::vector<std::string> missingArgs;
+ std::vector<std::string> parsedArgs;
+ parser.Bind("FILE"_s, file).Bind("RPATH"_s, rpath);
+ parser.Parse(cmMakeRange(args).advance(1), &unknownArgs, &missingArgs,
+ &parsedArgs);
+ if (!unknownArgs.empty()) {
+ status.SetError(
+ cmStrCat("RPATH_CHECK given unknown argument ", unknownArgs.front()));
+ return false;
+ }
+ if (!missingArgs.empty()) {
+ status.SetError(cmStrCat("RPATH_CHECK \"", missingArgs.front(),
+ "\" argument not given value."));
+ return false;
}
if (file.empty()) {
status.SetError("RPATH_CHECK not given FILE option.");
return false;
}
- if (!rpath) {
+ if (rpath.empty() &&
+ std::find(parsedArgs.begin(), parsedArgs.end(), "RPATH") ==
+ parsedArgs.end()) {
status.SetError("RPATH_CHECK not given RPATH option.");
return false;
}
@@ -3000,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, "\""));
@@ -3032,6 +3075,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
std::string ResolvedDependenciesVar;
std::string UnresolvedDependenciesVar;
std::string ConflictingDependenciesPrefix;
+ std::string RPathPrefix;
std::string BundleExecutable;
std::vector<std::string> Executables;
std::vector<std::string> Libraries;
@@ -3053,6 +3097,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
&Arguments::UnresolvedDependenciesVar)
.Bind("CONFLICTING_DEPENDENCIES_PREFIX"_s,
&Arguments::ConflictingDependenciesPrefix)
+ .Bind("RPATH_PREFIX"_s, &Arguments::RPathPrefix)
.Bind("BUNDLE_EXECUTABLE"_s, &Arguments::BundleExecutable)
.Bind("EXECUTABLES"_s, &Arguments::Executables)
.Bind("LIBRARIES"_s, &Arguments::Libraries)
@@ -3135,6 +3180,11 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
if (unique) {
deps.push_back(firstPath);
+ if (!parsedArgs.RPathPrefix.empty()) {
+ status.GetMakefile().AddDefinition(
+ parsedArgs.RPathPrefix + "_" + firstPath,
+ cmJoin(archive.GetRPaths().at(firstPath), ";"));
+ }
} else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
conflictingDeps.push_back(val.first);
std::vector<std::string> paths;
@@ -3741,6 +3791,7 @@ bool cmFileCommand(std::vector<std::string> const& args,
{ "DIFFERENT"_s, HandleDifferentCommand },
{ "RPATH_CHANGE"_s, HandleRPathChangeCommand },
{ "CHRPATH"_s, HandleRPathChangeCommand },
+ { "RPATH_SET"_s, HandleRPathSetCommand },
{ "RPATH_CHECK"_s, HandleRPathCheckCommand },
{ "RPATH_REMOVE"_s, HandleRPathRemoveCommand },
{ "READ_ELF"_s, HandleReadElfCommand },
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index d7da0d3..9193778 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -36,6 +36,7 @@
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmInstallGenerator.h"
+#include "cmInstallRuntimeDependencySet.h"
#include "cmLinkLineComputer.h"
#include "cmListFileCache.h"
#include "cmLocalGenerator.h"
@@ -3332,3 +3333,26 @@ bool cmGlobalGenerator::GenerateCPackPropertiesFile()
return true;
}
+
+cmInstallRuntimeDependencySet*
+cmGlobalGenerator::CreateAnonymousRuntimeDependencySet()
+{
+ auto set = cm::make_unique<cmInstallRuntimeDependencySet>();
+ auto* retval = set.get();
+ this->RuntimeDependencySets.push_back(std::move(set));
+ return retval;
+}
+
+cmInstallRuntimeDependencySet* cmGlobalGenerator::GetNamedRuntimeDependencySet(
+ const std::string& name)
+{
+ auto it = this->RuntimeDependencySetsByName.find(name);
+ if (it == this->RuntimeDependencySetsByName.end()) {
+ auto set = cm::make_unique<cmInstallRuntimeDependencySet>(name);
+ it =
+ this->RuntimeDependencySetsByName.insert(std::make_pair(name, set.get()))
+ .first;
+ this->RuntimeDependencySets.push_back(std::move(set));
+ }
+ return it->second;
+}
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index fee0359..147146e 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -42,6 +42,7 @@ class cmDirectoryId;
class cmExportBuildFileGenerator;
class cmExternalMakefileProjectGenerator;
class cmGeneratorTarget;
+class cmInstallRuntimeDependencySet;
class cmLinkLineComputer;
class cmLocalGenerator;
class cmMakefile;
@@ -528,6 +529,11 @@ public:
std::string NewDeferId();
+ cmInstallRuntimeDependencySet* CreateAnonymousRuntimeDependencySet();
+
+ cmInstallRuntimeDependencySet* GetNamedRuntimeDependencySet(
+ const std::string& name);
+
protected:
// for a project collect all its targets by following depend
// information, and also collect all the targets
@@ -747,6 +753,11 @@ private:
std::unordered_set<std::string> GeneratedFiles;
+ std::vector<std::unique_ptr<cmInstallRuntimeDependencySet>>
+ RuntimeDependencySets;
+ std::map<std::string, cmInstallRuntimeDependencySet*>
+ RuntimeDependencySetsByName;
+
#if !defined(CMAKE_BOOTSTRAP)
// Pool of file locks
cmFileLockPool FileLockPool;
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index c9bb467..79109b5 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,25 @@ 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::string runtimeDependencySetArg;
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.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
+ 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 +537,49 @@ bool HandleTargetsMode(std::vector<std::string> const& args,
return false;
}
+ cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
+ if (withRuntimeDependencies) {
+ if (!runtimeDependencySetArg.empty()) {
+ status.SetError("TARGETS cannot have both RUNTIME_DEPENDENCIES and "
+ "RUNTIME_DEPENDENCY_SET.");
+ return false;
+ }
+ 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();
+ } else if (!runtimeDependencySetArg.empty()) {
+ auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ system)) {
+ status.SetError(cmStrCat(
+ "TARGETS RUNTIME_DEPENDENCY_SET is not supported on system \"", system,
+ '"'));
+ return false;
+ }
+ runtimeDependencySet =
+ helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
+ runtimeDependencySetArg);
+ }
+
// Select the mode for installing symlinks to versioned shared libraries.
cmInstallTargetGenerator::NamelinkModeType namelinkMode =
cmInstallTargetGenerator::NamelinkModeNone;
@@ -546,6 +724,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 +772,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 +817,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 +872,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 +886,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 +1017,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) {
@@ -895,9 +1098,11 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
// now parse the generic args (i.e. the ones not specialized on LIBRARY,
// RUNTIME etc. (see above)
std::vector<std::string> targetList;
+ std::string runtimeDependencySetArg;
std::vector<std::string> unknownArgs;
cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
- genericArgs.Bind("IMPORTED_RUNTIME_ARTIFACTS"_s, targetList);
+ genericArgs.Bind("IMPORTED_RUNTIME_ARTIFACTS"_s, targetList)
+ .Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
genericArgs.Parse(genericArgVector, &unknownArgs);
bool success = genericArgs.Finalize();
@@ -936,6 +1141,22 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
return false;
}
+ cmInstallRuntimeDependencySet* runtimeDependencySet = nullptr;
+ if (!runtimeDependencySetArg.empty()) {
+ auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ system)) {
+ status.SetError(
+ cmStrCat("IMPORTED_RUNTIME_ARTIFACTS RUNTIME_DEPENDENCY_SET is not "
+ "supported on system \"",
+ system, '"'));
+ return false;
+ }
+ runtimeDependencySet =
+ helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
+ runtimeDependencySetArg);
+ }
+
// Check if there is something to do.
if (targetList.empty()) {
return true;
@@ -1014,6 +1235,9 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
if (target.IsDLLPlatform()) {
runtimeGenerator = createInstallGenerator(
target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddLibrary(runtimeGenerator.get());
+ }
} else if (target.IsFrameworkOnApple()) {
if (frameworkArgs.GetDestination().empty()) {
status.SetError(cmStrCat("IMPORTED_RUNTIME_ARTIFACTS given no "
@@ -1024,14 +1248,23 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
}
frameworkGenerator = createInstallGenerator(
target, frameworkArgs, frameworkArgs.GetDestination());
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddLibrary(frameworkGenerator.get());
+ }
} else {
libraryGenerator = createInstallGenerator(
target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddLibrary(libraryGenerator.get());
+ }
}
break;
case cmStateEnums::MODULE_LIBRARY:
libraryGenerator = createInstallGenerator(
target, libraryArgs, helper.GetLibraryDestination(&libraryArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddModule(libraryGenerator.get());
+ }
break;
case cmStateEnums::EXECUTABLE:
if (target.IsAppBundleOnApple()) {
@@ -1044,9 +1277,18 @@ bool HandleImportedRuntimeArtifactsMode(std::vector<std::string> const& args,
}
bundleGenerator = createInstallGenerator(
target, bundleArgs, bundleArgs.GetDestination());
+ if (runtimeDependencySet) {
+ if (!AddBundleExecutable(helper, runtimeDependencySet,
+ bundleGenerator.get())) {
+ return false;
+ }
+ }
} else {
runtimeGenerator = createInstallGenerator(
target, runtimeArgs, helper.GetRuntimeDestination(&runtimeArgs));
+ if (runtimeDependencySet) {
+ runtimeDependencySet->AddExecutable(runtimeGenerator.get());
+ }
}
break;
default:
@@ -1700,6 +1942,120 @@ bool HandleExportMode(std::vector<std::string> const& args,
return true;
}
+bool HandleRuntimeDependencySetMode(std::vector<std::string> const& args,
+ cmExecutionStatus& status)
+{
+ Helper helper(status);
+
+ auto system = helper.Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!cmRuntimeDependencyArchive::PlatformSupportsRuntimeDependencies(
+ system)) {
+ status.SetError(cmStrCat(
+ "RUNTIME_DEPENDENCY_SET is not supported on system \"", system, '"'));
+ return false;
+ }
+
+ // This is the RUNTIME_DEPENDENCY_SET mode.
+ cmInstallRuntimeDependencySet* runtimeDependencySet;
+
+ struct ArgVectors
+ {
+ std::vector<std::string> Library;
+ std::vector<std::string> Runtime;
+ std::vector<std::string> Framework;
+ };
+
+ static auto const argHelper = cmArgumentParser<ArgVectors>{}
+ .Bind("LIBRARY"_s, &ArgVectors::Library)
+ .Bind("RUNTIME"_s, &ArgVectors::Runtime)
+ .Bind("FRAMEWORK"_s, &ArgVectors::Framework);
+
+ std::vector<std::string> genericArgVector;
+ ArgVectors const argVectors = argHelper.Parse(args, &genericArgVector);
+
+ // now parse the generic args (i.e. the ones not specialized on LIBRARY,
+ // RUNTIME, FRAMEWORK etc. (see above)
+ // These generic args also contain the runtime dependency set
+ std::string runtimeDependencySetArg;
+ std::vector<std::string> runtimeDependencyArgVector;
+ std::vector<std::string> parsedArgs;
+ cmInstallCommandArguments genericArgs(helper.DefaultComponentName);
+ genericArgs.Bind("RUNTIME_DEPENDENCY_SET"_s, runtimeDependencySetArg);
+ genericArgs.Parse(genericArgVector, &runtimeDependencyArgVector, nullptr,
+ &parsedArgs);
+ bool success = genericArgs.Finalize();
+
+ cmInstallCommandArguments libraryArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments runtimeArgs(helper.DefaultComponentName);
+ cmInstallCommandArguments frameworkArgs(helper.DefaultComponentName);
+
+ // Now also parse the file(GET_RUNTIME_DEPENDENCY) args
+ std::vector<std::string> unknownArgs;
+ auto runtimeDependencyArgs = RuntimeDependenciesArgHelper.Parse(
+ runtimeDependencyArgVector, &unknownArgs);
+
+ // now parse the args for specific parts of the target (e.g. LIBRARY,
+ // RUNTIME, FRAMEWORK etc.
+ libraryArgs.Parse(argVectors.Library, &unknownArgs);
+ runtimeArgs.Parse(argVectors.Runtime, &unknownArgs);
+ frameworkArgs.Parse(argVectors.Framework, &unknownArgs);
+
+ libraryArgs.SetGenericArguments(&genericArgs);
+ runtimeArgs.SetGenericArguments(&genericArgs);
+ frameworkArgs.SetGenericArguments(&genericArgs);
+
+ success = success && libraryArgs.Finalize();
+ success = success && runtimeArgs.Finalize();
+ success = success && frameworkArgs.Finalize();
+
+ if (!success) {
+ return false;
+ }
+
+ if (!unknownArgs.empty()) {
+ helper.SetError(
+ cmStrCat("RUNTIME_DEPENDENCY_SET given unknown argument \"",
+ unknownArgs.front(), "\"."));
+ return false;
+ }
+
+ if (runtimeDependencySetArg.empty()) {
+ helper.SetError(
+ "RUNTIME_DEPENDENCY_SET not given a runtime dependency set.");
+ return false;
+ }
+
+ runtimeDependencySet =
+ helper.Makefile->GetGlobalGenerator()->GetNamedRuntimeDependencySet(
+ runtimeDependencySetArg);
+
+ bool installsRuntime = false;
+ bool installsLibrary = false;
+ bool installsFramework = false;
+
+ AddInstallRuntimeDependenciesGenerator(
+ helper, runtimeDependencySet, runtimeArgs, libraryArgs, frameworkArgs,
+ std::move(runtimeDependencyArgs), installsRuntime, installsLibrary,
+ installsFramework);
+
+ // Tell the global generator about any installation component names
+ // specified
+ if (installsLibrary) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ libraryArgs.GetComponent());
+ }
+ if (installsRuntime) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ runtimeArgs.GetComponent());
+ }
+ if (installsFramework) {
+ helper.Makefile->GetGlobalGenerator()->AddInstallComponent(
+ frameworkArgs.GetComponent());
+ }
+
+ return true;
+}
+
bool Helper::MakeFilesFullPath(const char* modeName,
const std::vector<std::string>& relFiles,
std::vector<std::string>& absFiles)
@@ -1934,6 +2290,7 @@ bool cmInstallCommand(std::vector<std::string> const& args,
{ "DIRECTORY"_s, HandleDirectoryMode },
{ "EXPORT"_s, HandleExportMode },
{ "EXPORT_ANDROID_MK"_s, HandleExportAndroidMKMode },
+ { "RUNTIME_DEPENDENCY_SET"_s, HandleRuntimeDependencySetMode },
};
return subcommand(args[0], args, status);
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/cmInstallRuntimeDependencySet.cxx b/Source/cmInstallRuntimeDependencySet.cxx
new file mode 100644
index 0000000..0cef49a
--- /dev/null
+++ b/Source/cmInstallRuntimeDependencySet.cxx
@@ -0,0 +1,95 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmInstallRuntimeDependencySet.h"
+
+#include <set>
+#include <string>
+#include <utility>
+
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallImportedRuntimeArtifactsGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmStateTypes.h"
+#include "cmTargetDepend.h"
+
+cmInstallRuntimeDependencySet::cmInstallRuntimeDependencySet(std::string name)
+ : Name(std::move(name))
+{
+}
+
+void cmInstallRuntimeDependencySet::AddExecutable(
+ std::unique_ptr<Item> executable)
+{
+ this->Executables.push_back(std::move(executable));
+}
+
+void cmInstallRuntimeDependencySet::AddLibrary(std::unique_ptr<Item> library)
+{
+ this->Libraries.push_back(std::move(library));
+}
+
+void cmInstallRuntimeDependencySet::AddModule(std::unique_ptr<Item> module)
+{
+ this->Modules.push_back(std::move(module));
+}
+
+bool cmInstallRuntimeDependencySet::AddBundleExecutable(
+ std::unique_ptr<Item> bundleExecutable)
+{
+ if (this->BundleExecutable) {
+ return false;
+ }
+ this->BundleExecutable = bundleExecutable.get();
+ this->AddExecutable(std::move(bundleExecutable));
+ return true;
+}
+
+std::string cmInstallRuntimeDependencySet::TargetItem::GetItemPath(
+ const std::string& config) const
+{
+ return this->Target->GetTarget()->GetFullPath(config);
+}
+
+namespace {
+const std::set<const cmGeneratorTarget*>& GetTargetDependsClosure(
+ std::map<const cmGeneratorTarget*, std::set<const cmGeneratorTarget*>>&
+ targetDepends,
+ const cmGeneratorTarget* tgt)
+{
+ auto it = targetDepends.insert({ tgt, {} });
+ auto& retval = it.first->second;
+ if (it.second) {
+ auto const& deps = tgt->GetGlobalGenerator()->GetTargetDirectDepends(tgt);
+ for (auto const& dep : deps) {
+ if (!dep.IsCross() && dep.IsLink()) {
+ auto type = dep->GetType();
+ if (type == cmStateEnums::EXECUTABLE ||
+ type == cmStateEnums::SHARED_LIBRARY ||
+ type == cmStateEnums::MODULE_LIBRARY) {
+ retval.insert(dep);
+ }
+ auto const& depDeps = GetTargetDependsClosure(targetDepends, dep);
+ retval.insert(depDeps.begin(), depDeps.end());
+ }
+ }
+ }
+ return retval;
+}
+}
+
+void cmInstallRuntimeDependencySet::TargetItem::AddPostExcludeFiles(
+ const std::string& config, std::set<std::string>& files,
+ cmInstallRuntimeDependencySet* set) const
+{
+ for (auto const* dep : GetTargetDependsClosure(set->TargetDepends,
+ this->Target->GetTarget())) {
+ files.insert(dep->GetFullPath(config));
+ }
+}
+
+std::string cmInstallRuntimeDependencySet::ImportedTargetItem::GetItemPath(
+ const std::string& config) const
+{
+ return this->Target->GetTarget()->GetFullPath(config);
+}
diff --git a/Source/cmInstallRuntimeDependencySet.h b/Source/cmInstallRuntimeDependencySet.h
new file mode 100644
index 0000000..7f51624
--- /dev/null
+++ b/Source/cmInstallRuntimeDependencySet.h
@@ -0,0 +1,163 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include <cm/memory>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+class cmGeneratorTarget;
+class cmInstallImportedRuntimeArtifactsGenerator;
+class cmInstallTargetGenerator;
+
+class cmInstallRuntimeDependencySet
+{
+public:
+ cmInstallRuntimeDependencySet(std::string name = "");
+
+ cmInstallRuntimeDependencySet(const cmInstallRuntimeDependencySet&) = delete;
+ cmInstallRuntimeDependencySet& operator=(
+ const cmInstallRuntimeDependencySet&) = delete;
+
+ cm::string_view GetName() const { return this->Name; }
+
+ cm::string_view GetDisplayName() const
+ {
+ if (this->Name.empty()) {
+ return "<anonymous>"_s;
+ }
+ return this->Name;
+ }
+
+ class Item
+ {
+ public:
+ virtual ~Item() = default;
+
+ virtual std::string GetItemPath(const std::string& config) const = 0;
+
+ virtual void AddPostExcludeFiles(
+ const std::string& /*config*/, std::set<std::string>& /*files*/,
+ cmInstallRuntimeDependencySet* /*set*/) const
+ {
+ }
+ };
+
+ class TargetItem : public Item
+ {
+ public:
+ TargetItem(cmInstallTargetGenerator* target)
+ : Target(target)
+ {
+ }
+
+ std::string GetItemPath(const std::string& config) const override;
+
+ void AddPostExcludeFiles(
+ const std::string& config, std::set<std::string>& files,
+ cmInstallRuntimeDependencySet* set) const override;
+
+ private:
+ cmInstallTargetGenerator* Target;
+ };
+
+ class ImportedTargetItem : public Item
+ {
+ public:
+ ImportedTargetItem(cmInstallImportedRuntimeArtifactsGenerator* target)
+ : Target(target)
+ {
+ }
+
+ std::string GetItemPath(const std::string& config) const override;
+
+ private:
+ cmInstallImportedRuntimeArtifactsGenerator* Target;
+ };
+
+ void AddExecutable(std::unique_ptr<Item> executable);
+ void AddLibrary(std::unique_ptr<Item> library);
+ void AddModule(std::unique_ptr<Item> module);
+ bool AddBundleExecutable(std::unique_ptr<Item> bundleExecutable);
+
+ void AddExecutable(cmInstallTargetGenerator* executable)
+ {
+ this->AddExecutable(cm::make_unique<TargetItem>(executable));
+ }
+
+ void AddLibrary(cmInstallTargetGenerator* library)
+ {
+ this->AddLibrary(cm::make_unique<TargetItem>(library));
+ }
+
+ void AddModule(cmInstallTargetGenerator* module)
+ {
+ this->AddModule(cm::make_unique<TargetItem>(module));
+ }
+
+ bool AddBundleExecutable(cmInstallTargetGenerator* bundleExecutable)
+ {
+ return this->AddBundleExecutable(
+ cm::make_unique<TargetItem>(bundleExecutable));
+ }
+
+ void AddExecutable(cmInstallImportedRuntimeArtifactsGenerator* executable)
+ {
+ this->AddExecutable(cm::make_unique<ImportedTargetItem>(executable));
+ }
+
+ void AddLibrary(cmInstallImportedRuntimeArtifactsGenerator* library)
+ {
+ this->AddLibrary(cm::make_unique<ImportedTargetItem>(library));
+ }
+
+ void AddModule(cmInstallImportedRuntimeArtifactsGenerator* module)
+ {
+ this->AddModule(cm::make_unique<ImportedTargetItem>(module));
+ }
+
+ bool AddBundleExecutable(
+ cmInstallImportedRuntimeArtifactsGenerator* bundleExecutable)
+ {
+ return this->AddBundleExecutable(
+ cm::make_unique<ImportedTargetItem>(bundleExecutable));
+ }
+
+ const std::vector<std::unique_ptr<Item>>& GetExecutables() const
+ {
+ return this->Executables;
+ }
+
+ const std::vector<std::unique_ptr<Item>>& GetLibraries() const
+ {
+ return this->Libraries;
+ }
+
+ const std::vector<std::unique_ptr<Item>>& GetModules() const
+ {
+ return this->Modules;
+ }
+
+ Item* GetBundleExecutable() const { return this->BundleExecutable; }
+
+ bool Empty() const
+ {
+ return this->Executables.empty() && this->Libraries.empty() &&
+ this->Modules.empty();
+ }
+
+private:
+ std::string Name;
+ std::vector<std::unique_ptr<Item>> Executables;
+ std::vector<std::unique_ptr<Item>> Libraries;
+ std::vector<std::unique_ptr<Item>> Modules;
+ Item* BundleExecutable = nullptr;
+
+ std::map<const cmGeneratorTarget*, std::set<const cmGeneratorTarget*>>
+ TargetDepends;
+};
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 a6ed523..26f255d 100644
--- a/Source/cmRuntimeDependencyArchive.cxx
+++ b/Source/cmRuntimeDependencyArchive.cxx
@@ -198,25 +198,26 @@ void cmRuntimeDependencyArchive::SetError(const std::string& e)
this->Status.SetError(e);
}
-std::string cmRuntimeDependencyArchive::GetBundleExecutable()
+const std::string& cmRuntimeDependencyArchive::GetBundleExecutable() const
{
return this->BundleExecutable;
}
const std::vector<std::string>&
-cmRuntimeDependencyArchive::GetSearchDirectories()
+cmRuntimeDependencyArchive::GetSearchDirectories() const
{
return this->SearchDirectories;
}
-std::string cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
+const std::string& cmRuntimeDependencyArchive::GetGetRuntimeDependenciesTool()
+ const
{
return this->GetMakefile()->GetSafeDefinition(
"CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL");
}
bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
- const std::string& search, std::vector<std::string>& command)
+ const std::string& search, std::vector<std::string>& command) const
{
// First see if it was supplied by the user
std::string toolCommand = this->GetMakefile()->GetSafeDefinition(
@@ -309,7 +310,7 @@ bool cmRuntimeDependencyArchive::GetGetRuntimeDependenciesCommand(
return false;
}
-bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
+bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name) const
{
cmsys::RegularExpressionMatch match;
auto const regexMatch =
@@ -326,7 +327,7 @@ bool cmRuntimeDependencyArchive::IsPreExcluded(const std::string& name)
regexSearch(this->PreExcludeRegexes);
}
-bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
+bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name) const
{
cmsys::RegularExpressionMatch match;
auto const regexMatch =
@@ -353,9 +354,9 @@ bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name)
fileSearch(this->PostExcludeFiles)));
}
-void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
- const std::string& path,
- bool& unique)
+void cmRuntimeDependencyArchive::AddResolvedPath(
+ const std::string& name, const std::string& path, bool& unique,
+ std::vector<std::string> rpaths)
{
auto it = this->ResolvedPaths.emplace(name, std::set<std::string>{}).first;
unique = true;
@@ -366,6 +367,7 @@ void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
}
}
it->second.insert(path);
+ this->RPaths[path] = std::move(rpaths);
}
void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
@@ -373,18 +375,33 @@ void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
this->UnresolvedPaths.insert(name);
}
-cmMakefile* cmRuntimeDependencyArchive::GetMakefile()
+cmMakefile* cmRuntimeDependencyArchive::GetMakefile() const
{
return &this->Status.GetMakefile();
}
const std::map<std::string, std::set<std::string>>&
-cmRuntimeDependencyArchive::GetResolvedPaths()
+cmRuntimeDependencyArchive::GetResolvedPaths() const
{
return this->ResolvedPaths;
}
const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
+ const
{
return this->UnresolvedPaths;
}
+
+const std::map<std::string, std::vector<std::string>>&
+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 1dc3261..b170815 100644
--- a/Source/cmRuntimeDependencyArchive.h
+++ b/Source/cmRuntimeDependencyArchive.h
@@ -36,21 +36,24 @@ public:
void SetError(const std::string& e);
- std::string GetBundleExecutable();
- const std::vector<std::string>& GetSearchDirectories();
- std::string GetGetRuntimeDependenciesTool();
- bool GetGetRuntimeDependenciesCommand(const std::string& search,
- std::vector<std::string>& command);
- bool IsPreExcluded(const std::string& name);
- bool IsPostExcluded(const std::string& name);
+ const std::string& GetBundleExecutable() const;
+ const std::vector<std::string>& GetSearchDirectories() const;
+ const std::string& GetGetRuntimeDependenciesTool() const;
+ bool GetGetRuntimeDependenciesCommand(
+ const std::string& search, std::vector<std::string>& command) const;
+ bool IsPreExcluded(const std::string& name) const;
+ bool IsPostExcluded(const std::string& name) const;
void AddResolvedPath(const std::string& name, const std::string& path,
- bool& unique);
+ bool& unique, std::vector<std::string> rpaths = {});
void AddUnresolvedPath(const std::string& name);
- cmMakefile* GetMakefile();
- const std::map<std::string, std::set<std::string>>& GetResolvedPaths();
- const std::set<std::string>& GetUnresolvedPaths();
+ cmMakefile* GetMakefile() const;
+ const std::map<std::string, std::set<std::string>>& GetResolvedPaths() const;
+ 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;
@@ -70,4 +73,5 @@ private:
std::vector<std::string> PostExcludeFilesStrict;
std::map<std::string, std::set<std::string>> ResolvedPaths;
std::set<std::string> UnresolvedPaths;
+ std::map<std::string, std::vector<std::string>> RPaths;
};
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 9b81bf2..10d2e50 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -14,6 +14,7 @@
#include "cmSystemTools.h"
+#include <cm/optional>
#include <cmext/algorithm>
#include <cm3p/uv.h>
@@ -65,6 +66,7 @@
#include <cstdlib>
#include <cstring>
#include <ctime>
+#include <functional>
#include <iostream>
#include <sstream>
#include <utility>
@@ -2524,6 +2526,7 @@ std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have,
#endif
#if defined(CMake_USE_ELF_PARSER)
+namespace {
struct cmSystemToolsRPathInfo
{
unsigned long Position;
@@ -2531,15 +2534,15 @@ struct cmSystemToolsRPathInfo
std::string Name;
std::string Value;
};
-#endif
+
+using EmptyCallback = std::function<bool(std::string*, const cmELF&)>;
+using AdjustCallback = std::function<bool(
+ cm::optional<std::string>&, const std::string&, const char*, std::string*)>;
// FIXME: Dispatch if multiple formats are supported.
-#if defined(CMake_USE_ELF_PARSER)
-bool cmSystemTools::ChangeRPath(std::string const& file,
- std::string const& oldRPath,
- std::string const& newRPath,
- bool removeEnvironmentRPath, std::string* emsg,
- bool* changed)
+bool AdjustRPath(std::string const& file, const EmptyCallback& emptyCallback,
+ const AdjustCallback& adjustCallback, std::string* emsg,
+ bool* changed)
{
if (changed) {
*changed = false;
@@ -2566,17 +2569,7 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
++se_count;
}
if (se_count == 0) {
- if (newRPath.empty()) {
- // The new rpath is empty and there is no rpath anyway so it is
- // okay.
- return true;
- }
- if (emsg) {
- *emsg =
- cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
- elf.GetErrorMessage());
- }
- return false;
+ return emptyCallback(emsg, elf);
}
for (int i = 0; i < se_count; ++i) {
@@ -2586,68 +2579,38 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
continue;
}
- // Make sure the current rpath contains the old rpath.
- std::string::size_type pos =
- cmSystemToolsFindRPath(se[i]->Value, oldRPath);
- if (pos == std::string::npos) {
- // If it contains the new rpath instead then it is okay.
- if (cmSystemToolsFindRPath(se[i]->Value, newRPath) !=
- std::string::npos) {
- remove_rpath = false;
- continue;
- }
- if (emsg) {
- std::ostringstream e;
- /* clang-format off */
- e << "The current " << se_name[i] << " is:\n"
- << " " << se[i]->Value << "\n"
- << "which does not contain:\n"
- << " " << oldRPath << "\n"
- << "as was expected.";
- /* clang-format on */
- *emsg = e.str();
- }
- return false;
- }
-
// Store information about the entry in the file.
rp[rp_count].Position = se[i]->Position;
rp[rp_count].Size = se[i]->Size;
rp[rp_count].Name = se_name[i];
- std::string::size_type prefix_len = pos;
-
- // If oldRPath was at the end of the file's RPath, and newRPath is empty,
- // we should remove the unnecessary ':' at the end.
- if (newRPath.empty() && pos > 0 && se[i]->Value[pos - 1] == ':' &&
- pos + oldRPath.length() == se[i]->Value.length()) {
- prefix_len--;
- }
-
- // Construct the new value which preserves the part of the path
- // not being changed.
- if (!removeEnvironmentRPath) {
- rp[rp_count].Value = se[i]->Value.substr(0, prefix_len);
+ // Adjust the rpath.
+ cm::optional<std::string> outRPath;
+ if (!adjustCallback(outRPath, se[i]->Value, se_name[i], emsg)) {
+ return false;
}
- rp[rp_count].Value += newRPath;
- rp[rp_count].Value += se[i]->Value.substr(pos + oldRPath.length());
- if (!rp[rp_count].Value.empty()) {
- remove_rpath = false;
- }
+ if (outRPath) {
+ if (!outRPath->empty()) {
+ remove_rpath = false;
+ }
- // Make sure there is enough room to store the new rpath and at
- // least one null terminator.
- if (rp[rp_count].Size < rp[rp_count].Value.length() + 1) {
- if (emsg) {
- *emsg = cmStrCat("The replacement path is too long for the ",
- se_name[i], " entry.");
+ // Make sure there is enough room to store the new rpath and at
+ // least one null terminator.
+ if (rp[rp_count].Size < outRPath->length() + 1) {
+ if (emsg) {
+ *emsg = cmStrCat("The replacement path is too long for the ",
+ se_name[i], " entry.");
+ }
+ return false;
}
- return false;
- }
- // This entry is ready for update.
- ++rp_count;
+ // This entry is ready for update.
+ rp[rp_count].Value = std::move(*outRPath);
+ ++rp_count;
+ } else {
+ remove_rpath = false;
+ }
}
}
@@ -2706,6 +2669,99 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
}
return true;
}
+
+std::function<bool(std::string*, const cmELF&)> MakeEmptyCallback(
+ const std::string& newRPath)
+{
+ return [newRPath](std::string* emsg, const cmELF& elf) -> bool {
+ if (newRPath.empty()) {
+ // The new rpath is empty and there is no rpath anyway so it is
+ // okay.
+ return true;
+ }
+ if (emsg) {
+ *emsg =
+ cmStrCat("No valid ELF RPATH or RUNPATH entry exists in the file; ",
+ elf.GetErrorMessage());
+ }
+ return false;
+ };
+};
+}
+
+bool cmSystemTools::ChangeRPath(std::string const& file,
+ std::string const& oldRPath,
+ std::string const& newRPath,
+ bool removeEnvironmentRPath, std::string* emsg,
+ bool* changed)
+{
+ auto adjustCallback = [oldRPath, newRPath, removeEnvironmentRPath](
+ cm::optional<std::string>& outRPath,
+ const std::string& inRPath, const char* se_name,
+ std::string* emsg2) -> bool {
+ // Make sure the current rpath contains the old rpath.
+ std::string::size_type pos = cmSystemToolsFindRPath(inRPath, oldRPath);
+ if (pos == std::string::npos) {
+ // If it contains the new rpath instead then it is okay.
+ if (cmSystemToolsFindRPath(inRPath, newRPath) != std::string::npos) {
+ return true;
+ }
+ if (emsg2) {
+ std::ostringstream e;
+ /* clang-format off */
+ e << "The current " << se_name << " is:\n"
+ << " " << inRPath << "\n"
+ << "which does not contain:\n"
+ << " " << oldRPath << "\n"
+ << "as was expected.";
+ /* clang-format on */
+ *emsg2 = e.str();
+ }
+ return false;
+ }
+
+ std::string::size_type prefix_len = pos;
+
+ // If oldRPath was at the end of the file's RPath, and newRPath is empty,
+ // we should remove the unnecessary ':' at the end.
+ if (newRPath.empty() && pos > 0 && inRPath[pos - 1] == ':' &&
+ pos + oldRPath.length() == inRPath.length()) {
+ prefix_len--;
+ }
+
+ // Construct the new value which preserves the part of the path
+ // not being changed.
+ outRPath.emplace();
+ if (!removeEnvironmentRPath) {
+ *outRPath += inRPath.substr(0, prefix_len);
+ }
+ *outRPath += newRPath;
+ *outRPath += inRPath.substr(pos + oldRPath.length());
+
+ return true;
+ };
+
+ return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
+ changed);
+}
+
+bool cmSystemTools::SetRPath(std::string const& file,
+ std::string const& newRPath, std::string* emsg,
+ bool* changed)
+{
+ auto adjustCallback = [newRPath](cm::optional<std::string>& outRPath,
+ const std::string& inRPath,
+ const char* /*se_name*/, std::string *
+ /*emsg*/) -> bool {
+ if (inRPath != newRPath) {
+ outRPath = newRPath;
+ }
+ return true;
+ };
+
+ return AdjustRPath(file, MakeEmptyCallback(newRPath), adjustCallback, emsg,
+ changed);
+}
#elif defined(CMake_USE_XCOFF_PARSER)
bool cmSystemTools::ChangeRPath(std::string const& file,
std::string const& oldRPath,
@@ -2775,6 +2831,13 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
}
return true;
}
+
+bool cmSystemTools::SetRPath(std::string const& /*file*/,
+ std::string const& /*newRPath*/,
+ std::string* /*emsg*/, bool* /*changed*/)
+{
+ return false;
+}
#else
bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
std::string const& /*oldRPath*/,
@@ -2784,6 +2847,13 @@ bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
{
return false;
}
+
+bool cmSystemTools::SetRPath(std::string const& /*file*/,
+ std::string const& /*newRPath*/,
+ std::string* /*emsg*/, bool* /*changed*/)
+{
+ return false;
+}
#endif
bool cmSystemTools::VersionCompare(cmSystemTools::CompareOp op,
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 5c3b5a9..44ccbf7 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -456,13 +456,17 @@ public:
static bool GuessLibraryInstallName(std::string const& fullPath,
std::string& soname);
- /** Try to set the RPATH in an ELF binary. */
+ /** Try to change the RPATH in an ELF binary. */
static bool ChangeRPath(std::string const& file, std::string const& oldRPath,
std::string const& newRPath,
bool removeEnvironmentRPath,
std::string* emsg = nullptr,
bool* changed = nullptr);
+ /** Try to set the RPATH in an ELF binary. */
+ static bool SetRPath(std::string const& file, std::string const& newRPath,
+ std::string* emsg = nullptr, bool* changed = nullptr);
+
/** Try to remove the RPATH from an ELF binary. */
static bool RemoveRPath(std::string const& file, std::string* emsg = nullptr,
bool* removed = nullptr);