CMake Nightly Date Stamp
[kiteware-cmake.git] / Source / cmDepends.cxx
blob04bccce5e7ab78633c8d3185b8ff8641370b695a
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 "cmDepends.h"
5 #include <utility>
7 #include "cmsys/FStream.hxx"
9 #include "cmFileTime.h"
10 #include "cmFileTimeCache.h"
11 #include "cmGeneratedFileStream.h"
12 #include "cmList.h"
13 #include "cmLocalUnixMakefileGenerator3.h"
14 #include "cmMakefile.h"
15 #include "cmStringAlgorithms.h"
16 #include "cmSystemTools.h"
17 #include "cmValue.h"
19 cmDepends::cmDepends(cmLocalUnixMakefileGenerator3* lg, std::string targetDir)
20 : LocalGenerator(lg)
21 , TargetDirectory(std::move(targetDir))
25 cmDepends::~cmDepends() = default;
27 bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends)
29 std::map<std::string, std::set<std::string>> dependencies;
31 // Lookup the set of sources to scan.
32 cmList pairs;
34 std::string const srcLang = "CMAKE_DEPENDS_CHECK_" + this->Language;
35 cmMakefile* mf = this->LocalGenerator->GetMakefile();
36 pairs.assign(mf->GetSafeDefinition(srcLang));
38 for (auto si = pairs.begin(); si != pairs.end();) {
39 // Get the source and object file.
40 std::string const& src = *si++;
41 if (si == pairs.end()) {
42 break;
44 std::string const& obj = *si++;
45 dependencies[obj].insert(src);
48 for (auto const& d : dependencies) {
49 // Write the dependencies for this pair.
50 if (!this->WriteDependencies(d.second, d.first, makeDepends,
51 internalDepends)) {
52 return false;
56 return this->Finalize(makeDepends, internalDepends);
59 bool cmDepends::Finalize(std::ostream& /*unused*/, std::ostream& /*unused*/)
61 return true;
64 bool cmDepends::Check(const std::string& makeFile,
65 const std::string& internalFile,
66 DependencyMap& validDeps)
68 // Check whether dependencies must be regenerated.
69 bool okay = true;
70 cmsys::ifstream fin(internalFile.c_str());
71 if (!(fin && this->CheckDependencies(fin, internalFile, validDeps))) {
72 // Clear all dependencies so they will be regenerated.
73 this->Clear(makeFile);
74 cmSystemTools::RemoveFile(internalFile);
75 this->FileTimeCache->Remove(internalFile);
76 okay = false;
78 return okay;
81 void cmDepends::Clear(const std::string& file) const
83 // Print verbose output.
84 if (this->Verbose) {
85 cmSystemTools::Stdout(
86 cmStrCat("Clearing dependencies in \"", file, "\".\n"));
89 // Write an empty dependency file.
90 cmGeneratedFileStream depFileStream(file);
91 depFileStream << "# Empty dependencies file\n"
92 "# This may be replaced when dependencies are built.\n";
95 bool cmDepends::WriteDependencies(const std::set<std::string>& /*unused*/,
96 const std::string& /*unused*/,
97 std::ostream& /*unused*/,
98 std::ostream& /*unused*/)
100 // This should be implemented by the subclass.
101 return false;
104 bool cmDepends::CheckDependencies(std::istream& internalDepends,
105 const std::string& internalDependsFileName,
106 DependencyMap& validDeps)
108 // Read internal depends file time
109 cmFileTime internalDependsTime;
110 if (!this->FileTimeCache->Load(internalDependsFileName,
111 internalDependsTime)) {
112 return false;
115 // Parse dependencies from the stream. If any dependee is missing
116 // or newer than the depender then dependencies should be
117 // regenerated.
118 bool okay = true;
119 bool dependerExists = false;
121 std::string line;
122 line.reserve(1024);
123 std::string depender;
124 std::string dependee;
125 cmFileTime dependerTime;
126 cmFileTime dependeeTime;
127 std::vector<std::string>* currentDependencies = nullptr;
129 while (std::getline(internalDepends, line)) {
130 // Check if this an empty or a comment line
131 if (line.empty() || line.front() == '#') {
132 continue;
134 // Drop carriage return character at the end
135 if (line.back() == '\r') {
136 line.pop_back();
137 if (line.empty()) {
138 continue;
141 // Check if this a depender line
142 if (line.front() != ' ') {
143 depender = line;
144 dependerExists = this->FileTimeCache->Load(depender, dependerTime);
145 // If we erase validDeps[this->Depender] by overwriting it with an empty
146 // vector, we lose dependencies for dependers that have multiple
147 // entries. No need to initialize the entry, std::map will do so on first
148 // access.
149 currentDependencies = &validDeps[depender];
150 continue;
153 // This is a dependee line
154 dependee = line.substr(1);
156 // Add dependee to depender's list
157 if (currentDependencies != nullptr) {
158 currentDependencies->push_back(dependee);
161 // Dependencies must be regenerated
162 // * if the dependee does not exist
163 // * if the depender exists and is older than the dependee.
164 // * if the depender does not exist, but the dependee is newer than the
165 // depends file
166 bool regenerate = false;
167 bool dependeeExists = this->FileTimeCache->Load(dependee, dependeeTime);
168 if (!dependeeExists) {
169 // The dependee does not exist.
170 regenerate = true;
172 // Print verbose output.
173 if (this->Verbose) {
174 cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
175 "\" does not exist for depender \"",
176 depender, "\".\n"));
178 } else if (dependerExists) {
179 // The dependee and depender both exist. Compare file times.
180 if (dependerTime.Older(dependeeTime)) {
181 // The depender is older than the dependee.
182 regenerate = true;
184 // Print verbose output.
185 if (this->Verbose) {
186 cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
187 "\" is newer than depender \"",
188 depender, "\".\n"));
191 } else {
192 // The dependee exists, but the depender doesn't. Regenerate if the
193 // internalDepends file is older than the dependee.
194 if (internalDependsTime.Older(dependeeTime)) {
195 // The depends-file is older than the dependee.
196 regenerate = true;
198 // Print verbose output.
199 if (this->Verbose) {
200 cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
201 "\" is newer than depends file \"",
202 internalDependsFileName, "\".\n"));
207 if (regenerate) {
208 // Dependencies must be regenerated.
209 okay = false;
211 // Remove the information of this depender from the map, it needs
212 // to be rescanned
213 if (currentDependencies != nullptr) {
214 validDeps.erase(depender);
215 currentDependencies = nullptr;
218 // Remove the depender to be sure it is rebuilt.
219 if (dependerExists) {
220 cmSystemTools::RemoveFile(depender);
221 this->FileTimeCache->Remove(depender);
222 dependerExists = false;
227 return okay;
230 void cmDepends::SetIncludePathFromLanguage(const std::string& lang)
232 // Look for the new per "TARGET_" variant first:
233 std::string includePathVar =
234 cmStrCat("CMAKE_", lang, "_TARGET_INCLUDE_PATH");
235 cmMakefile* mf = this->LocalGenerator->GetMakefile();
236 cmValue includePath = mf->GetDefinition(includePathVar);
237 if (includePath) {
238 cmExpandList(*includePath, this->IncludePath);
239 } else {
240 // Fallback to the old directory level variable if no per-target var:
241 includePathVar = cmStrCat("CMAKE_", lang, "_INCLUDE_PATH");
242 includePath = mf->GetDefinition(includePathVar);
243 if (includePath) {
244 cmExpandList(*includePath, this->IncludePath);