469eac3e5d45a6be1c7ebae8f4eccc5b0ddb5a1d
[platform/upstream/cmake.git] / Source / cmMakefile.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 #include "cmConfigure.h" // IWYU pragma: keep
4
5 #include "cmMakefile.h"
6
7 #include <algorithm>
8 #include <cassert>
9 #include <cctype>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 #include <sstream>
14 #include <utility>
15
16 #include <cm/iterator>
17 #include <cm/memory>
18 #include <cm/optional>
19 #include <cm/type_traits> // IWYU pragma: keep
20 #include <cm/vector>
21 #include <cmext/algorithm>
22 #include <cmext/string_view>
23
24 #ifndef CMAKE_BOOTSTRAP
25 #  include <cm3p/json/value.h>
26 #  include <cm3p/json/writer.h>
27 #endif
28
29 #include "cmsys/FStream.hxx"
30 #include "cmsys/RegularExpression.hxx"
31
32 #include "cmCommandArgumentParserHelper.h"
33 #include "cmCustomCommand.h"
34 #include "cmCustomCommandLines.h"
35 #include "cmExecutionStatus.h"
36 #include "cmExpandedCommandArgument.h" // IWYU pragma: keep
37 #include "cmExportBuildFileGenerator.h"
38 #include "cmFileLockPool.h"
39 #include "cmFunctionBlocker.h"
40 #include "cmGeneratedFileStream.h"
41 #include "cmGeneratorExpression.h"
42 #include "cmGeneratorExpressionEvaluationFile.h"
43 #include "cmGlobalGenerator.h"
44 #include "cmInstallGenerator.h" // IWYU pragma: keep
45 #include "cmInstallSubdirectoryGenerator.h"
46 #include "cmListFileCache.h"
47 #include "cmLocalGenerator.h"
48 #include "cmMessageType.h"
49 #include "cmRange.h"
50 #include "cmSourceFile.h"
51 #include "cmSourceFileLocation.h"
52 #include "cmState.h"
53 #include "cmStateDirectory.h"
54 #include "cmStateTypes.h"
55 #include "cmStringAlgorithms.h"
56 #include "cmSystemTools.h"
57 #include "cmTarget.h"
58 #include "cmTargetLinkLibraryType.h"
59 #include "cmTest.h"
60 #include "cmTestGenerator.h" // IWYU pragma: keep
61 #include "cmVersion.h"
62 #include "cmWorkingDirectory.h"
63 #include "cmake.h"
64
65 #ifndef CMAKE_BOOTSTRAP
66 #  include "cmMakefileProfilingData.h"
67 #  include "cmVariableWatch.h"
68 #endif
69
70 class cmMessenger;
71
72 cmDirectoryId::cmDirectoryId(std::string s)
73   : String(std::move(s))
74 {
75 }
76
77 // default is not to be building executables
78 cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
79                        cmStateSnapshot const& snapshot)
80   : GlobalGenerator(globalGenerator)
81   , StateSnapshot(snapshot)
82 {
83   this->IsSourceFileTryCompile = false;
84
85   this->CheckSystemVars = this->GetCMakeInstance()->GetCheckSystemVars();
86
87   this->SuppressSideEffects = false;
88
89   // Setup the default include complaint regular expression (match nothing).
90   this->ComplainFileRegularExpression = "^$";
91
92   this->DefineFlags = " ";
93
94   this->cmDefineRegex.compile("#([ \t]*)cmakedefine[ \t]+([A-Za-z_0-9]*)");
95   this->cmDefine01Regex.compile("#([ \t]*)cmakedefine01[ \t]+([A-Za-z_0-9]*)");
96   this->cmAtVarRegex.compile("(@[A-Za-z_0-9/.+-]+@)");
97   this->cmNamedCurly.compile("^[A-Za-z0-9/_.+-]+{");
98
99   this->StateSnapshot =
100     this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
101       this->StateSnapshot);
102   this->RecursionDepth = 0;
103
104   // Enter a policy level for this directory.
105   this->PushPolicy();
106
107   // push empty loop block
108   this->PushLoopBlockBarrier();
109
110   // By default the check is not done.  It is enabled by
111   // cmListFileCache in the top level if necessary.
112   this->CheckCMP0000 = false;
113
114 #if !defined(CMAKE_BOOTSTRAP)
115   this->AddSourceGroup("", "^.*$");
116   this->AddSourceGroup("Source Files", CM_SOURCE_REGEX);
117   this->AddSourceGroup("Header Files", CM_HEADER_REGEX);
118   this->AddSourceGroup("Precompile Header File", CM_PCH_REGEX);
119   this->AddSourceGroup("CMake Rules", "\\.rule$");
120   this->AddSourceGroup("Resources", CM_RESOURCE_REGEX);
121   this->AddSourceGroup("Object Files", "\\.(lo|o|obj)$");
122
123   this->ObjectLibrariesSourceGroupIndex = this->SourceGroups.size();
124   this->SourceGroups.emplace_back("Object Libraries", "^MATCH_NO_SOURCES$");
125 #endif
126 }
127
128 cmMakefile::~cmMakefile() = default;
129
130 cmDirectoryId cmMakefile::GetDirectoryId() const
131 {
132   // Use the instance pointer value to uniquely identify this directory.
133   // If we ever need to expose this to CMake language code we should
134   // add a read-only property in cmMakefile::GetProperty.
135   char buf[32];
136   snprintf(buf, sizeof(buf), "(%p)",
137            static_cast<void const*>(this)); // cast avoids format warning
138   return std::string(buf);
139 }
140
141 void cmMakefile::IssueMessage(MessageType t, std::string const& text) const
142 {
143   if (!this->ExecutionStatusStack.empty()) {
144     if ((t == MessageType::FATAL_ERROR) ||
145         (t == MessageType::INTERNAL_ERROR)) {
146       this->ExecutionStatusStack.back()->SetNestedError();
147     }
148   }
149   this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace);
150 }
151
152 bool cmMakefile::CheckCMP0037(std::string const& targetName,
153                               cmStateEnums::TargetType targetType) const
154 {
155   MessageType messageType = MessageType::AUTHOR_WARNING;
156   std::ostringstream e;
157   bool issueMessage = false;
158   switch (this->GetPolicyStatus(cmPolicies::CMP0037)) {
159     case cmPolicies::WARN:
160       if (targetType != cmStateEnums::INTERFACE_LIBRARY) {
161         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0037) << "\n";
162         issueMessage = true;
163       }
164       CM_FALLTHROUGH;
165     case cmPolicies::OLD:
166       break;
167     case cmPolicies::NEW:
168     case cmPolicies::REQUIRED_IF_USED:
169     case cmPolicies::REQUIRED_ALWAYS:
170       issueMessage = true;
171       messageType = MessageType::FATAL_ERROR;
172       break;
173   }
174   if (issueMessage) {
175     e << "The target name \"" << targetName
176       << "\" is reserved or not valid for certain "
177          "CMake features, such as generator expressions, and may result "
178          "in undefined behavior.";
179     this->IssueMessage(messageType, e.str());
180
181     if (messageType == MessageType::FATAL_ERROR) {
182       return false;
183     }
184   }
185   return true;
186 }
187
188 void cmMakefile::MaybeWarnCMP0074(std::string const& pkg)
189 {
190   // Warn if a <pkg>_ROOT variable we may use is set.
191   std::string const varName = pkg + "_ROOT";
192   cmValue var = this->GetDefinition(varName);
193   std::string env;
194   cmSystemTools::GetEnv(varName, env);
195
196   bool const haveVar = cmNonempty(var);
197   bool const haveEnv = !env.empty();
198   if ((haveVar || haveEnv) && this->WarnedCMP0074.insert(varName).second) {
199     std::ostringstream w;
200     w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0074) << "\n";
201     if (haveVar) {
202       w << "CMake variable " << varName << " is set to:\n"
203         << "  " << *var << "\n";
204     }
205     if (haveEnv) {
206       w << "Environment variable " << varName << " is set to:\n"
207         << "  " << env << "\n";
208     }
209     w << "For compatibility, CMake is ignoring the variable.";
210     this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
211   }
212 }
213
214 cmBTStringRange cmMakefile::GetIncludeDirectoriesEntries() const
215 {
216   return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries();
217 }
218
219 cmBTStringRange cmMakefile::GetCompileOptionsEntries() const
220 {
221   return this->StateSnapshot.GetDirectory().GetCompileOptionsEntries();
222 }
223
224 cmBTStringRange cmMakefile::GetCompileDefinitionsEntries() const
225 {
226   return this->StateSnapshot.GetDirectory().GetCompileDefinitionsEntries();
227 }
228
229 cmBTStringRange cmMakefile::GetLinkOptionsEntries() const
230 {
231   return this->StateSnapshot.GetDirectory().GetLinkOptionsEntries();
232 }
233
234 cmBTStringRange cmMakefile::GetLinkDirectoriesEntries() const
235 {
236   return this->StateSnapshot.GetDirectory().GetLinkDirectoriesEntries();
237 }
238
239 cmListFileBacktrace cmMakefile::GetBacktrace() const
240 {
241   return this->Backtrace;
242 }
243
244 void cmMakefile::PrintCommandTrace(cmListFileFunction const& lff,
245                                    cmListFileBacktrace const& bt,
246                                    CommandMissingFromStack missing) const
247 {
248   // Check if current file in the list of requested to trace...
249   std::vector<std::string> const& trace_only_this_files =
250     this->GetCMakeInstance()->GetTraceSources();
251   std::string const& full_path = bt.Top().FilePath;
252   std::string const& only_filename = cmSystemTools::GetFilenameName(full_path);
253   bool trace = trace_only_this_files.empty();
254   if (!trace) {
255     for (std::string const& file : trace_only_this_files) {
256       std::string::size_type const pos = full_path.rfind(file);
257       trace = (pos != std::string::npos) &&
258         ((pos + file.size()) == full_path.size()) &&
259         (only_filename == cmSystemTools::GetFilenameName(file));
260       if (trace) {
261         break;
262       }
263     }
264     // Do nothing if current file wasn't requested for trace...
265     if (!trace) {
266       return;
267     }
268   }
269
270   std::ostringstream msg;
271   std::vector<std::string> args;
272   std::string temp;
273   bool expand = this->GetCMakeInstance()->GetTraceExpand();
274
275   args.reserve(lff.Arguments().size());
276   for (cmListFileArgument const& arg : lff.Arguments()) {
277     if (expand && arg.Delim != cmListFileArgument::Bracket) {
278       temp = arg.Value;
279       this->ExpandVariablesInString(temp);
280       args.push_back(temp);
281     } else {
282       args.push_back(arg.Value);
283     }
284   }
285   cm::optional<std::string> const& deferId = bt.Top().DeferId;
286
287   switch (this->GetCMakeInstance()->GetTraceFormat()) {
288     case cmake::TraceFormat::TRACE_JSON_V1: {
289 #ifndef CMAKE_BOOTSTRAP
290       Json::Value val;
291       Json::StreamWriterBuilder builder;
292       builder["indentation"] = "";
293       val["file"] = full_path;
294       val["line"] = static_cast<Json::Value::Int64>(lff.Line());
295       if (lff.Line() != lff.LineEnd()) {
296         val["line_end"] = static_cast<Json::Value::Int64>(lff.LineEnd());
297       }
298       if (deferId) {
299         val["defer"] = *deferId;
300       }
301       val["cmd"] = lff.OriginalName();
302       val["args"] = Json::Value(Json::arrayValue);
303       for (std::string const& arg : args) {
304         val["args"].append(arg);
305       }
306       val["time"] = cmSystemTools::GetTime();
307       val["frame"] = (missing == CommandMissingFromStack::Yes ? 1 : 0) +
308         static_cast<Json::Value::UInt64>(this->ExecutionStatusStack.size());
309       val["global_frame"] = (missing == CommandMissingFromStack::Yes ? 1 : 0) +
310         static_cast<Json::Value::UInt64>(this->RecursionDepth);
311       msg << Json::writeString(builder, val);
312 #endif
313       break;
314     }
315     case cmake::TraceFormat::TRACE_HUMAN:
316       msg << full_path << "(" << lff.Line() << "):";
317       if (deferId) {
318         msg << "DEFERRED:" << *deferId << ":";
319       }
320       msg << "  " << lff.OriginalName() << "(";
321
322       for (std::string const& arg : args) {
323         msg << arg << " ";
324       }
325       msg << ")";
326       break;
327     case cmake::TraceFormat::TRACE_UNDEFINED:
328       msg << "INTERNAL ERROR: Trace format is TRACE_UNDEFINED";
329       break;
330   }
331
332   auto& f = this->GetCMakeInstance()->GetTraceFile();
333   if (f) {
334     f << msg.str() << '\n';
335   } else {
336     cmSystemTools::Message(msg.str());
337   }
338 }
339
340 // Helper class to make sure the call stack is valid.
341 class cmMakefileCall
342 {
343 public:
344   cmMakefileCall(cmMakefile* mf, cmListFileFunction const& lff,
345                  cm::optional<std::string> deferId, cmExecutionStatus& status)
346     : Makefile(mf)
347   {
348     cmListFileContext const& lfc = cmListFileContext::FromListFileFunction(
349       lff, this->Makefile->StateSnapshot.GetExecutionListFile(),
350       std::move(deferId));
351     this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
352     ++this->Makefile->RecursionDepth;
353     this->Makefile->ExecutionStatusStack.push_back(&status);
354 #if !defined(CMAKE_BOOTSTRAP)
355     if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
356       this->Makefile->GetCMakeInstance()->GetProfilingOutput().StartEntry(lff,
357                                                                           lfc);
358     }
359 #endif
360   }
361
362   ~cmMakefileCall()
363   {
364 #if !defined(CMAKE_BOOTSTRAP)
365     if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) {
366       this->Makefile->GetCMakeInstance()->GetProfilingOutput().StopEntry();
367     }
368 #endif
369     this->Makefile->ExecutionStatusStack.pop_back();
370     --this->Makefile->RecursionDepth;
371     this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
372   }
373
374   cmMakefileCall(const cmMakefileCall&) = delete;
375   cmMakefileCall& operator=(const cmMakefileCall&) = delete;
376
377 private:
378   cmMakefile* Makefile;
379 };
380
381 void cmMakefile::OnExecuteCommand(std::function<void()> callback)
382 {
383   this->ExecuteCommandCallback = std::move(callback);
384 }
385
386 bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
387                                 cmExecutionStatus& status,
388                                 cm::optional<std::string> deferId)
389 {
390   bool result = true;
391
392   // quick return if blocked
393   if (this->IsFunctionBlocked(lff, status)) {
394     // No error.
395     return result;
396   }
397
398   if (this->ExecuteCommandCallback) {
399     this->ExecuteCommandCallback();
400   }
401
402   // Place this call on the call stack.
403   cmMakefileCall stack_manager(this, lff, std::move(deferId), status);
404   static_cast<void>(stack_manager);
405
406   // Check for maximum recursion depth.
407   int depth = CMake_DEFAULT_RECURSION_LIMIT;
408   cmValue depthStr = this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
409   if (depthStr) {
410     std::istringstream s(*depthStr);
411     int d;
412     if (s >> d) {
413       depth = d;
414     }
415   }
416   if (this->RecursionDepth > depth) {
417     std::ostringstream e;
418     e << "Maximum recursion depth of " << depth << " exceeded";
419     this->IssueMessage(MessageType::FATAL_ERROR, e.str());
420     cmSystemTools::SetFatalErrorOccurred();
421     return false;
422   }
423
424   // Lookup the command prototype.
425   if (cmState::Command command =
426         this->GetState()->GetCommandByExactName(lff.LowerCaseName())) {
427     // Decide whether to invoke the command.
428     if (!cmSystemTools::GetFatalErrorOccurred()) {
429       // if trace is enabled, print out invoke information
430       if (this->GetCMakeInstance()->GetTrace()) {
431         this->PrintCommandTrace(lff, this->Backtrace);
432       }
433       // Try invoking the command.
434       bool invokeSucceeded = command(lff.Arguments(), status);
435       bool hadNestedError = status.GetNestedError();
436       if (!invokeSucceeded || hadNestedError) {
437         if (!hadNestedError) {
438           // The command invocation requested that we report an error.
439           std::string const error =
440             std::string(lff.OriginalName()) + " " + status.GetError();
441           this->IssueMessage(MessageType::FATAL_ERROR, error);
442         }
443         result = false;
444         if (this->GetCMakeInstance()->GetWorkingMode() != cmake::NORMAL_MODE) {
445           cmSystemTools::SetFatalErrorOccurred();
446         }
447       }
448     }
449   } else {
450     if (!cmSystemTools::GetFatalErrorOccurred()) {
451       std::string error =
452         cmStrCat("Unknown CMake command \"", lff.OriginalName(), "\".");
453       this->IssueMessage(MessageType::FATAL_ERROR, error);
454       result = false;
455       cmSystemTools::SetFatalErrorOccurred();
456     }
457   }
458
459   return result;
460 }
461
462 bool cmMakefile::IsImportedTargetGlobalScope() const
463 {
464   return this->CurrentImportedTargetScope == ImportedTargetScope::Global;
465 }
466
467 class cmMakefile::IncludeScope
468 {
469 public:
470   IncludeScope(cmMakefile* mf, std::string const& filenametoread,
471                bool noPolicyScope);
472   ~IncludeScope();
473   void Quiet() { this->ReportError = false; }
474
475   IncludeScope(const IncludeScope&) = delete;
476   IncludeScope& operator=(const IncludeScope&) = delete;
477
478 private:
479   cmMakefile* Makefile;
480   bool NoPolicyScope;
481   bool CheckCMP0011 = false;
482   bool ReportError = true;
483   void EnforceCMP0011();
484 };
485
486 cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf,
487                                        std::string const& filenametoread,
488                                        bool noPolicyScope)
489   : Makefile(mf)
490   , NoPolicyScope(noPolicyScope)
491 {
492   this->Makefile->Backtrace = this->Makefile->Backtrace.Push(
493     cmListFileContext::FromListFilePath(filenametoread));
494
495   this->Makefile->PushFunctionBlockerBarrier();
496
497   this->Makefile->StateSnapshot =
498     this->Makefile->GetState()->CreateIncludeFileSnapshot(
499       this->Makefile->StateSnapshot, filenametoread);
500   if (!this->NoPolicyScope) {
501     // Check CMP0011 to determine the policy scope type.
502     switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
503       case cmPolicies::WARN:
504         // We need to push a scope to detect whether the script sets
505         // any policies that would affect the includer and therefore
506         // requires a warning.  We use a weak scope to simulate OLD
507         // behavior by allowing policy changes to affect the includer.
508         this->Makefile->PushPolicy(true);
509         this->CheckCMP0011 = true;
510         break;
511       case cmPolicies::OLD:
512         // OLD behavior is to not push a scope at all.
513         this->NoPolicyScope = true;
514         break;
515       case cmPolicies::REQUIRED_IF_USED:
516       case cmPolicies::REQUIRED_ALWAYS:
517         // We should never make this policy required, but we handle it
518         // here just in case.
519         this->CheckCMP0011 = true;
520         CM_FALLTHROUGH;
521       case cmPolicies::NEW:
522         // NEW behavior is to push a (strong) scope.
523         this->Makefile->PushPolicy();
524         break;
525     }
526   }
527 }
528
529 cmMakefile::IncludeScope::~IncludeScope()
530 {
531   if (!this->NoPolicyScope) {
532     // If we need to enforce policy CMP0011 then the top entry is the
533     // one we pushed above.  If the entry is empty, then the included
534     // script did not set any policies that might affect the includer so
535     // we do not need to enforce the policy.
536     if (this->CheckCMP0011 &&
537         !this->Makefile->StateSnapshot.HasDefinedPolicyCMP0011()) {
538       this->CheckCMP0011 = false;
539     }
540
541     // Pop the scope we pushed for the script.
542     this->Makefile->PopPolicy();
543
544     // We enforce the policy after the script's policy stack entry has
545     // been removed.
546     if (this->CheckCMP0011) {
547       this->EnforceCMP0011();
548     }
549   }
550   this->Makefile->PopSnapshot(this->ReportError);
551
552   this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
553
554   this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
555 }
556
557 void cmMakefile::IncludeScope::EnforceCMP0011()
558 {
559   // We check the setting of this policy again because the included
560   // script might actually set this policy for its includer.
561   switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0011)) {
562     case cmPolicies::WARN:
563       // Warn because the user did not set this policy.
564       {
565         std::ostringstream w;
566         w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0011) << "\n"
567           << "The included script\n  "
568           << this->Makefile->GetBacktrace().Top().FilePath << "\n"
569           << "affects policy settings.  "
570           << "CMake is implying the NO_POLICY_SCOPE option for compatibility, "
571           << "so the effects are applied to the including context.";
572         this->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
573       }
574       break;
575     case cmPolicies::REQUIRED_IF_USED:
576     case cmPolicies::REQUIRED_ALWAYS: {
577       std::ostringstream e;
578       /* clang-format off */
579       e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0011) << "\n"
580         << "The included script\n  "
581         << this->Makefile->GetBacktrace().Top().FilePath << "\n"
582         << "affects policy settings, so it requires this policy to be set.";
583       /* clang-format on */
584       this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
585     } break;
586     case cmPolicies::OLD:
587     case cmPolicies::NEW:
588       // The script set this policy.  We assume the purpose of the
589       // script is to initialize policies for its includer, and since
590       // the policy is now set for later scripts, we do not warn.
591       break;
592   }
593 }
594
595 bool cmMakefile::ReadDependentFile(const std::string& filename,
596                                    bool noPolicyScope)
597 {
598   if (cmValue def = this->GetDefinition("CMAKE_CURRENT_LIST_FILE")) {
599     this->AddDefinition("CMAKE_PARENT_LIST_FILE", *def);
600   }
601   std::string filenametoread = cmSystemTools::CollapseFullPath(
602     filename, this->GetCurrentSourceDirectory());
603
604   IncludeScope incScope(this, filenametoread, noPolicyScope);
605
606   cmListFile listFile;
607   if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
608                           this->Backtrace)) {
609     return false;
610   }
611
612   this->RunListFile(listFile, filenametoread);
613   if (cmSystemTools::GetFatalErrorOccurred()) {
614     incScope.Quiet();
615   }
616   return true;
617 }
618
619 class cmMakefile::ListFileScope
620 {
621 public:
622   ListFileScope(cmMakefile* mf, std::string const& filenametoread)
623     : Makefile(mf)
624   {
625     this->Makefile->Backtrace = this->Makefile->Backtrace.Push(
626       cmListFileContext::FromListFilePath(filenametoread));
627
628     this->Makefile->StateSnapshot =
629       this->Makefile->GetState()->CreateInlineListFileSnapshot(
630         this->Makefile->StateSnapshot, filenametoread);
631     assert(this->Makefile->StateSnapshot.IsValid());
632
633     this->Makefile->PushFunctionBlockerBarrier();
634   }
635
636   ~ListFileScope()
637   {
638     this->Makefile->PopSnapshot(this->ReportError);
639     this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
640     this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
641   }
642
643   void Quiet() { this->ReportError = false; }
644
645   ListFileScope(const ListFileScope&) = delete;
646   ListFileScope& operator=(const ListFileScope&) = delete;
647
648 private:
649   cmMakefile* Makefile;
650   bool ReportError = true;
651 };
652
653 class cmMakefile::DeferScope
654 {
655 public:
656   DeferScope(cmMakefile* mf, std::string const& deferredInFile)
657     : Makefile(mf)
658   {
659     cmListFileContext lfc;
660     lfc.Line = cmListFileContext::DeferPlaceholderLine;
661     lfc.FilePath = deferredInFile;
662     this->Makefile->Backtrace = this->Makefile->Backtrace.Push(lfc);
663     this->Makefile->DeferRunning = true;
664   }
665
666   ~DeferScope()
667   {
668     this->Makefile->DeferRunning = false;
669     this->Makefile->Backtrace = this->Makefile->Backtrace.Pop();
670   }
671
672   DeferScope(const DeferScope&) = delete;
673   DeferScope& operator=(const DeferScope&) = delete;
674
675 private:
676   cmMakefile* Makefile;
677 };
678
679 class cmMakefile::DeferCallScope
680 {
681 public:
682   DeferCallScope(cmMakefile* mf, std::string const& deferredFromFile)
683     : Makefile(mf)
684   {
685     this->Makefile->StateSnapshot =
686       this->Makefile->GetState()->CreateDeferCallSnapshot(
687         this->Makefile->StateSnapshot, deferredFromFile);
688     assert(this->Makefile->StateSnapshot.IsValid());
689   }
690
691   ~DeferCallScope() { this->Makefile->PopSnapshot(); }
692
693   DeferCallScope(const DeferCallScope&) = delete;
694   DeferCallScope& operator=(const DeferCallScope&) = delete;
695
696 private:
697   cmMakefile* Makefile;
698 };
699
700 bool cmMakefile::ReadListFile(const std::string& filename)
701 {
702   std::string filenametoread = cmSystemTools::CollapseFullPath(
703     filename, this->GetCurrentSourceDirectory());
704
705   ListFileScope scope(this, filenametoread);
706
707   cmListFile listFile;
708   if (!listFile.ParseFile(filenametoread.c_str(), this->GetMessenger(),
709                           this->Backtrace)) {
710     return false;
711   }
712
713   this->RunListFile(listFile, filenametoread);
714   if (cmSystemTools::GetFatalErrorOccurred()) {
715     scope.Quiet();
716   }
717   return true;
718 }
719
720 bool cmMakefile::ReadListFileAsString(const std::string& content,
721                                       const std::string& virtualFileName)
722 {
723   std::string filenametoread = cmSystemTools::CollapseFullPath(
724     virtualFileName, this->GetCurrentSourceDirectory());
725
726   ListFileScope scope(this, filenametoread);
727
728   cmListFile listFile;
729   if (!listFile.ParseString(content.c_str(), virtualFileName.c_str(),
730                             this->GetMessenger(), this->Backtrace)) {
731     return false;
732   }
733
734   this->RunListFile(listFile, filenametoread);
735   if (cmSystemTools::GetFatalErrorOccurred()) {
736     scope.Quiet();
737   }
738   return true;
739 }
740
741 void cmMakefile::RunListFile(cmListFile const& listFile,
742                              std::string const& filenametoread,
743                              DeferCommands* defer)
744 {
745   // add this list file to the list of dependencies
746   this->ListFiles.push_back(filenametoread);
747
748   std::string currentParentFile =
749     this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
750   std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
751
752   this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread);
753   this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
754                       cmSystemTools::GetFilenamePath(filenametoread));
755
756   this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
757   this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
758   this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
759
760   // Run the parsed commands.
761   const size_t numberFunctions = listFile.Functions.size();
762   for (size_t i = 0; i < numberFunctions; ++i) {
763     cmExecutionStatus status(*this);
764     this->ExecuteCommand(listFile.Functions[i], status);
765     if (cmSystemTools::GetFatalErrorOccurred()) {
766       break;
767     }
768     if (status.GetReturnInvoked()) {
769       // Exit early due to return command.
770       break;
771     }
772   }
773
774   // Run any deferred commands.
775   if (defer) {
776     // Add a backtrace level indicating calls are deferred.
777     DeferScope scope(this, filenametoread);
778
779     // Iterate by index in case one deferred call schedules another.
780     // NOLINTNEXTLINE(modernize-loop-convert)
781     for (size_t i = 0; i < defer->Commands.size(); ++i) {
782       DeferCommand& d = defer->Commands[i];
783       if (d.Id.empty()) {
784         // Canceled.
785         continue;
786       }
787       // Mark as executed.
788       std::string id = std::move(d.Id);
789
790       // The deferred call may have come from another file.
791       DeferCallScope callScope(this, d.FilePath);
792
793       cmExecutionStatus status(*this);
794       this->ExecuteCommand(d.Command, status, std::move(id));
795       if (cmSystemTools::GetFatalErrorOccurred()) {
796         break;
797       }
798     }
799   }
800
801   this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile);
802   this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile);
803   this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
804                       cmSystemTools::GetFilenamePath(currentFile));
805   this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
806   this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
807   this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
808 }
809
810 void cmMakefile::EnforceDirectoryLevelRules() const
811 {
812   // Diagnose a violation of CMP0000 if necessary.
813   if (this->CheckCMP0000) {
814     std::ostringstream msg;
815     msg << "No cmake_minimum_required command is present.  "
816         << "A line of code such as\n"
817         << "  cmake_minimum_required(VERSION " << cmVersion::GetMajorVersion()
818         << "." << cmVersion::GetMinorVersion() << ")\n"
819         << "should be added at the top of the file.  "
820         << "The version specified may be lower if you wish to "
821         << "support older CMake versions for this project.  "
822         << "For more information run "
823         << "\"cmake --help-policy CMP0000\".";
824     switch (this->GetPolicyStatus(cmPolicies::CMP0000)) {
825       case cmPolicies::WARN:
826         // Warn because the user did not provide a minimum required
827         // version.
828         this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
829                                                msg.str(), this->Backtrace);
830         CM_FALLTHROUGH;
831       case cmPolicies::OLD:
832         // OLD behavior is to use policy version 2.4 set in
833         // cmListFileCache.
834         break;
835       case cmPolicies::REQUIRED_IF_USED:
836       case cmPolicies::REQUIRED_ALWAYS:
837       case cmPolicies::NEW:
838         // NEW behavior is to issue an error.
839         this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
840                                                msg.str(), this->Backtrace);
841         cmSystemTools::SetFatalErrorOccurred();
842         break;
843     }
844   }
845 }
846
847 void cmMakefile::AddEvaluationFile(
848   const std::string& inputFile, const std::string& targetName,
849   std::unique_ptr<cmCompiledGeneratorExpression> outputName,
850   std::unique_ptr<cmCompiledGeneratorExpression> condition,
851   const std::string& newLineCharacter, mode_t permissions, bool inputIsContent)
852 {
853   this->EvaluationFiles.push_back(
854     cm::make_unique<cmGeneratorExpressionEvaluationFile>(
855       inputFile, targetName, std::move(outputName), std::move(condition),
856       inputIsContent, newLineCharacter, permissions,
857       this->GetPolicyStatus(cmPolicies::CMP0070)));
858 }
859
860 const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
861 cmMakefile::GetEvaluationFiles() const
862 {
863   return this->EvaluationFiles;
864 }
865
866 std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const&
867 cmMakefile::GetExportBuildFileGenerators() const
868 {
869   return this->ExportBuildFileGenerators;
870 }
871
872 void cmMakefile::RemoveExportBuildFileGeneratorCMP0024(
873   cmExportBuildFileGenerator* gen)
874 {
875   auto it =
876     std::find_if(this->ExportBuildFileGenerators.begin(),
877                  this->ExportBuildFileGenerators.end(),
878                  [gen](std::unique_ptr<cmExportBuildFileGenerator> const& p) {
879                    return p.get() == gen;
880                  });
881   if (it != this->ExportBuildFileGenerators.end()) {
882     this->ExportBuildFileGenerators.erase(it);
883   }
884 }
885
886 void cmMakefile::AddExportBuildFileGenerator(
887   std::unique_ptr<cmExportBuildFileGenerator> gen)
888 {
889   this->ExportBuildFileGenerators.emplace_back(std::move(gen));
890 }
891
892 namespace {
893 struct file_not_persistent
894 {
895   bool operator()(const std::string& path) const
896   {
897     return !(path.find("CMakeTmp") == std::string::npos &&
898              cmSystemTools::FileExists(path));
899   }
900 };
901 }
902
903 void cmMakefile::AddGeneratorAction(GeneratorAction&& action)
904 {
905   assert(!this->GeneratorActionsInvoked);
906   this->GeneratorActions.emplace_back(std::move(action), this->Backtrace);
907 }
908
909 void cmMakefile::GeneratorAction::operator()(cmLocalGenerator& lg,
910                                              const cmListFileBacktrace& lfbt)
911 {
912   if (cc) {
913     CCAction(lg, lfbt, std::move(cc));
914   } else {
915     assert(Action);
916     Action(lg, lfbt);
917   }
918 }
919
920 void cmMakefile::DoGenerate(cmLocalGenerator& lg)
921 {
922   // do all the variable expansions here
923   this->ExpandVariablesCMP0019();
924
925   // give all the commands a chance to do something
926   // after the file has been parsed before generation
927   for (auto& action : this->GeneratorActions) {
928     action.Value(lg, action.Backtrace);
929   }
930   this->GeneratorActionsInvoked = true;
931
932   // go through all configured files and see which ones still exist.
933   // we don't want cmake to re-run if a configured file is created and deleted
934   // during processing as that would make it a transient file that can't
935   // influence the build process
936   cm::erase_if(this->OutputFiles, file_not_persistent());
937
938   // if a configured file is used as input for another configured file,
939   // and then deleted it will show up in the input list files so we
940   // need to scan those too
941   cm::erase_if(this->ListFiles, file_not_persistent());
942 }
943
944 // Generate the output file
945 void cmMakefile::Generate(cmLocalGenerator& lg)
946 {
947   this->DoGenerate(lg);
948   cmValue oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
949   if (oldValue &&
950       cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
951     this->GetCMakeInstance()->IssueMessage(
952       MessageType::FATAL_ERROR,
953       "You have set CMAKE_BACKWARDS_COMPATIBILITY to a CMake version less "
954       "than 2.4. This version of CMake only supports backwards compatibility "
955       "with CMake 2.4 or later. For compatibility with older versions please "
956       "use any CMake 2.8.x release or lower.",
957       this->Backtrace);
958   }
959 }
960
961 namespace {
962 // There are still too many implicit backtraces through cmMakefile.  As a
963 // workaround we reset the backtrace temporarily.
964 struct BacktraceGuard
965 {
966   BacktraceGuard(cmListFileBacktrace& lfbt, cmListFileBacktrace current)
967     : Backtrace(lfbt)
968     , Previous(lfbt)
969   {
970     this->Backtrace = std::move(current);
971   }
972
973   ~BacktraceGuard() { this->Backtrace = std::move(this->Previous); }
974
975 private:
976   cmListFileBacktrace& Backtrace;
977   cmListFileBacktrace Previous;
978 };
979 }
980
981 bool cmMakefile::ValidateCustomCommand(
982   const cmCustomCommandLines& commandLines) const
983 {
984   // TODO: More strict?
985   for (cmCustomCommandLine const& cl : commandLines) {
986     if (!cl.empty() && !cl[0].empty() && cl[0][0] == '"') {
987       std::ostringstream e;
988       e << "COMMAND may not contain literal quotes:\n  " << cl[0] << "\n";
989       this->IssueMessage(MessageType::FATAL_ERROR, e.str());
990       return false;
991     }
992   }
993
994   return true;
995 }
996
997 cmTarget* cmMakefile::GetCustomCommandTarget(
998   const std::string& target, cmObjectLibraryCommands objLibCommands,
999   const cmListFileBacktrace& lfbt) const
1000 {
1001   // Find the target to which to add the custom command.
1002   auto ti = this->Targets.find(target);
1003
1004   if (ti == this->Targets.end()) {
1005     MessageType messageType = MessageType::AUTHOR_WARNING;
1006     bool issueMessage = false;
1007     std::ostringstream e;
1008     switch (this->GetPolicyStatus(cmPolicies::CMP0040)) {
1009       case cmPolicies::WARN:
1010         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0040) << "\n";
1011         issueMessage = true;
1012         CM_FALLTHROUGH;
1013       case cmPolicies::OLD:
1014         break;
1015       case cmPolicies::NEW:
1016       case cmPolicies::REQUIRED_IF_USED:
1017       case cmPolicies::REQUIRED_ALWAYS:
1018         issueMessage = true;
1019         messageType = MessageType::FATAL_ERROR;
1020         break;
1021     }
1022
1023     if (issueMessage) {
1024       if (cmTarget const* t = this->FindTargetToUse(target)) {
1025         if (t->IsImported()) {
1026           e << "TARGET '" << target
1027             << "' is IMPORTED and does not build here.";
1028         } else {
1029           e << "TARGET '" << target << "' was not created in this directory.";
1030         }
1031       } else {
1032         e << "No TARGET '" << target
1033           << "' has been created in this directory.";
1034       }
1035       this->GetCMakeInstance()->IssueMessage(messageType, e.str(), lfbt);
1036     }
1037
1038     return nullptr;
1039   }
1040
1041   cmTarget* t = &ti->second;
1042   if (objLibCommands == cmObjectLibraryCommands::Reject &&
1043       t->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1044     std::ostringstream e;
1045     e << "Target \"" << target
1046       << "\" is an OBJECT library "
1047          "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
1048     this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
1049                                            lfbt);
1050     return nullptr;
1051   }
1052   if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1053     std::ostringstream e;
1054     e << "Target \"" << target
1055       << "\" is an INTERFACE library "
1056          "that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
1057     this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
1058                                            lfbt);
1059     return nullptr;
1060   }
1061
1062   return t;
1063 }
1064
1065 cmTarget* cmMakefile::AddCustomCommandToTarget(
1066   const std::string& target, cmCustomCommandType type,
1067   std::unique_ptr<cmCustomCommand> cc)
1068 {
1069   const auto& byproducts = cc->GetByproducts();
1070   const auto& commandLines = cc->GetCommandLines();
1071
1072   cmTarget* t = this->GetCustomCommandTarget(
1073     target, cmObjectLibraryCommands::Reject, this->Backtrace);
1074
1075   // Validate custom commands.
1076   if (!t || !this->ValidateCustomCommand(commandLines)) {
1077     return t;
1078   }
1079
1080   // Always create the byproduct sources and mark them generated.
1081   this->CreateGeneratedOutputs(byproducts);
1082
1083   cc->SetCMP0116Status(this->GetPolicyStatus(cmPolicies::CMP0116));
1084
1085   // Dispatch command creation to allow generator expressions in outputs.
1086   this->AddGeneratorAction(
1087     std::move(cc),
1088     [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
1089         std::unique_ptr<cmCustomCommand> tcc) {
1090       BacktraceGuard guard(this->Backtrace, lfbt);
1091       tcc->SetBacktrace(lfbt);
1092       detail::AddCustomCommandToTarget(lg, cmCommandOrigin::Project, t, type,
1093                                        std::move(tcc));
1094     });
1095
1096   return t;
1097 }
1098
1099 void cmMakefile::AddCustomCommandToOutput(
1100   std::unique_ptr<cmCustomCommand> cc, const CommandSourceCallback& callback,
1101   bool replace)
1102 {
1103   const auto& outputs = cc->GetOutputs();
1104   const auto& byproducts = cc->GetByproducts();
1105   const auto& commandLines = cc->GetCommandLines();
1106
1107   // Make sure there is at least one output.
1108   if (outputs.empty()) {
1109     cmSystemTools::Error("Attempt to add a custom rule with no output!");
1110     return;
1111   }
1112
1113   // Validate custom commands.
1114   if (!this->ValidateCustomCommand(commandLines)) {
1115     return;
1116   }
1117
1118   // Always create the output sources and mark them generated.
1119   this->CreateGeneratedOutputs(outputs);
1120   this->CreateGeneratedOutputs(byproducts);
1121
1122   cc->SetCMP0116Status(this->GetPolicyStatus(cmPolicies::CMP0116));
1123
1124   // Dispatch command creation to allow generator expressions in outputs.
1125   this->AddGeneratorAction(
1126     std::move(cc),
1127     [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
1128         std::unique_ptr<cmCustomCommand> tcc) {
1129       BacktraceGuard guard(this->Backtrace, lfbt);
1130       tcc->SetBacktrace(lfbt);
1131       cmSourceFile* sf = detail::AddCustomCommandToOutput(
1132         lg, cmCommandOrigin::Project, std::move(tcc), replace);
1133       if (callback && sf) {
1134         callback(sf);
1135       }
1136     });
1137 }
1138
1139 void cmMakefile::AddCustomCommandOldStyle(
1140   const std::string& target, const std::vector<std::string>& outputs,
1141   const std::vector<std::string>& depends, const std::string& source,
1142   const cmCustomCommandLines& commandLines, const char* comment)
1143 {
1144   auto cc = cm::make_unique<cmCustomCommand>();
1145   cc->SetDepends(depends);
1146   cc->SetCommandLines(commandLines);
1147   cc->SetComment(comment);
1148
1149   // Translate the old-style signature to one of the new-style
1150   // signatures.
1151   if (source == target) {
1152     // In the old-style signature if the source and target were the
1153     // same then it added a post-build rule to the target.  Preserve
1154     // this behavior.
1155     this->AddCustomCommandToTarget(target, cmCustomCommandType::POST_BUILD,
1156                                    std::move(cc));
1157     return;
1158   }
1159
1160   auto ti = this->Targets.find(target);
1161   cmTarget* t = ti != this->Targets.end() ? &ti->second : nullptr;
1162
1163   auto addRuleFileToTarget = [=](cmSourceFile* sf) {
1164     // If the rule was added to the source (and not a .rule file),
1165     // then add the source to the target to make sure the rule is
1166     // included.
1167     if (!sf->GetPropertyAsBool("__CMAKE_RULE")) {
1168       if (t) {
1169         t->AddSource(sf->ResolveFullPath());
1170       } else {
1171         cmSystemTools::Error("Attempt to add a custom rule to a target "
1172                              "that does not exist yet for target " +
1173                              target);
1174       }
1175     }
1176   };
1177
1178   // Each output must get its own copy of this rule.
1179   cmsys::RegularExpression sourceFiles(
1180     "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|ixx|cppm|cu|m|mm|"
1181     "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|"
1182     "hm|hpp|hxx|in|txx|inl)$");
1183
1184   // Choose whether to use a main dependency.
1185   if (sourceFiles.find(source)) {
1186     // The source looks like a real file.  Use it as the main dependency.
1187     for (std::string const& output : outputs) {
1188       auto cc1 = cm::make_unique<cmCustomCommand>(*cc);
1189       cc1->SetOutputs(output);
1190       cc1->SetMainDependency(source);
1191       this->AddCustomCommandToOutput(std::move(cc1), addRuleFileToTarget);
1192     }
1193   } else {
1194     cc->AppendDepends({ source });
1195
1196     // The source may not be a real file.  Do not use a main dependency.
1197     for (std::string const& output : outputs) {
1198       auto cc1 = cm::make_unique<cmCustomCommand>(*cc);
1199       cc1->SetOutputs(output);
1200       this->AddCustomCommandToOutput(std::move(cc1), addRuleFileToTarget);
1201     }
1202   }
1203 }
1204
1205 void cmMakefile::AppendCustomCommandToOutput(
1206   const std::string& output, const std::vector<std::string>& depends,
1207   const cmImplicitDependsList& implicit_depends,
1208   const cmCustomCommandLines& commandLines)
1209 {
1210   // Validate custom commands.
1211   if (this->ValidateCustomCommand(commandLines)) {
1212     // Dispatch command creation to allow generator expressions in outputs.
1213     this->AddGeneratorAction(
1214       [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
1215         BacktraceGuard guard(this->Backtrace, lfbt);
1216         detail::AppendCustomCommandToOutput(lg, lfbt, output, depends,
1217                                             implicit_depends, commandLines);
1218       });
1219   }
1220 }
1221
1222 cmTarget* cmMakefile::AddUtilityCommand(const std::string& utilityName,
1223                                         bool excludeFromAll,
1224                                         std::unique_ptr<cmCustomCommand> cc)
1225 {
1226   const auto& depends = cc->GetDepends();
1227   const auto& byproducts = cc->GetByproducts();
1228   const auto& commandLines = cc->GetCommandLines();
1229   cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll);
1230
1231   // Validate custom commands.
1232   if ((commandLines.empty() && depends.empty()) ||
1233       !this->ValidateCustomCommand(commandLines)) {
1234     return target;
1235   }
1236
1237   // Always create the byproduct sources and mark them generated.
1238   this->CreateGeneratedOutputs(byproducts);
1239
1240   cc->SetCMP0116Status(this->GetPolicyStatus(cmPolicies::CMP0116));
1241
1242   // Dispatch command creation to allow generator expressions in outputs.
1243   this->AddGeneratorAction(
1244     std::move(cc),
1245     [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
1246         std::unique_ptr<cmCustomCommand> tcc) {
1247       BacktraceGuard guard(this->Backtrace, lfbt);
1248       tcc->SetBacktrace(lfbt);
1249       detail::AddUtilityCommand(lg, cmCommandOrigin::Project, target,
1250                                 std::move(tcc));
1251     });
1252
1253   return target;
1254 }
1255
1256 static void s_AddDefineFlag(std::string const& flag, std::string& dflags)
1257 {
1258   // remove any \n\r
1259   std::string::size_type initSize = dflags.size();
1260   dflags += ' ';
1261   dflags += flag;
1262   std::string::iterator flagStart = dflags.begin() + initSize + 1;
1263   std::replace(flagStart, dflags.end(), '\n', ' ');
1264   std::replace(flagStart, dflags.end(), '\r', ' ');
1265 }
1266
1267 void cmMakefile::AddDefineFlag(std::string const& flag)
1268 {
1269   if (flag.empty()) {
1270     return;
1271   }
1272
1273   // Update the string used for the old DEFINITIONS property.
1274   s_AddDefineFlag(flag, this->DefineFlagsOrig);
1275
1276   // If this is really a definition, update COMPILE_DEFINITIONS.
1277   if (this->ParseDefineFlag(flag, false)) {
1278     return;
1279   }
1280
1281   // Add this flag that does not look like a definition.
1282   s_AddDefineFlag(flag, this->DefineFlags);
1283 }
1284
1285 static void s_RemoveDefineFlag(std::string const& flag, std::string& dflags)
1286 {
1287   std::string::size_type const len = flag.length();
1288   // Remove all instances of the flag that are surrounded by
1289   // whitespace or the beginning/end of the string.
1290   for (std::string::size_type lpos = dflags.find(flag, 0);
1291        lpos != std::string::npos; lpos = dflags.find(flag, lpos)) {
1292     std::string::size_type rpos = lpos + len;
1293     if ((lpos <= 0 || isspace(dflags[lpos - 1])) &&
1294         (rpos >= dflags.size() || isspace(dflags[rpos]))) {
1295       dflags.erase(lpos, len);
1296     } else {
1297       ++lpos;
1298     }
1299   }
1300 }
1301
1302 void cmMakefile::RemoveDefineFlag(std::string const& flag)
1303 {
1304   // Check the length of the flag to remove.
1305   if (flag.empty()) {
1306     return;
1307   }
1308
1309   // Update the string used for the old DEFINITIONS property.
1310   s_RemoveDefineFlag(flag, this->DefineFlagsOrig);
1311
1312   // If this is really a definition, update COMPILE_DEFINITIONS.
1313   if (this->ParseDefineFlag(flag, true)) {
1314     return;
1315   }
1316
1317   // Remove this flag that does not look like a definition.
1318   s_RemoveDefineFlag(flag, this->DefineFlags);
1319 }
1320
1321 void cmMakefile::AddCompileDefinition(std::string const& option)
1322 {
1323   this->AppendProperty("COMPILE_DEFINITIONS", option);
1324 }
1325
1326 void cmMakefile::AddCompileOption(std::string const& option)
1327 {
1328   this->AppendProperty("COMPILE_OPTIONS", option);
1329 }
1330
1331 void cmMakefile::AddLinkOption(std::string const& option)
1332 {
1333   this->AppendProperty("LINK_OPTIONS", option);
1334 }
1335
1336 void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
1337 {
1338   if (before) {
1339     this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(
1340       BT<std::string>(directory, this->Backtrace));
1341   } else {
1342     this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(
1343       BT<std::string>(directory, this->Backtrace));
1344   }
1345 }
1346
1347 bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
1348 {
1349   // Create a regular expression to match valid definitions.
1350   static cmsys::RegularExpression valid("^[-/]D[A-Za-z_][A-Za-z0-9_]*(=.*)?$");
1351
1352   // Make sure the definition matches.
1353   if (!valid.find(def)) {
1354     return false;
1355   }
1356
1357   // Definitions with non-trivial values require a policy check.
1358   static cmsys::RegularExpression trivial(
1359     "^[-/]D[A-Za-z_][A-Za-z0-9_]*(=[A-Za-z0-9_.]+)?$");
1360   if (!trivial.find(def)) {
1361     // This definition has a non-trivial value.
1362     switch (this->GetPolicyStatus(cmPolicies::CMP0005)) {
1363       case cmPolicies::WARN:
1364         this->IssueMessage(MessageType::AUTHOR_WARNING,
1365                            cmPolicies::GetPolicyWarning(cmPolicies::CMP0005));
1366         CM_FALLTHROUGH;
1367       case cmPolicies::OLD:
1368         // OLD behavior is to not escape the value.  We should not
1369         // convert the definition to use the property.
1370         return false;
1371       case cmPolicies::REQUIRED_IF_USED:
1372       case cmPolicies::REQUIRED_ALWAYS:
1373         this->IssueMessage(
1374           MessageType::FATAL_ERROR,
1375           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0005));
1376         return false;
1377       case cmPolicies::NEW:
1378         // NEW behavior is to escape the value.  Proceed to convert it
1379         // to an entry in the property.
1380         break;
1381     }
1382   }
1383
1384   // Get the definition part after the flag.
1385   const char* define = def.c_str() + 2;
1386
1387   if (remove) {
1388     if (cmValue cdefs = this->GetProperty("COMPILE_DEFINITIONS")) {
1389       // Expand the list.
1390       std::vector<std::string> defs = cmExpandedList(*cdefs);
1391
1392       // Recompose the list without the definition.
1393       auto defEnd = std::remove(defs.begin(), defs.end(), define);
1394       auto defBegin = defs.begin();
1395       std::string ndefs = cmJoin(cmMakeRange(defBegin, defEnd), ";");
1396
1397       // Store the new list.
1398       this->SetProperty("COMPILE_DEFINITIONS", ndefs);
1399     }
1400   } else {
1401     // Append the definition to the directory property.
1402     this->AppendProperty("COMPILE_DEFINITIONS", define);
1403   }
1404
1405   return true;
1406 }
1407
1408 void cmMakefile::InitializeFromParent(cmMakefile* parent)
1409 {
1410   this->SystemIncludeDirectories = parent->SystemIncludeDirectories;
1411
1412   // define flags
1413   this->DefineFlags = parent->DefineFlags;
1414   this->DefineFlagsOrig = parent->DefineFlagsOrig;
1415
1416   // Include transform property.  There is no per-config version.
1417   {
1418     const char* prop = "IMPLICIT_DEPENDS_INCLUDE_TRANSFORM";
1419     this->SetProperty(prop, parent->GetProperty(prop));
1420   }
1421
1422   // compile definitions property and per-config versions
1423   cmPolicies::PolicyStatus polSt = this->GetPolicyStatus(cmPolicies::CMP0043);
1424   if (polSt == cmPolicies::WARN || polSt == cmPolicies::OLD) {
1425     this->SetProperty("COMPILE_DEFINITIONS",
1426                       parent->GetProperty("COMPILE_DEFINITIONS"));
1427     std::vector<std::string> configs =
1428       this->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig);
1429     for (std::string const& config : configs) {
1430       std::string defPropName =
1431         cmStrCat("COMPILE_DEFINITIONS_", cmSystemTools::UpperCase(config));
1432       cmValue prop = parent->GetProperty(defPropName);
1433       this->SetProperty(defPropName, prop);
1434     }
1435   }
1436
1437   // labels
1438   this->SetProperty("LABELS", parent->GetProperty("LABELS"));
1439
1440   // link libraries
1441   this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES"));
1442
1443   // the initial project name
1444   this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
1445
1446   // Copy include regular expressions.
1447   this->ComplainFileRegularExpression = parent->ComplainFileRegularExpression;
1448
1449   // Imported targets.
1450   this->ImportedTargets = parent->ImportedTargets;
1451
1452   // Non-global Alias targets.
1453   this->AliasTargets = parent->AliasTargets;
1454
1455   // Recursion depth.
1456   this->RecursionDepth = parent->RecursionDepth;
1457 }
1458
1459 void cmMakefile::AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g)
1460 {
1461   if (g) {
1462     this->InstallGenerators.push_back(std::move(g));
1463   }
1464 }
1465
1466 void cmMakefile::AddTestGenerator(std::unique_ptr<cmTestGenerator> g)
1467 {
1468   if (g) {
1469     this->TestGenerators.push_back(std::move(g));
1470   }
1471 }
1472
1473 void cmMakefile::PushFunctionScope(std::string const& fileName,
1474                                    const cmPolicies::PolicyMap& pm)
1475 {
1476   this->StateSnapshot = this->GetState()->CreateFunctionCallSnapshot(
1477     this->StateSnapshot, fileName);
1478   assert(this->StateSnapshot.IsValid());
1479
1480   this->PushLoopBlockBarrier();
1481
1482 #if !defined(CMAKE_BOOTSTRAP)
1483   this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
1484 #endif
1485
1486   this->PushFunctionBlockerBarrier();
1487
1488   this->PushPolicy(true, pm);
1489 }
1490
1491 void cmMakefile::PopFunctionScope(bool reportError)
1492 {
1493   this->PopPolicy();
1494
1495   this->PopSnapshot(reportError);
1496
1497   this->PopFunctionBlockerBarrier(reportError);
1498
1499 #if !defined(CMAKE_BOOTSTRAP)
1500   this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
1501 #endif
1502
1503   this->PopLoopBlockBarrier();
1504 }
1505
1506 void cmMakefile::PushMacroScope(std::string const& fileName,
1507                                 const cmPolicies::PolicyMap& pm)
1508 {
1509   this->StateSnapshot =
1510     this->GetState()->CreateMacroCallSnapshot(this->StateSnapshot, fileName);
1511   assert(this->StateSnapshot.IsValid());
1512
1513   this->PushFunctionBlockerBarrier();
1514
1515   this->PushPolicy(true, pm);
1516 }
1517
1518 void cmMakefile::PopMacroScope(bool reportError)
1519 {
1520   this->PopPolicy();
1521   this->PopSnapshot(reportError);
1522
1523   this->PopFunctionBlockerBarrier(reportError);
1524 }
1525
1526 bool cmMakefile::IsRootMakefile() const
1527 {
1528   return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
1529 }
1530
1531 class cmMakefile::BuildsystemFileScope
1532 {
1533 public:
1534   BuildsystemFileScope(cmMakefile* mf)
1535     : Makefile(mf)
1536   {
1537     std::string currentStart =
1538       cmStrCat(this->Makefile->StateSnapshot.GetDirectory().GetCurrentSource(),
1539                "/CMakeLists.txt");
1540     this->Makefile->StateSnapshot.SetListFile(currentStart);
1541     this->Makefile->StateSnapshot =
1542       this->Makefile->StateSnapshot.GetState()->CreatePolicyScopeSnapshot(
1543         this->Makefile->StateSnapshot);
1544     this->Makefile->PushFunctionBlockerBarrier();
1545
1546     this->GG = mf->GetGlobalGenerator();
1547     this->CurrentMakefile = this->GG->GetCurrentMakefile();
1548     this->Snapshot = this->GG->GetCMakeInstance()->GetCurrentSnapshot();
1549     this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot);
1550     this->GG->SetCurrentMakefile(mf);
1551 #if !defined(CMAKE_BOOTSTRAP)
1552     this->GG->GetFileLockPool().PushFileScope();
1553 #endif
1554   }
1555
1556   ~BuildsystemFileScope()
1557   {
1558     this->Makefile->PopFunctionBlockerBarrier(this->ReportError);
1559     this->Makefile->PopSnapshot(this->ReportError);
1560 #if !defined(CMAKE_BOOTSTRAP)
1561     this->GG->GetFileLockPool().PopFileScope();
1562 #endif
1563     this->GG->SetCurrentMakefile(this->CurrentMakefile);
1564     this->GG->GetCMakeInstance()->SetCurrentSnapshot(this->Snapshot);
1565   }
1566
1567   void Quiet() { this->ReportError = false; }
1568
1569   BuildsystemFileScope(const BuildsystemFileScope&) = delete;
1570   BuildsystemFileScope& operator=(const BuildsystemFileScope&) = delete;
1571
1572 private:
1573   cmMakefile* Makefile;
1574   cmGlobalGenerator* GG;
1575   cmMakefile* CurrentMakefile;
1576   cmStateSnapshot Snapshot;
1577   bool ReportError = true;
1578 };
1579
1580 void cmMakefile::Configure()
1581 {
1582   std::string currentStart = cmStrCat(
1583     this->StateSnapshot.GetDirectory().GetCurrentSource(), "/CMakeLists.txt");
1584
1585   // Add the bottom of all backtraces within this directory.
1586   // We will never pop this scope because it should be available
1587   // for messages during the generate step too.
1588   this->Backtrace =
1589     this->Backtrace.Push(cmListFileContext::FromListFilePath(currentStart));
1590
1591   BuildsystemFileScope scope(this);
1592
1593   // make sure the CMakeFiles dir is there
1594   std::string filesDir = cmStrCat(
1595     this->StateSnapshot.GetDirectory().GetCurrentBinary(), "/CMakeFiles");
1596   cmSystemTools::MakeDirectory(filesDir);
1597
1598   assert(cmSystemTools::FileExists(currentStart, true));
1599   this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart);
1600
1601   cmListFile listFile;
1602   if (!listFile.ParseFile(currentStart.c_str(), this->GetMessenger(),
1603                           this->Backtrace)) {
1604     return;
1605   }
1606   if (this->IsRootMakefile()) {
1607     bool hasVersion = false;
1608     // search for the right policy command
1609     for (cmListFileFunction const& func : listFile.Functions) {
1610       if (func.LowerCaseName() == "cmake_minimum_required") {
1611         hasVersion = true;
1612         break;
1613       }
1614     }
1615     // if no policy command is found this is an error if they use any
1616     // non advanced functions or a lot of functions
1617     if (!hasVersion) {
1618       bool isProblem = true;
1619       if (listFile.Functions.size() < 30) {
1620         // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
1621         // these commands must have backwards compatibility forever and
1622         // and that is a lot longer than your tiny mind can comprehend mortal
1623         std::set<std::string> allowedCommands;
1624         allowedCommands.insert("project");
1625         allowedCommands.insert("set");
1626         allowedCommands.insert("if");
1627         allowedCommands.insert("endif");
1628         allowedCommands.insert("else");
1629         allowedCommands.insert("elseif");
1630         allowedCommands.insert("add_executable");
1631         allowedCommands.insert("add_library");
1632         allowedCommands.insert("target_link_libraries");
1633         allowedCommands.insert("option");
1634         allowedCommands.insert("message");
1635         isProblem = false;
1636         for (cmListFileFunction const& func : listFile.Functions) {
1637           if (!cm::contains(allowedCommands, func.LowerCaseName())) {
1638             isProblem = true;
1639             break;
1640           }
1641         }
1642       }
1643
1644       if (isProblem) {
1645         // Tell the top level cmMakefile to diagnose
1646         // this violation of CMP0000.
1647         this->SetCheckCMP0000(true);
1648
1649         // Implicitly set the version for the user.
1650         cmPolicies::ApplyPolicyVersion(this, 2, 4, 0,
1651                                        cmPolicies::WarnCompat::Off);
1652       }
1653     }
1654     bool hasProject = false;
1655     // search for a project command
1656     for (cmListFileFunction const& func : listFile.Functions) {
1657       if (func.LowerCaseName() == "project") {
1658         hasProject = true;
1659         break;
1660       }
1661     }
1662     // if no project command is found, add one
1663     if (!hasProject) {
1664       this->GetCMakeInstance()->IssueMessage(
1665         MessageType::AUTHOR_WARNING,
1666         "No project() command is present.  The top-level CMakeLists.txt "
1667         "file must contain a literal, direct call to the project() command.  "
1668         "Add a line of code such as\n"
1669         "  project(ProjectName)\n"
1670         "near the top of the file, but after cmake_minimum_required().\n"
1671         "CMake is pretending there is a \"project(Project)\" command on "
1672         "the first line.",
1673         this->Backtrace);
1674       cmListFileFunction project{ "project",
1675                                   0,
1676                                   0,
1677                                   { { "Project", cmListFileArgument::Unquoted,
1678                                       0 },
1679                                     { "__CMAKE_INJECTED_PROJECT_COMMAND__",
1680                                       cmListFileArgument::Unquoted, 0 } } };
1681       listFile.Functions.insert(listFile.Functions.begin(), project);
1682     }
1683   }
1684
1685   this->Defer = cm::make_unique<DeferCommands>();
1686   this->RunListFile(listFile, currentStart, this->Defer.get());
1687   this->Defer.reset();
1688   if (cmSystemTools::GetFatalErrorOccurred()) {
1689     scope.Quiet();
1690   }
1691
1692   // at the end handle any old style subdirs
1693   std::vector<cmMakefile*> subdirs = this->UnConfiguredDirectories;
1694
1695   // for each subdir recurse
1696   auto sdi = subdirs.begin();
1697   for (; sdi != subdirs.end(); ++sdi) {
1698     (*sdi)->StateSnapshot.InitializeFromParent_ForSubdirsCommand();
1699     this->ConfigureSubDirectory(*sdi);
1700   }
1701
1702   this->AddCMakeDependFilesFromUser();
1703 }
1704
1705 void cmMakefile::ConfigureSubDirectory(cmMakefile* mf)
1706 {
1707   mf->InitializeFromParent(this);
1708   std::string currentStart = mf->GetCurrentSourceDirectory();
1709   if (this->GetCMakeInstance()->GetDebugOutput()) {
1710     std::string msg = cmStrCat("   Entering             ", currentStart);
1711     cmSystemTools::Message(msg);
1712   }
1713
1714   std::string const currentStartFile = currentStart + "/CMakeLists.txt";
1715   if (!cmSystemTools::FileExists(currentStartFile, true)) {
1716     // The file is missing.  Check policy CMP0014.
1717     std::ostringstream e;
1718     /* clang-format off */
1719     e << "The source directory\n"
1720       << "  " << currentStart << "\n"
1721       << "does not contain a CMakeLists.txt file.";
1722     /* clang-format on */
1723     switch (this->GetPolicyStatus(cmPolicies::CMP0014)) {
1724       case cmPolicies::WARN:
1725         // Print the warning.
1726         /* clang-format off */
1727         e << "\n"
1728           << "CMake does not support this case but it used "
1729           << "to work accidentally and is being allowed for "
1730           << "compatibility."
1731           << "\n"
1732           << cmPolicies::GetPolicyWarning(cmPolicies::CMP0014);
1733         /* clang-format on */
1734         this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
1735         CM_FALLTHROUGH;
1736       case cmPolicies::OLD:
1737         // OLD behavior does not warn.
1738         break;
1739       case cmPolicies::REQUIRED_IF_USED:
1740       case cmPolicies::REQUIRED_ALWAYS:
1741         e << "\n" << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0014);
1742         CM_FALLTHROUGH;
1743       case cmPolicies::NEW:
1744         // NEW behavior prints the error.
1745         this->IssueMessage(MessageType::FATAL_ERROR, e.str());
1746         break;
1747     }
1748     return;
1749   }
1750   // finally configure the subdir
1751   mf->Configure();
1752
1753   if (this->GetCMakeInstance()->GetDebugOutput()) {
1754     std::string msg =
1755       cmStrCat("   Returning to         ", this->GetCurrentSourceDirectory());
1756     cmSystemTools::Message(msg);
1757   }
1758 }
1759
1760 void cmMakefile::AddSubDirectory(const std::string& srcPath,
1761                                  const std::string& binPath,
1762                                  bool excludeFromAll, bool immediate)
1763 {
1764   if (this->DeferRunning) {
1765     this->IssueMessage(
1766       MessageType::FATAL_ERROR,
1767       "Subdirectories may not be created during deferred execution.");
1768     return;
1769   }
1770
1771   // Make sure the binary directory is unique.
1772   if (!this->EnforceUniqueDir(srcPath, binPath)) {
1773     return;
1774   }
1775
1776   cmStateSnapshot newSnapshot =
1777     this->GetState()->CreateBuildsystemDirectorySnapshot(this->StateSnapshot);
1778
1779   newSnapshot.GetDirectory().SetCurrentSource(srcPath);
1780   newSnapshot.GetDirectory().SetCurrentBinary(binPath);
1781
1782   cmSystemTools::MakeDirectory(binPath);
1783
1784   auto subMfu =
1785     cm::make_unique<cmMakefile>(this->GlobalGenerator, newSnapshot);
1786   auto* subMf = subMfu.get();
1787   this->GetGlobalGenerator()->AddMakefile(std::move(subMfu));
1788
1789   if (excludeFromAll) {
1790     subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
1791   }
1792
1793   if (immediate) {
1794     this->ConfigureSubDirectory(subMf);
1795   } else {
1796     this->UnConfiguredDirectories.push_back(subMf);
1797   }
1798
1799   this->AddInstallGenerator(cm::make_unique<cmInstallSubdirectoryGenerator>(
1800     subMf, binPath, this->GetBacktrace()));
1801 }
1802
1803 const std::string& cmMakefile::GetCurrentSourceDirectory() const
1804 {
1805   return this->StateSnapshot.GetDirectory().GetCurrentSource();
1806 }
1807
1808 const std::string& cmMakefile::GetCurrentBinaryDirectory() const
1809 {
1810   return this->StateSnapshot.GetDirectory().GetCurrentBinary();
1811 }
1812
1813 std::vector<cmTarget*> cmMakefile::GetImportedTargets() const
1814 {
1815   std::vector<cmTarget*> tgts;
1816   tgts.reserve(this->ImportedTargets.size());
1817   for (auto const& impTarget : this->ImportedTargets) {
1818     tgts.push_back(impTarget.second);
1819   }
1820   return tgts;
1821 }
1822
1823 void cmMakefile::AddIncludeDirectories(const std::vector<std::string>& incs,
1824                                        bool before)
1825 {
1826   if (incs.empty()) {
1827     return;
1828   }
1829
1830   std::string entryString = cmJoin(incs, ";");
1831   if (before) {
1832     this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
1833       BT<std::string>(entryString, this->Backtrace));
1834   } else {
1835     this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry(
1836       BT<std::string>(entryString, this->Backtrace));
1837   }
1838
1839   // Property on each target:
1840   for (auto& target : this->Targets) {
1841     cmTarget& t = target.second;
1842     t.InsertInclude(BT<std::string>(entryString, this->Backtrace), before);
1843   }
1844 }
1845
1846 void cmMakefile::AddSystemIncludeDirectories(const std::set<std::string>& incs)
1847 {
1848   if (incs.empty()) {
1849     return;
1850   }
1851
1852   this->SystemIncludeDirectories.insert(incs.begin(), incs.end());
1853
1854   for (auto& target : this->Targets) {
1855     cmTarget& t = target.second;
1856     t.AddSystemIncludeDirectories(incs);
1857   }
1858 }
1859
1860 void cmMakefile::AddDefinition(const std::string& name, cm::string_view value)
1861 {
1862   this->StateSnapshot.SetDefinition(name, value);
1863
1864 #ifndef CMAKE_BOOTSTRAP
1865   cmVariableWatch* vv = this->GetVariableWatch();
1866   if (vv) {
1867     vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
1868                          value.data(), this);
1869   }
1870 #endif
1871 }
1872
1873 void cmMakefile::AddDefinitionBool(const std::string& name, bool value)
1874 {
1875   this->AddDefinition(name, value ? "ON" : "OFF");
1876 }
1877
1878 void cmMakefile::AddCacheDefinition(const std::string& name, const char* value,
1879                                     const char* doc,
1880                                     cmStateEnums::CacheEntryType type,
1881                                     bool force)
1882 {
1883   cmValue existingValue = this->GetState()->GetInitializedCacheValue(name);
1884   // must be outside the following if() to keep it alive long enough
1885   std::string nvalue;
1886
1887   if (existingValue &&
1888       (this->GetState()->GetCacheEntryType(name) ==
1889        cmStateEnums::UNINITIALIZED)) {
1890     // if this is not a force, then use the value from the cache
1891     // if it is a force, then use the value being passed in
1892     if (!force) {
1893       value = existingValue->c_str();
1894     }
1895     if (type == cmStateEnums::PATH || type == cmStateEnums::FILEPATH) {
1896       std::vector<std::string>::size_type cc;
1897       std::vector<std::string> files;
1898       nvalue = value ? value : "";
1899
1900       cmExpandList(nvalue, files);
1901       nvalue.clear();
1902       for (cc = 0; cc < files.size(); cc++) {
1903         if (!cmIsOff(files[cc])) {
1904           files[cc] = cmSystemTools::CollapseFullPath(files[cc]);
1905         }
1906         if (cc > 0) {
1907           nvalue += ";";
1908         }
1909         nvalue += files[cc];
1910       }
1911
1912       this->GetCMakeInstance()->AddCacheEntry(name, nvalue, doc, type);
1913       nvalue = *this->GetState()->GetInitializedCacheValue(name);
1914       value = nvalue.c_str();
1915     }
1916   }
1917   this->GetCMakeInstance()->AddCacheEntry(name, value, doc, type);
1918   switch (this->GetPolicyStatus(cmPolicies::CMP0126)) {
1919     case cmPolicies::WARN:
1920       if (this->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0126") &&
1921           this->IsNormalDefinitionSet(name)) {
1922         this->IssueMessage(
1923           MessageType::AUTHOR_WARNING,
1924           cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0126),
1925                    "\nFor compatibility with older versions of CMake, normal "
1926                    "variable \"",
1927                    name, "\" will be removed from the current scope."));
1928       }
1929       CM_FALLTHROUGH;
1930     case cmPolicies::OLD:
1931       // if there was a definition then remove it
1932       this->StateSnapshot.RemoveDefinition(name);
1933       break;
1934     case cmPolicies::NEW:
1935     case cmPolicies::REQUIRED_IF_USED:
1936     case cmPolicies::REQUIRED_ALWAYS:
1937       break;
1938   }
1939 }
1940
1941 void cmMakefile::MarkVariableAsUsed(const std::string& var)
1942 {
1943   this->StateSnapshot.GetDefinition(var);
1944 }
1945
1946 bool cmMakefile::VariableInitialized(const std::string& var) const
1947 {
1948   return this->StateSnapshot.IsInitialized(var);
1949 }
1950
1951 void cmMakefile::MaybeWarnUninitialized(std::string const& variable,
1952                                         const char* sourceFilename) const
1953 {
1954   // check to see if we need to print a warning
1955   // if strict mode is on and the variable has
1956   // not been "cleared"/initialized with a set(foo ) call
1957   if (this->GetCMakeInstance()->GetWarnUninitialized() &&
1958       !this->VariableInitialized(variable)) {
1959     if (this->CheckSystemVars ||
1960         (sourceFilename && this->IsProjectFile(sourceFilename))) {
1961       std::ostringstream msg;
1962       msg << "uninitialized variable \'" << variable << "\'";
1963       this->IssueMessage(MessageType::AUTHOR_WARNING, msg.str());
1964     }
1965   }
1966 }
1967
1968 void cmMakefile::RemoveDefinition(const std::string& name)
1969 {
1970   this->StateSnapshot.RemoveDefinition(name);
1971 #ifndef CMAKE_BOOTSTRAP
1972   cmVariableWatch* vv = this->GetVariableWatch();
1973   if (vv) {
1974     vv->VariableAccessed(name, cmVariableWatch::VARIABLE_REMOVED_ACCESS,
1975                          nullptr, this);
1976   }
1977 #endif
1978 }
1979
1980 void cmMakefile::RemoveCacheDefinition(const std::string& name) const
1981 {
1982   this->GetState()->RemoveCacheEntry(name);
1983 }
1984
1985 void cmMakefile::SetProjectName(std::string const& p)
1986 {
1987   this->StateSnapshot.SetProjectName(p);
1988 }
1989
1990 void cmMakefile::AddGlobalLinkInformation(cmTarget& target)
1991 {
1992   // for these targets do not add anything
1993   switch (target.GetType()) {
1994     case cmStateEnums::UTILITY:
1995     case cmStateEnums::GLOBAL_TARGET:
1996     case cmStateEnums::INTERFACE_LIBRARY:
1997       return;
1998     default:;
1999   }
2000
2001   if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
2002     std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp);
2003
2004     for (auto j = linkLibs.begin(); j != linkLibs.end(); ++j) {
2005       std::string libraryName = *j;
2006       cmTargetLinkLibraryType libType = GENERAL_LibraryType;
2007       if (libraryName == "optimized") {
2008         libType = OPTIMIZED_LibraryType;
2009         ++j;
2010         libraryName = *j;
2011       } else if (libraryName == "debug") {
2012         libType = DEBUG_LibraryType;
2013         ++j;
2014         libraryName = *j;
2015       }
2016       // This is equivalent to the target_link_libraries plain signature.
2017       target.AddLinkLibrary(*this, libraryName, libType);
2018       target.AppendProperty(
2019         "INTERFACE_LINK_LIBRARIES",
2020         target.GetDebugGeneratorExpressions(libraryName, libType));
2021     }
2022   }
2023 }
2024
2025 void cmMakefile::AddAlias(const std::string& lname, std::string const& tgtName,
2026                           bool globallyVisible)
2027 {
2028   this->AliasTargets[lname] = tgtName;
2029   if (globallyVisible) {
2030     this->GetGlobalGenerator()->AddAlias(lname, tgtName);
2031   }
2032 }
2033
2034 cmTarget* cmMakefile::AddLibrary(const std::string& lname,
2035                                  cmStateEnums::TargetType type,
2036                                  const std::vector<std::string>& srcs,
2037                                  bool excludeFromAll)
2038 {
2039   assert(type == cmStateEnums::STATIC_LIBRARY ||
2040          type == cmStateEnums::SHARED_LIBRARY ||
2041          type == cmStateEnums::MODULE_LIBRARY ||
2042          type == cmStateEnums::OBJECT_LIBRARY ||
2043          type == cmStateEnums::INTERFACE_LIBRARY);
2044
2045   cmTarget* target = this->AddNewTarget(type, lname);
2046   // Clear its dependencies. Otherwise, dependencies might persist
2047   // over changes in CMakeLists.txt, making the information stale and
2048   // hence useless.
2049   target->ClearDependencyInformation(*this);
2050   if (excludeFromAll) {
2051     target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
2052   }
2053   target->AddSources(srcs);
2054   this->AddGlobalLinkInformation(*target);
2055   return target;
2056 }
2057
2058 cmTarget* cmMakefile::AddExecutable(const std::string& exeName,
2059                                     const std::vector<std::string>& srcs,
2060                                     bool excludeFromAll)
2061 {
2062   cmTarget* target = this->AddNewTarget(cmStateEnums::EXECUTABLE, exeName);
2063   if (excludeFromAll) {
2064     target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
2065   }
2066   target->AddSources(srcs);
2067   this->AddGlobalLinkInformation(*target);
2068   return target;
2069 }
2070
2071 cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
2072                                    const std::string& name)
2073 {
2074   return &this->CreateNewTarget(name, type).first;
2075 }
2076
2077 std::pair<cmTarget&, bool> cmMakefile::CreateNewTarget(
2078   const std::string& name, cmStateEnums::TargetType type,
2079   cmTarget::PerConfig perConfig)
2080 {
2081   auto ib = this->Targets.emplace(
2082     name, cmTarget(name, type, cmTarget::VisibilityNormal, this, perConfig));
2083   auto it = ib.first;
2084   if (!ib.second) {
2085     return std::make_pair(std::ref(it->second), false);
2086   }
2087   this->OrderedTargets.push_back(&it->second);
2088   this->GetGlobalGenerator()->IndexTarget(&it->second);
2089   this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
2090   return std::make_pair(std::ref(it->second), true);
2091 }
2092
2093 cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
2094                                           bool excludeFromAll)
2095 {
2096   cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
2097   if (excludeFromAll) {
2098     target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
2099   }
2100   return target;
2101 }
2102
2103 namespace {
2104 }
2105
2106 #if !defined(CMAKE_BOOTSTRAP)
2107 cmSourceGroup* cmMakefile::GetSourceGroup(
2108   const std::vector<std::string>& name) const
2109 {
2110   cmSourceGroup* sg = nullptr;
2111
2112   // first look for source group starting with the same as the one we want
2113   for (cmSourceGroup const& srcGroup : this->SourceGroups) {
2114     std::string const& sgName = srcGroup.GetName();
2115     if (sgName == name[0]) {
2116       sg = const_cast<cmSourceGroup*>(&srcGroup);
2117       break;
2118     }
2119   }
2120
2121   if (sg != nullptr) {
2122     // iterate through its children to find match source group
2123     for (unsigned int i = 1; i < name.size(); ++i) {
2124       sg = sg->LookupChild(name[i]);
2125       if (sg == nullptr) {
2126         break;
2127       }
2128     }
2129   }
2130   return sg;
2131 }
2132
2133 void cmMakefile::AddSourceGroup(const std::string& name, const char* regex)
2134 {
2135   std::vector<std::string> nameVector;
2136   nameVector.push_back(name);
2137   this->AddSourceGroup(nameVector, regex);
2138 }
2139
2140 void cmMakefile::AddSourceGroup(const std::vector<std::string>& name,
2141                                 const char* regex)
2142 {
2143   cmSourceGroup* sg = nullptr;
2144   std::vector<std::string> currentName;
2145   int i = 0;
2146   const int lastElement = static_cast<int>(name.size() - 1);
2147   for (i = lastElement; i >= 0; --i) {
2148     currentName.assign(name.begin(), name.begin() + i + 1);
2149     sg = this->GetSourceGroup(currentName);
2150     if (sg != nullptr) {
2151       break;
2152     }
2153   }
2154
2155   // i now contains the index of the last found component
2156   if (i == lastElement) {
2157     // group already exists, replace its regular expression
2158     if (regex && sg) {
2159       // We only want to set the regular expression.  If there are already
2160       // source files in the group, we don't want to remove them.
2161       sg->SetGroupRegex(regex);
2162     }
2163     return;
2164   }
2165   if (i == -1) {
2166     // group does not exist nor belong to any existing group
2167     // add its first component
2168     this->SourceGroups.emplace_back(name[0], regex);
2169     sg = this->GetSourceGroup(currentName);
2170     i = 0; // last component found
2171   }
2172   if (!sg) {
2173     cmSystemTools::Error("Could not create source group ");
2174     return;
2175   }
2176   // build the whole source group path
2177   for (++i; i <= lastElement; ++i) {
2178     sg->AddChild(cmSourceGroup(name[i], nullptr, sg->GetFullName().c_str()));
2179     sg = sg->LookupChild(name[i]);
2180   }
2181
2182   sg->SetGroupRegex(regex);
2183 }
2184
2185 cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(
2186   const std::vector<std::string>& folders)
2187 {
2188   cmSourceGroup* sg = this->GetSourceGroup(folders);
2189   if (sg == nullptr) {
2190     this->AddSourceGroup(folders);
2191     sg = this->GetSourceGroup(folders);
2192   }
2193   return sg;
2194 }
2195
2196 cmSourceGroup* cmMakefile::GetOrCreateSourceGroup(const std::string& name)
2197 {
2198   std::string delimiters;
2199   if (cmValue p = this->GetDefinition("SOURCE_GROUP_DELIMITER")) {
2200     delimiters = *p;
2201   } else {
2202     delimiters = "/\\";
2203   }
2204   return this->GetOrCreateSourceGroup(cmTokenize(name, delimiters));
2205 }
2206
2207 /**
2208  * Find a source group whose regular expression matches the filename
2209  * part of the given source name.  Search backward through the list of
2210  * source groups, and take the first matching group found.  This way
2211  * non-inherited SOURCE_GROUP commands will have precedence over
2212  * inherited ones.
2213  */
2214 cmSourceGroup* cmMakefile::FindSourceGroup(
2215   const std::string& source, std::vector<cmSourceGroup>& groups) const
2216 {
2217   // First search for a group that lists the file explicitly.
2218   for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
2219     cmSourceGroup* result = sg->MatchChildrenFiles(source);
2220     if (result) {
2221       return result;
2222     }
2223   }
2224
2225   // Now search for a group whose regex matches the file.
2226   for (auto sg = groups.rbegin(); sg != groups.rend(); ++sg) {
2227     cmSourceGroup* result = sg->MatchChildrenRegex(source);
2228     if (result) {
2229       return result;
2230     }
2231   }
2232
2233   // Shouldn't get here, but just in case, return the default group.
2234   return groups.data();
2235 }
2236 #endif
2237
2238 static bool mightExpandVariablesCMP0019(const char* s)
2239 {
2240   return s && *s && strstr(s, "${") && strchr(s, '}');
2241 }
2242
2243 void cmMakefile::ExpandVariablesCMP0019()
2244 {
2245   // Drop this ancient compatibility behavior with a policy.
2246   cmPolicies::PolicyStatus pol = this->GetPolicyStatus(cmPolicies::CMP0019);
2247   if (pol != cmPolicies::OLD && pol != cmPolicies::WARN) {
2248     return;
2249   }
2250   std::ostringstream w;
2251
2252   cmValue includeDirs = this->GetProperty("INCLUDE_DIRECTORIES");
2253   if (includeDirs && mightExpandVariablesCMP0019(includeDirs->c_str())) {
2254     std::string dirs = *includeDirs;
2255     this->ExpandVariablesInString(dirs, true, true);
2256     if (pol == cmPolicies::WARN && dirs != *includeDirs) {
2257       /* clang-format off */
2258       w << "Evaluated directory INCLUDE_DIRECTORIES\n"
2259         << "  " << *includeDirs << "\n"
2260         << "as\n"
2261         << "  " << dirs << "\n";
2262       /* clang-format on */
2263     }
2264     this->SetProperty("INCLUDE_DIRECTORIES", dirs);
2265   }
2266
2267   // Also for each target's INCLUDE_DIRECTORIES property:
2268   for (auto& target : this->Targets) {
2269     cmTarget& t = target.second;
2270     if (t.GetType() == cmStateEnums::INTERFACE_LIBRARY ||
2271         t.GetType() == cmStateEnums::GLOBAL_TARGET) {
2272       continue;
2273     }
2274     includeDirs = t.GetProperty("INCLUDE_DIRECTORIES");
2275     if (includeDirs && mightExpandVariablesCMP0019(includeDirs->c_str())) {
2276       std::string dirs = *includeDirs;
2277       this->ExpandVariablesInString(dirs, true, true);
2278       if (pol == cmPolicies::WARN && dirs != *includeDirs) {
2279         /* clang-format off */
2280         w << "Evaluated target " << t.GetName() << " INCLUDE_DIRECTORIES\n"
2281           << "  " << *includeDirs << "\n"
2282           << "as\n"
2283           << "  " << dirs << "\n";
2284         /* clang-format on */
2285       }
2286       t.SetProperty("INCLUDE_DIRECTORIES", dirs);
2287     }
2288   }
2289
2290   if (cmValue linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
2291     if (mightExpandVariablesCMP0019(linkDirsProp->c_str())) {
2292       std::string d = *linkDirsProp;
2293       const std::string orig = d;
2294       this->ExpandVariablesInString(d, true, true);
2295       if (pol == cmPolicies::WARN && d != orig) {
2296         /* clang-format off */
2297         w << "Evaluated link directories\n"
2298           << "  " << orig << "\n"
2299           << "as\n"
2300           << "  " << d << "\n";
2301         /* clang-format on */
2302       }
2303     }
2304   }
2305
2306   if (cmValue linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
2307     std::vector<std::string> linkLibs = cmExpandedList(*linkLibsProp);
2308
2309     for (auto l = linkLibs.begin(); l != linkLibs.end(); ++l) {
2310       std::string libName = *l;
2311       if (libName == "optimized"_s || libName == "debug"_s) {
2312         ++l;
2313         libName = *l;
2314       }
2315       if (mightExpandVariablesCMP0019(libName.c_str())) {
2316         const std::string orig = libName;
2317         this->ExpandVariablesInString(libName, true, true);
2318         if (pol == cmPolicies::WARN && libName != orig) {
2319           /* clang-format off */
2320         w << "Evaluated link library\n"
2321           << "  " << orig << "\n"
2322           << "as\n"
2323           << "  " << libName << "\n";
2324           /* clang-format on */
2325         }
2326       }
2327     }
2328   }
2329
2330   if (!w.str().empty()) {
2331     std::ostringstream m;
2332     /* clang-format off */
2333     m << cmPolicies::GetPolicyWarning(cmPolicies::CMP0019)
2334       << "\n"
2335       << "The following variable evaluations were encountered:\n"
2336       << w.str();
2337     /* clang-format on */
2338     this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
2339                                            m.str(), this->Backtrace);
2340   }
2341 }
2342
2343 bool cmMakefile::IsOn(const std::string& name) const
2344 {
2345   return cmIsOn(this->GetDefinition(name));
2346 }
2347
2348 bool cmMakefile::IsSet(const std::string& name) const
2349 {
2350   cmValue value = this->GetDefinition(name);
2351   if (!value) {
2352     return false;
2353   }
2354
2355   if (value->empty()) {
2356     return false;
2357   }
2358
2359   if (cmIsNOTFOUND(*value)) {
2360     return false;
2361   }
2362
2363   return true;
2364 }
2365
2366 bool cmMakefile::PlatformIs32Bit() const
2367 {
2368   if (cmValue plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
2369     if (*plat_abi == "ELF X32") {
2370       return false;
2371     }
2372   }
2373   if (cmValue sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
2374     return atoi(sizeof_dptr->c_str()) == 4;
2375   }
2376   return false;
2377 }
2378
2379 bool cmMakefile::PlatformIs64Bit() const
2380 {
2381   if (cmValue sizeof_dptr = this->GetDefinition("CMAKE_SIZEOF_VOID_P")) {
2382     return atoi(sizeof_dptr->c_str()) == 8;
2383   }
2384   return false;
2385 }
2386
2387 bool cmMakefile::PlatformIsx32() const
2388 {
2389   if (cmValue plat_abi = this->GetDefinition("CMAKE_INTERNAL_PLATFORM_ABI")) {
2390     if (*plat_abi == "ELF X32") {
2391       return true;
2392     }
2393   }
2394   return false;
2395 }
2396
2397 cmMakefile::AppleSDK cmMakefile::GetAppleSDKType() const
2398 {
2399   std::string sdkRoot;
2400   sdkRoot = this->GetSafeDefinition("CMAKE_OSX_SYSROOT");
2401   sdkRoot = cmSystemTools::LowerCase(sdkRoot);
2402
2403   struct
2404   {
2405     std::string name;
2406     AppleSDK sdk;
2407   } const sdkDatabase[]{
2408     { "appletvos", AppleSDK::AppleTVOS },
2409     { "appletvsimulator", AppleSDK::AppleTVSimulator },
2410     { "iphoneos", AppleSDK::IPhoneOS },
2411     { "iphonesimulator", AppleSDK::IPhoneSimulator },
2412     { "watchos", AppleSDK::WatchOS },
2413     { "watchsimulator", AppleSDK::WatchSimulator },
2414   };
2415
2416   for (auto const& entry : sdkDatabase) {
2417     if (cmHasPrefix(sdkRoot, entry.name) ||
2418         sdkRoot.find(std::string("/") + entry.name) != std::string::npos) {
2419       return entry.sdk;
2420     }
2421   }
2422
2423   return AppleSDK::MacOS;
2424 }
2425
2426 bool cmMakefile::PlatformIsAppleEmbedded() const
2427 {
2428   return this->GetAppleSDKType() != AppleSDK::MacOS;
2429 }
2430
2431 const char* cmMakefile::GetSONameFlag(const std::string& language) const
2432 {
2433   std::string name = "CMAKE_SHARED_LIBRARY_SONAME";
2434   if (!language.empty()) {
2435     name += "_";
2436     name += language;
2437   }
2438   name += "_FLAG";
2439   return this->GetDefinition(name).GetCStr();
2440 }
2441
2442 bool cmMakefile::CanIWriteThisFile(std::string const& fileName) const
2443 {
2444   if (!this->IsOn("CMAKE_DISABLE_SOURCE_CHANGES")) {
2445     return true;
2446   }
2447   // If we are doing an in-source build, then the test will always fail
2448   if (cmSystemTools::SameFile(this->GetHomeDirectory(),
2449                               this->GetHomeOutputDirectory())) {
2450     return !this->IsOn("CMAKE_DISABLE_IN_SOURCE_BUILD");
2451   }
2452
2453   return !cmSystemTools::IsSubDirectory(fileName, this->GetHomeDirectory()) ||
2454     cmSystemTools::IsSubDirectory(fileName, this->GetHomeOutputDirectory()) ||
2455     cmSystemTools::SameFile(fileName, this->GetHomeOutputDirectory());
2456 }
2457
2458 const std::string& cmMakefile::GetRequiredDefinition(
2459   const std::string& name) const
2460 {
2461   static std::string const empty;
2462   cmValue def = this->GetDefinition(name);
2463   if (!def) {
2464     cmSystemTools::Error("Error required internal CMake variable not "
2465                          "set, cmake may not be built correctly.\n"
2466                          "Missing variable is:\n" +
2467                          name);
2468     return empty;
2469   }
2470   return *def;
2471 }
2472
2473 bool cmMakefile::IsDefinitionSet(const std::string& name) const
2474 {
2475   cmValue def = this->StateSnapshot.GetDefinition(name);
2476   if (!def) {
2477     def = this->GetState()->GetInitializedCacheValue(name);
2478   }
2479 #ifndef CMAKE_BOOTSTRAP
2480   if (cmVariableWatch* vv = this->GetVariableWatch()) {
2481     if (!def) {
2482       vv->VariableAccessed(
2483         name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, nullptr, this);
2484     }
2485   }
2486 #endif
2487   return def != nullptr;
2488 }
2489
2490 bool cmMakefile::IsNormalDefinitionSet(const std::string& name) const
2491 {
2492   cmValue def = this->StateSnapshot.GetDefinition(name);
2493 #ifndef CMAKE_BOOTSTRAP
2494   if (cmVariableWatch* vv = this->GetVariableWatch()) {
2495     if (!def) {
2496       vv->VariableAccessed(
2497         name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, nullptr, this);
2498     }
2499   }
2500 #endif
2501   return def != nullptr;
2502 }
2503
2504 cmValue cmMakefile::GetDefinition(const std::string& name) const
2505 {
2506   cmValue def = this->StateSnapshot.GetDefinition(name);
2507   if (!def) {
2508     def = this->GetState()->GetInitializedCacheValue(name);
2509   }
2510 #ifndef CMAKE_BOOTSTRAP
2511   cmVariableWatch* vv = this->GetVariableWatch();
2512   if (vv && !this->SuppressSideEffects) {
2513     bool const watch_function_executed =
2514       vv->VariableAccessed(name,
2515                            def ? cmVariableWatch::VARIABLE_READ_ACCESS
2516                                : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS,
2517                            def.GetCStr(), this);
2518
2519     if (watch_function_executed) {
2520       // A callback was executed and may have caused re-allocation of the
2521       // variable storage.  Look it up again for now.
2522       // FIXME: Refactor variable storage to avoid this problem.
2523       def = this->StateSnapshot.GetDefinition(name);
2524       if (!def) {
2525         def = this->GetState()->GetInitializedCacheValue(name);
2526       }
2527     }
2528   }
2529 #endif
2530   return def;
2531 }
2532
2533 const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const
2534 {
2535   return this->GetDefinition(name);
2536 }
2537
2538 bool cmMakefile::GetDefExpandList(const std::string& name,
2539                                   std::vector<std::string>& out,
2540                                   bool emptyArgs) const
2541 {
2542   cmValue def = this->GetDefinition(name);
2543   if (!def) {
2544     return false;
2545   }
2546   cmExpandList(*def, out, emptyArgs);
2547   return true;
2548 }
2549
2550 std::vector<std::string> cmMakefile::GetDefinitions() const
2551 {
2552   std::vector<std::string> res = this->StateSnapshot.ClosureKeys();
2553   cm::append(res, this->GetState()->GetCacheEntryKeys());
2554   std::sort(res.begin(), res.end());
2555   return res;
2556 }
2557
2558 const std::string& cmMakefile::ExpandVariablesInString(
2559   std::string& source) const
2560 {
2561   return this->ExpandVariablesInString(source, false, false);
2562 }
2563
2564 const std::string& cmMakefile::ExpandVariablesInString(
2565   std::string& source, bool escapeQuotes, bool noEscapes, bool atOnly,
2566   const char* filename, long line, bool removeEmpty, bool replaceAt) const
2567 {
2568   bool compareResults = false;
2569   MessageType mtype = MessageType::LOG;
2570   std::string errorstr;
2571   std::string original;
2572
2573   // Sanity check the @ONLY mode.
2574   if (atOnly && (!noEscapes || !removeEmpty)) {
2575     // This case should never be called.  At-only is for
2576     // configure-file/string which always does no escapes.
2577     this->IssueMessage(MessageType::INTERNAL_ERROR,
2578                        "ExpandVariablesInString @ONLY called "
2579                        "on something with escapes.");
2580     return source;
2581   }
2582
2583   // Variables used in the WARN case.
2584   std::string newResult;
2585   std::string newErrorstr;
2586   MessageType newError = MessageType::LOG;
2587
2588   switch (this->GetPolicyStatus(cmPolicies::CMP0053)) {
2589     case cmPolicies::WARN: {
2590       // Save the original string for the warning.
2591       original = source;
2592       newResult = source;
2593       compareResults = true;
2594       // Suppress variable watches to avoid calling hooks twice. Suppress new
2595       // dereferences since the OLD behavior is still what is actually used.
2596       this->SuppressSideEffects = true;
2597       newError = this->ExpandVariablesInStringNew(
2598         newErrorstr, newResult, escapeQuotes, noEscapes, atOnly, filename,
2599         line, replaceAt);
2600       this->SuppressSideEffects = false;
2601       CM_FALLTHROUGH;
2602     }
2603     case cmPolicies::OLD:
2604       mtype = this->ExpandVariablesInStringOld(errorstr, source, escapeQuotes,
2605                                                noEscapes, atOnly, filename,
2606                                                line, removeEmpty, true);
2607       break;
2608     case cmPolicies::REQUIRED_IF_USED:
2609     case cmPolicies::REQUIRED_ALWAYS:
2610     // Messaging here would be *very* verbose.
2611     case cmPolicies::NEW:
2612       mtype = this->ExpandVariablesInStringNew(errorstr, source, escapeQuotes,
2613                                                noEscapes, atOnly, filename,
2614                                                line, replaceAt);
2615       break;
2616   }
2617
2618   // If it's an error in either case, just report the error...
2619   if (mtype != MessageType::LOG) {
2620     if (mtype == MessageType::FATAL_ERROR) {
2621       cmSystemTools::SetFatalErrorOccurred();
2622     }
2623     this->IssueMessage(mtype, errorstr);
2624   }
2625   // ...otherwise, see if there's a difference that needs to be warned about.
2626   else if (compareResults && (newResult != source || newError != mtype)) {
2627     std::string msg =
2628       cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0053), '\n');
2629
2630     std::string msg_input = original;
2631     cmSystemTools::ReplaceString(msg_input, "\n", "\n  ");
2632     msg += "For input:\n  '";
2633     msg += msg_input;
2634     msg += "'\n";
2635
2636     std::string msg_old = source;
2637     cmSystemTools::ReplaceString(msg_old, "\n", "\n  ");
2638     msg += "the old evaluation rules produce:\n  '";
2639     msg += msg_old;
2640     msg += "'\n";
2641
2642     if (newError == mtype) {
2643       std::string msg_new = newResult;
2644       cmSystemTools::ReplaceString(msg_new, "\n", "\n  ");
2645       msg += "but the new evaluation rules produce:\n  '";
2646       msg += msg_new;
2647       msg += "'\n";
2648     } else {
2649       std::string msg_err = newErrorstr;
2650       cmSystemTools::ReplaceString(msg_err, "\n", "\n  ");
2651       msg += "but the new evaluation rules produce an error:\n  ";
2652       msg += msg_err;
2653       msg += "\n";
2654     }
2655
2656     msg +=
2657       "Using the old result for compatibility since the policy is not set.";
2658
2659     this->IssueMessage(MessageType::AUTHOR_WARNING, msg);
2660   }
2661
2662   return source;
2663 }
2664
2665 MessageType cmMakefile::ExpandVariablesInStringOld(
2666   std::string& errorstr, std::string& source, bool escapeQuotes,
2667   bool noEscapes, bool atOnly, const char* filename, long line,
2668   bool removeEmpty, bool replaceAt) const
2669 {
2670   // Fast path strings without any special characters.
2671   if (source.find_first_of("$@\\") == std::string::npos) {
2672     return MessageType::LOG;
2673   }
2674
2675   // Special-case the @ONLY mode.
2676   if (atOnly) {
2677     // Store an original copy of the input.
2678     std::string input = source;
2679
2680     // Start with empty output.
2681     source.clear();
2682
2683     // Look for one @VAR@ at a time.
2684     const char* in = input.c_str();
2685     while (this->cmAtVarRegex.find(in)) {
2686       // Get the range of the string to replace.
2687       const char* first = in + this->cmAtVarRegex.start();
2688       const char* last = in + this->cmAtVarRegex.end();
2689
2690       // Store the unchanged part of the string now.
2691       source.append(in, first - in);
2692
2693       // Lookup the definition of VAR.
2694       std::string var(first + 1, last - first - 2);
2695       if (cmValue val = this->GetDefinition(var)) {
2696         // Store the value in the output escaping as requested.
2697         if (escapeQuotes) {
2698           source.append(cmEscapeQuotes(*val));
2699         } else {
2700           source.append(*val);
2701         }
2702       }
2703
2704       // Continue looking for @VAR@ further along the string.
2705       in = last;
2706     }
2707
2708     // Append the rest of the unchanged part of the string.
2709     source.append(in);
2710
2711     return MessageType::LOG;
2712   }
2713
2714   // This method replaces ${VAR} and @VAR@ where VAR is looked up
2715   // with GetDefinition(), if not found in the map, nothing is expanded.
2716   // It also supports the $ENV{VAR} syntax where VAR is looked up in
2717   // the current environment variables.
2718
2719   cmCommandArgumentParserHelper parser;
2720   parser.SetMakefile(this);
2721   parser.SetLineFile(line, filename);
2722   parser.SetEscapeQuotes(escapeQuotes);
2723   parser.SetNoEscapeMode(noEscapes);
2724   parser.SetReplaceAtSyntax(replaceAt);
2725   parser.SetRemoveEmpty(removeEmpty);
2726   int res = parser.ParseString(source, 0);
2727   const char* emsg = parser.GetError();
2728   MessageType mtype = MessageType::LOG;
2729   if (res && !emsg[0]) {
2730     source = parser.GetResult();
2731   } else {
2732     // Construct the main error message.
2733     std::ostringstream error;
2734     error << "Syntax error in cmake code ";
2735     if (filename && line > 0) {
2736       // This filename and line number may be more specific than the
2737       // command context because one command invocation can have
2738       // arguments on multiple lines.
2739       error << "at\n"
2740             << "  " << filename << ":" << line << "\n";
2741     }
2742     error << "when parsing string\n"
2743           << "  " << source << "\n";
2744     error << emsg;
2745
2746     // If the parser failed ("res" is false) then this is a real
2747     // argument parsing error, so the policy applies.  Otherwise the
2748     // parser reported an error message without failing because the
2749     // helper implementation is unhappy, which has always reported an
2750     // error.
2751     mtype = MessageType::FATAL_ERROR;
2752     if (!res) {
2753       // This is a real argument parsing error.  Use policy CMP0010 to
2754       // decide whether it is an error.
2755       switch (this->GetPolicyStatus(cmPolicies::CMP0010)) {
2756         case cmPolicies::WARN:
2757           error << "\n" << cmPolicies::GetPolicyWarning(cmPolicies::CMP0010);
2758           CM_FALLTHROUGH;
2759         case cmPolicies::OLD:
2760           // OLD behavior is to just warn and continue.
2761           mtype = MessageType::AUTHOR_WARNING;
2762           break;
2763         case cmPolicies::REQUIRED_IF_USED:
2764         case cmPolicies::REQUIRED_ALWAYS:
2765           error << "\n"
2766                 << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0010);
2767           break;
2768         case cmPolicies::NEW:
2769           // NEW behavior is to report the error.
2770           break;
2771       }
2772     }
2773     errorstr = error.str();
2774   }
2775   return mtype;
2776 }
2777
2778 enum t_domain
2779 {
2780   NORMAL,
2781   ENVIRONMENT,
2782   CACHE
2783 };
2784
2785 struct t_lookup
2786 {
2787   t_domain domain = NORMAL;
2788   size_t loc = 0;
2789 };
2790
2791 bool cmMakefile::IsProjectFile(const char* filename) const
2792 {
2793   return cmSystemTools::IsSubDirectory(filename, this->GetHomeDirectory()) ||
2794     (cmSystemTools::IsSubDirectory(filename, this->GetHomeOutputDirectory()) &&
2795      !cmSystemTools::IsSubDirectory(filename, "/CMakeFiles"));
2796 }
2797
2798 int cmMakefile::GetRecursionDepth() const
2799 {
2800   return this->RecursionDepth;
2801 }
2802
2803 void cmMakefile::SetRecursionDepth(int recursionDepth)
2804 {
2805   this->RecursionDepth = recursionDepth;
2806 }
2807
2808 std::string cmMakefile::NewDeferId() const
2809 {
2810   return this->GetGlobalGenerator()->NewDeferId();
2811 }
2812
2813 bool cmMakefile::DeferCall(std::string id, std::string file,
2814                            cmListFileFunction lff)
2815 {
2816   if (!this->Defer) {
2817     return false;
2818   }
2819   this->Defer->Commands.emplace_back(
2820     DeferCommand{ std::move(id), std::move(file), std::move(lff) });
2821   return true;
2822 }
2823
2824 bool cmMakefile::DeferCancelCall(std::string const& id)
2825 {
2826   if (!this->Defer) {
2827     return false;
2828   }
2829   for (DeferCommand& dc : this->Defer->Commands) {
2830     if (dc.Id == id) {
2831       dc.Id.clear();
2832     }
2833   }
2834   return true;
2835 }
2836
2837 cm::optional<std::string> cmMakefile::DeferGetCallIds() const
2838 {
2839   cm::optional<std::string> ids;
2840   if (this->Defer) {
2841     ids = cmJoin(
2842       cmMakeRange(this->Defer->Commands)
2843         .filter([](DeferCommand const& dc) -> bool { return !dc.Id.empty(); })
2844         .transform(
2845           [](DeferCommand const& dc) -> std::string const& { return dc.Id; }),
2846       ";");
2847   }
2848   return ids;
2849 }
2850
2851 cm::optional<std::string> cmMakefile::DeferGetCall(std::string const& id) const
2852 {
2853   cm::optional<std::string> call;
2854   if (this->Defer) {
2855     std::string tmp;
2856     for (DeferCommand const& dc : this->Defer->Commands) {
2857       if (dc.Id == id) {
2858         tmp = dc.Command.OriginalName();
2859         for (cmListFileArgument const& arg : dc.Command.Arguments()) {
2860           tmp = cmStrCat(tmp, ';', arg.Value);
2861         }
2862         break;
2863       }
2864     }
2865     call = std::move(tmp);
2866   }
2867   return call;
2868 }
2869
2870 MessageType cmMakefile::ExpandVariablesInStringNew(
2871   std::string& errorstr, std::string& source, bool escapeQuotes,
2872   bool noEscapes, bool atOnly, const char* filename, long line,
2873   bool replaceAt) const
2874 {
2875   // This method replaces ${VAR} and @VAR@ where VAR is looked up
2876   // with GetDefinition(), if not found in the map, nothing is expanded.
2877   // It also supports the $ENV{VAR} syntax where VAR is looked up in
2878   // the current environment variables.
2879
2880   const char* in = source.c_str();
2881   const char* last = in;
2882   std::string result;
2883   result.reserve(source.size());
2884   std::vector<t_lookup> openstack;
2885   bool error = false;
2886   bool done = false;
2887   MessageType mtype = MessageType::LOG;
2888
2889   cmState* state = this->GetCMakeInstance()->GetState();
2890
2891   static const std::string lineVar = "CMAKE_CURRENT_LIST_LINE";
2892   do {
2893     char inc = *in;
2894     switch (inc) {
2895       case '}':
2896         if (!openstack.empty()) {
2897           t_lookup var = openstack.back();
2898           openstack.pop_back();
2899           result.append(last, in - last);
2900           std::string const& lookup = result.substr(var.loc);
2901           cmValue value = nullptr;
2902           std::string varresult;
2903           std::string svalue;
2904           switch (var.domain) {
2905             case NORMAL:
2906               if (filename && lookup == lineVar) {
2907                 cmListFileContext const& top = this->Backtrace.Top();
2908                 if (top.DeferId) {
2909                   varresult = cmStrCat("DEFERRED:"_s, *top.DeferId);
2910                 } else {
2911                   varresult = std::to_string(line);
2912                 }
2913               } else {
2914                 value = this->GetDefinition(lookup);
2915               }
2916               break;
2917             case ENVIRONMENT:
2918               if (cmSystemTools::GetEnv(lookup, svalue)) {
2919                 value = cmValue(svalue);
2920               }
2921               break;
2922             case CACHE:
2923               value = state->GetCacheEntryValue(lookup);
2924               break;
2925           }
2926           // Get the string we're meant to append to.
2927           if (value) {
2928             if (escapeQuotes) {
2929               varresult = cmEscapeQuotes(*value);
2930             } else {
2931               varresult = *value;
2932             }
2933           } else if (!this->SuppressSideEffects) {
2934             this->MaybeWarnUninitialized(lookup, filename);
2935           }
2936           result.replace(var.loc, result.size() - var.loc, varresult);
2937           // Start looking from here on out.
2938           last = in + 1;
2939         }
2940         break;
2941       case '$':
2942         if (!atOnly) {
2943           t_lookup lookup;
2944           const char* next = in + 1;
2945           const char* start = nullptr;
2946           char nextc = *next;
2947           if (nextc == '{') {
2948             // Looking for a variable.
2949             start = in + 2;
2950             lookup.domain = NORMAL;
2951           } else if (nextc == '<') {
2952           } else if (!nextc) {
2953             result.append(last, next - last);
2954             last = next;
2955           } else if (cmHasLiteralPrefix(next, "ENV{")) {
2956             // Looking for an environment variable.
2957             start = in + 5;
2958             lookup.domain = ENVIRONMENT;
2959           } else if (cmHasLiteralPrefix(next, "CACHE{")) {
2960             // Looking for a cache variable.
2961             start = in + 7;
2962             lookup.domain = CACHE;
2963           } else {
2964             if (this->cmNamedCurly.find(next)) {
2965               errorstr = "Syntax $" +
2966                 std::string(next, this->cmNamedCurly.end()) +
2967                 "{} is not supported.  Only ${}, $ENV{}, "
2968                 "and $CACHE{} are allowed.";
2969               mtype = MessageType::FATAL_ERROR;
2970               error = true;
2971             }
2972           }
2973           if (start) {
2974             result.append(last, in - last);
2975             last = start;
2976             in = start - 1;
2977             lookup.loc = result.size();
2978             openstack.push_back(lookup);
2979           }
2980           break;
2981         }
2982         CM_FALLTHROUGH;
2983       case '\\':
2984         if (!noEscapes) {
2985           const char* next = in + 1;
2986           char nextc = *next;
2987           if (nextc == 't') {
2988             result.append(last, in - last);
2989             result.append("\t");
2990             last = next + 1;
2991           } else if (nextc == 'n') {
2992             result.append(last, in - last);
2993             result.append("\n");
2994             last = next + 1;
2995           } else if (nextc == 'r') {
2996             result.append(last, in - last);
2997             result.append("\r");
2998             last = next + 1;
2999           } else if (nextc == ';' && openstack.empty()) {
3000             // Handled in ExpandListArgument; pass the backslash literally.
3001           } else if (isalnum(nextc) || nextc == '\0') {
3002             errorstr += "Invalid character escape '\\";
3003             if (nextc) {
3004               errorstr += nextc;
3005               errorstr += "'.";
3006             } else {
3007               errorstr += "' (at end of input).";
3008             }
3009             error = true;
3010           } else {
3011             // Take what we've found so far, skipping the escape character.
3012             result.append(last, in - last);
3013             // Start tracking from the next character.
3014             last = in + 1;
3015           }
3016           // Skip the next character since it was escaped, but don't read past
3017           // the end of the string.
3018           if (*last) {
3019             ++in;
3020           }
3021         }
3022         break;
3023       case '\n':
3024         // Onto the next line.
3025         ++line;
3026         break;
3027       case '\0':
3028         done = true;
3029         break;
3030       case '@':
3031         if (replaceAt) {
3032           const char* nextAt = strchr(in + 1, '@');
3033           if (nextAt && nextAt != in + 1 &&
3034               nextAt ==
3035                 in + 1 +
3036                   strspn(in + 1,
3037                          "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3038                          "abcdefghijklmnopqrstuvwxyz"
3039                          "0123456789/_.+-")) {
3040             std::string variable(in + 1, nextAt - in - 1);
3041
3042             std::string varresult;
3043             if (filename && variable == lineVar) {
3044               varresult = std::to_string(line);
3045             } else {
3046               cmValue def = this->GetDefinition(variable);
3047               if (def) {
3048                 varresult = *def;
3049               } else if (!this->SuppressSideEffects) {
3050                 this->MaybeWarnUninitialized(variable, filename);
3051               }
3052             }
3053
3054             if (escapeQuotes) {
3055               varresult = cmEscapeQuotes(varresult);
3056             }
3057             // Skip over the variable.
3058             result.append(last, in - last);
3059             result.append(varresult);
3060             in = nextAt;
3061             last = in + 1;
3062             break;
3063           }
3064         }
3065         // Failed to find a valid @ expansion; treat it as literal.
3066         CM_FALLTHROUGH;
3067       default: {
3068         if (!openstack.empty() &&
3069             !(isalnum(inc) || inc == '_' || inc == '/' || inc == '.' ||
3070               inc == '+' || inc == '-')) {
3071           errorstr += "Invalid character (\'";
3072           errorstr += inc;
3073           result.append(last, in - last);
3074           errorstr += "\') in a variable name: "
3075                       "'" +
3076             result.substr(openstack.back().loc) + "'";
3077           mtype = MessageType::FATAL_ERROR;
3078           error = true;
3079         }
3080         break;
3081       }
3082     }
3083     // Look at the next character.
3084   } while (!error && !done && *++in);
3085
3086   // Check for open variable references yet.
3087   if (!error && !openstack.empty()) {
3088     // There's an open variable reference waiting.  Policy CMP0010 flags
3089     // whether this is an error or not.  The new parser now enforces
3090     // CMP0010 as well.
3091     errorstr += "There is an unterminated variable reference.";
3092     error = true;
3093   }
3094
3095   if (error) {
3096     std::ostringstream emsg;
3097     emsg << "Syntax error in cmake code ";
3098     if (filename) {
3099       // This filename and line number may be more specific than the
3100       // command context because one command invocation can have
3101       // arguments on multiple lines.
3102       emsg << "at\n"
3103            << "  " << filename << ":" << line << "\n";
3104     }
3105     emsg << "when parsing string\n"
3106          << "  " << source << "\n";
3107     emsg << errorstr;
3108     mtype = MessageType::FATAL_ERROR;
3109     errorstr = emsg.str();
3110   } else {
3111     // Append the rest of the unchanged part of the string.
3112     result.append(last);
3113
3114     source = result;
3115   }
3116
3117   return mtype;
3118 }
3119
3120 void cmMakefile::RemoveVariablesInString(std::string& source,
3121                                          bool atOnly) const
3122 {
3123   if (!atOnly) {
3124     cmsys::RegularExpression var("(\\${[A-Za-z_0-9]*})");
3125     while (var.find(source)) {
3126       source.erase(var.start(), var.end() - var.start());
3127     }
3128   }
3129
3130   if (!atOnly) {
3131     cmsys::RegularExpression varb("(\\$ENV{[A-Za-z_0-9]*})");
3132     while (varb.find(source)) {
3133       source.erase(varb.start(), varb.end() - varb.start());
3134     }
3135   }
3136   cmsys::RegularExpression var2("(@[A-Za-z_0-9]*@)");
3137   while (var2.find(source)) {
3138     source.erase(var2.start(), var2.end() - var2.start());
3139   }
3140 }
3141
3142 void cmMakefile::InitCMAKE_CONFIGURATION_TYPES(std::string const& genDefault)
3143 {
3144   if (this->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
3145     return;
3146   }
3147   std::string initConfigs;
3148   if (this->GetCMakeInstance()->GetIsInTryCompile() ||
3149       !cmSystemTools::GetEnv("CMAKE_CONFIGURATION_TYPES", initConfigs)) {
3150     initConfigs = genDefault;
3151   }
3152   this->AddCacheDefinition(
3153     "CMAKE_CONFIGURATION_TYPES", initConfigs,
3154     "Semicolon separated list of supported configuration types, "
3155     "only supports Debug, Release, MinSizeRel, and RelWithDebInfo, "
3156     "anything else will be ignored.",
3157     cmStateEnums::STRING);
3158 }
3159
3160 std::string cmMakefile::GetDefaultConfiguration() const
3161 {
3162   if (this->GetGlobalGenerator()->IsMultiConfig()) {
3163     return std::string{};
3164   }
3165   return this->GetSafeDefinition("CMAKE_BUILD_TYPE");
3166 }
3167
3168 std::vector<std::string> cmMakefile::GetGeneratorConfigs(
3169   GeneratorConfigQuery mode) const
3170 {
3171   std::vector<std::string> configs;
3172   if (this->GetGlobalGenerator()->IsMultiConfig()) {
3173     this->GetDefExpandList("CMAKE_CONFIGURATION_TYPES", configs);
3174   } else if (mode != cmMakefile::OnlyMultiConfig) {
3175     const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE");
3176     if (!buildType.empty()) {
3177       configs.emplace_back(buildType);
3178     }
3179   }
3180   if (mode == cmMakefile::IncludeEmptyConfig && configs.empty()) {
3181     configs.emplace_back();
3182   }
3183   return configs;
3184 }
3185
3186 bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff,
3187                                    cmExecutionStatus& status)
3188 {
3189   // if there are no blockers get out of here
3190   if (this->FunctionBlockers.empty()) {
3191     return false;
3192   }
3193
3194   return this->FunctionBlockers.top()->IsFunctionBlocked(lff, status);
3195 }
3196
3197 void cmMakefile::PushFunctionBlockerBarrier()
3198 {
3199   this->FunctionBlockerBarriers.push_back(this->FunctionBlockers.size());
3200 }
3201
3202 void cmMakefile::PopFunctionBlockerBarrier(bool reportError)
3203 {
3204   // Remove any extra entries pushed on the barrier.
3205   FunctionBlockersType::size_type barrier =
3206     this->FunctionBlockerBarriers.back();
3207   while (this->FunctionBlockers.size() > barrier) {
3208     std::unique_ptr<cmFunctionBlocker> fb(
3209       std::move(this->FunctionBlockers.top()));
3210     this->FunctionBlockers.pop();
3211     if (reportError) {
3212       // Report the context in which the unclosed block was opened.
3213       cmListFileContext const& lfc = fb->GetStartingContext();
3214       std::ostringstream e;
3215       /* clang-format off */
3216       e << "A logical block opening on the line\n"
3217         << "  " << lfc << "\n"
3218         << "is not closed.";
3219       /* clang-format on */
3220       this->IssueMessage(MessageType::FATAL_ERROR, e.str());
3221       reportError = false;
3222     }
3223   }
3224
3225   // Remove the barrier.
3226   this->FunctionBlockerBarriers.pop_back();
3227 }
3228
3229 void cmMakefile::PushLoopBlock()
3230 {
3231   assert(!this->LoopBlockCounter.empty());
3232   this->LoopBlockCounter.top()++;
3233 }
3234
3235 void cmMakefile::PopLoopBlock()
3236 {
3237   assert(!this->LoopBlockCounter.empty());
3238   assert(this->LoopBlockCounter.top() > 0);
3239   this->LoopBlockCounter.top()--;
3240 }
3241
3242 void cmMakefile::PushLoopBlockBarrier()
3243 {
3244   this->LoopBlockCounter.push(0);
3245 }
3246
3247 void cmMakefile::PopLoopBlockBarrier()
3248 {
3249   assert(!this->LoopBlockCounter.empty());
3250   assert(this->LoopBlockCounter.top() == 0);
3251   this->LoopBlockCounter.pop();
3252 }
3253
3254 bool cmMakefile::IsLoopBlock() const
3255 {
3256   assert(!this->LoopBlockCounter.empty());
3257   return !this->LoopBlockCounter.empty() && this->LoopBlockCounter.top() > 0;
3258 }
3259
3260 bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
3261                                  std::vector<std::string>& outArgs) const
3262 {
3263   std::string const& filename = this->GetBacktrace().Top().FilePath;
3264   std::string value;
3265   outArgs.reserve(inArgs.size());
3266   for (cmListFileArgument const& i : inArgs) {
3267     // No expansion in a bracket argument.
3268     if (i.Delim == cmListFileArgument::Bracket) {
3269       outArgs.push_back(i.Value);
3270       continue;
3271     }
3272     // Expand the variables in the argument.
3273     value = i.Value;
3274     this->ExpandVariablesInString(value, false, false, false, filename.c_str(),
3275                                   i.Line, false, false);
3276
3277     // If the argument is quoted, it should be one argument.
3278     // Otherwise, it may be a list of arguments.
3279     if (i.Delim == cmListFileArgument::Quoted) {
3280       outArgs.push_back(value);
3281     } else {
3282       cmExpandList(value, outArgs);
3283     }
3284   }
3285   return !cmSystemTools::GetFatalErrorOccurred();
3286 }
3287
3288 bool cmMakefile::ExpandArguments(
3289   std::vector<cmListFileArgument> const& inArgs,
3290   std::vector<cmExpandedCommandArgument>& outArgs) const
3291 {
3292   std::string const& filename = this->GetBacktrace().Top().FilePath;
3293   std::string value;
3294   outArgs.reserve(inArgs.size());
3295   for (cmListFileArgument const& i : inArgs) {
3296     // No expansion in a bracket argument.
3297     if (i.Delim == cmListFileArgument::Bracket) {
3298       outArgs.emplace_back(i.Value, true);
3299       continue;
3300     }
3301     // Expand the variables in the argument.
3302     value = i.Value;
3303     this->ExpandVariablesInString(value, false, false, false, filename.c_str(),
3304                                   i.Line, false, false);
3305
3306     // If the argument is quoted, it should be one argument.
3307     // Otherwise, it may be a list of arguments.
3308     if (i.Delim == cmListFileArgument::Quoted) {
3309       outArgs.emplace_back(value, true);
3310     } else {
3311       std::vector<std::string> stringArgs = cmExpandedList(value);
3312       for (std::string const& stringArg : stringArgs) {
3313         outArgs.emplace_back(stringArg, false);
3314       }
3315     }
3316   }
3317   return !cmSystemTools::GetFatalErrorOccurred();
3318 }
3319
3320 void cmMakefile::AddFunctionBlocker(std::unique_ptr<cmFunctionBlocker> fb)
3321 {
3322   if (!this->ExecutionStatusStack.empty()) {
3323     // Record the context in which the blocker is created.
3324     fb->SetStartingContext(this->Backtrace.Top());
3325   }
3326
3327   this->FunctionBlockers.push(std::move(fb));
3328 }
3329
3330 std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker()
3331 {
3332   assert(!this->FunctionBlockers.empty());
3333   assert(this->FunctionBlockerBarriers.empty() ||
3334          this->FunctionBlockers.size() > this->FunctionBlockerBarriers.back());
3335
3336   auto b = std::move(this->FunctionBlockers.top());
3337   this->FunctionBlockers.pop();
3338   return b;
3339 }
3340
3341 std::string const& cmMakefile::GetHomeDirectory() const
3342 {
3343   return this->GetCMakeInstance()->GetHomeDirectory();
3344 }
3345
3346 std::string const& cmMakefile::GetHomeOutputDirectory() const
3347 {
3348   return this->GetCMakeInstance()->GetHomeOutputDirectory();
3349 }
3350
3351 void cmMakefile::SetScriptModeFile(std::string const& scriptfile)
3352 {
3353   this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile);
3354 }
3355
3356 void cmMakefile::SetArgcArgv(const std::vector<std::string>& args)
3357 {
3358   this->AddDefinition("CMAKE_ARGC", std::to_string(args.size()));
3359   // this->MarkVariableAsUsed("CMAKE_ARGC");
3360
3361   for (unsigned int t = 0; t < args.size(); ++t) {
3362     std::ostringstream tmpStream;
3363     tmpStream << "CMAKE_ARGV" << t;
3364     this->AddDefinition(tmpStream.str(), args[t]);
3365     // this->MarkVariableAsUsed(tmpStream.str().c_str());
3366   }
3367 }
3368
3369 cmSourceFile* cmMakefile::GetSource(const std::string& sourceName,
3370                                     cmSourceFileLocationKind kind) const
3371 {
3372   // First check "Known" paths (avoids the creation of cmSourceFileLocation)
3373   if (kind == cmSourceFileLocationKind::Known) {
3374     auto sfsi = this->KnownFileSearchIndex.find(sourceName);
3375     if (sfsi != this->KnownFileSearchIndex.end()) {
3376       return sfsi->second;
3377     }
3378   }
3379
3380   cmSourceFileLocation sfl(this, sourceName, kind);
3381   auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName());
3382 #if defined(_WIN32) || defined(__APPLE__)
3383   name = cmSystemTools::LowerCase(name);
3384 #endif
3385   auto sfsi = this->SourceFileSearchIndex.find(name);
3386   if (sfsi != this->SourceFileSearchIndex.end()) {
3387     for (auto* sf : sfsi->second) {
3388       if (sf->Matches(sfl)) {
3389         return sf;
3390       }
3391     }
3392   }
3393   return nullptr;
3394 }
3395
3396 cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName,
3397                                        bool generated,
3398                                        cmSourceFileLocationKind kind)
3399 {
3400   auto sf = cm::make_unique<cmSourceFile>(this, sourceName, generated, kind);
3401   auto name =
3402     this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName());
3403 #if defined(_WIN32) || defined(__APPLE__)
3404   name = cmSystemTools::LowerCase(name);
3405 #endif
3406   this->SourceFileSearchIndex[name].push_back(sf.get());
3407   // for "Known" paths add direct lookup (used for faster lookup in GetSource)
3408   if (kind == cmSourceFileLocationKind::Known) {
3409     this->KnownFileSearchIndex[sourceName] = sf.get();
3410   }
3411
3412   this->SourceFiles.push_back(std::move(sf));
3413
3414   return this->SourceFiles.back().get();
3415 }
3416
3417 cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName,
3418                                             bool generated,
3419                                             cmSourceFileLocationKind kind)
3420 {
3421   if (cmSourceFile* esf = this->GetSource(sourceName, kind)) {
3422     return esf;
3423   }
3424   return this->CreateSource(sourceName, generated, kind);
3425 }
3426
3427 cmSourceFile* cmMakefile::GetOrCreateGeneratedSource(
3428   const std::string& sourceName)
3429 {
3430   cmSourceFile* sf =
3431     this->GetOrCreateSource(sourceName, true, cmSourceFileLocationKind::Known);
3432   sf->MarkAsGenerated(); // In case we did not create the source file.
3433   return sf;
3434 }
3435
3436 void cmMakefile::CreateGeneratedOutputs(
3437   const std::vector<std::string>& outputs)
3438 {
3439   for (std::string const& o : outputs) {
3440     if (cmGeneratorExpression::Find(o) == std::string::npos) {
3441       this->GetOrCreateGeneratedSource(o);
3442     }
3443   }
3444 }
3445
3446 void cmMakefile::AddTargetObject(std::string const& tgtName,
3447                                  std::string const& objFile)
3448 {
3449   cmSourceFile* sf =
3450     this->GetOrCreateSource(objFile, true, cmSourceFileLocationKind::Known);
3451   sf->SetObjectLibrary(tgtName);
3452   sf->SetProperty("EXTERNAL_OBJECT", "1");
3453 #if !defined(CMAKE_BOOTSTRAP)
3454   this->SourceGroups[this->ObjectLibrariesSourceGroupIndex].AddGroupFile(
3455     sf->ResolveFullPath());
3456 #endif
3457 }
3458
3459 void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
3460                                 bool optional)
3461 {
3462   if (this->DeferRunning) {
3463     this->IssueMessage(
3464       MessageType::FATAL_ERROR,
3465       "Languages may not be enabled during deferred execution.");
3466     return;
3467   }
3468   if (const char* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) {
3469     this->AddDefinition("CMAKE_CFG_INTDIR", def);
3470   }
3471   // If RC is explicitly listed we need to do it after other languages.
3472   // On some platforms we enable RC implicitly while enabling others.
3473   // Do not let that look like recursive enable_language(RC).
3474   std::vector<std::string> langs;
3475   std::vector<std::string> langsRC;
3476   langs.reserve(lang.size());
3477   for (std::string const& i : lang) {
3478     if (i == "RC") {
3479       langsRC.push_back(i);
3480     } else {
3481       langs.push_back(i);
3482     }
3483   }
3484   if (!langs.empty()) {
3485     this->GetGlobalGenerator()->EnableLanguage(langs, this, optional);
3486   }
3487   if (!langsRC.empty()) {
3488     this->GetGlobalGenerator()->EnableLanguage(langsRC, this, optional);
3489   }
3490 }
3491
3492 int cmMakefile::TryCompile(const std::string& srcdir,
3493                            const std::string& bindir,
3494                            const std::string& projectName,
3495                            const std::string& targetName, bool fast, int jobs,
3496                            const std::vector<std::string>* cmakeArgs,
3497                            std::string& output)
3498 {
3499   this->IsSourceFileTryCompile = fast;
3500   // does the binary directory exist ? If not create it...
3501   if (!cmSystemTools::FileIsDirectory(bindir)) {
3502     cmSystemTools::MakeDirectory(bindir);
3503   }
3504
3505   // change to the tests directory and run cmake
3506   // use the cmake object instead of calling cmake
3507   cmWorkingDirectory workdir(bindir);
3508   if (workdir.Failed()) {
3509     this->IssueMessage(MessageType::FATAL_ERROR,
3510                        "Failed to set working directory to " + bindir + " : " +
3511                          std::strerror(workdir.GetLastResult()));
3512     cmSystemTools::SetFatalErrorOccurred();
3513     this->IsSourceFileTryCompile = false;
3514     return 1;
3515   }
3516
3517   // make sure the same generator is used
3518   // use this program as the cmake to be run, it should not
3519   // be run that way but the cmake object requires a vailid path
3520   cmake cm(cmake::RoleProject, cmState::Project,
3521            cmState::ProjectKind::TryCompile);
3522   auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
3523   if (!gg) {
3524     this->IssueMessage(MessageType::INTERNAL_ERROR,
3525                        "Global generator '" +
3526                          this->GetGlobalGenerator()->GetName() +
3527                          "' could not be created.");
3528     cmSystemTools::SetFatalErrorOccurred();
3529     this->IsSourceFileTryCompile = false;
3530     return 1;
3531   }
3532   gg->RecursionDepth = this->RecursionDepth;
3533   cm.SetGlobalGenerator(std::move(gg));
3534
3535   // do a configure
3536   cm.SetHomeDirectory(srcdir);
3537   cm.SetHomeOutputDirectory(bindir);
3538   cm.SetGeneratorInstance(this->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE"));
3539   cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM"));
3540   cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"));
3541   cm.LoadCache();
3542   if (!cm.GetGlobalGenerator()->IsMultiConfig()) {
3543     if (cmValue config =
3544           this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) {
3545       // Tell the single-configuration generator which one to use.
3546       // Add this before the user-provided CMake arguments in case
3547       // one of the arguments is -DCMAKE_BUILD_TYPE=...
3548       cm.AddCacheEntry("CMAKE_BUILD_TYPE", config, "Build configuration",
3549                        cmStateEnums::STRING);
3550     }
3551   }
3552   cmValue recursionDepth =
3553     this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH");
3554   if (recursionDepth) {
3555     cm.AddCacheEntry("CMAKE_MAXIMUM_RECURSION_DEPTH", recursionDepth,
3556                      "Maximum recursion depth", cmStateEnums::STRING);
3557   }
3558   // if cmake args were provided then pass them in
3559   if (cmakeArgs) {
3560     // FIXME: Workaround to ignore unused CLI variables in try-compile.
3561     //
3562     // Ideally we should use SetArgs for options like --no-warn-unused-cli.
3563     // However, there is a subtle problem when certain arguments are passed to
3564     // a macro wrapping around try_compile or try_run that does not escape
3565     // semicolons in its parameters but just passes ${ARGV} or ${ARGN}.  In
3566     // this case a list argument like "-DVAR=a;b" gets split into multiple
3567     // cmake arguments "-DVAR=a" and "b".  Currently SetCacheArgs ignores
3568     // argument "b" and uses just "-DVAR=a", leading to a subtle bug in that
3569     // the try_compile or try_run does not get the proper value of VAR.  If we
3570     // call SetArgs here then it would treat "b" as the source directory and
3571     // cause an error such as "The source directory .../CMakeFiles/CMakeTmp/b
3572     // does not exist", thus breaking the try_compile or try_run completely.
3573     //
3574     // Strictly speaking the bug is in the wrapper macro because the CMake
3575     // language has always flattened nested lists and the macro should escape
3576     // the semicolons in its arguments before forwarding them.  However, this
3577     // bug is so subtle that projects typically work anyway, usually because
3578     // the value VAR=a is sufficient for the try_compile or try_run to get the
3579     // correct result.  Calling SetArgs here would break such projects that
3580     // previously built.  Instead we work around the issue by never reporting
3581     // unused arguments and ignoring options such as --no-warn-unused-cli.
3582     cm.SetWarnUnusedCli(false);
3583     // cm.SetArgs(*cmakeArgs, true);
3584
3585     cm.SetCacheArgs(*cmakeArgs);
3586   }
3587   // to save time we pass the EnableLanguage info directly
3588   cm.GetGlobalGenerator()->EnableLanguagesFromGenerator(
3589     this->GetGlobalGenerator(), this);
3590   if (this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
3591     cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE", "",
3592                      cmStateEnums::INTERNAL);
3593   } else {
3594     cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "FALSE", "",
3595                      cmStateEnums::INTERNAL);
3596   }
3597   if (cm.Configure() != 0) {
3598     this->IssueMessage(MessageType::FATAL_ERROR,
3599                        "Failed to configure test project build system.");
3600     cmSystemTools::SetFatalErrorOccurred();
3601     this->IsSourceFileTryCompile = false;
3602     return 1;
3603   }
3604
3605   if (cm.Generate() != 0) {
3606     this->IssueMessage(MessageType::FATAL_ERROR,
3607                        "Failed to generate test project build system.");
3608     cmSystemTools::SetFatalErrorOccurred();
3609     this->IsSourceFileTryCompile = false;
3610     return 1;
3611   }
3612
3613   // finally call the generator to actually build the resulting project
3614   int ret = this->GetGlobalGenerator()->TryCompile(
3615     jobs, srcdir, bindir, projectName, targetName, fast, output, this);
3616
3617   this->IsSourceFileTryCompile = false;
3618   return ret;
3619 }
3620
3621 bool cmMakefile::GetIsSourceFileTryCompile() const
3622 {
3623   return this->IsSourceFileTryCompile;
3624 }
3625
3626 cmake* cmMakefile::GetCMakeInstance() const
3627 {
3628   return this->GlobalGenerator->GetCMakeInstance();
3629 }
3630
3631 cmMessenger* cmMakefile::GetMessenger() const
3632 {
3633   return this->GetCMakeInstance()->GetMessenger();
3634 }
3635
3636 cmGlobalGenerator* cmMakefile::GetGlobalGenerator() const
3637 {
3638   return this->GlobalGenerator;
3639 }
3640
3641 #ifndef CMAKE_BOOTSTRAP
3642 cmVariableWatch* cmMakefile::GetVariableWatch() const
3643 {
3644   if (this->GetCMakeInstance() &&
3645       this->GetCMakeInstance()->GetVariableWatch()) {
3646     return this->GetCMakeInstance()->GetVariableWatch();
3647   }
3648   return nullptr;
3649 }
3650 #endif
3651
3652 cmState* cmMakefile::GetState() const
3653 {
3654   return this->GetCMakeInstance()->GetState();
3655 }
3656
3657 void cmMakefile::DisplayStatus(const std::string& message, float s) const
3658 {
3659   cmake* cm = this->GetCMakeInstance();
3660   if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
3661     // don't output any STATUS message in FIND_PACKAGE_MODE, since they will
3662     // directly be fed to the compiler, which will be confused.
3663     return;
3664   }
3665   cm->UpdateProgress(message, s);
3666 }
3667
3668 std::string cmMakefile::GetModulesFile(const std::string& filename,
3669                                        bool& system, bool debug,
3670                                        std::string& debugBuffer) const
3671 {
3672   std::string result;
3673
3674   // We search the module always in CMAKE_ROOT and in CMAKE_MODULE_PATH,
3675   // and then decide based on the policy setting which one to return.
3676   // See CMP0017 for more details.
3677   // The specific problem was that KDE 4.5.0 installs a
3678   // FindPackageHandleStandardArgs.cmake which doesn't have the new features
3679   // of FPHSA.cmake introduced in CMake 2.8.3 yet, and by setting
3680   // CMAKE_MODULE_PATH also e.g. FindZLIB.cmake from cmake included
3681   // FPHSA.cmake from kdelibs and not from CMake, and tried to use the
3682   // new features, which were not there in the version from kdelibs, and so
3683   // failed ("
3684   std::string moduleInCMakeRoot;
3685   std::string moduleInCMakeModulePath;
3686
3687   // Always search in CMAKE_MODULE_PATH:
3688   cmValue cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH");
3689   if (cmakeModulePath) {
3690     std::vector<std::string> modulePath = cmExpandedList(*cmakeModulePath);
3691
3692     // Look through the possible module directories.
3693     for (std::string itempl : modulePath) {
3694       cmSystemTools::ConvertToUnixSlashes(itempl);
3695       itempl += "/";
3696       itempl += filename;
3697       if (cmSystemTools::FileExists(itempl)) {
3698         moduleInCMakeModulePath = itempl;
3699         break;
3700       }
3701       if (debug) {
3702         debugBuffer = cmStrCat(debugBuffer, "  ", itempl, "\n");
3703       }
3704     }
3705   }
3706
3707   // Always search in the standard modules location.
3708   moduleInCMakeRoot =
3709     cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/", filename);
3710   cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot);
3711   if (!cmSystemTools::FileExists(moduleInCMakeRoot)) {
3712     if (debug) {
3713       debugBuffer = cmStrCat(debugBuffer, "  ", moduleInCMakeRoot, "\n");
3714     }
3715     moduleInCMakeRoot.clear();
3716   }
3717
3718   // Normally, prefer the files found in CMAKE_MODULE_PATH. Only when the file
3719   // from which we are being called is located itself in CMAKE_ROOT, then
3720   // prefer results from CMAKE_ROOT depending on the policy setting.
3721   system = false;
3722   result = moduleInCMakeModulePath;
3723   if (result.empty()) {
3724     system = true;
3725     result = moduleInCMakeRoot;
3726   }
3727
3728   if (!moduleInCMakeModulePath.empty() && !moduleInCMakeRoot.empty()) {
3729     cmValue currentFile = this->GetDefinition("CMAKE_CURRENT_LIST_FILE");
3730     std::string mods = cmSystemTools::GetCMakeRoot() + "/Modules/";
3731     if (currentFile && cmSystemTools::IsSubDirectory(*currentFile, mods)) {
3732       switch (this->GetPolicyStatus(cmPolicies::CMP0017)) {
3733         case cmPolicies::WARN: {
3734           std::ostringstream e;
3735           /* clang-format off */
3736           e << "File " << *currentFile << " includes "
3737             << moduleInCMakeModulePath
3738             << " (found via CMAKE_MODULE_PATH) which shadows "
3739             << moduleInCMakeRoot  << ". This may cause errors later on .\n"
3740             << cmPolicies::GetPolicyWarning(cmPolicies::CMP0017);
3741           /* clang-format on */
3742
3743           this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
3744           CM_FALLTHROUGH;
3745         }
3746         case cmPolicies::OLD:
3747           system = false;
3748           result = moduleInCMakeModulePath;
3749           break;
3750         case cmPolicies::REQUIRED_IF_USED:
3751         case cmPolicies::REQUIRED_ALWAYS:
3752         case cmPolicies::NEW:
3753           system = true;
3754           result = moduleInCMakeRoot;
3755           break;
3756       }
3757     }
3758   }
3759
3760   return result;
3761 }
3762
3763 void cmMakefile::ConfigureString(const std::string& input, std::string& output,
3764                                  bool atOnly, bool escapeQuotes) const
3765 {
3766   // Split input to handle one line at a time.
3767   std::string::const_iterator lineStart = input.begin();
3768   while (lineStart != input.end()) {
3769     // Find the end of this line.
3770     std::string::const_iterator lineEnd = lineStart;
3771     while (lineEnd != input.end() && *lineEnd != '\n') {
3772       ++lineEnd;
3773     }
3774
3775     // Copy the line.
3776     std::string line(lineStart, lineEnd);
3777
3778     // Skip the newline character.
3779     bool haveNewline = (lineEnd != input.end());
3780     if (haveNewline) {
3781       ++lineEnd;
3782     }
3783
3784     // Replace #cmakedefine instances.
3785     if (this->cmDefineRegex.find(line)) {
3786       cmValue def = this->GetDefinition(this->cmDefineRegex.match(2));
3787       if (!cmIsOff(def)) {
3788         const std::string indentation = this->cmDefineRegex.match(1);
3789         cmSystemTools::ReplaceString(line, "#" + indentation + "cmakedefine",
3790                                      "#" + indentation + "define");
3791         output += line;
3792       } else {
3793         output += "/* #undef ";
3794         output += this->cmDefineRegex.match(2);
3795         output += " */";
3796       }
3797     } else if (this->cmDefine01Regex.find(line)) {
3798       const std::string indentation = this->cmDefine01Regex.match(1);
3799       cmValue def = this->GetDefinition(this->cmDefine01Regex.match(2));
3800       cmSystemTools::ReplaceString(line, "#" + indentation + "cmakedefine01",
3801                                    "#" + indentation + "define");
3802       output += line;
3803       if (!cmIsOff(def)) {
3804         output += " 1";
3805       } else {
3806         output += " 0";
3807       }
3808     } else {
3809       output += line;
3810     }
3811
3812     if (haveNewline) {
3813       output += "\n";
3814     }
3815
3816     // Move to the next line.
3817     lineStart = lineEnd;
3818   }
3819
3820   // Perform variable replacements.
3821   const char* filename = nullptr;
3822   long lineNumber = -1;
3823   if (!this->Backtrace.Empty()) {
3824     const auto& currentTrace = this->Backtrace.Top();
3825     filename = currentTrace.FilePath.c_str();
3826     lineNumber = currentTrace.Line;
3827   }
3828   this->ExpandVariablesInString(output, escapeQuotes, true, atOnly, filename,
3829                                 lineNumber, true, true);
3830 }
3831
3832 int cmMakefile::ConfigureFile(const std::string& infile,
3833                               const std::string& outfile, bool copyonly,
3834                               bool atOnly, bool escapeQuotes,
3835                               mode_t permissions, cmNewLineStyle newLine)
3836 {
3837   int res = 1;
3838   if (!this->CanIWriteThisFile(outfile)) {
3839     cmSystemTools::Error("Attempt to write file: " + outfile +
3840                          " into a source directory.");
3841     return 0;
3842   }
3843   if (!cmSystemTools::FileExists(infile)) {
3844     cmSystemTools::Error("File " + infile + " does not exist.");
3845     return 0;
3846   }
3847   std::string soutfile = outfile;
3848   const std::string& sinfile = infile;
3849   this->AddCMakeDependFile(sinfile);
3850   cmSystemTools::ConvertToUnixSlashes(soutfile);
3851
3852   // Re-generate if non-temporary outputs are missing.
3853   // when we finalize the configuration we will remove all
3854   // output files that now don't exist.
3855   this->AddCMakeOutputFile(soutfile);
3856
3857   if (permissions == 0) {
3858     cmSystemTools::GetPermissions(sinfile, permissions);
3859   }
3860
3861   std::string::size_type pos = soutfile.rfind('/');
3862   if (pos != std::string::npos) {
3863     std::string path = soutfile.substr(0, pos);
3864     cmSystemTools::MakeDirectory(path);
3865   }
3866
3867   if (copyonly) {
3868     if (!cmSystemTools::CopyFileIfDifferent(sinfile, soutfile)) {
3869       this->IssueMessage(MessageType::FATAL_ERROR,
3870                          cmSystemTools::GetLastSystemError());
3871       return 0;
3872     }
3873     if (!cmSystemTools::SetPermissions(soutfile, permissions)) {
3874       this->IssueMessage(MessageType::FATAL_ERROR,
3875                          cmSystemTools::GetLastSystemError());
3876       return 0;
3877     }
3878   } else {
3879     std::string newLineCharacters;
3880     std::ios::openmode omode = std::ios::out | std::ios::trunc;
3881     if (newLine.IsValid()) {
3882       newLineCharacters = newLine.GetCharacters();
3883       omode |= std::ios::binary;
3884     } else {
3885       newLineCharacters = "\n";
3886     }
3887     std::string tempOutputFile = cmStrCat(soutfile, ".tmp");
3888     cmsys::ofstream fout(tempOutputFile.c_str(), omode);
3889     if (!fout) {
3890       cmSystemTools::Error("Could not open file for write in copy operation " +
3891                            tempOutputFile);
3892       cmSystemTools::ReportLastSystemError("");
3893       return 0;
3894     }
3895     cmsys::ifstream fin(sinfile.c_str());
3896     if (!fin) {
3897       cmSystemTools::Error("Could not open file for read in copy operation " +
3898                            sinfile);
3899       return 0;
3900     }
3901
3902     cmsys::FStream::BOM bom = cmsys::FStream::ReadBOM(fin);
3903     if (bom != cmsys::FStream::BOM_None && bom != cmsys::FStream::BOM_UTF8) {
3904       std::ostringstream e;
3905       e << "File starts with a Byte-Order-Mark that is not UTF-8:\n  "
3906         << sinfile;
3907       this->IssueMessage(MessageType::FATAL_ERROR, e.str());
3908       return 0;
3909     }
3910     // rewind to copy BOM to output file
3911     fin.seekg(0);
3912
3913     // now copy input to output and expand variables in the
3914     // input file at the same time
3915     std::string inLine;
3916     std::string outLine;
3917     while (cmSystemTools::GetLineFromStream(fin, inLine)) {
3918       outLine.clear();
3919       this->ConfigureString(inLine, outLine, atOnly, escapeQuotes);
3920       fout << outLine << newLineCharacters;
3921     }
3922     // close the files before attempting to copy
3923     fin.close();
3924     fout.close();
3925     if (!cmSystemTools::CopyFileIfDifferent(tempOutputFile, soutfile)) {
3926       this->IssueMessage(MessageType::FATAL_ERROR,
3927                          cmSystemTools::GetLastSystemError());
3928       res = 0;
3929     } else {
3930       if (!cmSystemTools::SetPermissions(soutfile, permissions)) {
3931         this->IssueMessage(MessageType::FATAL_ERROR,
3932                            cmSystemTools::GetLastSystemError());
3933         res = 0;
3934       }
3935     }
3936     cmSystemTools::RemoveFile(tempOutputFile);
3937   }
3938   return res;
3939 }
3940
3941 void cmMakefile::SetProperty(const std::string& prop, const char* value)
3942 {
3943   this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace);
3944 }
3945 void cmMakefile::SetProperty(const std::string& prop, cmValue value)
3946 {
3947   this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace);
3948 }
3949
3950 void cmMakefile::AppendProperty(const std::string& prop,
3951                                 const std::string& value, bool asString)
3952 {
3953   this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString,
3954                                                     this->Backtrace);
3955 }
3956
3957 cmValue cmMakefile::GetProperty(const std::string& prop) const
3958 {
3959   // Check for computed properties.
3960   static std::string output;
3961   if (prop == "TESTS") {
3962     std::vector<std::string> keys;
3963     // get list of keys
3964     const auto* t = this;
3965     std::transform(
3966       t->Tests.begin(), t->Tests.end(), std::back_inserter(keys),
3967       [](decltype(t->Tests)::value_type const& pair) { return pair.first; });
3968     output = cmJoin(keys, ";");
3969     return cmValue(output);
3970   }
3971
3972   return this->StateSnapshot.GetDirectory().GetProperty(prop);
3973 }
3974
3975 cmValue cmMakefile::GetProperty(const std::string& prop, bool chain) const
3976 {
3977   return this->StateSnapshot.GetDirectory().GetProperty(prop, chain);
3978 }
3979
3980 bool cmMakefile::GetPropertyAsBool(const std::string& prop) const
3981 {
3982   return cmIsOn(this->GetProperty(prop));
3983 }
3984
3985 std::vector<std::string> cmMakefile::GetPropertyKeys() const
3986 {
3987   return this->StateSnapshot.GetDirectory().GetPropertyKeys();
3988 }
3989
3990 cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const
3991 {
3992   auto i = this->Targets.find(name);
3993   if (i != this->Targets.end()) {
3994     return &i->second;
3995   }
3996   return nullptr;
3997 }
3998
3999 cmTest* cmMakefile::CreateTest(const std::string& testName)
4000 {
4001   cmTest* test = this->GetTest(testName);
4002   if (test) {
4003     return test;
4004   }
4005   auto newTest = cm::make_unique<cmTest>(this);
4006   test = newTest.get();
4007   newTest->SetName(testName);
4008   this->Tests[testName] = std::move(newTest);
4009   return test;
4010 }
4011
4012 cmTest* cmMakefile::GetTest(const std::string& testName) const
4013 {
4014   auto mi = this->Tests.find(testName);
4015   if (mi != this->Tests.end()) {
4016     return mi->second.get();
4017   }
4018   return nullptr;
4019 }
4020
4021 void cmMakefile::GetTests(const std::string& config,
4022                           std::vector<cmTest*>& tests) const
4023 {
4024   for (const auto& generator : this->GetTestGenerators()) {
4025     if (generator->TestsForConfig(config)) {
4026       tests.push_back(generator->GetTest());
4027     }
4028   }
4029 }
4030
4031 void cmMakefile::AddCMakeDependFilesFromUser()
4032 {
4033   std::vector<std::string> deps;
4034   if (cmValue deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) {
4035     cmExpandList(*deps_str, deps);
4036   }
4037   for (std::string const& dep : deps) {
4038     if (cmSystemTools::FileIsFullPath(dep)) {
4039       this->AddCMakeDependFile(dep);
4040     } else {
4041       std::string f = cmStrCat(this->GetCurrentSourceDirectory(), '/', dep);
4042       this->AddCMakeDependFile(f);
4043     }
4044   }
4045 }
4046
4047 std::string cmMakefile::FormatListFileStack() const
4048 {
4049   std::vector<std::string> listFiles;
4050   cmStateSnapshot snp = this->StateSnapshot;
4051   while (snp.IsValid()) {
4052     listFiles.push_back(snp.GetExecutionListFile());
4053     snp = snp.GetCallStackParent();
4054   }
4055   std::reverse(listFiles.begin(), listFiles.end());
4056   std::ostringstream tmp;
4057   size_t depth = listFiles.size();
4058   if (depth > 0) {
4059     auto it = listFiles.end();
4060     do {
4061       if (depth != listFiles.size()) {
4062         tmp << "\n                ";
4063       }
4064       --it;
4065       tmp << "[";
4066       tmp << depth;
4067       tmp << "]\t";
4068       tmp << *it;
4069       depth--;
4070     } while (it != listFiles.begin());
4071   }
4072   return tmp.str();
4073 }
4074
4075 void cmMakefile::PushScope()
4076 {
4077   this->StateSnapshot =
4078     this->GetState()->CreateVariableScopeSnapshot(this->StateSnapshot);
4079   this->PushLoopBlockBarrier();
4080
4081 #if !defined(CMAKE_BOOTSTRAP)
4082   this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
4083 #endif
4084 }
4085
4086 void cmMakefile::PopScope()
4087 {
4088 #if !defined(CMAKE_BOOTSTRAP)
4089   this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
4090 #endif
4091
4092   this->PopLoopBlockBarrier();
4093
4094   this->PopSnapshot();
4095 }
4096
4097 void cmMakefile::RaiseScope(const std::string& var, const char* varDef)
4098 {
4099   if (var.empty()) {
4100     return;
4101   }
4102
4103   if (!this->StateSnapshot.RaiseScope(var, varDef)) {
4104     std::ostringstream m;
4105     m << "Cannot set \"" << var << "\": current scope has no parent.";
4106     this->IssueMessage(MessageType::AUTHOR_WARNING, m.str());
4107     return;
4108   }
4109
4110 #ifndef CMAKE_BOOTSTRAP
4111   cmVariableWatch* vv = this->GetVariableWatch();
4112   if (vv) {
4113     vv->VariableAccessed(var, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
4114                          varDef, this);
4115   }
4116 #endif
4117 }
4118
4119 cmTarget* cmMakefile::AddImportedTarget(const std::string& name,
4120                                         cmStateEnums::TargetType type,
4121                                         bool global)
4122 {
4123   // Create the target.
4124   std::unique_ptr<cmTarget> target(
4125     new cmTarget(name, type,
4126                  global ? cmTarget::VisibilityImportedGlobally
4127                         : cmTarget::VisibilityImported,
4128                  this, cmTarget::PerConfig::Yes));
4129
4130   // Add to the set of available imported targets.
4131   this->ImportedTargets[name] = target.get();
4132   this->GetGlobalGenerator()->IndexTarget(target.get());
4133   this->GetStateSnapshot().GetDirectory().AddImportedTargetName(name);
4134
4135   // Transfer ownership to this cmMakefile object.
4136   this->ImportedTargetsOwned.push_back(std::move(target));
4137   return this->ImportedTargetsOwned.back().get();
4138 }
4139
4140 cmTarget* cmMakefile::FindTargetToUse(const std::string& name,
4141                                       bool excludeAliases) const
4142 {
4143   // Look for an imported target.  These take priority because they
4144   // are more local in scope and do not have to be globally unique.
4145   auto targetName = name;
4146   if (!excludeAliases) {
4147     // Look for local alias targets.
4148     auto alias = this->AliasTargets.find(name);
4149     if (alias != this->AliasTargets.end()) {
4150       targetName = alias->second;
4151     }
4152   }
4153   auto imported = this->ImportedTargets.find(targetName);
4154   if (imported != this->ImportedTargets.end()) {
4155     return imported->second;
4156   }
4157
4158   // Look for a target built in this directory.
4159   if (cmTarget* t = this->FindLocalNonAliasTarget(name)) {
4160     return t;
4161   }
4162
4163   // Look for a target built in this project.
4164   return this->GetGlobalGenerator()->FindTarget(name, excludeAliases);
4165 }
4166
4167 bool cmMakefile::IsAlias(const std::string& name) const
4168 {
4169   if (cm::contains(this->AliasTargets, name)) {
4170     return true;
4171   }
4172   return this->GetGlobalGenerator()->IsAlias(name);
4173 }
4174
4175 bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg,
4176                                    bool isCustom) const
4177 {
4178   if (this->IsAlias(name)) {
4179     std::ostringstream e;
4180     e << "cannot create target \"" << name
4181       << "\" because an alias with the same name already exists.";
4182     msg = e.str();
4183     return false;
4184   }
4185   if (cmTarget* existing = this->FindTargetToUse(name)) {
4186     // The name given conflicts with an existing target.  Produce an
4187     // error in a compatible way.
4188     if (existing->IsImported()) {
4189       // Imported targets were not supported in previous versions.
4190       // This is new code, so we can make it an error.
4191       std::ostringstream e;
4192       e << "cannot create target \"" << name
4193         << "\" because an imported target with the same name already exists.";
4194       msg = e.str();
4195       return false;
4196     }
4197     // target names must be globally unique
4198     switch (this->GetPolicyStatus(cmPolicies::CMP0002)) {
4199       case cmPolicies::WARN:
4200         this->IssueMessage(MessageType::AUTHOR_WARNING,
4201                            cmPolicies::GetPolicyWarning(cmPolicies::CMP0002));
4202         CM_FALLTHROUGH;
4203       case cmPolicies::OLD:
4204         return true;
4205       case cmPolicies::REQUIRED_IF_USED:
4206       case cmPolicies::REQUIRED_ALWAYS:
4207         this->IssueMessage(
4208           MessageType::FATAL_ERROR,
4209           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0002));
4210         return true;
4211       case cmPolicies::NEW:
4212         break;
4213     }
4214
4215     // The conflict is with a non-imported target.
4216     // Allow this if the user has requested support.
4217     cmake* cm = this->GetCMakeInstance();
4218     if (isCustom && existing->GetType() == cmStateEnums::UTILITY &&
4219         this != existing->GetMakefile() &&
4220         cm->GetState()->GetGlobalPropertyAsBool(
4221           "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
4222       return true;
4223     }
4224
4225     // Produce an error that tells the user how to work around the
4226     // problem.
4227     std::ostringstream e;
4228     e << "cannot create target \"" << name
4229       << "\" because another target with the same name already exists.  "
4230       << "The existing target is ";
4231     switch (existing->GetType()) {
4232       case cmStateEnums::EXECUTABLE:
4233         e << "an executable ";
4234         break;
4235       case cmStateEnums::STATIC_LIBRARY:
4236         e << "a static library ";
4237         break;
4238       case cmStateEnums::SHARED_LIBRARY:
4239         e << "a shared library ";
4240         break;
4241       case cmStateEnums::MODULE_LIBRARY:
4242         e << "a module library ";
4243         break;
4244       case cmStateEnums::UTILITY:
4245         e << "a custom target ";
4246         break;
4247       case cmStateEnums::INTERFACE_LIBRARY:
4248         e << "an interface library ";
4249         break;
4250       default:
4251         break;
4252     }
4253     e << "created in source directory \""
4254       << existing->GetMakefile()->GetCurrentSourceDirectory() << "\".  "
4255       << "See documentation for policy CMP0002 for more details.";
4256     msg = e.str();
4257     return false;
4258   }
4259   return true;
4260 }
4261
4262 bool cmMakefile::EnforceUniqueDir(const std::string& srcPath,
4263                                   const std::string& binPath) const
4264 {
4265   // Make sure the binary directory is unique.
4266   cmGlobalGenerator* gg = this->GetGlobalGenerator();
4267   if (gg->BinaryDirectoryIsNew(binPath)) {
4268     return true;
4269   }
4270   std::ostringstream e;
4271   switch (this->GetPolicyStatus(cmPolicies::CMP0013)) {
4272     case cmPolicies::WARN:
4273       // Print the warning.
4274       /* clang-format off */
4275       e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0013)
4276         << "\n"
4277         << "The binary directory\n"
4278         << "  " << binPath << "\n"
4279         << "is already used to build a source directory.  "
4280         << "This command uses it to build source directory\n"
4281         << "  " << srcPath << "\n"
4282         << "which can generate conflicting build files.  "
4283         << "CMake does not support this use case but it used "
4284         << "to work accidentally and is being allowed for "
4285         << "compatibility.";
4286       /* clang-format on */
4287       this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
4288       CM_FALLTHROUGH;
4289     case cmPolicies::OLD:
4290       // OLD behavior does not warn.
4291       return true;
4292     case cmPolicies::REQUIRED_IF_USED:
4293     case cmPolicies::REQUIRED_ALWAYS:
4294       e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0013) << "\n";
4295       CM_FALLTHROUGH;
4296     case cmPolicies::NEW:
4297       // NEW behavior prints the error.
4298       /* clang-format off */
4299       e << "The binary directory\n"
4300         << "  " << binPath << "\n"
4301         << "is already used to build a source directory.  "
4302         << "It cannot be used to build source directory\n"
4303         << "  " << srcPath << "\n"
4304         << "Specify a unique binary directory name.";
4305       /* clang-format on */
4306       this->IssueMessage(MessageType::FATAL_ERROR, e.str());
4307       break;
4308   }
4309
4310   return false;
4311 }
4312
4313 static std::string const matchVariables[] = {
4314   "CMAKE_MATCH_0", "CMAKE_MATCH_1", "CMAKE_MATCH_2", "CMAKE_MATCH_3",
4315   "CMAKE_MATCH_4", "CMAKE_MATCH_5", "CMAKE_MATCH_6", "CMAKE_MATCH_7",
4316   "CMAKE_MATCH_8", "CMAKE_MATCH_9"
4317 };
4318
4319 static std::string const nMatchesVariable = "CMAKE_MATCH_COUNT";
4320
4321 void cmMakefile::ClearMatches()
4322 {
4323   cmValue nMatchesStr = this->GetDefinition(nMatchesVariable);
4324   if (!nMatchesStr) {
4325     return;
4326   }
4327   int nMatches = atoi(nMatchesStr->c_str());
4328   for (int i = 0; i <= nMatches; i++) {
4329     std::string const& var = matchVariables[i];
4330     std::string const& s = this->GetSafeDefinition(var);
4331     if (!s.empty()) {
4332       this->AddDefinition(var, "");
4333       this->MarkVariableAsUsed(var);
4334     }
4335   }
4336   this->AddDefinition(nMatchesVariable, "0");
4337   this->MarkVariableAsUsed(nMatchesVariable);
4338 }
4339
4340 void cmMakefile::StoreMatches(cmsys::RegularExpression& re)
4341 {
4342   char highest = 0;
4343   for (int i = 0; i < 10; i++) {
4344     std::string const& m = re.match(i);
4345     if (!m.empty()) {
4346       std::string const& var = matchVariables[i];
4347       this->AddDefinition(var, m);
4348       this->MarkVariableAsUsed(var);
4349       highest = static_cast<char>('0' + i);
4350     }
4351   }
4352   char nMatches[] = { highest, '\0' };
4353   this->AddDefinition(nMatchesVariable, nMatches);
4354   this->MarkVariableAsUsed(nMatchesVariable);
4355 }
4356
4357 cmStateSnapshot cmMakefile::GetStateSnapshot() const
4358 {
4359   return this->StateSnapshot;
4360 }
4361
4362 const char* cmMakefile::GetDefineFlagsCMP0059() const
4363 {
4364   return this->DefineFlagsOrig.c_str();
4365 }
4366
4367 cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id,
4368                                                      bool parent_scope) const
4369 {
4370   return this->StateSnapshot.GetPolicy(id, parent_scope);
4371 }
4372
4373 bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) const
4374 {
4375   // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting.
4376   if (cmValue val = this->GetDefinition(var)) {
4377     return cmIsOn(val);
4378   }
4379   // Enable optional policy warnings with --debug-output, --trace,
4380   // or --trace-expand.
4381   cmake* cm = this->GetCMakeInstance();
4382   return cm->GetDebugOutput() || cm->GetTrace();
4383 }
4384
4385 bool cmMakefile::SetPolicy(const char* id, cmPolicies::PolicyStatus status)
4386 {
4387   cmPolicies::PolicyID pid;
4388   if (!cmPolicies::GetPolicyID(id, /* out */ pid)) {
4389     std::ostringstream e;
4390     e << "Policy \"" << id << "\" is not known to this version of CMake.";
4391     this->IssueMessage(MessageType::FATAL_ERROR, e.str());
4392     return false;
4393   }
4394   return this->SetPolicy(pid, status);
4395 }
4396
4397 bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
4398                            cmPolicies::PolicyStatus status)
4399 {
4400   // A REQUIRED_ALWAYS policy may be set only to NEW.
4401   if (status != cmPolicies::NEW &&
4402       cmPolicies::GetPolicyStatus(id) == cmPolicies::REQUIRED_ALWAYS) {
4403     std::string msg = cmPolicies::GetRequiredAlwaysPolicyError(id);
4404     this->IssueMessage(MessageType::FATAL_ERROR, msg);
4405     return false;
4406   }
4407
4408   // Deprecate old policies.
4409   if (status == cmPolicies::OLD && id <= cmPolicies::CMP0097 &&
4410       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
4411         (
4412           // Policies set by cmCoreTryCompile::TryCompileCode.
4413           id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083 ||
4414           id == cmPolicies::CMP0091)) &&
4415       (!this->IsSet("CMAKE_WARN_DEPRECATED") ||
4416        this->IsOn("CMAKE_WARN_DEPRECATED"))) {
4417     this->IssueMessage(MessageType::DEPRECATION_WARNING,
4418                        cmPolicies::GetPolicyDeprecatedWarning(id));
4419   }
4420
4421   this->StateSnapshot.SetPolicy(id, status);
4422   return true;
4423 }
4424
4425 cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m)
4426   : Makefile(m)
4427 {
4428   this->Makefile->PushPolicy();
4429 }
4430
4431 cmMakefile::PolicyPushPop::~PolicyPushPop()
4432 {
4433   this->Makefile->PopPolicy();
4434 }
4435
4436 void cmMakefile::PushPolicy(bool weak, cmPolicies::PolicyMap const& pm)
4437 {
4438   this->StateSnapshot.PushPolicy(pm, weak);
4439 }
4440
4441 void cmMakefile::PopPolicy()
4442 {
4443   if (!this->StateSnapshot.PopPolicy()) {
4444     this->IssueMessage(MessageType::FATAL_ERROR,
4445                        "cmake_policy POP without matching PUSH");
4446   }
4447 }
4448
4449 void cmMakefile::PopSnapshot(bool reportError)
4450 {
4451   // cmStateSnapshot manages nested policy scopes within it.
4452   // Since the scope corresponding to the snapshot is closing,
4453   // reject any still-open nested policy scopes with an error.
4454   while (this->StateSnapshot.CanPopPolicyScope()) {
4455     if (reportError) {
4456       this->IssueMessage(MessageType::FATAL_ERROR,
4457                          "cmake_policy PUSH without matching POP");
4458       reportError = false;
4459     }
4460     this->PopPolicy();
4461   }
4462
4463   this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot);
4464   assert(this->StateSnapshot.IsValid());
4465 }
4466
4467 bool cmMakefile::SetPolicyVersion(std::string const& version_min,
4468                                   std::string const& version_max)
4469 {
4470   return cmPolicies::ApplyPolicyVersion(this, version_min, version_max,
4471                                         cmPolicies::WarnCompat::On);
4472 }
4473
4474 bool cmMakefile::HasCMP0054AlreadyBeenReported(
4475   cmListFileContext const& context) const
4476 {
4477   return !this->CMP0054ReportedIds.insert(context).second;
4478 }
4479
4480 void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) const
4481 {
4482   /* Record the setting of every policy.  */
4483   using PolicyID = cmPolicies::PolicyID;
4484   for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT;
4485        pid = static_cast<PolicyID>(pid + 1)) {
4486     pm.Set(pid, this->GetPolicyStatus(pid));
4487   }
4488 }
4489
4490 bool cmMakefile::IgnoreErrorsCMP0061() const
4491 {
4492   bool ignoreErrors = true;
4493   switch (this->GetPolicyStatus(cmPolicies::CMP0061)) {
4494     case cmPolicies::WARN:
4495       // No warning for this policy!
4496       CM_FALLTHROUGH;
4497     case cmPolicies::OLD:
4498       break;
4499     case cmPolicies::REQUIRED_IF_USED:
4500     case cmPolicies::REQUIRED_ALWAYS:
4501     case cmPolicies::NEW:
4502       ignoreErrors = false;
4503       break;
4504   }
4505   return ignoreErrors;
4506 }
4507
4508 cmMakefile::FunctionPushPop::FunctionPushPop(cmMakefile* mf,
4509                                              const std::string& fileName,
4510                                              cmPolicies::PolicyMap const& pm)
4511   : Makefile(mf)
4512 {
4513   this->Makefile->PushFunctionScope(fileName, pm);
4514 }
4515
4516 cmMakefile::FunctionPushPop::~FunctionPushPop()
4517 {
4518   this->Makefile->PopFunctionScope(this->ReportError);
4519 }
4520
4521 cmMakefile::MacroPushPop::MacroPushPop(cmMakefile* mf,
4522                                        const std::string& fileName,
4523                                        const cmPolicies::PolicyMap& pm)
4524   : Makefile(mf)
4525 {
4526   this->Makefile->PushMacroScope(fileName, pm);
4527 }
4528
4529 cmMakefile::MacroPushPop::~MacroPushPop()
4530 {
4531   this->Makefile->PopMacroScope(this->ReportError);
4532 }
4533
4534 cmMakefile::DebugFindPkgRAII::DebugFindPkgRAII(cmMakefile* mf,
4535                                                std::string const& pkg)
4536   : Makefile(mf)
4537   , OldValue(this->Makefile->DebugFindPkg)
4538 {
4539   this->Makefile->DebugFindPkg =
4540     this->Makefile->GetCMakeInstance()->GetDebugFindPkgOutput(pkg);
4541 }
4542
4543 cmMakefile::DebugFindPkgRAII::~DebugFindPkgRAII()
4544 {
4545   this->Makefile->DebugFindPkg = this->OldValue;
4546 }
4547
4548 bool cmMakefile::GetDebugFindPkgMode() const
4549 {
4550   return this->DebugFindPkg;
4551 }