cmVariableWatchCommand.cxx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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.emplace_back(variable, cmListFileArgument::Quoted, 9999);
  39. newLFF.Arguments.emplace_back(accessString, cmListFileArgument::Quoted,
  40. 9999);
  41. newLFF.Arguments.emplace_back(newValue ? newValue : "",
  42. cmListFileArgument::Quoted, 9999);
  43. newLFF.Arguments.emplace_back(currentListFile, cmListFileArgument::Quoted,
  44. 9999);
  45. newLFF.Arguments.emplace_back(stack, cmListFileArgument::Quoted, 9999);
  46. newLFF.Name = data->Command;
  47. newLFF.Line = 9999;
  48. cmExecutionStatus status;
  49. if (!makefile->ExecuteCommand(newLFF, status)) {
  50. std::ostringstream error;
  51. error << "Error in cmake code at\nUnknown:0:\n"
  52. << "A command failed during the invocation of callback \""
  53. << data->Command << "\".";
  54. cmSystemTools::Error(error.str().c_str());
  55. data->InCallback = false;
  56. return;
  57. }
  58. processed = true;
  59. }
  60. if (!processed) {
  61. std::ostringstream msg;
  62. msg << "Variable \"" << variable << "\" was accessed using "
  63. << accessString << " with value \"" << (newValue ? newValue : "")
  64. << "\".";
  65. makefile->IssueMessage(cmake::LOG, msg.str());
  66. }
  67. data->InCallback = false;
  68. }
  69. static void deleteVariableWatchCallbackData(void* client_data)
  70. {
  71. cmVariableWatchCallbackData* data =
  72. static_cast<cmVariableWatchCallbackData*>(client_data);
  73. delete data;
  74. }
  75. cmVariableWatchCommand::cmVariableWatchCommand()
  76. {
  77. }
  78. cmVariableWatchCommand::~cmVariableWatchCommand()
  79. {
  80. for (std::string const& wv : this->WatchedVariables) {
  81. this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch(
  82. wv, cmVariableWatchCommandVariableAccessed);
  83. }
  84. }
  85. bool cmVariableWatchCommand::InitialPass(std::vector<std::string> const& args,
  86. cmExecutionStatus&)
  87. {
  88. if (args.empty()) {
  89. this->SetError("must be called with at least one argument.");
  90. return false;
  91. }
  92. std::string const& variable = args[0];
  93. std::string command;
  94. if (args.size() > 1) {
  95. command = args[1];
  96. }
  97. if (variable == "CMAKE_CURRENT_LIST_FILE") {
  98. std::ostringstream ostr;
  99. ostr << "cannot be set on the variable: " << variable;
  100. this->SetError(ostr.str());
  101. return false;
  102. }
  103. cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData;
  104. data->InCallback = false;
  105. data->Command = command;
  106. this->WatchedVariables.insert(variable);
  107. if (!this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch(
  108. variable, cmVariableWatchCommandVariableAccessed, data,
  109. deleteVariableWatchCallbackData)) {
  110. deleteVariableWatchCallbackData(data);
  111. return false;
  112. }
  113. return true;
  114. }