cmLoadCacheCommand.cxx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include "cmLoadCacheCommand.h"
  4. #include <set>
  5. #include "cmsys/FStream.hxx"
  6. #include "cmExecutionStatus.h"
  7. #include "cmMakefile.h"
  8. #include "cmState.h"
  9. #include "cmStateTypes.h"
  10. #include "cmSystemTools.h"
  11. #include "cmake.h"
  12. static bool ReadWithPrefix(std::vector<std::string> const& args,
  13. cmExecutionStatus& status);
  14. static void CheckLine(cmMakefile& mf, std::string const& prefix,
  15. std::set<std::string> const& variablesToRead,
  16. char const* line);
  17. bool cmLoadCacheCommand(std::vector<std::string> const& args,
  18. cmExecutionStatus& status)
  19. {
  20. if (args.empty()) {
  21. status.SetError("called with wrong number of arguments.");
  22. return false;
  23. }
  24. if (args.size() >= 2 && args[1] == "READ_WITH_PREFIX") {
  25. return ReadWithPrefix(args, status);
  26. }
  27. cmState::Role const role =
  28. status.GetMakefile().GetCMakeInstance()->GetState()->GetRole();
  29. if (role != cmState::Role::Project) {
  30. status.SetError(
  31. "Only load_cache(READ_WITH_PREFIX) may be used in script mode");
  32. return false;
  33. }
  34. // Cache entries to be excluded from the import list.
  35. // If this set is empty, all cache entries are brought in
  36. // and they can not be overridden.
  37. bool excludeFiles = false;
  38. std::set<std::string> excludes;
  39. for (std::string const& arg : args) {
  40. if (excludeFiles) {
  41. excludes.insert(arg);
  42. }
  43. if (arg == "EXCLUDE") {
  44. excludeFiles = true;
  45. }
  46. if (excludeFiles && (arg == "INCLUDE_INTERNALS")) {
  47. break;
  48. }
  49. }
  50. // Internal cache entries to be imported.
  51. // If this set is empty, no internal cache entries are
  52. // brought in.
  53. bool includeFiles = false;
  54. std::set<std::string> includes;
  55. for (std::string const& arg : args) {
  56. if (includeFiles) {
  57. includes.insert(arg);
  58. }
  59. if (arg == "INCLUDE_INTERNALS") {
  60. includeFiles = true;
  61. }
  62. if (includeFiles && (arg == "EXCLUDE")) {
  63. break;
  64. }
  65. }
  66. cmMakefile& mf = status.GetMakefile();
  67. // Loop over each build directory listed in the arguments. Each
  68. // directory has a cache file.
  69. for (std::string const& arg : args) {
  70. if ((arg == "EXCLUDE") || (arg == "INCLUDE_INTERNALS")) {
  71. break;
  72. }
  73. mf.GetCMakeInstance()->LoadCache(arg, false, excludes, includes);
  74. }
  75. return true;
  76. }
  77. static bool ReadWithPrefix(std::vector<std::string> const& args,
  78. cmExecutionStatus& status)
  79. {
  80. // Make sure we have a prefix.
  81. if (args.size() < 3) {
  82. status.SetError("READ_WITH_PREFIX form must specify a prefix.");
  83. return false;
  84. }
  85. // Make sure the cache file exists.
  86. std::string cacheFile = args[0] + "/CMakeCache.txt";
  87. if (!cmSystemTools::FileExists(cacheFile)) {
  88. std::string e = "Cannot load cache file from " + cacheFile;
  89. status.SetError(e);
  90. return false;
  91. }
  92. // Prepare the table of variables to read.
  93. std::string const& prefix = args[2];
  94. std::set<std::string> const variablesToRead(args.begin() + 3, args.end());
  95. // Read the cache file.
  96. cmsys::ifstream fin(cacheFile.c_str());
  97. cmMakefile& mf = status.GetMakefile();
  98. // This is a big hack read loop to overcome a buggy ifstream
  99. // implementation on HP-UX. This should work on all platforms even
  100. // for small buffer sizes.
  101. int const bufferSize = 4096;
  102. char buffer[bufferSize];
  103. std::string line;
  104. while (fin) {
  105. // Read a block of the file.
  106. fin.read(buffer, bufferSize);
  107. if (fin.gcount()) {
  108. // Parse for newlines directly.
  109. char const* i = buffer;
  110. char const* end = buffer + fin.gcount();
  111. while (i != end) {
  112. char const* begin = i;
  113. while (i != end && *i != '\n') {
  114. ++i;
  115. }
  116. if (i == begin || *(i - 1) != '\r') {
  117. // Include this portion of the line.
  118. line += std::string(begin, i - begin);
  119. } else {
  120. // Include this portion of the line.
  121. // Don't include the \r in a \r\n pair.
  122. line += std::string(begin, i - 1 - begin);
  123. }
  124. if (i != end) {
  125. // Completed a line.
  126. CheckLine(mf, prefix, variablesToRead, line.c_str());
  127. line.clear();
  128. // Skip the newline character.
  129. ++i;
  130. }
  131. }
  132. }
  133. }
  134. if (!line.empty()) {
  135. // Partial last line.
  136. CheckLine(mf, prefix, variablesToRead, line.c_str());
  137. }
  138. return true;
  139. }
  140. static void CheckLine(cmMakefile& mf, std::string const& prefix,
  141. std::set<std::string> const& variablesToRead,
  142. char const* line)
  143. {
  144. // Check one line of the cache file.
  145. std::string var;
  146. std::string value;
  147. cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
  148. if (cmake::ParseCacheEntry(line, var, value, type)) {
  149. // Found a real entry. See if this one was requested.
  150. if (variablesToRead.find(var) != variablesToRead.end()) {
  151. // This was requested. Set this variable locally with the given
  152. // prefix.
  153. var = prefix + var;
  154. if (!value.empty()) {
  155. mf.AddDefinition(var, value);
  156. } else {
  157. mf.RemoveDefinition(var);
  158. }
  159. }
  160. }
  161. }