Merge branch 'dev/fix-variable-watch-crash' into cmake-syntax
Resolve conflict in Source/cmVariableWatchCommand.cxx by integrating the changes from both sides.
This commit is contained in:
commit
b93982fb64
|
@ -37,37 +37,63 @@ cmVariableWatch::cmVariableWatch()
|
||||||
|
|
||||||
cmVariableWatch::~cmVariableWatch()
|
cmVariableWatch::~cmVariableWatch()
|
||||||
{
|
{
|
||||||
|
cmVariableWatch::StringToVectorOfPairs::iterator svp_it;
|
||||||
|
|
||||||
|
for ( svp_it = this->WatchMap.begin();
|
||||||
|
svp_it != this->WatchMap.end(); ++svp_it )
|
||||||
|
{
|
||||||
|
cmVariableWatch::VectorOfPairs::iterator p_it;
|
||||||
|
|
||||||
|
for ( p_it = svp_it->second.begin();
|
||||||
|
p_it != svp_it->second.end(); ++p_it )
|
||||||
|
{
|
||||||
|
delete *p_it;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmVariableWatch::AddWatch(const std::string& variable,
|
bool cmVariableWatch::AddWatch(const std::string& variable,
|
||||||
WatchMethod method, void* client_data /*=0*/)
|
WatchMethod method, void* client_data /*=0*/,
|
||||||
|
DeleteData delete_data /*=0*/)
|
||||||
{
|
{
|
||||||
cmVariableWatch::Pair p;
|
cmVariableWatch::Pair* p = new cmVariableWatch::Pair;
|
||||||
p.Method = method;
|
p->Method = method;
|
||||||
p.ClientData = client_data;
|
p->ClientData = client_data;
|
||||||
|
p->DeleteDataCall = delete_data;
|
||||||
cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable];
|
cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable];
|
||||||
cmVariableWatch::VectorOfPairs::size_type cc;
|
cmVariableWatch::VectorOfPairs::size_type cc;
|
||||||
for ( cc = 0; cc < vp->size(); cc ++ )
|
for ( cc = 0; cc < vp->size(); cc ++ )
|
||||||
{
|
{
|
||||||
cmVariableWatch::Pair* pair = &(*vp)[cc];
|
cmVariableWatch::Pair* pair = (*vp)[cc];
|
||||||
if ( pair->Method == method )
|
if ( pair->Method == method &&
|
||||||
|
client_data && client_data == pair->ClientData)
|
||||||
{
|
{
|
||||||
(*vp)[cc] = p;
|
// Callback already exists
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vp->push_back(p);
|
vp->push_back(p);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmVariableWatch::RemoveWatch(const std::string& variable,
|
void cmVariableWatch::RemoveWatch(const std::string& variable,
|
||||||
WatchMethod method)
|
WatchMethod method,
|
||||||
|
void* client_data /*=0*/)
|
||||||
{
|
{
|
||||||
|
if ( !this->WatchMap.count(variable) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable];
|
cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable];
|
||||||
cmVariableWatch::VectorOfPairs::iterator it;
|
cmVariableWatch::VectorOfPairs::iterator it;
|
||||||
for ( it = vp->begin(); it != vp->end(); ++it )
|
for ( it = vp->begin(); it != vp->end(); ++it )
|
||||||
{
|
{
|
||||||
if ( it->Method == method )
|
if ( (*it)->Method == method &&
|
||||||
|
// If client_data is NULL, we want to disconnect all watches against
|
||||||
|
// the given method; otherwise match ClientData as well.
|
||||||
|
(!client_data || (client_data == (*it)->ClientData)))
|
||||||
{
|
{
|
||||||
|
delete *it;
|
||||||
vp->erase(it);
|
vp->erase(it);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +113,7 @@ void cmVariableWatch::VariableAccessed(const std::string& variable,
|
||||||
cmVariableWatch::VectorOfPairs::const_iterator it;
|
cmVariableWatch::VectorOfPairs::const_iterator it;
|
||||||
for ( it = vp->begin(); it != vp->end(); it ++ )
|
for ( it = vp->begin(); it != vp->end(); it ++ )
|
||||||
{
|
{
|
||||||
it->Method(variable, access_type, it->ClientData,
|
(*it)->Method(variable, access_type, (*it)->ClientData,
|
||||||
newValue, mf);
|
newValue, mf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ class cmVariableWatch
|
||||||
public:
|
public:
|
||||||
typedef void (*WatchMethod)(const std::string& variable, int access_type,
|
typedef void (*WatchMethod)(const std::string& variable, int access_type,
|
||||||
void* client_data, const char* newValue, const cmMakefile* mf);
|
void* client_data, const char* newValue, const cmMakefile* mf);
|
||||||
|
typedef void (*DeleteData)(void* client_data);
|
||||||
|
|
||||||
cmVariableWatch();
|
cmVariableWatch();
|
||||||
~cmVariableWatch();
|
~cmVariableWatch();
|
||||||
|
@ -33,9 +34,10 @@ public:
|
||||||
/**
|
/**
|
||||||
* Add watch to the variable
|
* Add watch to the variable
|
||||||
*/
|
*/
|
||||||
void AddWatch(const std::string& variable, WatchMethod method,
|
bool AddWatch(const std::string& variable, WatchMethod method,
|
||||||
void* client_data=0);
|
void* client_data=0, DeleteData delete_data=0);
|
||||||
void RemoveWatch(const std::string& variable, WatchMethod method);
|
void RemoveWatch(const std::string& variable, WatchMethod method,
|
||||||
|
void* client_data=0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called when variable is accessed
|
* This method is called when variable is accessed
|
||||||
|
@ -67,10 +69,18 @@ protected:
|
||||||
{
|
{
|
||||||
WatchMethod Method;
|
WatchMethod Method;
|
||||||
void* ClientData;
|
void* ClientData;
|
||||||
Pair() : Method(0), ClientData(0) {}
|
DeleteData DeleteDataCall;
|
||||||
|
Pair() : Method(0), ClientData(0), DeleteDataCall(0) {}
|
||||||
|
~Pair()
|
||||||
|
{
|
||||||
|
if (this->DeleteDataCall && this->ClientData)
|
||||||
|
{
|
||||||
|
this->DeleteDataCall(this->ClientData);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector< Pair > VectorOfPairs;
|
typedef std::vector< Pair* > VectorOfPairs;
|
||||||
typedef std::map<cmStdString, VectorOfPairs > StringToVectorOfPairs;
|
typedef std::map<cmStdString, VectorOfPairs > StringToVectorOfPairs;
|
||||||
|
|
||||||
StringToVectorOfPairs WatchMap;
|
StringToVectorOfPairs WatchMap;
|
||||||
|
|
|
@ -13,64 +13,28 @@
|
||||||
|
|
||||||
#include "cmVariableWatch.h"
|
#include "cmVariableWatch.h"
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
struct cmVariableWatchCallbackData
|
||||||
|
{
|
||||||
|
bool InCallback;
|
||||||
|
std::string Command;
|
||||||
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
static void cmVariableWatchCommandVariableAccessed(
|
static void cmVariableWatchCommandVariableAccessed(
|
||||||
const std::string& variable, int access_type, void* client_data,
|
const std::string& variable, int access_type, void* client_data,
|
||||||
const char* newValue, const cmMakefile* mf)
|
const char* newValue, const cmMakefile* mf)
|
||||||
{
|
{
|
||||||
cmVariableWatchCommand* command
|
cmVariableWatchCallbackData* data
|
||||||
= static_cast<cmVariableWatchCommand*>(client_data);
|
= static_cast<cmVariableWatchCallbackData*>(client_data);
|
||||||
command->VariableAccessed(variable, access_type, newValue, mf);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
if ( data->InCallback )
|
||||||
cmVariableWatchCommand::cmVariableWatchCommand()
|
|
||||||
{
|
|
||||||
this->InCallback = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool cmVariableWatchCommand
|
|
||||||
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
|
|
||||||
{
|
|
||||||
if ( args.size() < 1 )
|
|
||||||
{
|
|
||||||
this->SetError("must be called with at least one argument.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::string variable = args[0];
|
|
||||||
if ( args.size() > 1 )
|
|
||||||
{
|
|
||||||
std::string command = args[1];
|
|
||||||
this->Handlers[variable].Commands.push_back(args[1]);
|
|
||||||
}
|
|
||||||
if ( variable == "CMAKE_CURRENT_LIST_FILE" )
|
|
||||||
{
|
|
||||||
cmOStringStream ostr;
|
|
||||||
ostr << "cannot be set on the variable: " << variable.c_str();
|
|
||||||
this->SetError(ostr.str().c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch(
|
|
||||||
variable, cmVariableWatchCommandVariableAccessed, this);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void cmVariableWatchCommand::VariableAccessed(const std::string& variable,
|
|
||||||
int access_type, const char* newValue, const cmMakefile* mf)
|
|
||||||
{
|
|
||||||
if ( this->InCallback )
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->InCallback = true;
|
data->InCallback = true;
|
||||||
|
|
||||||
cmListFileFunction newLFF;
|
cmListFileFunction newLFF;
|
||||||
cmVariableWatchCommandHandler *handler = &this->Handlers[variable];
|
|
||||||
cmVariableWatchCommandHandler::VectorOfCommands::iterator it;
|
|
||||||
cmListFileArgument arg;
|
cmListFileArgument arg;
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
const char* accessString = cmVariableWatch::GetAccessAsString(access_type);
|
const char* accessString = cmVariableWatch::GetAccessAsString(access_type);
|
||||||
|
@ -80,10 +44,8 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable,
|
||||||
cmMakefile* makefile = const_cast<cmMakefile*>(mf);
|
cmMakefile* makefile = const_cast<cmMakefile*>(mf);
|
||||||
|
|
||||||
std::string stack = makefile->GetProperty("LISTFILE_STACK");
|
std::string stack = makefile->GetProperty("LISTFILE_STACK");
|
||||||
for ( it = handler->Commands.begin(); it != handler->Commands.end();
|
if ( !data->Command.empty() )
|
||||||
++ it )
|
|
||||||
{
|
{
|
||||||
std::string command = *it;
|
|
||||||
newLFF.Arguments.clear();
|
newLFF.Arguments.clear();
|
||||||
newLFF.Arguments.push_back(
|
newLFF.Arguments.push_back(
|
||||||
cmListFileArgument(variable, cmListFileArgument::Quoted,
|
cmListFileArgument(variable, cmListFileArgument::Quoted,
|
||||||
|
@ -100,7 +62,7 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable,
|
||||||
newLFF.Arguments.push_back(
|
newLFF.Arguments.push_back(
|
||||||
cmListFileArgument(stack, cmListFileArgument::Quoted,
|
cmListFileArgument(stack, cmListFileArgument::Quoted,
|
||||||
"unknown", 9999));
|
"unknown", 9999));
|
||||||
newLFF.Name = command;
|
newLFF.Name = data->Command;
|
||||||
newLFF.FilePath = "Some weird path";
|
newLFF.FilePath = "Some weird path";
|
||||||
newLFF.Line = 9999;
|
newLFF.Line = 9999;
|
||||||
cmExecutionStatus status;
|
cmExecutionStatus status;
|
||||||
|
@ -111,10 +73,10 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable,
|
||||||
cmOStringStream error;
|
cmOStringStream error;
|
||||||
error << "Error in cmake code at\n"
|
error << "Error in cmake code at\n"
|
||||||
<< arg.FilePath << ":" << arg.Line << ":\n"
|
<< arg.FilePath << ":" << arg.Line << ":\n"
|
||||||
<< "A command failed during the invocation of callback\""
|
<< "A command failed during the invocation of callback \""
|
||||||
<< command << "\".";
|
<< data->Command << "\".";
|
||||||
cmSystemTools::Error(error.str().c_str());
|
cmSystemTools::Error(error.str().c_str());
|
||||||
this->InCallback = false;
|
data->InCallback = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
processed = true;
|
processed = true;
|
||||||
|
@ -123,8 +85,75 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable,
|
||||||
{
|
{
|
||||||
cmOStringStream msg;
|
cmOStringStream msg;
|
||||||
msg << "Variable \"" << variable.c_str() << "\" was accessed using "
|
msg << "Variable \"" << variable.c_str() << "\" was accessed using "
|
||||||
<< accessString << " with value \"" << newValue << "\".";
|
<< accessString << " with value \"" << (newValue?newValue:"") << "\".";
|
||||||
makefile->IssueMessage(cmake::LOG, msg.str());
|
makefile->IssueMessage(cmake::LOG, msg.str());
|
||||||
}
|
}
|
||||||
this->InCallback = false;
|
|
||||||
|
data->InCallback = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static void deleteVariableWatchCallbackData(void* client_data)
|
||||||
|
{
|
||||||
|
cmVariableWatchCallbackData* data
|
||||||
|
= static_cast<cmVariableWatchCallbackData*>(client_data);
|
||||||
|
delete data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmVariableWatchCommand::cmVariableWatchCommand()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
cmVariableWatchCommand::~cmVariableWatchCommand()
|
||||||
|
{
|
||||||
|
std::set<std::string>::const_iterator it;
|
||||||
|
for ( it = this->WatchedVariables.begin();
|
||||||
|
it != this->WatchedVariables.end();
|
||||||
|
++it )
|
||||||
|
{
|
||||||
|
this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch(
|
||||||
|
*it, cmVariableWatchCommandVariableAccessed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool cmVariableWatchCommand
|
||||||
|
::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
|
||||||
|
{
|
||||||
|
if ( args.size() < 1 )
|
||||||
|
{
|
||||||
|
this->SetError("must be called with at least one argument.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string variable = args[0];
|
||||||
|
std::string command;
|
||||||
|
if ( args.size() > 1 )
|
||||||
|
{
|
||||||
|
command = args[1];
|
||||||
|
}
|
||||||
|
if ( variable == "CMAKE_CURRENT_LIST_FILE" )
|
||||||
|
{
|
||||||
|
cmOStringStream ostr;
|
||||||
|
ostr << "cannot be set on the variable: " << variable.c_str();
|
||||||
|
this->SetError(ostr.str().c_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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,6 @@
|
||||||
|
|
||||||
#include "cmCommand.h"
|
#include "cmCommand.h"
|
||||||
|
|
||||||
class cmVariableWatchCommandHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::vector<std::string> VectorOfCommands;
|
|
||||||
VectorOfCommands Commands;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \class cmVariableWatchCommand
|
/** \class cmVariableWatchCommand
|
||||||
* \brief Watch when the variable changes and invoke command
|
* \brief Watch when the variable changes and invoke command
|
||||||
*
|
*
|
||||||
|
@ -39,6 +32,9 @@ public:
|
||||||
//! Default constructor
|
//! Default constructor
|
||||||
cmVariableWatchCommand();
|
cmVariableWatchCommand();
|
||||||
|
|
||||||
|
//! Destructor.
|
||||||
|
~cmVariableWatchCommand();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called when the command is first encountered in
|
* This is called when the command is first encountered in
|
||||||
* the CMakeLists.txt file.
|
* the CMakeLists.txt file.
|
||||||
|
@ -83,13 +79,8 @@ public:
|
||||||
|
|
||||||
cmTypeMacro(cmVariableWatchCommand, cmCommand);
|
cmTypeMacro(cmVariableWatchCommand, cmCommand);
|
||||||
|
|
||||||
void VariableAccessed(const std::string& variable, int access_type,
|
|
||||||
const char* newValue, const cmMakefile* mf);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::map<std::string, cmVariableWatchCommandHandler> Handlers;
|
std::set<std::string> WatchedVariables;
|
||||||
|
|
||||||
bool InCallback;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,3 +2,4 @@ include(RunCMake)
|
||||||
|
|
||||||
run_cmake(ModifiedAccess)
|
run_cmake(ModifiedAccess)
|
||||||
run_cmake(NoWatcher)
|
run_cmake(NoWatcher)
|
||||||
|
run_cmake(WatchTwice)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
From watch1
|
||||||
|
From watch2
|
|
@ -0,0 +1,11 @@
|
||||||
|
function (watch1)
|
||||||
|
message("From watch1")
|
||||||
|
endfunction ()
|
||||||
|
|
||||||
|
function (watch2)
|
||||||
|
message("From watch2")
|
||||||
|
endfunction ()
|
||||||
|
|
||||||
|
variable_watch(watched watch1)
|
||||||
|
variable_watch(watched watch2)
|
||||||
|
set(access "${watched}")
|
Loading…
Reference in New Issue