cmSetCommand.cxx 5.3 KB

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