cmSetCommand.cxx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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 "cmSetCommand.h"
  4. #include "cmAlgorithms.h"
  5. #include "cmMakefile.h"
  6. #include "cmState.h"
  7. #include "cmStateTypes.h"
  8. #include "cmSystemTools.h"
  9. class cmExecutionStatus;
  10. // cmSetCommand
  11. bool cmSetCommand::InitialPass(std::vector<std::string> const& args,
  12. cmExecutionStatus&)
  13. {
  14. if (args.empty()) {
  15. this->SetError("called with incorrect number of arguments");
  16. return false;
  17. }
  18. // watch for ENV signatures
  19. auto const& variable = args[0]; // VAR is always first
  20. if (cmHasLiteralPrefix(variable, "ENV{") && variable.size() > 5) {
  21. // what is the variable name
  22. auto const& varName = variable.substr(4, variable.size() - 5);
  23. std::string putEnvArg = varName + "=";
  24. // what is the current value if any
  25. std::string currValue;
  26. const bool currValueSet = cmSystemTools::GetEnv(varName, currValue);
  27. // will it be set to something, then set it
  28. if (args.size() > 1 && !args[1].empty()) {
  29. // but only if it is different from current value
  30. if (!currValueSet || currValue != args[1]) {
  31. putEnvArg += args[1];
  32. cmSystemTools::PutEnv(putEnvArg);
  33. }
  34. return true;
  35. }
  36. // if it will be cleared, then clear it if it isn't already clear
  37. if (currValueSet) {
  38. cmSystemTools::PutEnv(putEnvArg);
  39. }
  40. return true;
  41. }
  42. // SET (VAR) // Removes the definition of VAR.
  43. if (args.size() == 1) {
  44. this->Makefile->RemoveDefinition(variable);
  45. return true;
  46. }
  47. // SET (VAR PARENT_SCOPE) // Removes the definition of VAR
  48. // in the parent scope.
  49. if (args.size() == 2 && args[args.size() - 1] == "PARENT_SCOPE") {
  50. this->Makefile->RaiseScope(variable, nullptr);
  51. return true;
  52. }
  53. // here are the remaining options
  54. // SET (VAR value )
  55. // SET (VAR value PARENT_SCOPE)
  56. // SET (VAR CACHE TYPE "doc String" [FORCE])
  57. // SET (VAR value CACHE TYPE "doc string" [FORCE])
  58. std::string value; // optional
  59. bool cache = false; // optional
  60. bool force = false; // optional
  61. bool parentScope = false;
  62. cmStateEnums::CacheEntryType type =
  63. cmStateEnums::STRING; // required if cache
  64. const char* docstring = nullptr; // required if cache
  65. unsigned int ignoreLastArgs = 0;
  66. // look for PARENT_SCOPE argument
  67. if (args.size() > 1 && args[args.size() - 1] == "PARENT_SCOPE") {
  68. parentScope = true;
  69. ignoreLastArgs++;
  70. } else {
  71. // look for FORCE argument
  72. if (args.size() > 4 && args[args.size() - 1] == "FORCE") {
  73. force = true;
  74. ignoreLastArgs++;
  75. }
  76. // check for cache signature
  77. if (args.size() > 3 &&
  78. args[args.size() - 3 - (force ? 1 : 0)] == "CACHE") {
  79. cache = true;
  80. ignoreLastArgs += 3;
  81. }
  82. }
  83. // collect any values into a single semi-colon separated value list
  84. value = cmJoin(cmMakeRange(args).advance(1).retreat(ignoreLastArgs), ";");
  85. if (parentScope) {
  86. this->Makefile->RaiseScope(variable, value.c_str());
  87. return true;
  88. }
  89. // we should be nice and try to catch some simple screwups if the last or
  90. // next to last args are CACHE then they screwed up. If they used FORCE
  91. // without CACHE they screwed up
  92. if ((args[args.size() - 1] == "CACHE") ||
  93. (args.size() > 1 && args[args.size() - 2] == "CACHE") ||
  94. (force && !cache)) {
  95. this->SetError("given invalid arguments for CACHE mode.");
  96. return false;
  97. }
  98. if (cache) {
  99. std::string::size_type cacheStart = args.size() - 3 - (force ? 1 : 0);
  100. type = cmState::StringToCacheEntryType(args[cacheStart + 1].c_str());
  101. docstring = args[cacheStart + 2].c_str();
  102. }
  103. // see if this is already in the cache
  104. cmState* state = this->Makefile->GetState();
  105. const char* existingValue = state->GetCacheEntryValue(variable);
  106. if (existingValue &&
  107. (state->GetCacheEntryType(variable) != cmStateEnums::UNINITIALIZED)) {
  108. // if the set is trying to CACHE the value but the value
  109. // is already in the cache and the type is not internal
  110. // then leave now without setting any definitions in the cache
  111. // or the makefile
  112. if (cache && type != cmStateEnums::INTERNAL && !force) {
  113. return true;
  114. }
  115. }
  116. // if it is meant to be in the cache then define it in the cache
  117. if (cache) {
  118. this->Makefile->AddCacheDefinition(variable, value.c_str(), docstring,
  119. type, force);
  120. } else {
  121. // add the definition
  122. this->Makefile->AddDefinition(variable, value.c_str());
  123. }
  124. return true;
  125. }