cmLoadCacheCommand.cxx 5.1 KB

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