summaryrefslogtreecommitdiffstats
path: root/Source/cmFileCommand.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmFileCommand.cxx')
-rw-r--r--Source/cmFileCommand.cxx229
1 files changed, 204 insertions, 25 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 7a3954e..22f0d1f 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -12,13 +12,16 @@
#include <assert.h>
#include <cmath>
#include <ctype.h>
-#include <memory> // IWYU pragma: keep
+#include <map>
+#include <set>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <utility>
#include <vector>
+#include "cm_memory.hxx"
+
#include "cmAlgorithms.h"
#include "cmArgumentParser.h"
#include "cmCryptoHash.h"
@@ -34,6 +37,9 @@
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmRange.h"
+#include "cmRuntimeDependencyArchive.h"
+#include "cmState.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTimestamp.h"
#include "cm_sys_stat.h"
@@ -184,6 +190,9 @@ bool cmFileCommand::InitialPass(std::vector<std::string> const& args,
if (subCommand == "CREATE_LINK") {
return this->HandleCreateLinkCommand(args);
}
+ if (subCommand == "GET_RUNTIME_DEPENDENCIES") {
+ return this->HandleGetRuntimeDependenciesCommand(args);
+ }
std::string e = "does not recognize sub-command " + subCommand;
this->SetError(e);
@@ -357,7 +366,7 @@ bool cmFileCommand::HandleReadCommand(std::vector<std::string> const& args)
}
}
}
- this->Makefile->AddDefinition(variable, output.c_str());
+ this->Makefile->AddDefinition(variable, output);
return true;
}
@@ -375,7 +384,7 @@ bool cmFileCommand::HandleHashCommand(std::vector<std::string> const& args)
if (hash) {
std::string out = hash->HashFile(args[1]);
if (!out.empty()) {
- this->Makefile->AddDefinition(args[2], out.c_str());
+ this->Makefile->AddDefinition(args[2], out);
return true;
}
std::ostringstream e;
@@ -743,7 +752,7 @@ bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args)
}
// Save the output in a makefile variable.
- this->Makefile->AddDefinition(outVar, output.c_str());
+ this->Makefile->AddDefinition(outVar, output);
return true;
}
@@ -930,7 +939,7 @@ bool cmFileCommand::HandleGlobCommand(std::vector<std::string> const& args,
std::sort(files.begin(), files.end());
files.erase(std::unique(files.begin(), files.end()), files.end());
- this->Makefile->AddDefinition(variable, cmJoin(files, ";").c_str());
+ this->Makefile->AddDefinition(variable, cmJoin(files, ";"));
return true;
}
@@ -1063,6 +1072,7 @@ bool cmFileCommand::HandleRPathChangeCommand(
std::string file;
const char* oldRPath = nullptr;
const char* newRPath = nullptr;
+ bool removeEnvironmentRPath = false;
enum Doing
{
DoingNone,
@@ -1078,6 +1088,8 @@ bool cmFileCommand::HandleRPathChangeCommand(
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;
@@ -1116,7 +1128,9 @@ bool cmFileCommand::HandleRPathChangeCommand(
cmFileTimes const ft(file);
std::string emsg;
bool changed;
- if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed)) {
+
+ if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath,
+ removeEnvironmentRPath, &emsg, &changed)) {
std::ostringstream e;
/* clang-format off */
e << "RPATH_CHANGE could not write new RPATH:\n"
@@ -1290,14 +1304,14 @@ bool cmFileCommand::HandleReadElfCommand(std::vector<std::string> const& args)
if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
std::string rpath(se_rpath->Value);
std::replace(rpath.begin(), rpath.end(), ':', ';');
- this->Makefile->AddDefinition(arguments.RPath, rpath.c_str());
+ this->Makefile->AddDefinition(arguments.RPath, rpath);
}
}
if (!arguments.RunPath.empty()) {
if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
std::string runpath(se_runpath->Value);
std::replace(runpath.begin(), runpath.end(), ':', ';');
- this->Makefile->AddDefinition(arguments.RunPath, runpath.c_str());
+ this->Makefile->AddDefinition(arguments.RunPath, runpath);
}
}
@@ -1308,7 +1322,7 @@ bool cmFileCommand::HandleReadElfCommand(std::vector<std::string> const& args)
this->SetError(error);
return false;
}
- this->Makefile->AddDefinition(arguments.Error, error.c_str());
+ this->Makefile->AddDefinition(arguments.Error, error);
return true;
#endif
}
@@ -1346,7 +1360,7 @@ bool cmFileCommand::HandleRelativePathCommand(
}
std::string res = cmSystemTools::RelativePath(directoryName, fileName);
- this->Makefile->AddDefinition(outVar, res.c_str());
+ this->Makefile->AddDefinition(outVar, res);
return true;
}
@@ -1452,7 +1466,7 @@ bool cmFileCommand::HandleCMakePathCommand(
std::string value = cmJoin(
cmMakeRange(path).transform(nativePath ? ToNativePath : ToCMakePath), ";");
- this->Makefile->AddDefinition(args[2], value.c_str());
+ this->Makefile->AddDefinition(args[2], value);
return true;
}
@@ -1792,7 +1806,7 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args)
if (!statusVar.empty()) {
std::ostringstream result;
result << 0 << ";\"" << msg;
- this->Makefile->AddDefinition(statusVar, result.str().c_str());
+ this->Makefile->AddDefinition(statusVar, result.str());
}
return true;
}
@@ -1941,7 +1955,7 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args)
std::ostringstream result;
result << static_cast<int>(res) << ";\"" << ::curl_easy_strerror(res)
<< "\"";
- this->Makefile->AddDefinition(statusVar, result.str().c_str());
+ this->Makefile->AddDefinition(statusVar, result.str());
}
::curl_global_cleanup();
@@ -1973,7 +1987,7 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args)
std::string status = "1;HASH mismatch: "
"expected: " +
expectedHash + " actual: " + actualHash;
- this->Makefile->AddDefinition(statusVar, status.c_str());
+ this->Makefile->AddDefinition(statusVar, status);
}
this->SetError(oss.str());
@@ -2228,7 +2242,7 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args)
std::ostringstream result;
result << static_cast<int>(res) << ";\"" << ::curl_easy_strerror(res)
<< "\"";
- this->Makefile->AddDefinition(statusVar, result.str().c_str());
+ this->Makefile->AddDefinition(statusVar, result.str());
}
::curl_global_cleanup();
@@ -2253,7 +2267,7 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args)
log += "\n";
}
- this->Makefile->AddDefinition(logVar, log.c_str());
+ this->Makefile->AddDefinition(logVar, log);
}
return true;
@@ -2471,7 +2485,7 @@ bool cmFileCommand::HandleLockCommand(std::vector<std::string> const& args)
}
if (!resultVariable.empty()) {
- this->Makefile->AddDefinition(resultVariable, result.c_str());
+ this->Makefile->AddDefinition(resultVariable, result);
}
return true;
@@ -2520,7 +2534,7 @@ bool cmFileCommand::HandleTimestampCommand(
cmTimestamp timestamp;
std::string result =
timestamp.FileModificationTime(filename.c_str(), formatString, utcFlag);
- this->Makefile->AddDefinition(outputVariable, result.c_str());
+ this->Makefile->AddDefinition(outputVariable, result);
return true;
}
@@ -2548,8 +2562,7 @@ bool cmFileCommand::HandleSizeCommand(std::vector<std::string> const& args)
}
this->Makefile->AddDefinition(
- outputVariable,
- std::to_string(cmSystemTools::FileLength(filename)).c_str());
+ outputVariable, std::to_string(cmSystemTools::FileLength(filename)));
return true;
}
@@ -2576,7 +2589,7 @@ bool cmFileCommand::HandleReadSymlinkCommand(
return false;
}
- this->Makefile->AddDefinition(outputVariable, result.c_str());
+ this->Makefile->AddDefinition(outputVariable, result);
return true;
}
@@ -2622,7 +2635,7 @@ bool cmFileCommand::HandleCreateLinkCommand(
if (fileName == newFileName) {
result = "CREATE_LINK cannot use same file and newfile";
if (!arguments.Result.empty()) {
- this->Makefile->AddDefinition(arguments.Result, result.c_str());
+ this->Makefile->AddDefinition(arguments.Result, result);
return true;
}
this->SetError(result);
@@ -2633,7 +2646,7 @@ bool cmFileCommand::HandleCreateLinkCommand(
if (!arguments.Symbolic && !cmSystemTools::FileExists(fileName)) {
result = "Cannot hard link \'" + fileName + "\' as it does not exist.";
if (!arguments.Result.empty()) {
- this->Makefile->AddDefinition(arguments.Result, result.c_str());
+ this->Makefile->AddDefinition(arguments.Result, result);
return true;
}
this->SetError(result);
@@ -2650,7 +2663,7 @@ bool cmFileCommand::HandleCreateLinkCommand(
<< cmSystemTools::GetLastSystemError() << "\n";
if (!arguments.Result.empty()) {
- this->Makefile->AddDefinition(arguments.Result, e.str().c_str());
+ this->Makefile->AddDefinition(arguments.Result, e.str());
return true;
}
this->SetError(e.str());
@@ -2685,8 +2698,174 @@ bool cmFileCommand::HandleCreateLinkCommand(
}
if (!arguments.Result.empty()) {
- this->Makefile->AddDefinition(arguments.Result, result.c_str());
+ this->Makefile->AddDefinition(arguments.Result, result);
+ }
+
+ return true;
+}
+
+bool cmFileCommand::HandleGetRuntimeDependenciesCommand(
+ std::vector<std::string> const& args)
+{
+ static const std::set<std::string> supportedPlatforms = { "Windows", "Linux",
+ "Darwin" };
+ std::string platform =
+ this->Makefile->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
+ if (!supportedPlatforms.count(platform)) {
+ std::ostringstream e;
+ e << "GET_RUNTIME_DEPENDENCIES is not supported on system \"" << platform
+ << "\"";
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (this->Makefile->GetState()->GetMode() == cmState::Project) {
+ this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING,
+ "You have used file(GET_RUNTIME_DEPENDENCIES)"
+ " in project mode. This is probably not what "
+ "you intended to do. Instead, please consider"
+ " using it in an install(CODE) or "
+ "install(SCRIPT) command. For example:"
+ "\n install(CODE [["
+ "\n file(GET_RUNTIME_DEPENDENCIES"
+ "\n # ..."
+ "\n )"
+ "\n ]])");
+ }
+
+ struct Arguments
+ {
+ std::string ResolvedDependenciesVar;
+ std::string UnresolvedDependenciesVar;
+ std::string ConflictingDependenciesPrefix;
+ std::string BundleExecutable;
+ std::vector<std::string> Executables;
+ std::vector<std::string> Libraries;
+ std::vector<std::string> Directories;
+ std::vector<std::string> Modules;
+ std::vector<std::string> PreIncludeRegexes;
+ std::vector<std::string> PreExcludeRegexes;
+ std::vector<std::string> PostIncludeRegexes;
+ std::vector<std::string> PostExcludeRegexes;
+ };
+
+ static auto const parser =
+ cmArgumentParser<Arguments>{}
+ .Bind("RESOLVED_DEPENDENCIES_VAR"_s, &Arguments::ResolvedDependenciesVar)
+ .Bind("UNRESOLVED_DEPENDENCIES_VAR"_s,
+ &Arguments::UnresolvedDependenciesVar)
+ .Bind("CONFLICTING_DEPENDENCIES_PREFIX"_s,
+ &Arguments::ConflictingDependenciesPrefix)
+ .Bind("BUNDLE_EXECUTABLE"_s, &Arguments::BundleExecutable)
+ .Bind("EXECUTABLES"_s, &Arguments::Executables)
+ .Bind("LIBRARIES"_s, &Arguments::Libraries)
+ .Bind("MODULES"_s, &Arguments::Modules)
+ .Bind("DIRECTORIES"_s, &Arguments::Directories)
+ .Bind("PRE_INCLUDE_REGEXES"_s, &Arguments::PreIncludeRegexes)
+ .Bind("PRE_EXCLUDE_REGEXES"_s, &Arguments::PreExcludeRegexes)
+ .Bind("POST_INCLUDE_REGEXES"_s, &Arguments::PostIncludeRegexes)
+ .Bind("POST_EXCLUDE_REGEXES"_s, &Arguments::PostExcludeRegexes);
+
+ std::vector<std::string> unrecognizedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ auto parsedArgs =
+ parser.Parse(cmMakeRange(args).advance(1), &unrecognizedArguments,
+ &keywordsMissingValues);
+ auto argIt = unrecognizedArguments.begin();
+ if (argIt != unrecognizedArguments.end()) {
+ std::ostringstream e;
+ e << "Unrecognized argument: \"" << *argIt << "\"";
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ argIt = keywordsMissingValues.begin();
+ if (argIt != keywordsMissingValues.end()) {
+ std::ostringstream e;
+ e << "Keyword missing value: " << *argIt;
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ cmRuntimeDependencyArchive archive(
+ this, parsedArgs.Directories, parsedArgs.BundleExecutable,
+ parsedArgs.PreIncludeRegexes, parsedArgs.PreExcludeRegexes,
+ parsedArgs.PostIncludeRegexes, parsedArgs.PostExcludeRegexes);
+ if (!archive.Prepare()) {
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ if (!archive.GetRuntimeDependencies(
+ parsedArgs.Executables, parsedArgs.Libraries, parsedArgs.Modules)) {
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+
+ std::vector<std::string> deps, unresolvedDeps, conflictingDeps;
+ for (auto const& val : archive.GetResolvedPaths()) {
+ bool unique = true;
+ auto it = val.second.begin();
+ assert(it != val.second.end());
+ auto const& firstPath = *it;
+ while (++it != val.second.end()) {
+ if (!cmSystemTools::SameFile(firstPath, *it)) {
+ unique = false;
+ break;
+ }
+ }
+
+ if (unique) {
+ deps.push_back(firstPath);
+ } else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
+ conflictingDeps.push_back(val.first);
+ std::vector<std::string> paths;
+ paths.insert(paths.begin(), val.second.begin(), val.second.end());
+ std::string varName =
+ parsedArgs.ConflictingDependenciesPrefix + "_" + val.first;
+ std::string pathsStr = cmJoin(paths, ";");
+ this->Makefile->AddDefinition(varName, pathsStr);
+ } else {
+ std::ostringstream e;
+ e << "Multiple conflicting paths found for " << val.first << ":";
+ for (auto const& path : val.second) {
+ e << "\n " << path;
+ }
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
+ }
+ if (!archive.GetUnresolvedPaths().empty()) {
+ if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
+ unresolvedDeps.insert(unresolvedDeps.begin(),
+ archive.GetUnresolvedPaths().begin(),
+ archive.GetUnresolvedPaths().end());
+ } else {
+ auto it = archive.GetUnresolvedPaths().begin();
+ assert(it != archive.GetUnresolvedPaths().end());
+ std::ostringstream e;
+ e << "Could not resolve file " << *it;
+ this->SetError(e.str());
+ cmSystemTools::SetFatalErrorOccured();
+ return false;
+ }
}
+ if (!parsedArgs.ResolvedDependenciesVar.empty()) {
+ std::string val = cmJoin(deps, ";");
+ this->Makefile->AddDefinition(parsedArgs.ResolvedDependenciesVar, val);
+ }
+ if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
+ std::string val = cmJoin(unresolvedDeps, ";");
+ this->Makefile->AddDefinition(parsedArgs.UnresolvedDependenciesVar, val);
+ }
+ if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
+ std::string val = cmJoin(conflictingDeps, ";");
+ this->Makefile->AddDefinition(
+ parsedArgs.ConflictingDependenciesPrefix + "_FILENAMES", val);
+ }
return true;
}