summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Cedilnik <andy.cedilnik@kitware.com>2007-04-11 19:13:05 (GMT)
committerAndy Cedilnik <andy.cedilnik@kitware.com>2007-04-11 19:13:05 (GMT)
commitf9f1ccadb370b7b3466d491b1824104d81a15308 (patch)
tree8428b8e66ce907c5befa5b86fa3fb6773722e8c4
parent76e5344590f6259fcfc73d35e286509f9e260678 (diff)
downloadCMake-f9f1ccadb370b7b3466d491b1824104d81a15308.zip
CMake-f9f1ccadb370b7b3466d491b1824104d81a15308.tar.gz
CMake-f9f1ccadb370b7b3466d491b1824104d81a15308.tar.bz2
ENH: Add variable watch command
-rw-r--r--Source/cmCommands.cxx3
-rw-r--r--Source/cmFindPackageCommand.cxx4
-rw-r--r--Source/cmMakefile.cxx21
-rw-r--r--Source/cmVariableWatch.cxx26
-rw-r--r--Source/cmVariableWatch.h24
-rw-r--r--Source/cmVariableWatchCommand.cxx136
-rw-r--r--Source/cmVariableWatchCommand.h98
-rw-r--r--Source/cmake.cxx2
-rw-r--r--Tests/CMakeTests/CMakeLists.txt3
-rw-r--r--Tests/CMakeTests/VariableWatchTest.cmake.in22
10 files changed, 318 insertions, 21 deletions
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index 3ecc82c..81a9d25 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -52,6 +52,8 @@
#include "cmUseMangledMesaCommand.cxx"
#include "cmUtilitySourceCommand.cxx"
#include "cmVariableRequiresCommand.cxx"
+#include "cmVariableWatchCommand.cxx"
+
#include "cmWhileCommand.cxx"
#include "cmWriteFileCommand.cxx"
@@ -105,6 +107,7 @@ void GetPredefinedCommands(std::list<cmCommand*>&
commands.push_back(new cmUseMangledMesaCommand);
commands.push_back(new cmUtilitySourceCommand);
commands.push_back(new cmVariableRequiresCommand);
+ commands.push_back(new cmVariableWatchCommand);
commands.push_back(new cmWhileCommand);
commands.push_back(new cmWriteFileCommand);
#endif
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index b4118d9..518d3a9 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -22,8 +22,10 @@
#endif
void cmFindPackageNeedBackwardsCompatibility(const std::string& variable,
- int access_type, void* )
+ int access_type, void*, const char* newValue,
+ const cmMakefile*)
{
+ (void)newValue;
#ifdef CMAKE_BUILD_WITH_CMAKE
if(access_type == cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS)
{
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 428ea6a..a698b6a 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -1215,7 +1215,9 @@ void cmMakefile::AddDefinition(const char* name, const char* value)
if ( vv )
{
vv->VariableAccessed(this->TemporaryDefinitionKey,
- cmVariableWatch::VARIABLE_MODIFIED_ACCESS);
+ cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
+ value,
+ this);
}
#endif
}
@@ -1275,7 +1277,8 @@ void cmMakefile::AddDefinition(const char* name, bool value)
cmVariableWatch* vv = this->GetVariableWatch();
if ( vv )
{
- vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS);
+ vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
+ value?"ON":"OFF", this);
}
#endif
}
@@ -1304,7 +1307,8 @@ void cmMakefile::RemoveDefinition(const char* name)
cmVariableWatch* vv = this->GetVariableWatch();
if ( vv )
{
- vv->VariableAccessed(name, cmVariableWatch::VARIABLE_REMOVED_ACCESS);
+ vv->VariableAccessed(name, cmVariableWatch::VARIABLE_REMOVED_ACCESS,
+ 0, this);
}
#endif
}
@@ -1649,7 +1653,8 @@ const char* cmMakefile::GetDefinition(const char* name) const
{
if ( def )
{
- vv->VariableAccessed(name, cmVariableWatch::VARIABLE_READ_ACCESS);
+ vv->VariableAccessed(name, cmVariableWatch::VARIABLE_READ_ACCESS,
+ def, this);
}
else
{
@@ -1659,13 +1664,13 @@ const char* cmMakefile::GetDefinition(const char* name) const
if (pos2 != this->Definitions.end() &&
cmSystemTools::IsOn((*pos2).second.c_str()))
{
- vv->VariableAccessed
- (name, cmVariableWatch::ALLOWED_UNKNOWN_VARIABLE_READ_ACCESS);
+ vv->VariableAccessed(name,
+ cmVariableWatch::ALLOWED_UNKNOWN_VARIABLE_READ_ACCESS, def, this);
}
else
{
- vv->VariableAccessed(name, cmVariableWatch::
- UNKNOWN_VARIABLE_READ_ACCESS);
+ vv->VariableAccessed(name,
+ cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS, def, this);
}
}
}
diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx
index d267a52..d234f28 100644
--- a/Source/cmVariableWatch.cxx
+++ b/Source/cmVariableWatch.cxx
@@ -16,6 +16,25 @@
=========================================================================*/
#include "cmVariableWatch.h"
+static const char* const cmVariableWatchAccessStrings[] =
+{
+ "READ_ACCESS",
+ "UNKNOWN_READ_ACCESS",
+ "ALLOWED_UNKNOWN_READ_ACCESS",
+ "MODIFIED_ACCESS",
+ "REMOVED_ACCESS",
+ "NO_ACCESS"
+};
+
+const char* cmVariableWatch::GetAccessAsString(int access_type)
+{
+ if ( access_type < 0 || access_type >= cmVariableWatch::NO_ACCESS )
+ {
+ return "NO_ACCESS";
+ }
+ return cmVariableWatchAccessStrings[access_type];
+}
+
cmVariableWatch::cmVariableWatch()
{
}
@@ -60,7 +79,9 @@ void cmVariableWatch::RemoveWatch(const std::string& variable,
}
void cmVariableWatch::VariableAccessed(const std::string& variable,
- int access_type) const
+ int access_type,
+ const char* newValue,
+ const cmMakefile* mf) const
{
cmVariableWatch::StringToVectorOfPairs::const_iterator mit =
this->WatchMap.find(variable);
@@ -70,7 +91,8 @@ void cmVariableWatch::VariableAccessed(const std::string& variable,
cmVariableWatch::VectorOfPairs::const_iterator 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);
}
}
}
diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h
index 15e8f90..7f97c28 100644
--- a/Source/cmVariableWatch.h
+++ b/Source/cmVariableWatch.h
@@ -19,6 +19,8 @@
#include "cmStandardIncludes.h"
+class cmMakefile;
+
/** \class cmVariableWatch
* \brief Helper class for watching of variable accesses.
*
@@ -28,7 +30,7 @@ class cmVariableWatch
{
public:
typedef void (*WatchMethod)(const std::string& variable, int access_type,
- void* client_data);
+ void* client_data, const char* newValue, const cmMakefile* mf);
cmVariableWatch();
~cmVariableWatch();
@@ -43,20 +45,26 @@ public:
/**
* This method is called when variable is accessed
*/
- void VariableAccessed(const std::string& variable, int access_type) const;
+ void VariableAccessed(const std::string& variable, int access_type,
+ const char* newValue, const cmMakefile* mf) const;
/**
* Different access types.
*/
enum
{
- VARIABLE_READ_ACCESS,
- UNKNOWN_VARIABLE_READ_ACCESS,
- ALLOWED_UNKNOWN_VARIABLE_READ_ACCESS,
- VARIABLE_MODIFIED_ACCESS,
- VARIABLE_REMOVED_ACCESS,
- NO_ACCESS
+ VARIABLE_READ_ACCESS = 0,
+ UNKNOWN_VARIABLE_READ_ACCESS,
+ ALLOWED_UNKNOWN_VARIABLE_READ_ACCESS,
+ VARIABLE_MODIFIED_ACCESS,
+ VARIABLE_REMOVED_ACCESS,
+ NO_ACCESS
};
+
+ /**
+ * Return the access as string
+ */
+ static const char* GetAccessAsString(int access_type);
protected:
struct Pair
diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx
new file mode 100644
index 0000000..8e83756
--- /dev/null
+++ b/Source/cmVariableWatchCommand.cxx
@@ -0,0 +1,136 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmVariableWatchCommand.h"
+
+#include "cmVariableWatch.h"
+
+//----------------------------------------------------------------------------
+static void cmVariableWatchCommandVariableAccessed(
+ const std::string& variable, int access_type, void* client_data,
+ const char* newValue, const cmMakefile* mf)
+{
+ cmVariableWatchCommand* command = static_cast<cmVariableWatchCommand*>(client_data);
+ command->VariableAccessed(variable, access_type, newValue, mf);
+}
+
+//----------------------------------------------------------------------------
+cmVariableWatchCommand::cmVariableWatchCommand()
+{
+ this->InCallback = false;
+}
+
+//----------------------------------------------------------------------------
+bool cmVariableWatchCommand::InitialPass(std::vector<std::string> const& args)
+{
+ 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;
+ }
+ this->InCallback = true;
+
+ cmListFileFunction newLFF;
+ cmVariableWatchCommandHandler *handler = &this->Handlers[variable];
+ cmVariableWatchCommandHandler::VectorOfCommands::iterator it;
+ 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");
+ for ( it = handler->Commands.begin(); it != handler->Commands.end();
+ ++ it )
+ {
+ std::string command = *it;
+ newLFF.Arguments.clear();
+ newLFF.Arguments.push_back(cmListFileArgument(variable, true, "unknown", 9999));
+ newLFF.Arguments.push_back(cmListFileArgument(accessString, true, "unknown", 9999));
+ newLFF.Arguments.push_back(cmListFileArgument(newValue?newValue:"", true, "unknown", 9999));
+ newLFF.Arguments.push_back(cmListFileArgument(currentListFile, true, "unknown", 9999));
+ newLFF.Arguments.push_back(cmListFileArgument(stack, true, "unknown", 9999));
+ newLFF.Name = command;
+ newLFF.FilePath = "Some weird path";
+ newLFF.Line = 9999;
+ if(!makefile->ExecuteCommand(newLFF))
+ {
+ arg.FilePath = "Unknown";
+ arg.Line = 0;
+ cmOStringStream error;
+ error << "Error in cmake code at\n"
+ << arg.FilePath << ":" << arg.Line << ":\n"
+ << "A command failed during the invocation of callback\""
+ << command << "\".";
+ cmSystemTools::Error(error.str().c_str());
+ this->InCallback = false;
+ return;
+ }
+ processed = true;
+ }
+ if ( !processed )
+ {
+ cmOStringStream msg;
+ msg << "* Variable \"" << variable.c_str() << "\" was accessed using "
+ << accessString << " in: " << currentListFile << std::endl;
+ msg << " The value of the variable: \"" << newValue << "\"" << std::endl;
+ msg << " The list file stack: " << stack.c_str();
+ cmSystemTools::Message(msg.str().c_str());
+ std::vector<std::string> vars = makefile->GetDefinitions();
+ cmOStringStream msg2;
+ size_t cc;
+ for ( cc = 0; cc < vars.size(); cc ++ )
+ {
+ if ( vars[cc] == variable )
+ {
+ continue;
+ }
+ msg2 << vars[cc] << " = \"" << makefile->GetDefinition(vars[cc].c_str()) << "\"" << std::endl;
+ }
+ //cmSystemTools::Message(msg2.str().c_str());
+ }
+ this->InCallback = false;
+}
diff --git a/Source/cmVariableWatchCommand.h b/Source/cmVariableWatchCommand.h
new file mode 100644
index 0000000..244aea9
--- /dev/null
+++ b/Source/cmVariableWatchCommand.h
@@ -0,0 +1,98 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmVariableWatchCommand_h
+#define cmVariableWatchCommand_h
+
+#include "cmCommand.h"
+
+class cmVariableWatchCommandHandler
+{
+public:
+ typedef std::vector<std::string> VectorOfCommands;
+ VectorOfCommands Commands;
+};
+
+/** \class cmVariableWatchCommand
+ * \brief Watch when the variable changes and invoke command
+ *
+ */
+class cmVariableWatchCommand : public cmCommand
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ virtual cmCommand* Clone()
+ {
+ return new cmVariableWatchCommand;
+ }
+
+ //! Default constructor
+ cmVariableWatchCommand();
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ virtual bool InitialPass(std::vector<std::string> const& args);
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ virtual bool IsScriptable() { return true; }
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ virtual const char* GetName() { return "VARIABLE_WATCH";}
+
+ /**
+ * Succinct documentation.
+ */
+ virtual const char* GetTerseDocumentation()
+ {
+ return "Watch the CMake variable for change.";
+ }
+
+ /**
+ * More documentation.
+ */
+ virtual const char* GetFullDocumentation()
+ {
+ return
+ " VARIABLE_WATCH(<variable name> [<command to execute>])\n"
+ "If the specified variable changes, the message will be printed about "
+ "the variable being changed. If the command is spceified, the command "
+ "will be executed. The command will receive the following arguments:"
+ " COMMAND(<variable> <access> <value> <current list file> <stack>)";
+ }
+
+ cmTypeMacro(cmVariableWatchCommand, cmCommand);
+
+ void VariableAccessed(const std::string& variable, int access_type,
+ const char* newValue, const cmMakefile* mf);
+
+protected:
+ std::map<std::string, cmVariableWatchCommandHandler> Handlers;
+
+ bool InCallback;
+};
+
+
+#endif
+
+
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index e2e624d..973fc20 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -88,7 +88,7 @@
#include <memory> // auto_ptr
void cmNeedBackwardsCompatibility(const std::string& variable,
- int access_type, void* )
+ int access_type, void*, const char*, const cmMakefile*)
{
#ifdef CMAKE_BUILD_WITH_CMAKE
if (access_type == cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS)
diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt
index a1eefb5..6f5167f 100644
--- a/Tests/CMakeTests/CMakeLists.txt
+++ b/Tests/CMakeTests/CMakeLists.txt
@@ -4,7 +4,8 @@ SET(CMAKE_EXECUTABLE "${EXECUTABLE_OUTPUT_PATH}/cmake")
MACRO(AddCMakeTest TestName Arguments)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/${TestName}Test.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${TestName}Test.cmake" @ONLY IMMEDIATE)
- ADD_TEST(CMake.List ${CMAKE_EXECUTABLE} -P "${CMAKE_CURRENT_BINARY_DIR}/ListTest.cmake" ${Arguments})
+ ADD_TEST(CMake.${TestName} ${CMAKE_EXECUTABLE} -P "${CMAKE_CURRENT_BINARY_DIR}/${TestName}Test.cmake" ${Arguments})
ENDMACRO(AddCMakeTest)
AddCMakeTest(List "")
+AddCMakeTest(VariableWatch "")
diff --git a/Tests/CMakeTests/VariableWatchTest.cmake.in b/Tests/CMakeTests/VariableWatchTest.cmake.in
new file mode 100644
index 0000000..0caeeb0
--- /dev/null
+++ b/Tests/CMakeTests/VariableWatchTest.cmake.in
@@ -0,0 +1,22 @@
+MESSAGE("Start")
+
+VARIABLE_WATCH(TESTVAR MESSAGE)
+VARIABLE_WATCH(TESTVAR1)
+
+macro(testwatch var access file stack)
+ MESSAGE("There was a ${access} access done on the variable: ${var} in file ${file}")
+ MESSAGE("List file stack is: ${stack}")
+endmacro(testwatch)
+
+VARIABLE_WATCH(somevar testwatch)
+
+set(TESTVAR1 "1")
+set(TESTVAR "1")
+set(TESTVAR1 "0")
+set(TESTVAR "0")
+
+
+message("Variable: ${somevar}")
+set(somevar "1")
+message("Variable: ${somevar}")
+remove(somevar)