1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3
4 #include "cmStateSnapshot.h"
5
6 #include <algorithm>
7 #include <cassert>
8 #include <string>
9
10 #include <cm/iterator>
11
12 #include "cmDefinitions.h"
13 #include "cmListFileCache.h"
14 #include "cmPropertyMap.h"
15 #include "cmState.h"
16 #include "cmStateDirectory.h"
17 #include "cmStatePrivate.h"
18 #include "cmSystemTools.h"
19 #include "cmValue.h"
20 #include "cmVersion.h"
21
22 #if defined(__CYGWIN__)
23 # include "cmStringAlgorithms.h"
24 #endif
25
cmStateSnapshot(cmState * state)26 cmStateSnapshot::cmStateSnapshot(cmState* state)
27 : State(state)
28 {
29 }
30
GetChildren()31 std::vector<cmStateSnapshot> cmStateSnapshot::GetChildren()
32 {
33 return this->Position->BuildSystemDirectory->Children;
34 }
35
cmStateSnapshot(cmState * state,cmStateDetail::PositionType position)36 cmStateSnapshot::cmStateSnapshot(cmState* state,
37 cmStateDetail::PositionType position)
38 : State(state)
39 , Position(position)
40 {
41 }
42
GetType() const43 cmStateEnums::SnapshotType cmStateSnapshot::GetType() const
44 {
45 return this->Position->SnapshotType;
46 }
47
SetListFile(const std::string & listfile)48 void cmStateSnapshot::SetListFile(const std::string& listfile)
49 {
50 *this->Position->ExecutionListFile = listfile;
51 }
52
GetExecutionListFile() const53 std::string const& cmStateSnapshot::GetExecutionListFile() const
54 {
55 return *this->Position->ExecutionListFile;
56 }
57
IsValid() const58 bool cmStateSnapshot::IsValid() const
59 {
60 return this->State && this->Position.IsValid()
61 ? this->Position != this->State->SnapshotData.Root()
62 : false;
63 }
64
GetBuildsystemDirectory() const65 cmStateSnapshot cmStateSnapshot::GetBuildsystemDirectory() const
66 {
67 return { this->State, this->Position->BuildSystemDirectory->DirectoryEnd };
68 }
69
GetBuildsystemDirectoryParent() const70 cmStateSnapshot cmStateSnapshot::GetBuildsystemDirectoryParent() const
71 {
72 cmStateSnapshot snapshot;
73 if (!this->State || this->Position == this->State->SnapshotData.Root()) {
74 return snapshot;
75 }
76 cmStateDetail::PositionType parentPos = this->Position->DirectoryParent;
77 if (parentPos != this->State->SnapshotData.Root()) {
78 snapshot = cmStateSnapshot(this->State,
79 parentPos->BuildSystemDirectory->DirectoryEnd);
80 }
81
82 return snapshot;
83 }
84
GetCallStackParent() const85 cmStateSnapshot cmStateSnapshot::GetCallStackParent() const
86 {
87 assert(this->State);
88 assert(this->Position != this->State->SnapshotData.Root());
89
90 cmStateSnapshot snapshot;
91 cmStateDetail::PositionType parentPos = this->Position;
92 while (parentPos->SnapshotType == cmStateEnums::PolicyScopeType ||
93 parentPos->SnapshotType == cmStateEnums::VariableScopeType) {
94 ++parentPos;
95 }
96 if (parentPos->SnapshotType == cmStateEnums::BuildsystemDirectoryType ||
97 parentPos->SnapshotType == cmStateEnums::BaseType) {
98 return snapshot;
99 }
100
101 ++parentPos;
102 while (parentPos->SnapshotType == cmStateEnums::PolicyScopeType ||
103 parentPos->SnapshotType == cmStateEnums::VariableScopeType) {
104 ++parentPos;
105 }
106
107 if (parentPos == this->State->SnapshotData.Root()) {
108 return snapshot;
109 }
110
111 snapshot = cmStateSnapshot(this->State, parentPos);
112 return snapshot;
113 }
114
GetCallStackBottom() const115 cmStateSnapshot cmStateSnapshot::GetCallStackBottom() const
116 {
117 assert(this->State);
118 assert(this->Position != this->State->SnapshotData.Root());
119
120 cmStateDetail::PositionType pos = this->Position;
121 while (pos->SnapshotType != cmStateEnums::BaseType &&
122 pos->SnapshotType != cmStateEnums::BuildsystemDirectoryType &&
123 pos != this->State->SnapshotData.Root()) {
124 ++pos;
125 }
126 return { this->State, pos };
127 }
128
PushPolicy(cmPolicies::PolicyMap const & entry,bool weak)129 void cmStateSnapshot::PushPolicy(cmPolicies::PolicyMap const& entry, bool weak)
130 {
131 cmStateDetail::PositionType pos = this->Position;
132 pos->Policies = this->State->PolicyStack.Push(
133 pos->Policies, cmStateDetail::PolicyStackEntry(entry, weak));
134 }
135
PopPolicy()136 bool cmStateSnapshot::PopPolicy()
137 {
138 cmStateDetail::PositionType pos = this->Position;
139 if (pos->Policies == pos->PolicyScope) {
140 return false;
141 }
142 pos->Policies = this->State->PolicyStack.Pop(pos->Policies);
143 return true;
144 }
145
CanPopPolicyScope()146 bool cmStateSnapshot::CanPopPolicyScope()
147 {
148 return this->Position->Policies != this->Position->PolicyScope;
149 }
150
SetPolicy(cmPolicies::PolicyID id,cmPolicies::PolicyStatus status)151 void cmStateSnapshot::SetPolicy(cmPolicies::PolicyID id,
152 cmPolicies::PolicyStatus status)
153 {
154 // Update the policy stack from the top to the top-most strong entry.
155 bool previous_was_weak = true;
156 for (cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator psi =
157 this->Position->Policies;
158 previous_was_weak && psi != this->Position->PolicyRoot; ++psi) {
159 psi->Set(id, status);
160 previous_was_weak = psi->Weak;
161 }
162 }
163
GetPolicy(cmPolicies::PolicyID id,bool parent_scope) const164 cmPolicies::PolicyStatus cmStateSnapshot::GetPolicy(cmPolicies::PolicyID id,
165 bool parent_scope) const
166 {
167 cmPolicies::PolicyStatus status = cmPolicies::GetPolicyStatus(id);
168
169 if (status == cmPolicies::REQUIRED_ALWAYS ||
170 status == cmPolicies::REQUIRED_IF_USED) {
171 return status;
172 }
173
174 cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator dir =
175 this->Position->BuildSystemDirectory;
176
177 while (true) {
178 assert(dir.IsValid());
179 cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator leaf =
180 dir->DirectoryEnd->Policies;
181 cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator root =
182 dir->DirectoryEnd->PolicyRoot;
183 for (; leaf != root; ++leaf) {
184 if (parent_scope) {
185 parent_scope = false;
186 continue;
187 }
188 if (leaf->IsDefined(id)) {
189 status = leaf->Get(id);
190 return status;
191 }
192 }
193 cmStateDetail::PositionType e = dir->DirectoryEnd;
194 cmStateDetail::PositionType p = e->DirectoryParent;
195 if (p == this->State->SnapshotData.Root()) {
196 break;
197 }
198 dir = p->BuildSystemDirectory;
199 }
200 return status;
201 }
202
HasDefinedPolicyCMP0011()203 bool cmStateSnapshot::HasDefinedPolicyCMP0011()
204 {
205 return !this->Position->Policies->IsEmpty();
206 }
207
GetDefinition(std::string const & name) const208 cmValue cmStateSnapshot::GetDefinition(std::string const& name) const
209 {
210 assert(this->Position->Vars.IsValid());
211 return cmDefinitions::Get(name, this->Position->Vars, this->Position->Root);
212 }
213
IsInitialized(std::string const & name) const214 bool cmStateSnapshot::IsInitialized(std::string const& name) const
215 {
216 return cmDefinitions::HasKey(name, this->Position->Vars,
217 this->Position->Root);
218 }
219
SetDefinition(std::string const & name,cm::string_view value)220 void cmStateSnapshot::SetDefinition(std::string const& name,
221 cm::string_view value)
222 {
223 this->Position->Vars->Set(name, value);
224 }
225
RemoveDefinition(std::string const & name)226 void cmStateSnapshot::RemoveDefinition(std::string const& name)
227 {
228 this->Position->Vars->Unset(name);
229 }
230
ClosureKeys() const231 std::vector<std::string> cmStateSnapshot::ClosureKeys() const
232 {
233 return cmDefinitions::ClosureKeys(this->Position->Vars,
234 this->Position->Root);
235 }
236
RaiseScope(std::string const & var,const char * varDef)237 bool cmStateSnapshot::RaiseScope(std::string const& var, const char* varDef)
238 {
239 if (this->Position->ScopeParent == this->Position->DirectoryParent) {
240 cmStateSnapshot parentDir = this->GetBuildsystemDirectoryParent();
241 if (!parentDir.IsValid()) {
242 return false;
243 }
244 // Update the definition in the parent directory top scope. This
245 // directory's scope was initialized by the closure of the parent
246 // scope, so we do not need to localize the definition first.
247 if (varDef) {
248 parentDir.SetDefinition(var, varDef);
249 } else {
250 parentDir.RemoveDefinition(var);
251 }
252 return true;
253 }
254 // First localize the definition in the current scope.
255 cmDefinitions::Raise(var, this->Position->Vars, this->Position->Root);
256
257 // Now update the definition in the parent scope.
258 if (varDef) {
259 this->Position->Parent->Set(var, varDef);
260 } else {
261 this->Position->Parent->Unset(var);
262 }
263 return true;
264 }
265
266 template <typename T, typename U>
InitializeContentFromParent(T & parentContent,T & thisContent,U & contentEndPosition)267 void InitializeContentFromParent(T& parentContent, T& thisContent,
268 U& contentEndPosition)
269 {
270 auto parentEnd = parentContent.end();
271
272 auto parentRbegin = cm::make_reverse_iterator(parentEnd);
273 auto parentRend = parentContent.rend();
274 parentRbegin = std::find(parentRbegin, parentRend, cmPropertySentinal);
275 auto parentIt = parentRbegin.base();
276
277 thisContent = std::vector<BT<std::string>>(parentIt, parentEnd);
278
279 contentEndPosition = thisContent.size();
280 }
281
SetDefaultDefinitions()282 void cmStateSnapshot::SetDefaultDefinitions()
283 {
284 /* Up to CMake 2.4 here only WIN32, UNIX and APPLE were set.
285 With CMake must separate between target and host platform. In most cases
286 the tests for WIN32, UNIX and APPLE will be for the target system, so an
287 additional set of variables for the host system is required ->
288 CMAKE_HOST_WIN32, CMAKE_HOST_UNIX, CMAKE_HOST_APPLE.
289 WIN32, UNIX and APPLE are now set in the platform files in
290 Modules/Platforms/.
291 To keep cmake scripts (-P) and custom language and compiler modules
292 working, these variables are still also set here in this place, but they
293 will be reset in CMakeSystemSpecificInformation.cmake before the platform
294 files are executed. */
295 cm::string_view hostSystemName = cmSystemTools::GetSystemName();
296 this->SetDefinition("CMAKE_HOST_SYSTEM_NAME", hostSystemName);
297 if (hostSystemName == "Windows") {
298 this->SetDefinition("WIN32", "1");
299 this->SetDefinition("CMAKE_HOST_WIN32", "1");
300 } else {
301 this->SetDefinition("UNIX", "1");
302 this->SetDefinition("CMAKE_HOST_UNIX", "1");
303 }
304 #if defined(__CYGWIN__)
305 std::string legacy;
306 if (cmSystemTools::GetEnv("CMAKE_LEGACY_CYGWIN_WIN32", legacy) &&
307 cmIsOn(legacy)) {
308 this->SetDefinition("WIN32", "1");
309 this->SetDefinition("CMAKE_HOST_WIN32", "1");
310 }
311 #endif
312 #if defined(__APPLE__)
313 this->SetDefinition("APPLE", "1");
314 this->SetDefinition("CMAKE_HOST_APPLE", "1");
315 #endif
316 #if defined(__sun__)
317 this->SetDefinition("CMAKE_HOST_SOLARIS", "1");
318 #endif
319
320 this->SetDefinition("CMAKE_MAJOR_VERSION",
321 std::to_string(cmVersion::GetMajorVersion()));
322 this->SetDefinition("CMAKE_MINOR_VERSION",
323 std::to_string(cmVersion::GetMinorVersion()));
324 this->SetDefinition("CMAKE_PATCH_VERSION",
325 std::to_string(cmVersion::GetPatchVersion()));
326 this->SetDefinition("CMAKE_TWEAK_VERSION",
327 std::to_string(cmVersion::GetTweakVersion()));
328 this->SetDefinition("CMAKE_VERSION", cmVersion::GetCMakeVersion());
329
330 this->SetDefinition("CMAKE_FILES_DIRECTORY", "/CMakeFiles");
331
332 // Setup the default include file regular expression (match everything).
333 this->Position->BuildSystemDirectory->Properties.SetProperty(
334 "INCLUDE_REGULAR_EXPRESSION", "^.*$");
335 }
336
SetDirectoryDefinitions()337 void cmStateSnapshot::SetDirectoryDefinitions()
338 {
339 this->SetDefinition("CMAKE_SOURCE_DIR", this->State->GetSourceDirectory());
340 this->SetDefinition("CMAKE_CURRENT_SOURCE_DIR",
341 this->State->GetSourceDirectory());
342 this->SetDefinition("CMAKE_BINARY_DIR", this->State->GetBinaryDirectory());
343 this->SetDefinition("CMAKE_CURRENT_BINARY_DIR",
344 this->State->GetBinaryDirectory());
345 }
346
InitializeFromParent()347 void cmStateSnapshot::InitializeFromParent()
348 {
349 cmStateDetail::PositionType parent = this->Position->DirectoryParent;
350 assert(this->Position->Vars.IsValid());
351 assert(parent->Vars.IsValid());
352
353 *this->Position->Vars =
354 cmDefinitions::MakeClosure(parent->Vars, parent->Root);
355
356 InitializeContentFromParent(
357 parent->BuildSystemDirectory->IncludeDirectories,
358 this->Position->BuildSystemDirectory->IncludeDirectories,
359 this->Position->IncludeDirectoryPosition);
360
361 InitializeContentFromParent(
362 parent->BuildSystemDirectory->CompileDefinitions,
363 this->Position->BuildSystemDirectory->CompileDefinitions,
364 this->Position->CompileDefinitionsPosition);
365
366 InitializeContentFromParent(
367 parent->BuildSystemDirectory->CompileOptions,
368 this->Position->BuildSystemDirectory->CompileOptions,
369 this->Position->CompileOptionsPosition);
370
371 InitializeContentFromParent(
372 parent->BuildSystemDirectory->LinkOptions,
373 this->Position->BuildSystemDirectory->LinkOptions,
374 this->Position->LinkOptionsPosition);
375
376 InitializeContentFromParent(
377 parent->BuildSystemDirectory->LinkDirectories,
378 this->Position->BuildSystemDirectory->LinkDirectories,
379 this->Position->LinkDirectoriesPosition);
380
381 cmValue include_regex =
382 parent->BuildSystemDirectory->Properties.GetPropertyValue(
383 "INCLUDE_REGULAR_EXPRESSION");
384 this->Position->BuildSystemDirectory->Properties.SetProperty(
385 "INCLUDE_REGULAR_EXPRESSION", include_regex);
386 }
387
GetState() const388 cmState* cmStateSnapshot::GetState() const
389 {
390 return this->State;
391 }
392
GetDirectory() const393 cmStateDirectory cmStateSnapshot::GetDirectory() const
394 {
395 return { this->Position->BuildSystemDirectory, *this };
396 }
397
SetProjectName(const std::string & name)398 void cmStateSnapshot::SetProjectName(const std::string& name)
399 {
400 this->Position->BuildSystemDirectory->ProjectName = name;
401 }
402
GetProjectName() const403 std::string cmStateSnapshot::GetProjectName() const
404 {
405 return this->Position->BuildSystemDirectory->ProjectName;
406 }
407
InitializeFromParent_ForSubdirsCommand()408 void cmStateSnapshot::InitializeFromParent_ForSubdirsCommand()
409 {
410 std::string currentSrcDir = *this->GetDefinition("CMAKE_CURRENT_SOURCE_DIR");
411 std::string currentBinDir = *this->GetDefinition("CMAKE_CURRENT_BINARY_DIR");
412 this->InitializeFromParent();
413 this->SetDefinition("CMAKE_SOURCE_DIR", this->State->GetSourceDirectory());
414 this->SetDefinition("CMAKE_BINARY_DIR", this->State->GetBinaryDirectory());
415
416 this->SetDefinition("CMAKE_CURRENT_SOURCE_DIR", currentSrcDir);
417 this->SetDefinition("CMAKE_CURRENT_BINARY_DIR", currentBinDir);
418 }
419
operator ()(const cmStateSnapshot & lhs,const cmStateSnapshot & rhs) const420 bool cmStateSnapshot::StrictWeakOrder::operator()(
421 const cmStateSnapshot& lhs, const cmStateSnapshot& rhs) const
422 {
423 return lhs.Position.StrictWeakOrdered(rhs.Position);
424 }
425
operator ==(const cmStateSnapshot & lhs,const cmStateSnapshot & rhs)426 bool operator==(const cmStateSnapshot& lhs, const cmStateSnapshot& rhs)
427 {
428 return lhs.Position == rhs.Position;
429 }
430
operator !=(const cmStateSnapshot & lhs,const cmStateSnapshot & rhs)431 bool operator!=(const cmStateSnapshot& lhs, const cmStateSnapshot& rhs)
432 {
433 return lhs.Position != rhs.Position;
434 }
435