cmVariableWatchCommand.cxx 4.2 KB

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