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