diff options
Diffstat (limited to 'Source/cmFileCommand.cxx')
-rw-r--r-- | Source/cmFileCommand.cxx | 229 |
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; } |