diff options
Diffstat (limited to 'Source/cmVariableWatchCommand.cxx')
-rw-r--r-- | Source/cmVariableWatchCommand.cxx | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx new file mode 100644 index 0000000..5fe55bd --- /dev/null +++ b/Source/cmVariableWatchCommand.cxx @@ -0,0 +1,130 @@ +/* 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 "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; + 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; +} + +cmVariableWatchCommand::cmVariableWatchCommand() = default; + +cmVariableWatchCommand::~cmVariableWatchCommand() +{ + for (std::string const& wv : this->WatchedVariables) { + this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch( + wv, cmVariableWatchCommandVariableAccessed); + } +} + +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; + + this->WatchedVariables.insert(variable); + if (!this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch( + variable, cmVariableWatchCommandVariableAccessed, data, + deleteVariableWatchCallbackData)) { + deleteVariableWatchCallbackData(data); + return false; + } + + return true; +} |