cmake/Source/cmCustomCommandGenerator.cxx

261 lines
7.7 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
2011-01-16 11:35:12 +01:00
#include "cmCustomCommandGenerator.h"
2020-02-01 23:06:01 +01:00
#include <cstddef>
#include <memory>
#include <utility>
2020-08-30 11:54:41 +02:00
#include <cmext/algorithm>
2015-11-17 17:22:37 +01:00
#include "cmCustomCommand.h"
2016-10-30 18:24:19 +01:00
#include "cmCustomCommandLines.h"
2011-01-16 11:35:12 +01:00
#include "cmGeneratorExpression.h"
2016-10-30 18:24:19 +01:00
#include "cmGeneratorTarget.h"
2016-07-09 11:21:54 +02:00
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
2020-08-30 11:54:41 +02:00
#include "cmProperty.h"
2017-04-14 19:02:05 +02:00
#include "cmStateTypes.h"
2020-02-01 23:06:01 +01:00
#include "cmStringAlgorithms.h"
2016-10-30 18:24:19 +01:00
#include "cmSystemTools.h"
2020-02-01 23:06:01 +01:00
namespace {
void AppendPaths(const std::vector<std::string>& inputs,
cmGeneratorExpression const& ge, cmLocalGenerator* lg,
std::string const& config, std::vector<std::string>& output)
{
for (std::string const& in : inputs) {
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(in);
std::vector<std::string> result =
cmExpandedList(cge->Evaluate(lg, config));
for (std::string& it : result) {
cmSystemTools::ConvertToUnixSlashes(it);
if (cmSystemTools::FileIsFullPath(it)) {
2020-08-30 11:54:41 +02:00
it = cmSystemTools::CollapseFullPath(
it, lg->GetMakefile()->GetHomeOutputDirectory());
2020-02-01 23:06:01 +01:00
}
}
2020-08-30 11:54:41 +02:00
cm::append(output, result);
2020-02-01 23:06:01 +01:00
}
}
}
2011-01-16 11:35:12 +01:00
2016-07-09 11:21:54 +02:00
cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
2019-11-11 23:01:05 +01:00
std::string config,
2016-07-09 11:21:54 +02:00
cmLocalGenerator* lg)
: CC(cc)
2019-11-11 23:01:05 +01:00
, Config(std::move(config))
2016-07-09 11:21:54 +02:00
, LG(lg)
, OldStyle(cc.GetEscapeOldStyle())
, MakeVars(cc.GetEscapeAllowMakeVars())
2019-11-11 23:01:05 +01:00
, EmulatorsWithArguments(cc.GetCommandLines().size())
2011-01-16 11:35:12 +01:00
{
2020-02-01 23:06:01 +01:00
cmGeneratorExpression ge(cc.GetBacktrace());
2017-04-14 19:02:05 +02:00
const cmCustomCommandLines& cmdlines = this->CC.GetCommandLines();
2018-01-26 17:06:56 +01:00
for (cmCustomCommandLine const& cmdline : cmdlines) {
2017-04-14 19:02:05 +02:00
cmCustomCommandLine argv;
2018-01-26 17:06:56 +01:00
for (std::string const& clarg : cmdline) {
2020-02-01 23:06:01 +01:00
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(clarg);
2017-04-14 19:02:05 +02:00
std::string parsed_arg = cge->Evaluate(this->LG, this->Config);
if (this->CC.GetCommandExpandLists()) {
2020-08-30 11:54:41 +02:00
cm::append(argv, cmExpandedList(parsed_arg));
2017-04-14 19:02:05 +02:00
} else {
2018-04-23 21:13:27 +02:00
argv.push_back(std::move(parsed_arg));
2017-04-14 19:02:05 +02:00
}
}
2018-05-19 10:45:57 +02:00
// Later code assumes at least one entry exists, but expanding
// lists on an empty command may have left this empty.
// FIXME: Should we define behavior for removing empty commands?
if (argv.empty()) {
2020-02-01 23:06:01 +01:00
argv.emplace_back();
2018-05-19 10:45:57 +02:00
}
2018-04-23 21:13:27 +02:00
this->CommandLines.push_back(std::move(argv));
2017-04-14 19:02:05 +02:00
}
2018-01-26 17:06:56 +01:00
2020-02-01 23:06:01 +01:00
AppendPaths(cc.GetByproducts(), ge, this->LG, this->Config,
this->Byproducts);
AppendPaths(cc.GetDepends(), ge, this->LG, this->Config, this->Depends);
2018-10-28 12:09:07 +01:00
const std::string& workingdirectory = this->CC.GetWorkingDirectory();
if (!workingdirectory.empty()) {
std::unique_ptr<cmCompiledGeneratorExpression> cge =
2020-02-01 23:06:01 +01:00
ge.Parse(workingdirectory);
2018-10-28 12:09:07 +01:00
this->WorkingDirectory = cge->Evaluate(this->LG, this->Config);
2018-11-29 20:27:00 +01:00
// Convert working directory to a full path.
if (!this->WorkingDirectory.empty()) {
std::string const& build_dir = this->LG->GetCurrentBinaryDirectory();
this->WorkingDirectory =
cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir);
}
2018-10-28 12:09:07 +01:00
}
2019-11-11 23:01:05 +01:00
this->FillEmulatorsWithArguments();
2011-01-16 11:35:12 +01:00
}
unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
{
return static_cast<unsigned int>(this->CC.GetCommandLines().size());
}
2019-11-11 23:01:05 +01:00
void cmCustomCommandGenerator::FillEmulatorsWithArguments()
2016-07-09 11:21:54 +02:00
{
2017-04-14 19:02:05 +02:00
if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
2019-11-11 23:01:05 +01:00
return;
2017-04-14 19:02:05 +02:00
}
2019-11-11 23:01:05 +01:00
for (unsigned int c = 0; c < this->GetNumberOfCommands(); ++c) {
std::string const& argv0 = this->CommandLines[c][0];
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
!target->IsImported()) {
2020-08-30 11:54:41 +02:00
cmProp emulator_property =
2019-11-11 23:01:05 +01:00
target->GetProperty("CROSSCOMPILING_EMULATOR");
if (!emulator_property) {
continue;
}
2020-08-30 11:54:41 +02:00
cmExpandList(*emulator_property, this->EmulatorsWithArguments[c]);
2019-11-11 23:01:05 +01:00
}
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
}
std::vector<std::string> cmCustomCommandGenerator::GetCrossCompilingEmulator(
unsigned int c) const
{
if (c >= this->EmulatorsWithArguments.size()) {
return std::vector<std::string>();
}
return this->EmulatorsWithArguments[c];
2016-07-09 11:21:54 +02:00
}
2017-04-14 19:02:05 +02:00
const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
2011-01-16 11:35:12 +01:00
{
2017-04-14 19:02:05 +02:00
std::string const& argv0 = this->CommandLines[c][0];
2016-07-09 11:21:54 +02:00
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
2017-04-14 19:02:05 +02:00
if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
2016-07-09 11:21:54 +02:00
(target->IsImported() ||
2017-04-14 19:02:05 +02:00
target->GetProperty("CROSSCOMPILING_EMULATOR") ||
2016-07-09 11:21:54 +02:00
!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) {
2020-08-30 11:54:41 +02:00
return target->GetLocation(this->Config).c_str();
2016-07-09 11:21:54 +02:00
}
2018-01-26 17:06:56 +01:00
return nullptr;
}
bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const
{
for (size_t i = 0; i < this->CommandLines.size(); ++i) {
for (size_t j = 0; j < this->CommandLines[i].size(); ++j) {
if (!this->CommandLines[i][j].empty()) {
return false;
}
}
}
return true;
2017-04-14 19:02:05 +02:00
}
2016-07-09 11:21:54 +02:00
2017-04-14 19:02:05 +02:00
std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
{
2019-11-11 23:01:05 +01:00
std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
if (!emulator.empty()) {
return emulator[0];
2017-04-14 19:02:05 +02:00
}
if (const char* location = this->GetArgv0Location(c)) {
return std::string(location);
}
2016-07-09 11:21:54 +02:00
2017-04-14 19:02:05 +02:00
return this->CommandLines[c][0];
2011-01-16 11:35:12 +01:00
}
2015-08-17 11:37:30 +02:00
std::string escapeForShellOldStyle(const std::string& str)
{
std::string result;
#if defined(_WIN32) && !defined(__CYGWIN__)
// if there are spaces
std::string temp = str;
if (temp.find(" ") != std::string::npos &&
2016-07-09 11:21:54 +02:00
temp.find("\"") == std::string::npos) {
2020-02-01 23:06:01 +01:00
result = cmStrCat('"', str, '"');
2015-08-17 11:37:30 +02:00
return result;
2016-07-09 11:21:54 +02:00
}
2015-08-17 11:37:30 +02:00
return str;
#else
2016-07-09 11:21:54 +02:00
for (const char* ch = str.c_str(); *ch != '\0'; ++ch) {
if (*ch == ' ') {
2015-08-17 11:37:30 +02:00
result += '\\';
}
2016-07-09 11:21:54 +02:00
result += *ch;
}
2015-08-17 11:37:30 +02:00
return result;
#endif
}
2016-07-09 11:21:54 +02:00
void cmCustomCommandGenerator::AppendArguments(unsigned int c,
std::string& cmd) const
2011-01-16 11:35:12 +01:00
{
2016-07-09 11:21:54 +02:00
unsigned int offset = 1;
2019-11-11 23:01:05 +01:00
std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
if (!emulator.empty()) {
for (unsigned j = 1; j < emulator.size(); ++j) {
cmd += " ";
if (this->OldStyle) {
cmd += escapeForShellOldStyle(emulator[j]);
} else {
2020-08-30 11:54:41 +02:00
cmd +=
this->LG->EscapeForShell(emulator[j], this->MakeVars, false, false,
this->MakeVars && this->LG->IsNinjaMulti());
2019-11-11 23:01:05 +01:00
}
}
2016-07-09 11:21:54 +02:00
offset = 0;
}
2019-11-11 23:01:05 +01:00
2017-04-14 19:02:05 +02:00
cmCustomCommandLine const& commandLine = this->CommandLines[c];
2016-07-09 11:21:54 +02:00
for (unsigned int j = offset; j < commandLine.size(); ++j) {
2017-04-14 19:02:05 +02:00
std::string arg;
2018-01-26 17:06:56 +01:00
if (const char* location = j == 0 ? this->GetArgv0Location(c) : nullptr) {
2017-04-14 19:02:05 +02:00
// GetCommand returned the emulator instead of the argv0 location,
// so transform the latter now.
arg = location;
} else {
arg = commandLine[j];
}
2011-01-16 11:35:12 +01:00
cmd += " ";
2016-07-09 11:21:54 +02:00
if (this->OldStyle) {
2015-08-17 11:37:30 +02:00
cmd += escapeForShellOldStyle(arg);
2016-07-09 11:21:54 +02:00
} else {
2020-08-30 11:54:41 +02:00
cmd +=
this->LG->EscapeForShell(arg, this->MakeVars, false, false,
this->MakeVars && this->LG->IsNinjaMulti());
2011-01-16 11:35:12 +01:00
}
2016-07-09 11:21:54 +02:00
}
2011-01-16 11:35:12 +01:00
}
2015-04-27 22:25:09 +02:00
const char* cmCustomCommandGenerator::GetComment() const
{
return this->CC.GetComment();
}
std::string cmCustomCommandGenerator::GetWorkingDirectory() const
{
2018-10-28 12:09:07 +01:00
return this->WorkingDirectory;
2015-04-27 22:25:09 +02:00
}
std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const
{
return this->CC.GetOutputs();
}
std::vector<std::string> const& cmCustomCommandGenerator::GetByproducts() const
{
2020-02-01 23:06:01 +01:00
return this->Byproducts;
2015-04-27 22:25:09 +02:00
}
std::vector<std::string> const& cmCustomCommandGenerator::GetDepends() const
{
return this->Depends;
}