f73df8f08ac5df148c38f86cf99abf2b1bd1ddb4
[platform/upstream/cmake.git] / Source / cmStateSnapshot.cxx
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
26 cmStateSnapshot::cmStateSnapshot(cmState* state)
27   : State(state)
28 {
29 }
30
31 std::vector<cmStateSnapshot> cmStateSnapshot::GetChildren()
32 {
33   return this->Position->BuildSystemDirectory->Children;
34 }
35
36 cmStateSnapshot::cmStateSnapshot(cmState* state,
37                                  cmStateDetail::PositionType position)
38   : State(state)
39   , Position(position)
40 {
41 }
42
43 cmStateEnums::SnapshotType cmStateSnapshot::GetType() const
44 {
45   return this->Position->SnapshotType;
46 }
47
48 void cmStateSnapshot::SetListFile(const std::string& listfile)
49 {
50   *this->Position->ExecutionListFile = listfile;
51 }
52
53 std::string const& cmStateSnapshot::GetExecutionListFile() const
54 {
55   return *this->Position->ExecutionListFile;
56 }
57
58 bool cmStateSnapshot::IsValid() const
59 {
60   return this->State && this->Position.IsValid()
61     ? this->Position != this->State->SnapshotData.Root()
62     : false;
63 }
64
65 cmStateSnapshot cmStateSnapshot::GetBuildsystemDirectory() const
66 {
67   return { this->State, this->Position->BuildSystemDirectory->DirectoryEnd };
68 }
69
70 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
85 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
115 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
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
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
146 bool cmStateSnapshot::CanPopPolicyScope()
147 {
148   return this->Position->Policies != this->Position->PolicyScope;
149 }
150
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
164 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
203 bool cmStateSnapshot::HasDefinedPolicyCMP0011()
204 {
205   return !this->Position->Policies->IsEmpty();
206 }
207
208 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
214 bool cmStateSnapshot::IsInitialized(std::string const& name) const
215 {
216   return cmDefinitions::HasKey(name, this->Position->Vars,
217                                this->Position->Root);
218 }
219
220 void cmStateSnapshot::SetDefinition(std::string const& name,
221                                     cm::string_view value)
222 {
223   this->Position->Vars->Set(name, value);
224 }
225
226 void cmStateSnapshot::RemoveDefinition(std::string const& name)
227 {
228   this->Position->Vars->Unset(name);
229 }
230
231 std::vector<std::string> cmStateSnapshot::ClosureKeys() const
232 {
233   return cmDefinitions::ClosureKeys(this->Position->Vars,
234                                     this->Position->Root);
235 }
236
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>
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
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
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
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
388 cmState* cmStateSnapshot::GetState() const
389 {
390   return this->State;
391 }
392
393 cmStateDirectory cmStateSnapshot::GetDirectory() const
394 {
395   return { this->Position->BuildSystemDirectory, *this };
396 }
397
398 void cmStateSnapshot::SetProjectName(const std::string& name)
399 {
400   this->Position->BuildSystemDirectory->ProjectName = name;
401 }
402
403 std::string cmStateSnapshot::GetProjectName() const
404 {
405   return this->Position->BuildSystemDirectory->ProjectName;
406 }
407
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
420 bool cmStateSnapshot::StrictWeakOrder::operator()(
421   const cmStateSnapshot& lhs, const cmStateSnapshot& rhs) const
422 {
423   return lhs.Position.StrictWeakOrdered(rhs.Position);
424 }
425
426 bool operator==(const cmStateSnapshot& lhs, const cmStateSnapshot& rhs)
427 {
428   return lhs.Position == rhs.Position;
429 }
430
431 bool operator!=(const cmStateSnapshot& lhs, const cmStateSnapshot& rhs)
432 {
433   return lhs.Position != rhs.Position;
434 }