cmLoadCacheCommand.cxx 4.41 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
3 4
#include "cmLoadCacheCommand.h"

5
#include "cmsys/FStream.hxx"
6 7

#include "cmMakefile.h"
8
#include "cmStateTypes.h"
9 10 11 12
#include "cmSystemTools.h"
#include "cmake.h"

class cmExecutionStatus;
13

14
// cmLoadCacheCommand
15 16
bool cmLoadCacheCommand::InitialPass(std::vector<std::string> const& args,
                                     cmExecutionStatus&)
17
{
18
  if (args.empty()) {
19
    this->SetError("called with wrong number of arguments.");
20
  }
21

22
  if (args.size() >= 2 && args[1] == "READ_WITH_PREFIX") {
23
    return this->ReadWithPrefix(args);
24
  }
25

26 27 28
  // Cache entries to be excluded from the import list.
  // If this set is empty, all cache entries are brought in
  // and they can not be overridden.
29
  bool excludeFiles = false;
30
  std::set<std::string> excludes;
31

32
  for (std::string const& arg : args) {
33
    if (excludeFiles) {
34
      excludes.insert(arg);
35
    }
36
    if (arg == "EXCLUDE") {
37 38
      excludeFiles = true;
    }
39
    if (excludeFiles && (arg == "INCLUDE_INTERNALS")) {
40
      break;
41
    }
42
  }
43

44 45 46
  // Internal cache entries to be imported.
  // If this set is empty, no internal cache entries are
  // brought in.
47
  bool includeFiles = false;
48
  std::set<std::string> includes;
49

50
  for (std::string const& arg : args) {
51
    if (includeFiles) {
52
      includes.insert(arg);
53
    }
54
    if (arg == "INCLUDE_INTERNALS") {
55 56
      includeFiles = true;
    }
57
    if (includeFiles && (arg == "EXCLUDE")) {
58 59
      break;
    }
60
  }
61

62 63
  // Loop over each build directory listed in the arguments.  Each
  // directory has a cache file.
64 65
  for (std::string const& arg : args) {
    if ((arg == "EXCLUDE") || (arg == "INCLUDE_INTERNALS")) {
66 67
      break;
    }
68
    this->Makefile->GetCMakeInstance()->LoadCache(arg, false, excludes,
69 70
                                                  includes);
  }
71

72 73 74
  return true;
}

75 76 77
bool cmLoadCacheCommand::ReadWithPrefix(std::vector<std::string> const& args)
{
  // Make sure we have a prefix.
78
  if (args.size() < 3) {
79 80
    this->SetError("READ_WITH_PREFIX form must specify a prefix.");
    return false;
81
  }
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
    this->SetError(e);
88
    return false;
89
  }
90

91 92
  // Prepare the table of variables to read.
  this->Prefix = args[2];
93
  this->VariablesToRead.insert(args.begin() + 3, args.end());
94

95
  // Read the cache file.
96
  cmsys::ifstream fin(cacheFile.c_str());
97

98 99 100 101
  // This is a big hack read loop to overcome a buggy ifstream
  // implementation on HP-UX.  This should work on all platforms even
  // for small buffer sizes.
  const int bufferSize = 4096;
102
  char buffer[bufferSize];
103
  std::string line;
104
  while (fin) {
105 106
    // Read a block of the file.
    fin.read(buffer, bufferSize);
107
    if (fin.gcount()) {
108 109
      // Parse for newlines directly.
      const char* i = buffer;
110 111
      const char* end = buffer + fin.gcount();
      while (i != end) {
112
        const char* begin = i;
113 114 115 116
        while (i != end && *i != '\n') {
          ++i;
        }
        if (i == begin || *(i - 1) != '\r') {
117
          // Include this portion of the line.
118 119
          line += std::string(begin, i - begin);
        } else {
120 121
          // Include this portion of the line.
          // Don't include the \r in a \r\n pair.
122 123 124
          line += std::string(begin, i - 1 - begin);
        }
        if (i != end) {
125 126
          // Completed a line.
          this->CheckLine(line.c_str());
127
          line.clear();
128

129 130 131 132 133
          // Skip the newline character.
          ++i;
        }
      }
    }
134 135
  }
  if (!line.empty()) {
136 137
    // Partial last line.
    this->CheckLine(line.c_str());
138
  }
139

140 141
  return true;
}
142

143 144 145 146 147
void cmLoadCacheCommand::CheckLine(const char* line)
{
  // Check one line of the cache file.
  std::string var;
  std::string value;
148
  cmStateEnums::CacheEntryType type = cmStateEnums::UNINITIALIZED;
149
  if (cmake::ParseCacheEntry(line, var, value, type)) {
150
    // Found a real entry.  See if this one was requested.
151
    if (this->VariablesToRead.find(var) != this->VariablesToRead.end()) {
152 153 154
      // This was requested.  Set this variable locally with the given
      // prefix.
      var = this->Prefix + var;
155
      if (!value.empty()) {
156
        this->Makefile->AddDefinition(var, value.c_str());
157
      } else {
158
        this->Makefile->RemoveDefinition(var);
159 160
      }
    }
161
  }
162
}