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