71359a27100201173f606a4fea08e96156344613
[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 }
2309
2310 const char* cmMakefile::GetRequiredDefinition(const std::string& name) const
2311 {
2312   const char* ret = this->GetDefinition(name);
2313   if (!ret) {
2314     cmSystemTools::Error("Error required internal CMake variable not "
2315                          "set, cmake may not be built correctly.\n",
2316                          "Missing variable is:\n", name.c_str());
2317     return "";
2318   }
2319   return ret;
2320 }
2321
2322 bool cmMakefile::IsDefinitionSet(const std::string& name) const
2323 {
2324   const char* def = this->StateSnapshot.GetDefinition(name);
2325   if (!def) {
2326     def = this->GetState()->GetInitializedCacheValue(name);
2327   }
2328 #ifdef CMAKE_BUILD_WITH_CMAKE
2329   if (cmVariableWatch* vv = this->GetVariableWatch()) {
2330     if (!def) {
2331       vv->VariableAccessed(
2332         name, cmVariableWatch::UNKNOWN_VARIABLE_DEFINED_ACCESS, def, this);
2333     }
2334   }
2335 #endif
2336   return def != nullptr;
2337 }
2338
2339 const char* cmMakefile::GetDefinition(const std::string& name) const
2340 {
2341   const char* def = this->StateSnapshot.GetDefinition(name);
2342   if (!def) {
2343     def = this->GetState()->GetInitializedCacheValue(name);
2344   }
2345 #ifdef CMAKE_BUILD_WITH_CMAKE
2346   cmVariableWatch* vv = this->GetVariableWatch();
2347   if (vv && !this->SuppressWatches) {
2348     bool const watch_function_executed = vv->VariableAccessed(
2349       name, def ? cmVariableWatch::VARIABLE_READ_ACCESS
2350                 : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS,
2351       def, this);
2352
2353     if (watch_function_executed) {
2354       // A callback was executed and may have caused re-allocation of the
2355       // variable storage.  Look it up again for now.
2356       // FIXME: Refactor variable storage to avoid this problem.
2357       def = this->StateSnapshot.GetDefinition(name);
2358       if (!def) {
2359         def = this->GetState()->GetInitializedCacheValue(name);
2360       }
2361     }
2362   }
2363 #endif
2364   return def;
2365 }
2366
2367 const char* cmMakefile::GetSafeDefinition(const std::string& def) const
2368 {
2369   const char* ret = this->GetDefinition(def);
2370   if (!ret) {
2371     return "";
2372   }
2373   return ret;
2374 }
2375
2376 std::vector<std::string> cmMakefile::GetDefinitions() const
2377 {
2378   std::vector<std::string> res = this->StateSnapshot.ClosureKeys();
2379   std::vector<std::string> cacheKeys = this->GetState()->GetCacheEntryKeys();
2380   res.insert(res.end(), cacheKeys.begin(), cacheKeys.end());
2381   std::sort(res.begin(), res.end());
2382   return res;
2383 }
2384
2385 const char* cmMakefile::ExpandVariablesInString(std::string& source) const
2386 {
2387   return this->ExpandVariablesInString(source, false, false);
2388 }
2389
2390 const char* cmMakefile::ExpandVariablesInString(
2391   std::string& source, bool escapeQuotes, bool noEscapes, bool atOnly,
2392   const char* filename, long line, bool removeEmpty, bool replaceAt) const
2393 {
2394   bool compareResults = false;
2395   cmake::MessageType mtype = cmake::LOG;
2396   std::string errorstr;
2397   std::string original;
2398
2399   // Sanity check the @ONLY mode.
2400   if (atOnly && (!noEscapes || !removeEmpty)) {
2401     // This case should never be called.  At-only is for
2402     // configure-file/string which always does no escapes.
2403     this->IssueMessage(cmake::INTERNAL_ERROR,
2404                        "ExpandVariablesInString @ONLY called "
2405                        "on something with escapes.");
2406     return source.c_str();
2407   }
2408
2409   // Variables used in the WARN case.
2410   std::string newResult;
2411   std::string newErrorstr;
2412   cmake::MessageType newError = cmake::LOG;
2413
2414   switch (this->GetPolicyStatus(cmPolicies::CMP0053)) {
2415     case cmPolicies::WARN: {
2416       // Save the original string for the warning.
2417       original = source;
2418       newResult = source;
2419       compareResults = true;
2420       // Suppress variable watches to avoid calling hooks twice. Suppress new
2421       // dereferences since the OLD behavior is still what is actually used.
2422       this->SuppressWatches = true;
2423       newError = ExpandVariablesInStringNew(
2424         newErrorstr, newResult, escapeQuotes, noEscapes, atOnly, filename,
2425         line, removeEmpty, replaceAt);
2426       this->SuppressWatches = false;
2427       CM_FALLTHROUGH;
2428     }
2429     case cmPolicies::OLD:
2430       mtype =
2431         ExpandVariablesInStringOld(errorstr, source, escapeQuotes, noEscapes,
2432                                    atOnly, filename, line, removeEmpty, true);
2433       break;
2434     case cmPolicies::REQUIRED_IF_USED:
2435     case cmPolicies::REQUIRED_ALWAYS:
2436     // Messaging here would be *very* verbose.
2437     case cmPolicies::NEW:
2438       mtype = ExpandVariablesInStringNew(errorstr, source, escapeQuotes,
2439                                          noEscapes, atOnly, filename, line,
2440                                          removeEmpty, replaceAt);
2441       break;
2442   }
2443
2444   // If it's an error in either case, just report the error...
2445   if (mtype != cmake::LOG) {
2446     if (mtype == cmake::FATAL_ERROR) {
2447       cmSystemTools::SetFatalErrorOccured();
2448     }
2449     this->IssueMessage(mtype, errorstr);
2450   }
2451   // ...otherwise, see if there's a difference that needs to be warned about.
2452   else if (compareResults && (newResult != source || newError != mtype)) {
2453     std::string msg = cmPolicies::GetPolicyWarning(cmPolicies::CMP0053);
2454     msg += "\n";
2455
2456     std::string msg_input = original;
2457     cmSystemTools::ReplaceString(msg_input, "\n", "\n  ");
2458     msg += "For input:\n  '";
2459     msg += msg_input;
2460     msg += "'\n";
2461
2462     std::string msg_old = source;
2463     cmSystemTools::ReplaceString(msg_old, "\n", "\n  ");
2464     msg += "the old evaluation rules produce:\n  '";
2465     msg += msg_old;
2466     msg += "'\n";
2467
2468     if (newError == mtype) {
2469       std::string msg_new = newResult;
2470       cmSystemTools::ReplaceString(msg_new, "\n", "\n  ");
2471       msg += "but the new evaluation rules produce:\n  '";
2472       msg += msg_new;
2473       msg += "'\n";
2474     } else {
2475       std::string msg_err = newErrorstr;
2476       cmSystemTools::ReplaceString(msg_err, "\n", "\n  ");
2477       msg += "but the new evaluation rules produce an error:\n  ";
2478       msg += msg_err;
2479       msg += "\n";
2480     }
2481
2482     msg +=
2483       "Using the old result for compatibility since the policy is not set.";
2484
2485     this->IssueMessage(cmake::AUTHOR_WARNING, msg);
2486   }
2487
2488   return source.c_str();
2489 }
2490
2491 cmake::MessageType cmMakefile::ExpandVariablesInStringOld(
2492   std::string& errorstr, std::string& source, bool escapeQuotes,
2493   bool noEscapes, bool atOnly, const char* filename, long line,
2494   bool removeEmpty, bool replaceAt) const
2495 {
2496   // Fast path strings without any special characters.
2497   if (source.find_first_of("$@\\") == std::string::npos) {
2498     return cmake::LOG;
2499   }
2500
2501   // Special-case the @ONLY mode.
2502   if (atOnly) {
2503     // Store an original copy of the input.
2504     std::string input = source;
2505
2506     // Start with empty output.
2507     source.clear();
2508
2509     // Look for one @VAR@ at a time.
2510     const char* in = input.c_str();
2511     while (this->cmAtVarRegex.find(in)) {
2512       // Get the range of the string to replace.
2513       const char* first = in + this->cmAtVarRegex.start();
2514       const char* last = in + this->cmAtVarRegex.end();
2515
2516       // Store the unchanged part of the string now.
2517       source.append(in, first - in);
2518
2519       // Lookup the definition of VAR.
2520       std::string var(first + 1, last - first - 2);
2521       if (const char* val = this->GetDefinition(var)) {
2522         // Store the value in the output escaping as requested.
2523         if (escapeQuotes) {
2524           source.append(cmSystemTools::EscapeQuotes(val));
2525         } else {
2526           source.append(val);
2527         }
2528       }
2529
2530       // Continue looking for @VAR@ further along the string.
2531       in = last;
2532     }
2533
2534     // Append the rest of the unchanged part of the string.
2535     source.append(in);
2536
2537     return cmake::LOG;
2538   }
2539
2540   // This method replaces ${VAR} and @VAR@ where VAR is looked up
2541   // with GetDefinition(), if not found in the map, nothing is expanded.
2542   // It also supports the $ENV{VAR} syntax where VAR is looked up in
2543   // the current environment variables.
2544
2545   cmCommandArgumentParserHelper parser;
2546   parser.SetMakefile(this);
2547   parser.SetLineFile(line, filename);
2548   parser.SetEscapeQuotes(escapeQuotes);
2549   parser.SetNoEscapeMode(noEscapes);
2550   parser.SetReplaceAtSyntax(replaceAt);
2551   parser.SetRemoveEmpty(removeEmpty);
2552   int res = parser.ParseString(source.c_str(), 0);
2553   const char* emsg = parser.GetError();
2554   cmake::MessageType mtype = cmake::LOG;
2555   if (res && !emsg[0]) {
2556     source = parser.GetResult();
2557   } else {
2558     // Construct the main error message.
2559     std::ostringstream error;
2560     error << "Syntax error in cmake code ";
2561     if (filename && line > 0) {
2562       // This filename and line number may be more specific than the
2563       // command context because one command invocation can have
2564       // arguments on multiple lines.
2565       error << "at\n"
2566             << "  " << filename << ":" << line << "\n";
2567     }
2568     error << "when parsing string\n"
2569           << "  " << source << "\n";
2570     error << emsg;
2571
2572     // If the parser failed ("res" is false) then this is a real
2573     // argument parsing error, so the policy applies.  Otherwise the
2574     // parser reported an error message without failing because the
2575     // helper implementation is unhappy, which has always reported an
2576     // error.
2577     mtype = cmake::FATAL_ERROR;
2578     if (!res) {
2579       // This is a real argument parsing error.  Use policy CMP0010 to
2580       // decide whether it is an error.
2581       switch (this->GetPolicyStatus(cmPolicies::CMP0010)) {
2582         case cmPolicies::WARN:
2583           error << "\n" << cmPolicies::GetPolicyWarning(cmPolicies::CMP0010);
2584           CM_FALLTHROUGH;
2585         case cmPolicies::OLD:
2586           // OLD behavior is to just warn and continue.
2587           mtype = cmake::AUTHOR_WARNING;
2588           break;
2589         case cmPolicies::REQUIRED_IF_USED:
2590         case cmPolicies::REQUIRED_ALWAYS:
2591           error << "\n"
2592                 << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0010);
2593         case cmPolicies::NEW:
2594           // NEW behavior is to report the error.
2595           break;
2596       }
2597     }
2598     errorstr = error.str();
2599   }
2600   return mtype;
2601 }
2602
2603 typedef enum { NORMAL, ENVIRONMENT, CACHE } t_domain;
2604 struct t_lookup
2605 {
2606   t_lookup()
2607     : domain(NORMAL)
2608     , loc(0)
2609   {
2610   }
2611   t_domain domain;
2612   size_t loc;
2613 };
2614
2615 cmake::MessageType cmMakefile::ExpandVariablesInStringNew(
2616   std::string& errorstr, std::string& source, bool escapeQuotes,
2617   bool noEscapes, bool atOnly, const char* filename, long line,
2618   bool removeEmpty, bool replaceAt) const
2619 {
2620   // This method replaces ${VAR} and @VAR@ where VAR is looked up
2621   // with GetDefinition(), if not found in the map, nothing is expanded.
2622   // It also supports the $ENV{VAR} syntax where VAR is looked up in
2623   // the current environment variables.
2624
2625   const char* in = source.c_str();
2626   const char* last = in;
2627   std::string result;
2628   result.reserve(source.size());
2629   std::vector<t_lookup> openstack;
2630   bool error = false;
2631   bool done = false;
2632   cmake::MessageType mtype = cmake::LOG;
2633
2634   cmState* state = this->GetCMakeInstance()->GetState();
2635
2636   do {
2637     char inc = *in;
2638     switch (inc) {
2639       case '}':
2640         if (!openstack.empty()) {
2641           t_lookup var = openstack.back();
2642           openstack.pop_back();
2643           result.append(last, in - last);
2644           std::string const& lookup = result.substr(var.loc);
2645           const char* value = nullptr;
2646           std::string varresult;
2647           std::string svalue;
2648           static const std::string lineVar = "CMAKE_CURRENT_LIST_LINE";
2649           switch (var.domain) {
2650             case NORMAL:
2651               if (filename && lookup == lineVar) {
2652                 std::ostringstream ostr;
2653                 ostr << line;
2654                 varresult = ostr.str();
2655               } else {
2656                 value = this->GetDefinition(lookup);
2657               }
2658               break;
2659             case ENVIRONMENT:
2660               if (cmSystemTools::GetEnv(lookup, svalue)) {
2661                 value = svalue.c_str();
2662               }
2663               break;
2664             case CACHE:
2665               value = state->GetCacheEntryValue(lookup);
2666               break;
2667           }
2668           // Get the string we're meant to append to.
2669           if (value) {
2670             if (escapeQuotes) {
2671               varresult = cmSystemTools::EscapeQuotes(value);
2672             } else {
2673               varresult = value;
2674             }
2675           } else if (!removeEmpty) {
2676             // check to see if we need to print a warning
2677             // if strict mode is on and the variable has
2678             // not been "cleared"/initialized with a set(foo ) call
2679             if (this->GetCMakeInstance()->GetWarnUninitialized() &&
2680                 !this->VariableInitialized(lookup)) {
2681               if (this->CheckSystemVars ||
2682                   (filename &&
2683                    (cmSystemTools::IsSubDirectory(filename,
2684                                                   this->GetHomeDirectory()) ||
2685                     cmSystemTools::IsSubDirectory(
2686                       filename, this->GetHomeOutputDirectory())))) {
2687                 std::ostringstream msg;
2688                 msg << "uninitialized variable \'" << lookup << "\'";
2689                 this->IssueMessage(cmake::AUTHOR_WARNING, msg.str());
2690               }
2691             }
2692           }
2693           result.replace(var.loc, result.size() - var.loc, varresult);
2694           // Start looking from here on out.
2695           last = in + 1;
2696         }
2697         break;
2698       case '$':
2699         if (!atOnly) {
2700           t_lookup lookup;
2701           const char* next = in + 1;
2702           const char* start = nullptr;
2703           char nextc = *next;
2704           if (nextc == '{') {
2705             // Looking for a variable.
2706             start = in + 2;
2707             lookup.domain = NORMAL;
2708           } else if (nextc == '<') {
2709           } else if (!nextc) {
2710             result.append(last, next - last);
2711             last = next;
2712           } else if (cmHasLiteralPrefix(next, "ENV{")) {
2713             // Looking for an environment variable.
2714             start = in + 5;
2715             lookup.domain = ENVIRONMENT;
2716           } else if (cmHasLiteralPrefix(next, "CACHE{")) {
2717             // Looking for a cache variable.
2718             start = in + 7;
2719             lookup.domain = CACHE;
2720           } else {
2721             if (this->cmNamedCurly.find(next)) {
2722               errorstr = "Syntax $" +
2723                 std::string(next, this->cmNamedCurly.end()) +
2724                 "{} is not supported.  Only ${}, $ENV{}, "
2725                 "and $CACHE{} are allowed.";
2726               mtype = cmake::FATAL_ERROR;
2727               error = true;
2728             }
2729           }
2730           if (start) {
2731             result.append(last, in - last);
2732             last = start;
2733             in = start - 1;
2734             lookup.loc = result.size();
2735             openstack.push_back(lookup);
2736           }
2737           break;
2738         }
2739         CM_FALLTHROUGH;
2740       case '\\':
2741         if (!noEscapes) {
2742           const char* next = in + 1;
2743           char nextc = *next;
2744           if (nextc == 't') {
2745             result.append(last, in - last);
2746             result.append("\t");
2747             last = next + 1;
2748           } else if (nextc == 'n') {
2749             result.append(last, in - last);
2750             result.append("\n");
2751             last = next + 1;
2752           } else if (nextc == 'r') {
2753             result.append(last, in - last);
2754             result.append("\r");
2755             last = next + 1;
2756           } else if (nextc == ';' && openstack.empty()) {
2757             // Handled in ExpandListArgument; pass the backslash literally.
2758           } else if (isalnum(nextc) || nextc == '\0') {
2759             errorstr += "Invalid character escape '\\";
2760             if (nextc) {
2761               errorstr += nextc;
2762               errorstr += "'.";
2763             } else {
2764               errorstr += "' (at end of input).";
2765             }
2766             error = true;
2767           } else {
2768             // Take what we've found so far, skipping the escape character.
2769             result.append(last, in - last);
2770             // Start tracking from the next character.
2771             last = in + 1;
2772           }
2773           // Skip the next character since it was escaped, but don't read past
2774           // the end of the string.
2775           if (*last) {
2776             ++in;
2777           }
2778         }
2779         break;
2780       case '\n':
2781         // Onto the next line.
2782         ++line;
2783         break;
2784       case '\0':
2785         done = true;
2786         break;
2787       case '@':
2788         if (replaceAt) {
2789           const char* nextAt = strchr(in + 1, '@');
2790           if (nextAt && nextAt != in + 1 &&
2791               nextAt ==
2792                 in + 1 + strspn(in + 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2793                                         "abcdefghijklmnopqrstuvwxyz"
2794                                         "0123456789/_.+-")) {
2795             std::string variable(in + 1, nextAt - in - 1);
2796             std::string varresult = this->GetSafeDefinition(variable);
2797             if (escapeQuotes) {
2798               varresult = cmSystemTools::EscapeQuotes(varresult);
2799             }
2800             // Skip over the variable.
2801             result.append(last, in - last);
2802             result.append(varresult);
2803             in = nextAt;
2804             last = in + 1;
2805             break;
2806           }
2807         }
2808       // Failed to find a valid @ expansion; treat it as literal.
2809       /* FALLTHROUGH */
2810       default: {
2811         if (!openstack.empty() &&
2812             !(isalnum(inc) || inc == '_' || inc == '/' || inc == '.' ||
2813               inc == '+' || inc == '-')) {
2814           errorstr += "Invalid character (\'";
2815           errorstr += inc;
2816           result.append(last, in - last);
2817           errorstr += "\') in a variable name: "
2818                       "'" +
2819             result.substr(openstack.back().loc) + "'";
2820           mtype = cmake::FATAL_ERROR;
2821           error = true;
2822         }
2823         break;
2824       }
2825     }
2826     // Look at the next character.
2827   } while (!error && !done && *++in);
2828
2829   // Check for open variable references yet.
2830   if (!error && !openstack.empty()) {
2831     // There's an open variable reference waiting.  Policy CMP0010 flags
2832     // whether this is an error or not.  The new parser now enforces
2833     // CMP0010 as well.
2834     errorstr += "There is an unterminated variable reference.";
2835     error = true;
2836   }
2837
2838   if (error) {
2839     std::ostringstream emsg;
2840     emsg << "Syntax error in cmake code ";
2841     if (filename) {
2842       // This filename and line number may be more specific than the
2843       // command context because one command invocation can have
2844       // arguments on multiple lines.
2845       emsg << "at\n"
2846            << "  " << filename << ":" << line << "\n";
2847     }
2848     emsg << "when parsing string\n"
2849          << "  " << source << "\n";
2850     emsg << errorstr;
2851     mtype = cmake::FATAL_ERROR;
2852     errorstr = emsg.str();
2853   } else {
2854     // Append the rest of the unchanged part of the string.
2855     result.append(last);
2856
2857     source = result;
2858   }
2859
2860   return mtype;
2861 }
2862
2863 void cmMakefile::RemoveVariablesInString(std::string& source,
2864                                          bool atOnly) const
2865 {
2866   if (!atOnly) {
2867     cmsys::RegularExpression var("(\\${[A-Za-z_0-9]*})");
2868     while (var.find(source)) {
2869       source.erase(var.start(), var.end() - var.start());
2870     }
2871   }
2872
2873   if (!atOnly) {
2874     cmsys::RegularExpression varb("(\\$ENV{[A-Za-z_0-9]*})");
2875     while (varb.find(source)) {
2876       source.erase(varb.start(), varb.end() - varb.start());
2877     }
2878   }
2879   cmsys::RegularExpression var2("(@[A-Za-z_0-9]*@)");
2880   while (var2.find(source)) {
2881     source.erase(var2.start(), var2.end() - var2.start());
2882   }
2883 }
2884
2885 std::string cmMakefile::GetConfigurations(std::vector<std::string>& configs,
2886                                           bool singleConfig) const
2887 {
2888   if (this->GetGlobalGenerator()->IsMultiConfig()) {
2889     if (const char* configTypes =
2890           this->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
2891       cmSystemTools::ExpandListArgument(configTypes, configs);
2892     }
2893     return "";
2894   }
2895   const std::string& buildType = this->GetSafeDefinition("CMAKE_BUILD_TYPE");
2896   if (singleConfig && !buildType.empty()) {
2897     configs.push_back(buildType);
2898   }
2899   return buildType;
2900 }
2901
2902 bool cmMakefile::IsFunctionBlocked(const cmListFileFunction& lff,
2903                                    cmExecutionStatus& status)
2904 {
2905   // if there are no blockers get out of here
2906   if (this->FunctionBlockers.begin() == this->FunctionBlockers.end()) {
2907     return false;
2908   }
2909
2910   // loop over all function blockers to see if any block this command
2911   // evaluate in reverse, this is critical for balanced IF statements etc
2912   std::vector<cmFunctionBlocker*>::reverse_iterator pos;
2913   for (pos = this->FunctionBlockers.rbegin();
2914        pos != this->FunctionBlockers.rend(); ++pos) {
2915     if ((*pos)->IsFunctionBlocked(lff, *this, status)) {
2916       return true;
2917     }
2918   }
2919
2920   return false;
2921 }
2922
2923 void cmMakefile::PushFunctionBlockerBarrier()
2924 {
2925   this->FunctionBlockerBarriers.push_back(this->FunctionBlockers.size());
2926 }
2927
2928 void cmMakefile::PopFunctionBlockerBarrier(bool reportError)
2929 {
2930   // Remove any extra entries pushed on the barrier.
2931   FunctionBlockersType::size_type barrier =
2932     this->FunctionBlockerBarriers.back();
2933   while (this->FunctionBlockers.size() > barrier) {
2934     std::unique_ptr<cmFunctionBlocker> fb(this->FunctionBlockers.back());
2935     this->FunctionBlockers.pop_back();
2936     if (reportError) {
2937       // Report the context in which the unclosed block was opened.
2938       cmListFileContext const& lfc = fb->GetStartingContext();
2939       std::ostringstream e;
2940       /* clang-format off */
2941       e << "A logical block opening on the line\n"
2942         << "  " << lfc << "\n"
2943         << "is not closed.";
2944       /* clang-format on */
2945       this->IssueMessage(cmake::FATAL_ERROR, e.str());
2946       reportError = false;
2947     }
2948   }
2949
2950   // Remove the barrier.
2951   this->FunctionBlockerBarriers.pop_back();
2952 }
2953
2954 void cmMakefile::PushLoopBlock()
2955 {
2956   assert(!this->LoopBlockCounter.empty());
2957   this->LoopBlockCounter.top()++;
2958 }
2959
2960 void cmMakefile::PopLoopBlock()
2961 {
2962   assert(!this->LoopBlockCounter.empty());
2963   assert(this->LoopBlockCounter.top() > 0);
2964   this->LoopBlockCounter.top()--;
2965 }
2966
2967 void cmMakefile::PushLoopBlockBarrier()
2968 {
2969   this->LoopBlockCounter.push(0);
2970 }
2971
2972 void cmMakefile::PopLoopBlockBarrier()
2973 {
2974   assert(!this->LoopBlockCounter.empty());
2975   assert(this->LoopBlockCounter.top() == 0);
2976   this->LoopBlockCounter.pop();
2977 }
2978
2979 bool cmMakefile::IsLoopBlock() const
2980 {
2981   assert(!this->LoopBlockCounter.empty());
2982   return !this->LoopBlockCounter.empty() && this->LoopBlockCounter.top() > 0;
2983 }
2984
2985 std::string cmMakefile::GetExecutionFilePath() const
2986 {
2987   assert(this->StateSnapshot.IsValid());
2988   return this->StateSnapshot.GetExecutionListFile();
2989 }
2990
2991 bool cmMakefile::ExpandArguments(std::vector<cmListFileArgument> const& inArgs,
2992                                  std::vector<std::string>& outArgs,
2993                                  const char* filename) const
2994 {
2995   std::string efp = this->GetExecutionFilePath();
2996   if (!filename) {
2997     filename = efp.c_str();
2998   }
2999   std::string value;
3000   outArgs.reserve(inArgs.size());
3001   for (cmListFileArgument const& i : inArgs) {
3002     // No expansion in a bracket argument.
3003     if (i.Delim == cmListFileArgument::Bracket) {
3004       outArgs.push_back(i.Value);
3005       continue;
3006     }
3007     // Expand the variables in the argument.
3008     value = i.Value;
3009     this->ExpandVariablesInString(value, false, false, false, filename, i.Line,
3010                                   false, false);
3011
3012     // If the argument is quoted, it should be one argument.
3013     // Otherwise, it may be a list of arguments.
3014     if (i.Delim == cmListFileArgument::Quoted) {
3015       outArgs.push_back(value);
3016     } else {
3017       cmSystemTools::ExpandListArgument(value, outArgs);
3018     }
3019   }
3020   return !cmSystemTools::GetFatalErrorOccured();
3021 }
3022
3023 bool cmMakefile::ExpandArguments(
3024   std::vector<cmListFileArgument> const& inArgs,
3025   std::vector<cmExpandedCommandArgument>& outArgs, const char* filename) const
3026 {
3027   std::string efp = this->GetExecutionFilePath();
3028   if (!filename) {
3029     filename = efp.c_str();
3030   }
3031   std::string value;
3032   outArgs.reserve(inArgs.size());
3033   for (cmListFileArgument const& i : inArgs) {
3034     // No expansion in a bracket argument.
3035     if (i.Delim == cmListFileArgument::Bracket) {
3036       outArgs.emplace_back(i.Value, true);
3037       continue;
3038     }
3039     // Expand the variables in the argument.
3040     value = i.Value;
3041     this->ExpandVariablesInString(value, false, false, false, filename, i.Line,
3042                                   false, false);
3043
3044     // If the argument is quoted, it should be one argument.
3045     // Otherwise, it may be a list of arguments.
3046     if (i.Delim == cmListFileArgument::Quoted) {
3047       outArgs.emplace_back(value, true);
3048     } else {
3049       std::vector<std::string> stringArgs;
3050       cmSystemTools::ExpandListArgument(value, stringArgs);
3051       for (std::string const& stringArg : stringArgs) {
3052         outArgs.emplace_back(stringArg, false);
3053       }
3054     }
3055   }
3056   return !cmSystemTools::GetFatalErrorOccured();
3057 }
3058
3059 void cmMakefile::AddFunctionBlocker(cmFunctionBlocker* fb)
3060 {
3061   if (!this->ExecutionStatusStack.empty()) {
3062     // Record the context in which the blocker is created.
3063     fb->SetStartingContext(this->GetExecutionContext());
3064   }
3065
3066   this->FunctionBlockers.push_back(fb);
3067 }
3068
3069 std::unique_ptr<cmFunctionBlocker> cmMakefile::RemoveFunctionBlocker(
3070   cmFunctionBlocker* fb, const cmListFileFunction& lff)
3071 {
3072   // Find the function blocker stack barrier for the current scope.
3073   // We only remove a blocker whose index is not less than the barrier.
3074   FunctionBlockersType::size_type barrier = 0;
3075   if (!this->FunctionBlockerBarriers.empty()) {
3076     barrier = this->FunctionBlockerBarriers.back();
3077   }
3078
3079   // Search for the function blocker whose scope this command ends.
3080   for (FunctionBlockersType::size_type i = this->FunctionBlockers.size();
3081        i > barrier; --i) {
3082     std::vector<cmFunctionBlocker*>::iterator pos =
3083       this->FunctionBlockers.begin() + (i - 1);
3084     if (*pos == fb) {
3085       // Warn if the arguments do not match, but always remove.
3086       if (!(*pos)->ShouldRemove(lff, *this)) {
3087         cmListFileContext const& lfc = fb->GetStartingContext();
3088         cmListFileContext closingContext =
3089           cmListFileContext::FromCommandContext(lff, lfc.FilePath);
3090         std::ostringstream e;
3091         /* clang-format off */
3092         e << "A logical block opening on the line\n"
3093           << "  " << lfc << "\n"
3094           << "closes on the line\n"
3095           << "  " << closingContext << "\n"
3096           << "with mis-matching arguments.";
3097         /* clang-format on */
3098         this->IssueMessage(cmake::AUTHOR_WARNING, e.str());
3099       }
3100       cmFunctionBlocker* b = *pos;
3101       this->FunctionBlockers.erase(pos);
3102       return std::unique_ptr<cmFunctionBlocker>(b);
3103     }
3104   }
3105
3106   return std::unique_ptr<cmFunctionBlocker>();
3107 }
3108
3109 std::string const& cmMakefile::GetHomeDirectory() const
3110 {
3111   return this->GetCMakeInstance()->GetHomeDirectory();
3112 }
3113
3114 std::string const& cmMakefile::GetHomeOutputDirectory() const
3115 {
3116   return this->GetCMakeInstance()->GetHomeOutputDirectory();
3117 }
3118
3119 void cmMakefile::SetScriptModeFile(std::string const& scriptfile)
3120 {
3121   this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile.c_str());
3122 }
3123
3124 void cmMakefile::SetArgcArgv(const std::vector<std::string>& args)
3125 {
3126   std::ostringstream strStream;
3127   strStream << args.size();
3128   this->AddDefinition("CMAKE_ARGC", strStream.str().c_str());
3129   // this->MarkVariableAsUsed("CMAKE_ARGC");
3130
3131   for (unsigned int t = 0; t < args.size(); ++t) {
3132     std::ostringstream tmpStream;
3133     tmpStream << "CMAKE_ARGV" << t;
3134     this->AddDefinition(tmpStream.str(), args[t].c_str());
3135     // this->MarkVariableAsUsed(tmpStream.str().c_str());
3136   }
3137 }
3138
3139 cmSourceFile* cmMakefile::GetSource(const std::string& sourceName,
3140                                     cmSourceFileLocationKind kind) const
3141 {
3142   cmSourceFileLocation sfl(this, sourceName, kind);
3143   auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName());
3144 #if defined(_WIN32) || defined(__APPLE__)
3145   name = cmSystemTools::LowerCase(name);
3146 #endif
3147   auto sfsi = this->SourceFileSearchIndex.find(name);
3148   if (sfsi != this->SourceFileSearchIndex.end()) {
3149     for (auto sf : sfsi->second) {
3150       if (sf->Matches(sfl)) {
3151         return sf;
3152       }
3153     }
3154   }
3155   return nullptr;
3156 }
3157
3158 cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName,
3159                                        bool generated,
3160                                        cmSourceFileLocationKind kind)
3161 {
3162   cmSourceFile* sf = new cmSourceFile(this, sourceName, kind);
3163   if (generated) {
3164     sf->SetProperty("GENERATED", "1");
3165   }
3166   this->SourceFiles.push_back(sf);
3167
3168   auto name =
3169     this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName());
3170 #if defined(_WIN32) || defined(__APPLE__)
3171   name = cmSystemTools::LowerCase(name);
3172 #endif
3173   this->SourceFileSearchIndex[name].push_back(sf);
3174
3175   return sf;
3176 }
3177
3178 cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName,
3179                                             bool generated,
3180                                             cmSourceFileLocationKind kind)
3181 {
3182   if (cmSourceFile* esf = this->GetSource(sourceName, kind)) {
3183     return esf;
3184   }
3185   return this->CreateSource(sourceName, generated, kind);
3186 }
3187
3188 void cmMakefile::AddTargetObject(std::string const& tgtName,
3189                                  std::string const& objFile)
3190 {
3191   cmSourceFile* sf = this->GetOrCreateSource(objFile, true);
3192   sf->SetObjectLibrary(tgtName);
3193   sf->SetProperty("EXTERNAL_OBJECT", "1");
3194 #if defined(CMAKE_BUILD_WITH_CMAKE)
3195   this->SourceGroups[this->ObjectLibrariesSourceGroupIndex].AddGroupFile(
3196     sf->GetFullPath());
3197 #endif
3198 }
3199
3200 void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
3201                                 bool optional)
3202 {
3203   this->AddDefinition("CMAKE_CFG_INTDIR",
3204                       this->GetGlobalGenerator()->GetCMakeCFGIntDir());
3205   // If RC is explicitly listed we need to do it after other languages.
3206   // On some platforms we enable RC implicitly while enabling others.
3207   // Do not let that look like recursive enable_language(RC).
3208   std::vector<std::string> langs;
3209   std::vector<std::string> langsRC;
3210   langs.reserve(lang.size());
3211   for (std::string const& i : lang) {
3212     if (i == "RC") {
3213       langsRC.push_back(i);
3214     } else {
3215       langs.push_back(i);
3216     }
3217   }
3218   if (!langs.empty()) {
3219     this->GetGlobalGenerator()->EnableLanguage(langs, this, optional);
3220   }
3221   if (!langsRC.empty()) {
3222     this->GetGlobalGenerator()->EnableLanguage(langsRC, this, optional);
3223   }
3224 }
3225
3226 int cmMakefile::TryCompile(const std::string& srcdir,
3227                            const std::string& bindir,
3228                            const std::string& projectName,
3229                            const std::string& targetName, bool fast,
3230                            const std::vector<std::string>* cmakeArgs,
3231                            std::string& output)
3232 {
3233   this->IsSourceFileTryCompile = fast;
3234   // does the binary directory exist ? If not create it...
3235   if (!cmSystemTools::FileIsDirectory(bindir)) {
3236     cmSystemTools::MakeDirectory(bindir);
3237   }
3238
3239   // change to the tests directory and run cmake
3240   // use the cmake object instead of calling cmake
3241   cmWorkingDirectory workdir(bindir);
3242
3243   // make sure the same generator is used
3244   // use this program as the cmake to be run, it should not
3245   // be run that way but the cmake object requires a vailid path
3246   cmake cm(cmake::RoleProject);
3247   cm.SetIsInTryCompile(true);
3248   cmGlobalGenerator* gg =
3249     cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
3250   if (!gg) {
3251     this->IssueMessage(cmake::INTERNAL_ERROR, "Global generator '" +
3252                          this->GetGlobalGenerator()->GetName() +
3253                          "' could not be created.");
3254     cmSystemTools::SetFatalErrorOccured();
3255     this->IsSourceFileTryCompile = false;
3256     return 1;
3257   }
3258   cm.SetGlobalGenerator(gg);
3259
3260   // do a configure
3261   cm.SetHomeDirectory(srcdir);
3262   cm.SetHomeOutputDirectory(bindir);
3263   cm.SetGeneratorInstance(this->GetSafeDefinition("CMAKE_GENERATOR_INSTANCE"));
3264   cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM"));
3265   cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"));
3266   cm.LoadCache();
3267   if (!gg->IsMultiConfig()) {
3268     if (const char* config =
3269           this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) {
3270       // Tell the single-configuration generator which one to use.
3271       // Add this before the user-provided CMake arguments in case
3272       // one of the arguments is -DCMAKE_BUILD_TYPE=...
3273       cm.AddCacheEntry("CMAKE_BUILD_TYPE", config, "Build configuration",
3274                        cmStateEnums::STRING);
3275     }
3276   }
3277   // if cmake args were provided then pass them in
3278   if (cmakeArgs) {
3279     // FIXME: Workaround to ignore unused CLI variables in try-compile.
3280     //
3281     // Ideally we should use SetArgs to honor options like --warn-unused-vars.
3282     // However, there is a subtle problem when certain arguments are passed to
3283     // a macro wrapping around try_compile or try_run that does not escape
3284     // semicolons in its parameters but just passes ${ARGV} or ${ARGN}.  In
3285     // this case a list argument like "-DVAR=a;b" gets split into multiple
3286     // cmake arguments "-DVAR=a" and "b".  Currently SetCacheArgs ignores
3287     // argument "b" and uses just "-DVAR=a", leading to a subtle bug in that
3288     // the try_compile or try_run does not get the proper value of VAR.  If we
3289     // call SetArgs here then it would treat "b" as the source directory and
3290     // cause an error such as "The source directory .../CMakeFiles/CMakeTmp/b
3291     // does not exist", thus breaking the try_compile or try_run completely.
3292     //
3293     // Strictly speaking the bug is in the wrapper macro because the CMake
3294     // language has always flattened nested lists and the macro should escape
3295     // the semicolons in its arguments before forwarding them.  However, this
3296     // bug is so subtle that projects typically work anyway, usually because
3297     // the value VAR=a is sufficient for the try_compile or try_run to get the
3298     // correct result.  Calling SetArgs here would break such projects that
3299     // previously built.  Instead we work around the issue by never reporting
3300     // unused arguments and ignoring options such as --warn-unused-vars.
3301     cm.SetWarnUnusedCli(false);
3302     // cm.SetArgs(*cmakeArgs, true);
3303
3304     cm.SetCacheArgs(*cmakeArgs);
3305   }
3306   // to save time we pass the EnableLanguage info directly
3307   gg->EnableLanguagesFromGenerator(this->GetGlobalGenerator(), this);
3308   if (this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
3309     cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE", "",
3310                      cmStateEnums::INTERNAL);
3311   } else {
3312     cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "FALSE", "",
3313                      cmStateEnums::INTERNAL);
3314   }
3315   if (cm.Configure() != 0) {
3316     this->IssueMessage(cmake::FATAL_ERROR,
3317                        "Failed to configure test project build system.");
3318     cmSystemTools::SetFatalErrorOccured();
3319     this->IsSourceFileTryCompile = false;
3320     return 1;
3321   }
3322
3323   if (cm.Generate() != 0) {
3324     this->IssueMessage(cmake::FATAL_ERROR,
3325                        "Failed to generate test project build system.");
3326     cmSystemTools::SetFatalErrorOccured();
3327     this->IsSourceFileTryCompile = false;
3328     return 1;
3329   }
3330
3331   // finally call the generator to actually build the resulting project
3332   int ret = this->GetGlobalGenerator()->TryCompile(
3333     srcdir, bindir, projectName, targetName, fast, output, this);
3334
3335   this->IsSourceFileTryCompile = false;
3336   return ret;
3337 }
3338
3339 bool cmMakefile::GetIsSourceFileTryCompile() const
3340 {
3341   return this->IsSourceFileTryCompile;
3342 }
3343
3344 cmake* cmMakefile::GetCMakeInstance() const
3345 {
3346   return this->GlobalGenerator->GetCMakeInstance();
3347 }
3348
3349 cmMessenger* cmMakefile::GetMessenger() const
3350 {
3351   return this->GetCMakeInstance()->GetMessenger();
3352 }
3353
3354 cmGlobalGenerator* cmMakefile::GetGlobalGenerator() const
3355 {
3356   return this->GlobalGenerator;
3357 }
3358
3359 #ifdef CMAKE_BUILD_WITH_CMAKE
3360 cmVariableWatch* cmMakefile::GetVariableWatch() const
3361 {
3362   if (this->GetCMakeInstance() &&
3363       this->GetCMakeInstance()->GetVariableWatch()) {
3364     return this->GetCMakeInstance()->GetVariableWatch();
3365   }
3366   return nullptr;
3367 }
3368 #endif
3369
3370 cmState* cmMakefile::GetState() const
3371 {
3372   return this->GetCMakeInstance()->GetState();
3373 }
3374
3375 void cmMakefile::DisplayStatus(const char* message, float s) const
3376 {
3377   cmake* cm = this->GetCMakeInstance();
3378   if (cm->GetWorkingMode() == cmake::FIND_PACKAGE_MODE) {
3379     // don't output any STATUS message in FIND_PACKAGE_MODE, since they will
3380     // directly be fed to the compiler, which will be confused.
3381     return;
3382   }
3383   cm->UpdateProgress(message, s);
3384 }
3385
3386 std::string cmMakefile::GetModulesFile(const char* filename) const
3387 {
3388   std::string result;
3389
3390   // We search the module always in CMAKE_ROOT and in CMAKE_MODULE_PATH,
3391   // and then decide based on the policy setting which one to return.
3392   // See CMP0017 for more details.
3393   // The specific problem was that KDE 4.5.0 installs a
3394   // FindPackageHandleStandardArgs.cmake which doesn't have the new features
3395   // of FPHSA.cmake introduced in CMake 2.8.3 yet, and by setting
3396   // CMAKE_MODULE_PATH also e.g. FindZLIB.cmake from cmake included
3397   // FPHSA.cmake from kdelibs and not from CMake, and tried to use the
3398   // new features, which were not there in the version from kdelibs, and so
3399   // failed ("
3400   std::string moduleInCMakeRoot;
3401   std::string moduleInCMakeModulePath;
3402
3403   // Always search in CMAKE_MODULE_PATH:
3404   const char* cmakeModulePath = this->GetDefinition("CMAKE_MODULE_PATH");
3405   if (cmakeModulePath) {
3406     std::vector<std::string> modulePath;
3407     cmSystemTools::ExpandListArgument(cmakeModulePath, modulePath);
3408
3409     // Look through the possible module directories.
3410     for (std::string itempl : modulePath) {
3411       cmSystemTools::ConvertToUnixSlashes(itempl);
3412       itempl += "/";
3413       itempl += filename;
3414       if (cmSystemTools::FileExists(itempl)) {
3415         moduleInCMakeModulePath = itempl;
3416         break;
3417       }
3418     }
3419   }
3420
3421   // Always search in the standard modules location.
3422   moduleInCMakeRoot = cmSystemTools::GetCMakeRoot();
3423   moduleInCMakeRoot += "/Modules/";
3424   moduleInCMakeRoot += filename;
3425   cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot);
3426   if (!cmSystemTools::FileExists(moduleInCMakeRoot)) {
3427     moduleInCMakeRoot.clear();
3428   }
3429
3430   // Normally, prefer the files found in CMAKE_MODULE_PATH. Only when the file
3431   // from which we are being called is located itself in CMAKE_ROOT, then
3432   // prefer results from CMAKE_ROOT depending on the policy setting.
3433   result = moduleInCMakeModulePath;
3434   if (result.empty()) {
3435     result = moduleInCMakeRoot;
3436   }
3437
3438   if (!moduleInCMakeModulePath.empty() && !moduleInCMakeRoot.empty()) {
3439     const char* currentFile = this->GetDefinition("CMAKE_CURRENT_LIST_FILE");
3440     std::string mods = cmSystemTools::GetCMakeRoot() + "/Modules/";
3441     if (currentFile && cmSystemTools::IsSubDirectory(currentFile, mods)) {
3442       switch (this->GetPolicyStatus(cmPolicies::CMP0017)) {
3443         case cmPolicies::WARN: {
3444           std::ostringstream e;
3445           /* clang-format off */
3446           e << "File " << currentFile << " includes "
3447             << moduleInCMakeModulePath
3448             << " (found via CMAKE_MODULE_PATH) which shadows "
3449             << moduleInCMakeRoot  << ". This may cause errors later on .\n"
3450             << cmPolicies::GetPolicyWarning(cmPolicies::CMP0017);
3451           /* clang-format on */
3452
3453           this->IssueMessage(cmake::AUTHOR_WARNING, e.str());
3454           CM_FALLTHROUGH;
3455         }
3456         case cmPolicies::OLD:
3457           result = moduleInCMakeModulePath;
3458           break;
3459         case cmPolicies::REQUIRED_IF_USED:
3460         case cmPolicies::REQUIRED_ALWAYS:
3461         case cmPolicies::NEW:
3462           result = moduleInCMakeRoot;
3463           break;
3464       }
3465     }
3466   }
3467
3468   return result;
3469 }
3470
3471 void cmMakefile::ConfigureString(const std::string& input, std::string& output,
3472                                  bool atOnly, bool escapeQuotes) const
3473 {
3474   // Split input to handle one line at a time.
3475   std::string::const_iterator lineStart = input.begin();
3476   while (lineStart != input.end()) {
3477     // Find the end of this line.
3478     std::string::const_iterator lineEnd = lineStart;
3479     while (lineEnd != input.end() && *lineEnd != '\n') {
3480       ++lineEnd;
3481     }
3482
3483     // Copy the line.
3484     std::string line(lineStart, lineEnd);
3485
3486     // Skip the newline character.
3487     bool haveNewline = (lineEnd != input.end());
3488     if (haveNewline) {
3489       ++lineEnd;
3490     }
3491
3492     // Replace #cmakedefine instances.
3493     if (this->cmDefineRegex.find(line)) {
3494       const char* def = this->GetDefinition(this->cmDefineRegex.match(2));
3495       if (!cmSystemTools::IsOff(def)) {
3496         const std::string indentation = this->cmDefineRegex.match(1);
3497         cmSystemTools::ReplaceString(line, "#" + indentation + "cmakedefine",
3498                                      "#" + indentation + "define");
3499         output += line;
3500       } else {
3501         output += "/* #undef ";
3502         output += this->cmDefineRegex.match(2);
3503         output += " */";
3504       }
3505     } else if (this->cmDefine01Regex.find(line)) {
3506       const std::string indentation = this->cmDefine01Regex.match(1);
3507       const char* def = this->GetDefinition(this->cmDefine01Regex.match(2));
3508       cmSystemTools::ReplaceString(line, "#" + indentation + "cmakedefine01",
3509                                    "#" + indentation + "define");
3510       output += line;
3511       if (!cmSystemTools::IsOff(def)) {
3512         output += " 1";
3513       } else {
3514         output += " 0";
3515       }
3516     } else {
3517       output += line;
3518     }
3519
3520     if (haveNewline) {
3521       output += "\n";
3522     }
3523
3524     // Move to the next line.
3525     lineStart = lineEnd;
3526   }
3527
3528   // Perform variable replacements.
3529   this->ExpandVariablesInString(output, escapeQuotes, true, atOnly, nullptr,
3530                                 -1, true, true);
3531 }
3532
3533 int cmMakefile::ConfigureFile(const char* infile, const char* outfile,
3534                               bool copyonly, bool atOnly, bool escapeQuotes,
3535                               cmNewLineStyle newLine)
3536 {
3537   int res = 1;
3538   if (!this->CanIWriteThisFile(outfile)) {
3539     cmSystemTools::Error("Attempt to write file: ", outfile,
3540                          " into a source directory.");
3541     return 0;
3542   }
3543   if (!cmSystemTools::FileExists(infile)) {
3544     cmSystemTools::Error("File ", infile, " does not exist.");
3545     return 0;
3546   }
3547   std::string soutfile = outfile;
3548   std::string sinfile = infile;
3549   this->AddCMakeDependFile(sinfile);
3550   cmSystemTools::ConvertToUnixSlashes(soutfile);
3551
3552   // Re-generate if non-temporary outputs are missing.
3553   // when we finalize the configuration we will remove all
3554   // output files that now don't exist.
3555   this->AddCMakeOutputFile(soutfile);
3556
3557   mode_t perm = 0;
3558   cmSystemTools::GetPermissions(sinfile, perm);
3559   std::string::size_type pos = soutfile.rfind('/');
3560   if (pos != std::string::npos) {
3561     std::string path = soutfile.substr(0, pos);
3562     cmSystemTools::MakeDirectory(path);
3563   }
3564
3565   if (copyonly) {
3566     if (!cmSystemTools::CopyFileIfDifferent(sinfile.c_str(),
3567                                             soutfile.c_str())) {
3568       return 0;
3569     }
3570   } else {
3571     std::string newLineCharacters;
3572     std::ios::openmode omode = std::ios::out | std::ios::trunc;
3573     if (newLine.IsValid()) {
3574       newLineCharacters = newLine.GetCharacters();
3575       omode |= std::ios::binary;
3576     } else {
3577       newLineCharacters = "\n";
3578     }
3579     std::string tempOutputFile = soutfile;
3580     tempOutputFile += ".tmp";
3581     cmsys::ofstream fout(tempOutputFile.c_str(), omode);
3582     if (!fout) {
3583       cmSystemTools::Error("Could not open file for write in copy operation ",
3584                            tempOutputFile.c_str());
3585       cmSystemTools::ReportLastSystemError("");
3586       return 0;
3587     }
3588     cmsys::ifstream fin(sinfile.c_str());
3589     if (!fin) {
3590       cmSystemTools::Error("Could not open file for read in copy operation ",
3591                            sinfile.c_str());
3592       return 0;
3593     }
3594
3595     cmsys::FStream::BOM bom = cmsys::FStream::ReadBOM(fin);
3596     if (bom != cmsys::FStream::BOM_None && bom != cmsys::FStream::BOM_UTF8) {
3597       std::ostringstream e;
3598       e << "File starts with a Byte-Order-Mark that is not UTF-8:\n  "
3599         << sinfile;
3600       this->IssueMessage(cmake::FATAL_ERROR, e.str());
3601       return 0;
3602     }
3603     // rewind to copy BOM to output file
3604     fin.seekg(0);
3605
3606     // now copy input to output and expand variables in the
3607     // input file at the same time
3608     std::string inLine;
3609     std::string outLine;
3610     while (cmSystemTools::GetLineFromStream(fin, inLine)) {
3611       outLine.clear();
3612       this->ConfigureString(inLine, outLine, atOnly, escapeQuotes);
3613       fout << outLine << newLineCharacters;
3614     }
3615     // close the files before attempting to copy
3616     fin.close();
3617     fout.close();
3618     if (!cmSystemTools::CopyFileIfDifferent(tempOutputFile.c_str(),
3619                                             soutfile.c_str())) {
3620       res = 0;
3621     } else {
3622       cmSystemTools::SetPermissions(soutfile, perm);
3623     }
3624     cmSystemTools::RemoveFile(tempOutputFile);
3625   }
3626   return res;
3627 }
3628
3629 void cmMakefile::SetProperty(const std::string& prop, const char* value)
3630 {
3631   cmListFileBacktrace lfbt = this->GetBacktrace();
3632   this->StateSnapshot.GetDirectory().SetProperty(prop, value, lfbt);
3633 }
3634
3635 void cmMakefile::AppendProperty(const std::string& prop, const char* value,
3636                                 bool asString)
3637 {
3638   cmListFileBacktrace lfbt = this->GetBacktrace();
3639   this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString,
3640                                                     lfbt);
3641 }
3642
3643 const char* cmMakefile::GetProperty(const std::string& prop) const
3644 {
3645   return this->StateSnapshot.GetDirectory().GetProperty(prop);
3646 }
3647
3648 const char* cmMakefile::GetProperty(const std::string& prop, bool chain) const
3649 {
3650   return this->StateSnapshot.GetDirectory().GetProperty(prop, chain);
3651 }
3652
3653 bool cmMakefile::GetPropertyAsBool(const std::string& prop) const
3654 {
3655   return cmSystemTools::IsOn(this->GetProperty(prop));
3656 }
3657
3658 std::vector<std::string> cmMakefile::GetPropertyKeys() const
3659 {
3660   return this->StateSnapshot.GetDirectory().GetPropertyKeys();
3661 }
3662
3663 cmTarget* cmMakefile::FindLocalNonAliasTarget(const std::string& name) const
3664 {
3665   cmTargets::iterator i = this->Targets.find(name);
3666   if (i != this->Targets.end()) {
3667     return &i->second;
3668   }
3669   return nullptr;
3670 }
3671
3672 cmTest* cmMakefile::CreateTest(const std::string& testName)
3673 {
3674   cmTest* test = this->GetTest(testName);
3675   if (test) {
3676     return test;
3677   }
3678   test = new cmTest(this);
3679   test->SetName(testName);
3680   this->Tests[testName] = test;
3681   return test;
3682 }
3683
3684 cmTest* cmMakefile::GetTest(const std::string& testName) const
3685 {
3686   std::map<std::string, cmTest*>::const_iterator mi =
3687     this->Tests.find(testName);
3688   if (mi != this->Tests.end()) {
3689     return mi->second;
3690   }
3691   return nullptr;
3692 }
3693
3694 void cmMakefile::GetTests(const std::string& config,
3695                           std::vector<cmTest*>& tests)
3696 {
3697   for (auto generator : this->GetTestGenerators()) {
3698     if (generator->TestsForConfig(config)) {
3699       tests.push_back(generator->GetTest());
3700     }
3701   }
3702 }
3703
3704 void cmMakefile::AddCMakeDependFilesFromUser()
3705 {
3706   std::vector<std::string> deps;
3707   if (const char* deps_str = this->GetProperty("CMAKE_CONFIGURE_DEPENDS")) {
3708     cmSystemTools::ExpandListArgument(deps_str, deps);
3709   }
3710   for (std::string const& dep : deps) {
3711     if (cmSystemTools::FileIsFullPath(dep)) {
3712       this->AddCMakeDependFile(dep);
3713     } else {
3714       std::string f = this->GetCurrentSourceDirectory();
3715       f += "/";
3716       f += dep;
3717       this->AddCMakeDependFile(f);
3718     }
3719   }
3720 }
3721
3722 std::string cmMakefile::FormatListFileStack() const
3723 {
3724   std::vector<std::string> listFiles;
3725   cmStateSnapshot snp = this->StateSnapshot;
3726   while (snp.IsValid()) {
3727     listFiles.push_back(snp.GetExecutionListFile());
3728     snp = snp.GetCallStackParent();
3729   }
3730   std::reverse(listFiles.begin(), listFiles.end());
3731   std::ostringstream tmp;
3732   size_t depth = listFiles.size();
3733   if (depth > 0) {
3734     std::vector<std::string>::const_iterator it = listFiles.end();
3735     do {
3736       if (depth != listFiles.size()) {
3737         tmp << "\n                ";
3738       }
3739       --it;
3740       tmp << "[";
3741       tmp << depth;
3742       tmp << "]\t";
3743       tmp << *it;
3744       depth--;
3745     } while (it != listFiles.begin());
3746   }
3747   return tmp.str();
3748 }
3749
3750 void cmMakefile::PushScope()
3751 {
3752   this->StateSnapshot =
3753     this->GetState()->CreateVariableScopeSnapshot(this->StateSnapshot);
3754   this->PushLoopBlockBarrier();
3755
3756 #if defined(CMAKE_BUILD_WITH_CMAKE)
3757   this->GetGlobalGenerator()->GetFileLockPool().PushFunctionScope();
3758 #endif
3759 }
3760
3761 void cmMakefile::PopScope()
3762 {
3763 #if defined(CMAKE_BUILD_WITH_CMAKE)
3764   this->GetGlobalGenerator()->GetFileLockPool().PopFunctionScope();
3765 #endif
3766
3767   this->PopLoopBlockBarrier();
3768
3769   this->CheckForUnusedVariables();
3770
3771   this->PopSnapshot();
3772 }
3773
3774 void cmMakefile::RaiseScope(const std::string& var, const char* varDef)
3775 {
3776   if (var.empty()) {
3777     return;
3778   }
3779
3780   if (!this->StateSnapshot.RaiseScope(var, varDef)) {
3781     std::ostringstream m;
3782     m << "Cannot set \"" << var << "\": current scope has no parent.";
3783     this->IssueMessage(cmake::AUTHOR_WARNING, m.str());
3784   }
3785 }
3786
3787 cmTarget* cmMakefile::AddImportedTarget(const std::string& name,
3788                                         cmStateEnums::TargetType type,
3789                                         bool global)
3790 {
3791   // Create the target.
3792   std::unique_ptr<cmTarget> target(
3793     new cmTarget(name, type, global ? cmTarget::VisibilityImportedGlobally
3794                                     : cmTarget::VisibilityImported,
3795                  this));
3796
3797   // Add to the set of available imported targets.
3798   this->ImportedTargets[name] = target.get();
3799   this->GetGlobalGenerator()->IndexTarget(target.get());
3800
3801   // Transfer ownership to this cmMakefile object.
3802   this->ImportedTargetsOwned.push_back(target.get());
3803   return target.release();
3804 }
3805
3806 cmTarget* cmMakefile::FindTargetToUse(const std::string& name,
3807                                       bool excludeAliases) const
3808 {
3809   // Look for an imported target.  These take priority because they
3810   // are more local in scope and do not have to be globally unique.
3811   TargetMap::const_iterator imported = this->ImportedTargets.find(name);
3812   if (imported != this->ImportedTargets.end()) {
3813     return imported->second;
3814   }
3815
3816   // Look for a target built in this directory.
3817   if (cmTarget* t = this->FindLocalNonAliasTarget(name)) {
3818     return t;
3819   }
3820
3821   // Look for a target built in this project.
3822   return this->GetGlobalGenerator()->FindTarget(name, excludeAliases);
3823 }
3824
3825 bool cmMakefile::IsAlias(const std::string& name) const
3826 {
3827   if (this->AliasTargets.find(name) != this->AliasTargets.end()) {
3828     return true;
3829   }
3830   return this->GetGlobalGenerator()->IsAlias(name);
3831 }
3832
3833 bool cmMakefile::EnforceUniqueName(std::string const& name, std::string& msg,
3834                                    bool isCustom) const
3835 {
3836   if (this->IsAlias(name)) {
3837     std::ostringstream e;
3838     e << "cannot create target \"" << name
3839       << "\" because an alias with the same name already exists.";
3840     msg = e.str();
3841     return false;
3842   }
3843   if (cmTarget* existing = this->FindTargetToUse(name)) {
3844     // The name given conflicts with an existing target.  Produce an
3845     // error in a compatible way.
3846     if (existing->IsImported()) {
3847       // Imported targets were not supported in previous versions.
3848       // This is new code, so we can make it an error.
3849       std::ostringstream e;
3850       e << "cannot create target \"" << name
3851         << "\" because an imported target with the same name already exists.";
3852       msg = e.str();
3853       return false;
3854     }
3855     // target names must be globally unique
3856     switch (this->GetPolicyStatus(cmPolicies::CMP0002)) {
3857       case cmPolicies::WARN:
3858         this->IssueMessage(cmake::AUTHOR_WARNING,
3859                            cmPolicies::GetPolicyWarning(cmPolicies::CMP0002));
3860         CM_FALLTHROUGH;
3861       case cmPolicies::OLD:
3862         return true;
3863       case cmPolicies::REQUIRED_IF_USED:
3864       case cmPolicies::REQUIRED_ALWAYS:
3865         this->IssueMessage(
3866           cmake::FATAL_ERROR,
3867           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0002));
3868         return true;
3869       case cmPolicies::NEW:
3870         break;
3871     }
3872
3873     // The conflict is with a non-imported target.
3874     // Allow this if the user has requested support.
3875     cmake* cm = this->GetCMakeInstance();
3876     if (isCustom && existing->GetType() == cmStateEnums::UTILITY &&
3877         this != existing->GetMakefile() &&
3878         cm->GetState()->GetGlobalPropertyAsBool(
3879           "ALLOW_DUPLICATE_CUSTOM_TARGETS")) {
3880       return true;
3881     }
3882
3883     // Produce an error that tells the user how to work around the
3884     // problem.
3885     std::ostringstream e;
3886     e << "cannot create target \"" << name
3887       << "\" because another target with the same name already exists.  "
3888       << "The existing target is ";
3889     switch (existing->GetType()) {
3890       case cmStateEnums::EXECUTABLE:
3891         e << "an executable ";
3892         break;
3893       case cmStateEnums::STATIC_LIBRARY:
3894         e << "a static library ";
3895         break;
3896       case cmStateEnums::SHARED_LIBRARY:
3897         e << "a shared library ";
3898         break;
3899       case cmStateEnums::MODULE_LIBRARY:
3900         e << "a module library ";
3901         break;
3902       case cmStateEnums::UTILITY:
3903         e << "a custom target ";
3904         break;
3905       case cmStateEnums::INTERFACE_LIBRARY:
3906         e << "an interface library ";
3907         break;
3908       default:
3909         break;
3910     }
3911     e << "created in source directory \""
3912       << existing->GetMakefile()->GetCurrentSourceDirectory() << "\".  "
3913       << "See documentation for policy CMP0002 for more details.";
3914     msg = e.str();
3915     return false;
3916   }
3917   return true;
3918 }
3919
3920 bool cmMakefile::EnforceUniqueDir(const std::string& srcPath,
3921                                   const std::string& binPath) const
3922 {
3923   // Make sure the binary directory is unique.
3924   cmGlobalGenerator* gg = this->GetGlobalGenerator();
3925   if (gg->BinaryDirectoryIsNew(binPath)) {
3926     return true;
3927   }
3928   std::ostringstream e;
3929   switch (this->GetPolicyStatus(cmPolicies::CMP0013)) {
3930     case cmPolicies::WARN:
3931       // Print the warning.
3932       /* clang-format off */
3933       e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0013)
3934         << "\n"
3935         << "The binary directory\n"
3936         << "  " << binPath << "\n"
3937         << "is already used to build a source directory.  "
3938         << "This command uses it to build source directory\n"
3939         << "  " << srcPath << "\n"
3940         << "which can generate conflicting build files.  "
3941         << "CMake does not support this use case but it used "
3942         << "to work accidentally and is being allowed for "
3943         << "compatibility.";
3944       /* clang-format on */
3945       this->IssueMessage(cmake::AUTHOR_WARNING, e.str());
3946       CM_FALLTHROUGH;
3947     case cmPolicies::OLD:
3948       // OLD behavior does not warn.
3949       return true;
3950     case cmPolicies::REQUIRED_IF_USED:
3951     case cmPolicies::REQUIRED_ALWAYS:
3952       e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0013) << "\n";
3953       CM_FALLTHROUGH;
3954     case cmPolicies::NEW:
3955       // NEW behavior prints the error.
3956       /* clang-format off */
3957       e << "The binary directory\n"
3958         << "  " << binPath << "\n"
3959         << "is already used to build a source directory.  "
3960         << "It cannot be used to build source directory\n"
3961         << "  " << srcPath << "\n"
3962         << "Specify a unique binary directory name.";
3963       /* clang-format on */
3964       this->IssueMessage(cmake::FATAL_ERROR, e.str());
3965       break;
3966   }
3967
3968   return false;
3969 }
3970
3971 static std::string const matchVariables[] = {
3972   "CMAKE_MATCH_0", "CMAKE_MATCH_1", "CMAKE_MATCH_2", "CMAKE_MATCH_3",
3973   "CMAKE_MATCH_4", "CMAKE_MATCH_5", "CMAKE_MATCH_6", "CMAKE_MATCH_7",
3974   "CMAKE_MATCH_8", "CMAKE_MATCH_9"
3975 };
3976
3977 static std::string const nMatchesVariable = "CMAKE_MATCH_COUNT";
3978
3979 void cmMakefile::ClearMatches()
3980 {
3981   const char* nMatchesStr = this->GetDefinition(nMatchesVariable);
3982   if (!nMatchesStr) {
3983     return;
3984   }
3985   int nMatches = atoi(nMatchesStr);
3986   for (int i = 0; i <= nMatches; i++) {
3987     std::string const& var = matchVariables[i];
3988     std::string const& s = this->GetSafeDefinition(var);
3989     if (!s.empty()) {
3990       this->AddDefinition(var, "");
3991       this->MarkVariableAsUsed(var);
3992     }
3993   }
3994   this->AddDefinition(nMatchesVariable, "0");
3995   this->MarkVariableAsUsed(nMatchesVariable);
3996 }
3997
3998 void cmMakefile::StoreMatches(cmsys::RegularExpression& re)
3999 {
4000   char highest = 0;
4001   for (int i = 0; i < 10; i++) {
4002     std::string const& m = re.match(i);
4003     if (!m.empty()) {
4004       std::string const& var = matchVariables[i];
4005       this->AddDefinition(var, m.c_str());
4006       this->MarkVariableAsUsed(var);
4007       highest = static_cast<char>('0' + i);
4008     }
4009   }
4010   char nMatches[] = { highest, '\0' };
4011   this->AddDefinition(nMatchesVariable, nMatches);
4012   this->MarkVariableAsUsed(nMatchesVariable);
4013 }
4014
4015 cmStateSnapshot cmMakefile::GetStateSnapshot() const
4016 {
4017   return this->StateSnapshot;
4018 }
4019
4020 const char* cmMakefile::GetDefineFlagsCMP0059() const
4021 {
4022   return this->DefineFlagsOrig.c_str();
4023 }
4024
4025 cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(
4026   cmPolicies::PolicyID id) const
4027 {
4028   return this->StateSnapshot.GetPolicy(id);
4029 }
4030
4031 bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var)
4032 {
4033   // Check for an explicit CMAKE_POLICY_WARNING_CMP<NNNN> setting.
4034   if (const char* val = this->GetDefinition(var)) {
4035     return cmSystemTools::IsOn(val);
4036   }
4037   // Enable optional policy warnings with --debug-output, --trace,
4038   // or --trace-expand.
4039   cmake* cm = this->GetCMakeInstance();
4040   return cm->GetDebugOutput() || cm->GetTrace();
4041 }
4042
4043 bool cmMakefile::SetPolicy(const char* id, cmPolicies::PolicyStatus status)
4044 {
4045   cmPolicies::PolicyID pid;
4046   if (!cmPolicies::GetPolicyID(id, /* out */ pid)) {
4047     std::ostringstream e;
4048     e << "Policy \"" << id << "\" is not known to this version of CMake.";
4049     this->IssueMessage(cmake::FATAL_ERROR, e.str());
4050     return false;
4051   }
4052   return this->SetPolicy(pid, status);
4053 }
4054
4055 bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
4056                            cmPolicies::PolicyStatus status)
4057 {
4058   // A REQUIRED_ALWAYS policy may be set only to NEW.
4059   if (status != cmPolicies::NEW &&
4060       cmPolicies::GetPolicyStatus(id) == cmPolicies::REQUIRED_ALWAYS) {
4061     std::string msg = cmPolicies::GetRequiredAlwaysPolicyError(id);
4062     this->IssueMessage(cmake::FATAL_ERROR, msg);
4063     return false;
4064   }
4065
4066   // Deprecate old policies, especially those that require a lot
4067   // of code to maintain the old behavior.
4068   if (status == cmPolicies::OLD && id <= cmPolicies::CMP0054) {
4069     this->IssueMessage(cmake::DEPRECATION_WARNING,
4070                        cmPolicies::GetPolicyDeprecatedWarning(id));
4071   }
4072
4073   this->StateSnapshot.SetPolicy(id, status);
4074   return true;
4075 }
4076
4077 cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m)
4078   : Makefile(m)
4079 {
4080   this->Makefile->PushPolicy();
4081 }
4082
4083 cmMakefile::PolicyPushPop::~PolicyPushPop()
4084 {
4085   this->Makefile->PopPolicy();
4086 }
4087
4088 void cmMakefile::PushPolicy(bool weak, cmPolicies::PolicyMap const& pm)
4089 {
4090   this->StateSnapshot.PushPolicy(pm, weak);
4091 }
4092
4093 void cmMakefile::PopPolicy()
4094 {
4095   if (!this->StateSnapshot.PopPolicy()) {
4096     this->IssueMessage(cmake::FATAL_ERROR,
4097                        "cmake_policy POP without matching PUSH");
4098   }
4099 }
4100
4101 void cmMakefile::PopSnapshot(bool reportError)
4102 {
4103   // cmStateSnapshot manages nested policy scopes within it.
4104   // Since the scope corresponding to the snapshot is closing,
4105   // reject any still-open nested policy scopes with an error.
4106   while (!this->StateSnapshot.CanPopPolicyScope()) {
4107     if (reportError) {
4108       this->IssueMessage(cmake::FATAL_ERROR,
4109                          "cmake_policy PUSH without matching POP");
4110       reportError = false;
4111     }
4112     this->PopPolicy();
4113   }
4114
4115   this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot);
4116   assert(this->StateSnapshot.IsValid());
4117 }
4118
4119 bool cmMakefile::SetPolicyVersion(const char* version)
4120 {
4121   return cmPolicies::ApplyPolicyVersion(this, version);
4122 }
4123
4124 bool cmMakefile::HasCMP0054AlreadyBeenReported(
4125   cmListFileContext const& context) const
4126 {
4127   return !this->CMP0054ReportedIds.insert(context).second;
4128 }
4129
4130 void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm)
4131 {
4132   /* Record the setting of every policy.  */
4133   typedef cmPolicies::PolicyID PolicyID;
4134   for (PolicyID pid = cmPolicies::CMP0000; pid != cmPolicies::CMPCOUNT;
4135        pid = PolicyID(pid + 1)) {
4136     pm.Set(pid, this->GetPolicyStatus(pid));
4137   }
4138 }
4139
4140 bool cmMakefile::IgnoreErrorsCMP0061() const
4141 {
4142   bool ignoreErrors = true;
4143   switch (this->GetPolicyStatus(cmPolicies::CMP0061)) {
4144     case cmPolicies::WARN:
4145     // No warning for this policy!
4146     case cmPolicies::OLD:
4147       break;
4148     case cmPolicies::REQUIRED_IF_USED:
4149     case cmPolicies::REQUIRED_ALWAYS:
4150     case cmPolicies::NEW:
4151       ignoreErrors = false;
4152       break;
4153   }
4154   return ignoreErrors;
4155 }
4156
4157 #define FEATURE_STRING(F) , #F
4158 static const char* const C_FEATURES[] = { nullptr FOR_EACH_C_FEATURE(
4159   FEATURE_STRING) };
4160
4161 static const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE(
4162   FEATURE_STRING) };
4163 #undef FEATURE_STRING
4164
4165 static const char* const C_STANDARDS[] = { "90", "99", "11" };
4166 static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17" };
4167
4168 bool cmMakefile::AddRequiredTargetFeature(cmTarget* target,
4169                                           const std::string& feature,
4170                                           std::string* error) const
4171 {
4172   if (cmGeneratorExpression::Find(feature) != std::string::npos) {
4173     target->AppendProperty("COMPILE_FEATURES", feature.c_str());
4174     return true;
4175   }
4176
4177   std::string lang;
4178   if (!this->CompileFeatureKnown(target, feature, lang, error)) {
4179     return false;
4180   }
4181
4182   const char* features = this->CompileFeaturesAvailable(lang, error);
4183   if (!features) {
4184     return false;
4185   }
4186
4187   std::vector<std::string> availableFeatures;
4188   cmSystemTools::ExpandListArgument(features, availableFeatures);
4189   if (std::find(availableFeatures.begin(), availableFeatures.end(), feature) ==
4190       availableFeatures.end()) {
4191     std::ostringstream e;
4192     e << "The compiler feature \"" << feature << "\" is not known to " << lang
4193       << " compiler\n\""
4194       << this->GetDefinition("CMAKE_" + lang + "_COMPILER_ID")
4195       << "\"\nversion "
4196       << this->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << ".";
4197     if (error) {
4198       *error = e.str();
4199     } else {
4200       this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
4201                                              this->Backtrace);
4202     }
4203     return false;
4204   }
4205
4206   target->AppendProperty("COMPILE_FEATURES", feature.c_str());
4207
4208   return lang == "C"
4209     ? this->AddRequiredTargetCFeature(target, feature, error)
4210     : this->AddRequiredTargetCxxFeature(target, feature, error);
4211 }
4212
4213 bool cmMakefile::CompileFeatureKnown(cmTarget const* target,
4214                                      const std::string& feature,
4215                                      std::string& lang,
4216                                      std::string* error) const
4217 {
4218   assert(cmGeneratorExpression::Find(feature) == std::string::npos);
4219
4220   bool isCFeature =
4221     std::find_if(cm::cbegin(C_FEATURES) + 1, cm::cend(C_FEATURES),
4222                  cmStrCmp(feature)) != cm::cend(C_FEATURES);
4223   if (isCFeature) {
4224     lang = "C";
4225     return true;
4226   }
4227   bool isCxxFeature =
4228     std::find_if(cm::cbegin(CXX_FEATURES) + 1, cm::cend(CXX_FEATURES),
4229                  cmStrCmp(feature)) != cm::cend(CXX_FEATURES);
4230   if (isCxxFeature) {
4231     lang = "CXX";
4232     return true;
4233   }
4234   std::ostringstream e;
4235   if (error) {
4236     e << "specified";
4237   } else {
4238     e << "Specified";
4239   }
4240   e << " unknown feature \"" << feature << "\" for "
4241                                            "target \""
4242     << target->GetName() << "\".";
4243   if (error) {
4244     *error = e.str();
4245   } else {
4246     this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
4247                                            this->Backtrace);
4248   }
4249   return false;
4250 }
4251
4252 const char* cmMakefile::CompileFeaturesAvailable(const std::string& lang,
4253                                                  std::string* error) const
4254 {
4255   if (!this->GlobalGenerator->GetLanguageEnabled(lang)) {
4256     std::ostringstream e;
4257     if (error) {
4258       e << "cannot";
4259     } else {
4260       e << "Cannot";
4261     }
4262     e << " use features from non-enabled language " << lang;
4263     if (error) {
4264       *error = e.str();
4265     } else {
4266       this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
4267                                              this->Backtrace);
4268     }
4269     return nullptr;
4270   }
4271
4272   const char* featuresKnown =
4273     this->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
4274
4275   if (!featuresKnown || !*featuresKnown) {
4276     std::ostringstream e;
4277     if (error) {
4278       e << "no";
4279     } else {
4280       e << "No";
4281     }
4282     e << " known features for " << lang << " compiler\n\""
4283       << this->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID")
4284       << "\"\nversion "
4285       << this->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_VERSION") << ".";
4286     if (error) {
4287       *error = e.str();
4288     } else {
4289       this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
4290                                              this->Backtrace);
4291     }
4292     return nullptr;
4293   }
4294   return featuresKnown;
4295 }
4296
4297 bool cmMakefile::HaveStandardAvailable(cmTarget const* target,
4298                                        std::string const& lang,
4299                                        const std::string& feature) const
4300 {
4301   return lang == "C" ? this->HaveCStandardAvailable(target, feature)
4302                      : this->HaveCxxStandardAvailable(target, feature);
4303 }
4304
4305 bool cmMakefile::HaveCStandardAvailable(cmTarget const* target,
4306                                         const std::string& feature) const
4307 {
4308   const char* defaultCStandard =
4309     this->GetDefinition("CMAKE_C_STANDARD_DEFAULT");
4310   if (!defaultCStandard) {
4311     std::ostringstream e;
4312     e << "CMAKE_C_STANDARD_DEFAULT is not set.  COMPILE_FEATURES support "
4313          "not fully configured for this compiler.";
4314     this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
4315     // Return true so the caller does not try to lookup the default standard.
4316     return true;
4317   }
4318   if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS),
4319                    cmStrCmp(defaultCStandard)) == cm::cend(C_STANDARDS)) {
4320     std::ostringstream e;
4321     e << "The CMAKE_C_STANDARD_DEFAULT variable contains an "
4322          "invalid value: \""
4323       << defaultCStandard << "\".";
4324     this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
4325     return false;
4326   }
4327
4328   bool needC90 = false;
4329   bool needC99 = false;
4330   bool needC11 = false;
4331
4332   this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
4333
4334   const char* existingCStandard = target->GetProperty("C_STANDARD");
4335   if (!existingCStandard) {
4336     existingCStandard = defaultCStandard;
4337   }
4338
4339   if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS),
4340                    cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) {
4341     std::ostringstream e;
4342     e << "The C_STANDARD property on target \"" << target->GetName()
4343       << "\" contained an invalid value: \"" << existingCStandard << "\".";
4344     this->IssueMessage(cmake::FATAL_ERROR, e.str());
4345     return false;
4346   }
4347
4348   const char* const* existingCIt = existingCStandard
4349     ? std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS),
4350                    cmStrCmp(existingCStandard))
4351     : cm::cend(C_STANDARDS);
4352
4353   if (needC11 && existingCStandard &&
4354       existingCIt < std::find_if(cm::cbegin(C_STANDARDS),
4355                                  cm::cend(C_STANDARDS), cmStrCmp("11"))) {
4356     return false;
4357   }
4358   if (needC99 && existingCStandard &&
4359       existingCIt < std::find_if(cm::cbegin(C_STANDARDS),
4360                                  cm::cend(C_STANDARDS), cmStrCmp("99"))) {
4361     return false;
4362   }
4363   if (needC90 && existingCStandard &&
4364       existingCIt < std::find_if(cm::cbegin(C_STANDARDS),
4365                                  cm::cend(C_STANDARDS), cmStrCmp("90"))) {
4366     return false;
4367   }
4368   return true;
4369 }
4370
4371 bool cmMakefile::IsLaterStandard(std::string const& lang,
4372                                  std::string const& lhs,
4373                                  std::string const& rhs)
4374 {
4375   if (lang == "C") {
4376     const char* const* rhsIt = std::find_if(
4377       cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(rhs));
4378
4379     return std::find_if(rhsIt, cm::cend(C_STANDARDS), cmStrCmp(lhs)) !=
4380       cm::cend(C_STANDARDS);
4381   }
4382   const char* const* rhsIt = std::find_if(
4383     cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(rhs));
4384
4385   return std::find_if(rhsIt, cm::cend(CXX_STANDARDS), cmStrCmp(lhs)) !=
4386     cm::cend(CXX_STANDARDS);
4387 }
4388
4389 bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target,
4390                                           const std::string& feature) const
4391 {
4392   const char* defaultCxxStandard =
4393     this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
4394   if (!defaultCxxStandard) {
4395     std::ostringstream e;
4396     e << "CMAKE_CXX_STANDARD_DEFAULT is not set.  COMPILE_FEATURES support "
4397          "not fully configured for this compiler.";
4398     this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
4399     // Return true so the caller does not try to lookup the default standard.
4400     return true;
4401   }
4402   if (std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS),
4403                    cmStrCmp(defaultCxxStandard)) == cm::cend(CXX_STANDARDS)) {
4404     std::ostringstream e;
4405     e << "The CMAKE_CXX_STANDARD_DEFAULT variable contains an "
4406          "invalid value: \""
4407       << defaultCxxStandard << "\".";
4408     this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
4409     return false;
4410   }
4411
4412   bool needCxx98 = false;
4413   bool needCxx11 = false;
4414   bool needCxx14 = false;
4415   bool needCxx17 = false;
4416   this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14,
4417                                needCxx17);
4418
4419   const char* existingCxxStandard = target->GetProperty("CXX_STANDARD");
4420   if (!existingCxxStandard) {
4421     existingCxxStandard = defaultCxxStandard;
4422   }
4423
4424   const char* const* existingCxxLevel =
4425     std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS),
4426                  cmStrCmp(existingCxxStandard));
4427   if (existingCxxLevel == cm::cend(CXX_STANDARDS)) {
4428     std::ostringstream e;
4429     e << "The CXX_STANDARD property on target \"" << target->GetName()
4430       << "\" contained an invalid value: \"" << existingCxxStandard << "\".";
4431     this->IssueMessage(cmake::FATAL_ERROR, e.str());
4432     return false;
4433   }
4434
4435   /* clang-format off */
4436   const char* const* needCxxLevel =
4437     needCxx17 ? &CXX_STANDARDS[3]
4438     : needCxx14 ? &CXX_STANDARDS[2]
4439     : needCxx11 ? &CXX_STANDARDS[1]
4440     : needCxx98 ? &CXX_STANDARDS[0]
4441     : nullptr;
4442   /* clang-format on */
4443
4444   return !needCxxLevel || needCxxLevel <= existingCxxLevel;
4445 }
4446
4447 void cmMakefile::CheckNeededCxxLanguage(const std::string& feature,
4448                                         bool& needCxx98, bool& needCxx11,
4449                                         bool& needCxx14, bool& needCxx17) const
4450 {
4451   if (const char* propCxx98 =
4452         this->GetDefinition("CMAKE_CXX98_COMPILE_FEATURES")) {
4453     std::vector<std::string> props;
4454     cmSystemTools::ExpandListArgument(propCxx98, props);
4455     needCxx98 = std::find(props.begin(), props.end(), feature) != props.end();
4456   }
4457   if (const char* propCxx11 =
4458         this->GetDefinition("CMAKE_CXX11_COMPILE_FEATURES")) {
4459     std::vector<std::string> props;
4460     cmSystemTools::ExpandListArgument(propCxx11, props);
4461     needCxx11 = std::find(props.begin(), props.end(), feature) != props.end();
4462   }
4463   if (const char* propCxx14 =
4464         this->GetDefinition("CMAKE_CXX14_COMPILE_FEATURES")) {
4465     std::vector<std::string> props;
4466     cmSystemTools::ExpandListArgument(propCxx14, props);
4467     needCxx14 = std::find(props.begin(), props.end(), feature) != props.end();
4468   }
4469   if (const char* propCxx17 =
4470         this->GetDefinition("CMAKE_CXX17_COMPILE_FEATURES")) {
4471     std::vector<std::string> props;
4472     cmSystemTools::ExpandListArgument(propCxx17, props);
4473     needCxx17 = std::find(props.begin(), props.end(), feature) != props.end();
4474   }
4475 }
4476
4477 bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target,
4478                                              const std::string& feature,
4479                                              std::string* error) const
4480 {
4481   bool needCxx98 = false;
4482   bool needCxx11 = false;
4483   bool needCxx14 = false;
4484   bool needCxx17 = false;
4485
4486   this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14,
4487                                needCxx17);
4488
4489   const char* existingCxxStandard = target->GetProperty("CXX_STANDARD");
4490   const char* const* existingCxxLevel = nullptr;
4491   if (existingCxxStandard) {
4492     existingCxxLevel =
4493       std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS),
4494                    cmStrCmp(existingCxxStandard));
4495     if (existingCxxLevel == cm::cend(CXX_STANDARDS)) {
4496       std::ostringstream e;
4497       e << "The CXX_STANDARD property on target \"" << target->GetName()
4498         << "\" contained an invalid value: \"" << existingCxxStandard << "\".";
4499       if (error) {
4500         *error = e.str();
4501       } else {
4502         this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
4503                                                this->Backtrace);
4504       }
4505       return false;
4506     }
4507   }
4508
4509   const char* existingCudaStandard = target->GetProperty("CUDA_STANDARD");
4510   const char* const* existingCudaLevel = nullptr;
4511   if (existingCudaStandard) {
4512     existingCudaLevel =
4513       std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS),
4514                    cmStrCmp(existingCudaStandard));
4515     if (existingCudaLevel == cm::cend(CXX_STANDARDS)) {
4516       std::ostringstream e;
4517       e << "The CUDA_STANDARD property on target \"" << target->GetName()
4518         << "\" contained an invalid value: \"" << existingCudaStandard
4519         << "\".";
4520       if (error) {
4521         *error = e.str();
4522       } else {
4523         this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
4524                                                this->Backtrace);
4525       }
4526       return false;
4527     }
4528   }
4529
4530   /* clang-format off */
4531   const char* const* needCxxLevel =
4532     needCxx17 ? &CXX_STANDARDS[3]
4533     : needCxx14 ? &CXX_STANDARDS[2]
4534     : needCxx11 ? &CXX_STANDARDS[1]
4535     : needCxx98 ? &CXX_STANDARDS[0]
4536     : nullptr;
4537   /* clang-format on */
4538
4539   if (needCxxLevel) {
4540     // Ensure the C++ language level is high enough to support
4541     // the needed C++ features.
4542     if (!existingCxxLevel || existingCxxLevel < needCxxLevel) {
4543       target->SetProperty("CXX_STANDARD", *needCxxLevel);
4544     }
4545
4546     // Ensure the CUDA language level is high enough to support
4547     // the needed C++ features.
4548     if (!existingCudaLevel || existingCudaLevel < needCxxLevel) {
4549       target->SetProperty("CUDA_STANDARD", *needCxxLevel);
4550     }
4551   }
4552
4553   return true;
4554 }
4555
4556 void cmMakefile::CheckNeededCLanguage(const std::string& feature,
4557                                       bool& needC90, bool& needC99,
4558                                       bool& needC11) const
4559 {
4560   if (const char* propC90 =
4561         this->GetDefinition("CMAKE_C90_COMPILE_FEATURES")) {
4562     std::vector<std::string> props;
4563     cmSystemTools::ExpandListArgument(propC90, props);
4564     needC90 = std::find(props.begin(), props.end(), feature) != props.end();
4565   }
4566   if (const char* propC99 =
4567         this->GetDefinition("CMAKE_C99_COMPILE_FEATURES")) {
4568     std::vector<std::string> props;
4569     cmSystemTools::ExpandListArgument(propC99, props);
4570     needC99 = std::find(props.begin(), props.end(), feature) != props.end();
4571   }
4572   if (const char* propC11 =
4573         this->GetDefinition("CMAKE_C11_COMPILE_FEATURES")) {
4574     std::vector<std::string> props;
4575     cmSystemTools::ExpandListArgument(propC11, props);
4576     needC11 = std::find(props.begin(), props.end(), feature) != props.end();
4577   }
4578 }
4579
4580 bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target,
4581                                            const std::string& feature,
4582                                            std::string* error) const
4583 {
4584   bool needC90 = false;
4585   bool needC99 = false;
4586   bool needC11 = false;
4587
4588   this->CheckNeededCLanguage(feature, needC90, needC99, needC11);
4589
4590   const char* existingCStandard = target->GetProperty("C_STANDARD");
4591   if (existingCStandard) {
4592     if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS),
4593                      cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) {
4594       std::ostringstream e;
4595       e << "The C_STANDARD property on target \"" << target->GetName()
4596         << "\" contained an invalid value: \"" << existingCStandard << "\".";
4597       if (error) {
4598         *error = e.str();
4599       } else {
4600         this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
4601                                                this->Backtrace);
4602       }
4603       return false;
4604     }
4605   }
4606   const char* const* existingCIt = existingCStandard
4607     ? std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS),
4608                    cmStrCmp(existingCStandard))
4609     : cm::cend(C_STANDARDS);
4610
4611   bool setC90 = needC90 && !existingCStandard;
4612   bool setC99 = needC99 && !existingCStandard;
4613   bool setC11 = needC11 && !existingCStandard;
4614
4615   if (needC11 && existingCStandard &&
4616       existingCIt < std::find_if(cm::cbegin(C_STANDARDS),
4617                                  cm::cend(C_STANDARDS), cmStrCmp("11"))) {
4618     setC11 = true;
4619   } else if (needC99 && existingCStandard &&
4620              existingCIt < std::find_if(cm::cbegin(C_STANDARDS),
4621                                         cm::cend(C_STANDARDS),
4622                                         cmStrCmp("99"))) {
4623     setC99 = true;
4624   } else if (needC90 && existingCStandard &&
4625              existingCIt < std::find_if(cm::cbegin(C_STANDARDS),
4626                                         cm::cend(C_STANDARDS),
4627                                         cmStrCmp("90"))) {
4628     setC90 = true;
4629   }
4630
4631   if (setC11) {
4632     target->SetProperty("C_STANDARD", "11");
4633   } else if (setC99) {
4634     target->SetProperty("C_STANDARD", "99");
4635   } else if (setC90) {
4636     target->SetProperty("C_STANDARD", "90");
4637   }
4638   return true;
4639 }
4640
4641 cmMakefile::FunctionPushPop::FunctionPushPop(cmMakefile* mf,
4642                                              const std::string& fileName,
4643                                              cmPolicies::PolicyMap const& pm)
4644   : Makefile(mf)
4645   , ReportError(true)
4646 {
4647   this->Makefile->PushFunctionScope(fileName, pm);
4648 }
4649
4650 cmMakefile::FunctionPushPop::~FunctionPushPop()
4651 {
4652   this->Makefile->PopFunctionScope(this->ReportError);
4653 }
4654
4655 cmMakefile::MacroPushPop::MacroPushPop(cmMakefile* mf,
4656                                        const std::string& fileName,
4657                                        const cmPolicies::PolicyMap& pm)
4658   : Makefile(mf)
4659   , ReportError(true)
4660 {
4661   this->Makefile->PushMacroScope(fileName, pm);
4662 }
4663
4664 cmMakefile::MacroPushPop::~MacroPushPop()
4665 {
4666   this->Makefile->PopMacroScope(this->ReportError);
4667 }