cmSetCommand.cxx 5.3 KB

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