mirror of
https://github.com/reactos/CMake.git
synced 2025-05-13 18:15:53 +00:00

Replace the members for the Makefile and the Error with a cmExecutionStatus. Re-implement GetMakefile and SetError based on that. Both functions should be called directly on the cmExecutionStatus that is passed to InitialPass. This will help us make all Commands immutable and remove the need for cloning.
156 lines
4.6 KiB
C++
156 lines
4.6 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
#include "cmVariableWatchCommand.h"
|
|
|
|
#include <sstream>
|
|
#include <utility>
|
|
|
|
#include "cmExecutionStatus.h"
|
|
#include "cmListFileCache.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmMessageType.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmVariableWatch.h"
|
|
#include "cmake.h"
|
|
|
|
struct cmVariableWatchCallbackData
|
|
{
|
|
bool InCallback;
|
|
std::string Command;
|
|
};
|
|
|
|
static void cmVariableWatchCommandVariableAccessed(const std::string& variable,
|
|
int access_type,
|
|
void* client_data,
|
|
const char* newValue,
|
|
const cmMakefile* mf)
|
|
{
|
|
cmVariableWatchCallbackData* data =
|
|
static_cast<cmVariableWatchCallbackData*>(client_data);
|
|
|
|
if (data->InCallback) {
|
|
return;
|
|
}
|
|
data->InCallback = true;
|
|
|
|
cmListFileFunction newLFF;
|
|
cmListFileArgument arg;
|
|
bool processed = false;
|
|
const char* accessString = cmVariableWatch::GetAccessAsString(access_type);
|
|
const char* currentListFile = mf->GetDefinition("CMAKE_CURRENT_LIST_FILE");
|
|
|
|
/// Ultra bad!!
|
|
cmMakefile* makefile = const_cast<cmMakefile*>(mf);
|
|
|
|
std::string stack = makefile->GetProperty("LISTFILE_STACK");
|
|
if (!data->Command.empty()) {
|
|
newLFF.Arguments.clear();
|
|
newLFF.Arguments.emplace_back(variable, cmListFileArgument::Quoted, 9999);
|
|
newLFF.Arguments.emplace_back(accessString, cmListFileArgument::Quoted,
|
|
9999);
|
|
newLFF.Arguments.emplace_back(newValue ? newValue : "",
|
|
cmListFileArgument::Quoted, 9999);
|
|
newLFF.Arguments.emplace_back(currentListFile, cmListFileArgument::Quoted,
|
|
9999);
|
|
newLFF.Arguments.emplace_back(stack, cmListFileArgument::Quoted, 9999);
|
|
newLFF.Name = data->Command;
|
|
newLFF.Line = 9999;
|
|
cmExecutionStatus status(*makefile);
|
|
if (!makefile->ExecuteCommand(newLFF, status)) {
|
|
std::ostringstream error;
|
|
error << "Error in cmake code at\nUnknown:0:\n"
|
|
<< "A command failed during the invocation of callback \""
|
|
<< data->Command << "\".";
|
|
cmSystemTools::Error(error.str());
|
|
data->InCallback = false;
|
|
return;
|
|
}
|
|
processed = true;
|
|
}
|
|
if (!processed) {
|
|
std::ostringstream msg;
|
|
msg << "Variable \"" << variable << "\" was accessed using "
|
|
<< accessString << " with value \"" << (newValue ? newValue : "")
|
|
<< "\".";
|
|
makefile->IssueMessage(MessageType::LOG, msg.str());
|
|
}
|
|
|
|
data->InCallback = false;
|
|
}
|
|
|
|
static void deleteVariableWatchCallbackData(void* client_data)
|
|
{
|
|
cmVariableWatchCallbackData* data =
|
|
static_cast<cmVariableWatchCallbackData*>(client_data);
|
|
delete data;
|
|
}
|
|
|
|
/** This command does not really have a final pass but it needs to
|
|
stay alive since it owns variable watch callback information. */
|
|
class FinalAction
|
|
{
|
|
public:
|
|
FinalAction(cmMakefile* makefile, std::string variable)
|
|
: Action(std::make_shared<Impl>(makefile, std::move(variable)))
|
|
{
|
|
}
|
|
|
|
void operator()(cmMakefile&) const {}
|
|
|
|
private:
|
|
struct Impl
|
|
{
|
|
Impl(cmMakefile* makefile, std::string variable)
|
|
: Makefile(makefile)
|
|
, Variable(std::move(variable))
|
|
{
|
|
}
|
|
|
|
~Impl()
|
|
{
|
|
this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch(
|
|
this->Variable, cmVariableWatchCommandVariableAccessed);
|
|
}
|
|
|
|
cmMakefile* Makefile;
|
|
std::string Variable;
|
|
};
|
|
|
|
std::shared_ptr<Impl const> Action;
|
|
};
|
|
|
|
bool cmVariableWatchCommand::InitialPass(std::vector<std::string> const& args,
|
|
cmExecutionStatus&)
|
|
{
|
|
if (args.empty()) {
|
|
this->SetError("must be called with at least one argument.");
|
|
return false;
|
|
}
|
|
std::string const& variable = args[0];
|
|
std::string command;
|
|
if (args.size() > 1) {
|
|
command = args[1];
|
|
}
|
|
if (variable == "CMAKE_CURRENT_LIST_FILE") {
|
|
std::ostringstream ostr;
|
|
ostr << "cannot be set on the variable: " << variable;
|
|
this->SetError(ostr.str());
|
|
return false;
|
|
}
|
|
|
|
cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData;
|
|
|
|
data->InCallback = false;
|
|
data->Command = command;
|
|
|
|
if (!this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch(
|
|
variable, cmVariableWatchCommandVariableAccessed, data,
|
|
deleteVariableWatchCallbackData)) {
|
|
deleteVariableWatchCallbackData(data);
|
|
return false;
|
|
}
|
|
|
|
this->Makefile->AddFinalAction(FinalAction(this->Makefile, variable));
|
|
return true;
|
|
}
|