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