cmake/Source/cmVariableWatchCommand.cxx

156 lines
4.5 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. */
#include "cmVariableWatchCommand.h"
2020-08-30 11:54:41 +02:00
#include <limits>
2020-02-01 23:06:01 +01:00
#include <memory>
#include <utility>
2017-04-14 19:02:05 +02:00
#include "cmExecutionStatus.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
2019-11-11 23:01:05 +01:00
#include "cmMessageType.h"
2020-02-01 23:06:01 +01:00
#include "cmStringAlgorithms.h"
2017-04-14 19:02:05 +02:00
#include "cmSystemTools.h"
2021-11-20 13:41:27 +01:00
#include "cmValue.h"
#include "cmVariableWatch.h"
2017-04-14 19:02:05 +02:00
#include "cmake.h"
2020-08-30 11:54:41 +02:00
class cmLocalGenerator;
namespace {
2013-11-03 12:27:13 +02:00
struct cmVariableWatchCallbackData
{
2013-11-03 12:27:13 +02:00
bool InCallback;
std::string Command;
};
2020-08-30 11:54:41 +02:00
void cmVariableWatchCommandVariableAccessed(const std::string& variable,
int access_type, void* client_data,
const char* newValue,
const cmMakefile* mf)
{
2016-07-09 11:21:54 +02:00
cmVariableWatchCallbackData* data =
static_cast<cmVariableWatchCallbackData*>(client_data);
2016-07-09 11:21:54 +02:00
if (data->InCallback) {
return;
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
data->InCallback = true;
2020-08-30 11:54:41 +02:00
auto accessString = cmVariableWatch::GetAccessAsString(access_type);
/// Ultra bad!!
cmMakefile* makefile = const_cast<cmMakefile*>(mf);
2020-08-30 11:54:41 +02:00
std::string stack = *mf->GetProperty("LISTFILE_STACK");
2016-07-09 11:21:54 +02:00
if (!data->Command.empty()) {
2021-11-20 13:41:27 +01:00
cmValue const currentListFile =
2020-08-30 11:54:41 +02:00
mf->GetDefinition("CMAKE_CURRENT_LIST_FILE");
const auto fakeLineNo =
std::numeric_limits<decltype(cmListFileArgument::Line)>::max();
2021-09-14 00:13:48 +02:00
std::vector<cmListFileArgument> newLFFArgs{
2020-08-30 11:54:41 +02:00
{ variable, cmListFileArgument::Quoted, fakeLineNo },
{ accessString, cmListFileArgument::Quoted, fakeLineNo },
{ newValue ? newValue : "", cmListFileArgument::Quoted, fakeLineNo },
2021-09-14 00:13:48 +02:00
{ *currentListFile, cmListFileArgument::Quoted, fakeLineNo },
2020-08-30 11:54:41 +02:00
{ stack, cmListFileArgument::Quoted, fakeLineNo }
};
2021-09-14 00:13:48 +02:00
2022-08-04 22:12:04 +02:00
cmListFileFunction newLFF{ data->Command, fakeLineNo, fakeLineNo,
2021-09-14 00:13:48 +02:00
std::move(newLFFArgs) };
2020-02-01 23:06:01 +01:00
cmExecutionStatus status(*makefile);
2016-07-09 11:21:54 +02:00
if (!makefile->ExecuteCommand(newLFF, status)) {
2020-02-01 23:06:01 +01:00
cmSystemTools::Error(
cmStrCat("Error in cmake code at\nUnknown:0:\nA command failed "
"during the invocation of callback \"",
data->Command, "\"."));
}
2020-08-30 11:54:41 +02:00
} else {
2020-02-01 23:06:01 +01:00
makefile->IssueMessage(
MessageType::LOG,
cmStrCat("Variable \"", variable, "\" was accessed using ", accessString,
" with value \"", (newValue ? newValue : ""), "\"."));
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
data->InCallback = false;
}
2020-08-30 11:54:41 +02:00
void deleteVariableWatchCallbackData(void* client_data)
2013-11-03 12:27:13 +02:00
{
2016-07-09 11:21:54 +02:00
cmVariableWatchCallbackData* data =
static_cast<cmVariableWatchCallbackData*>(client_data);
2013-11-03 12:27:13 +02:00
delete data;
}
2020-02-01 23:06:01 +01:00
/** This command does not really have a final pass but it needs to
stay alive since it owns variable watch callback information. */
class FinalAction
2013-11-03 12:27:13 +02:00
{
2020-02-01 23:06:01 +01:00
public:
/* NOLINTNEXTLINE(performance-unnecessary-value-param) */
FinalAction(cmMakefile* makefile, std::string variable)
2020-08-30 11:54:41 +02:00
: Action{ std::make_shared<Impl>(makefile, std::move(variable)) }
2020-02-01 23:06:01 +01:00
{
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
2020-08-30 11:54:41 +02:00
void operator()(cmLocalGenerator&, const cmListFileBacktrace&) const {}
2020-02-01 23:06:01 +01:00
private:
struct Impl
{
Impl(cmMakefile* makefile, std::string variable)
2020-08-30 11:54:41 +02:00
: Makefile{ makefile }
, Variable{ std::move(variable) }
2020-02-01 23:06:01 +01:00
{
}
~Impl()
{
this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch(
this->Variable, cmVariableWatchCommandVariableAccessed);
}
2020-08-30 11:54:41 +02:00
cmMakefile* const Makefile;
std::string const Variable;
2020-02-01 23:06:01 +01:00
};
std::shared_ptr<Impl const> Action;
};
2020-08-30 11:54:41 +02:00
} // anonymous namespace
2020-02-01 23:06:01 +01:00
bool cmVariableWatchCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
2013-11-03 12:27:13 +02:00
{
2016-10-30 18:24:19 +01:00
if (args.empty()) {
2020-02-01 23:06:01 +01:00
status.SetError("must be called with at least one argument.");
2013-11-03 12:27:13 +02:00
return false;
2016-07-09 11:21:54 +02:00
}
2017-07-20 19:35:53 +02:00
std::string const& variable = args[0];
2013-11-03 12:27:13 +02:00
std::string command;
2016-07-09 11:21:54 +02:00
if (args.size() > 1) {
2013-11-03 12:27:13 +02:00
command = args[1];
2016-07-09 11:21:54 +02:00
}
if (variable == "CMAKE_CURRENT_LIST_FILE") {
2020-02-01 23:06:01 +01:00
status.SetError(cmStrCat("cannot be set on the variable: ", variable));
2013-11-03 12:27:13 +02:00
return false;
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
2020-08-30 11:54:41 +02:00
auto* const data = new cmVariableWatchCallbackData;
2013-11-03 12:27:13 +02:00
data->InCallback = false;
2020-08-30 11:54:41 +02:00
data->Command = std::move(command);
2013-11-03 12:27:13 +02:00
2020-02-01 23:06:01 +01:00
if (!status.GetMakefile().GetCMakeInstance()->GetVariableWatch()->AddWatch(
2016-07-09 11:21:54 +02:00
variable, cmVariableWatchCommandVariableAccessed, data,
deleteVariableWatchCallbackData)) {
2013-11-03 12:27:13 +02:00
deleteVariableWatchCallbackData(data);
return false;
2016-07-09 11:21:54 +02:00
}
2013-11-03 12:27:13 +02:00
2020-08-30 11:54:41 +02:00
status.GetMakefile().AddGeneratorAction(
FinalAction{ &status.GetMakefile(), variable });
2013-11-03 12:27:13 +02:00
return true;
}