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:
Brad King 2013-08-08 13:35:15 -04:00
commit b93982fb64
7 changed files with 156 additions and 86 deletions

View File

@ -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);
} }
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
}; };

View File

@ -2,3 +2,4 @@ include(RunCMake)
run_cmake(ModifiedAccess) run_cmake(ModifiedAccess)
run_cmake(NoWatcher) run_cmake(NoWatcher)
run_cmake(WatchTwice)

View File

@ -0,0 +1,2 @@
From watch1
From watch2

View File

@ -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}")