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