cmVariableWatchCommand.cxx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmVariableWatchCommand.h"
  11. #include "cmVariableWatch.h"
  12. struct cmVariableWatchCallbackData
  13. {
  14. bool InCallback;
  15. std::string Command;
  16. };
  17. static void cmVariableWatchCommandVariableAccessed(const std::string& variable,
  18. int access_type,
  19. void* client_data,
  20. const char* newValue,
  21. const cmMakefile* mf)
  22. {
  23. cmVariableWatchCallbackData* data =
  24. static_cast<cmVariableWatchCallbackData*>(client_data);
  25. if (data->InCallback) {
  26. return;
  27. }
  28. data->InCallback = true;
  29. cmListFileFunction newLFF;
  30. cmListFileArgument arg;
  31. bool processed = false;
  32. const char* accessString = cmVariableWatch::GetAccessAsString(access_type);
  33. const char* currentListFile = mf->GetDefinition("CMAKE_CURRENT_LIST_FILE");
  34. /// Ultra bad!!
  35. cmMakefile* makefile = const_cast<cmMakefile*>(mf);
  36. std::string stack = makefile->GetProperty("LISTFILE_STACK");
  37. if (!data->Command.empty()) {
  38. newLFF.Arguments.clear();
  39. newLFF.Arguments.push_back(
  40. cmListFileArgument(variable, cmListFileArgument::Quoted, 9999));
  41. newLFF.Arguments.push_back(
  42. cmListFileArgument(accessString, cmListFileArgument::Quoted, 9999));
  43. newLFF.Arguments.push_back(cmListFileArgument(
  44. newValue ? newValue : "", cmListFileArgument::Quoted, 9999));
  45. newLFF.Arguments.push_back(
  46. cmListFileArgument(currentListFile, cmListFileArgument::Quoted, 9999));
  47. newLFF.Arguments.push_back(
  48. cmListFileArgument(stack, cmListFileArgument::Quoted, 9999));
  49. newLFF.Name = data->Command;
  50. newLFF.Line = 9999;
  51. cmExecutionStatus status;
  52. if (!makefile->ExecuteCommand(newLFF, status)) {
  53. std::ostringstream error;
  54. error << "Error in cmake code at\nUnknown:0:\n"
  55. << "A command failed during the invocation of callback \""
  56. << data->Command << "\".";
  57. cmSystemTools::Error(error.str().c_str());
  58. data->InCallback = false;
  59. return;
  60. }
  61. processed = true;
  62. }
  63. if (!processed) {
  64. std::ostringstream msg;
  65. msg << "Variable \"" << variable << "\" was accessed using "
  66. << accessString << " with value \"" << (newValue ? newValue : "")
  67. << "\".";
  68. makefile->IssueMessage(cmake::LOG, msg.str());
  69. }
  70. data->InCallback = false;
  71. }
  72. static void deleteVariableWatchCallbackData(void* client_data)
  73. {
  74. cmVariableWatchCallbackData* data =
  75. static_cast<cmVariableWatchCallbackData*>(client_data);
  76. delete data;
  77. }
  78. cmVariableWatchCommand::cmVariableWatchCommand()
  79. {
  80. }
  81. cmVariableWatchCommand::~cmVariableWatchCommand()
  82. {
  83. std::set<std::string>::const_iterator it;
  84. for (it = this->WatchedVariables.begin(); it != this->WatchedVariables.end();
  85. ++it) {
  86. this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch(
  87. *it, cmVariableWatchCommandVariableAccessed);
  88. }
  89. }
  90. bool cmVariableWatchCommand::InitialPass(std::vector<std::string> const& args,
  91. cmExecutionStatus&)
  92. {
  93. if (args.empty()) {
  94. this->SetError("must be called with at least one argument.");
  95. return false;
  96. }
  97. std::string variable = args[0];
  98. std::string command;
  99. if (args.size() > 1) {
  100. command = args[1];
  101. }
  102. if (variable == "CMAKE_CURRENT_LIST_FILE") {
  103. std::ostringstream ostr;
  104. ostr << "cannot be set on the variable: " << variable;
  105. this->SetError(ostr.str());
  106. return false;
  107. }
  108. cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData;
  109. data->InCallback = false;
  110. data->Command = command;
  111. this->WatchedVariables.insert(variable);
  112. if (!this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch(
  113. variable, cmVariableWatchCommandVariableAccessed, data,
  114. deleteVariableWatchCallbackData)) {
  115. deleteVariableWatchCallbackData(data);
  116. return false;
  117. }
  118. return true;
  119. }