cf6802db76ffdef8fe3285e60cec5c54005906ed
[platform/upstream/cmake.git] / Source / cmLocalGenerator.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 "cmLocalGenerator.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cstdio>
8 #include <cstdlib>
9 #include <cstring>
10 #include <initializer_list>
11 #include <iterator>
12 #include <sstream>
13 #include <unordered_set>
14 #include <utility>
15 #include <vector>
16
17 #include <cm/memory>
18 #include <cm/string_view>
19 #include <cmext/algorithm>
20
21 #include "cmsys/RegularExpression.hxx"
22
23 #include "cmAlgorithms.h"
24 #include "cmComputeLinkInformation.h"
25 #include "cmCustomCommand.h"
26 #include "cmCustomCommandGenerator.h"
27 #include "cmCustomCommandLines.h"
28 #include "cmCustomCommandTypes.h"
29 #include "cmGeneratedFileStream.h"
30 #include "cmGeneratorExpression.h"
31 #include "cmGeneratorExpressionEvaluationFile.h"
32 #include "cmGeneratorTarget.h"
33 #include "cmGlobalGenerator.h"
34 #include "cmInstallGenerator.h"
35 #include "cmInstallScriptGenerator.h"
36 #include "cmInstallTargetGenerator.h"
37 #include "cmLinkLineComputer.h"
38 #include "cmLinkLineDeviceComputer.h"
39 #include "cmMakefile.h"
40 #include "cmRulePlaceholderExpander.h"
41 #include "cmSourceFile.h"
42 #include "cmSourceFileLocation.h"
43 #include "cmSourceFileLocationKind.h"
44 #include "cmState.h"
45 #include "cmStateDirectory.h"
46 #include "cmStateTypes.h"
47 #include "cmStringAlgorithms.h"
48 #include "cmSystemTools.h"
49 #include "cmTarget.h"
50 #include "cmTestGenerator.h"
51 #include "cmVersion.h"
52 #include "cmake.h"
53
54 #if !defined(CMAKE_BOOTSTRAP)
55 #  define CM_LG_ENCODE_OBJECT_NAMES
56 #  include "cmCryptoHash.h"
57 #endif
58
59 #if defined(__HAIKU__)
60 #  include <FindDirectory.h>
61 #  include <StorageDefs.h>
62 #endif
63
64 // List of variables that are replaced when
65 // rules are expanced.  These variables are
66 // replaced in the form <var> with GetSafeDefinition(var).
67 // ${LANG} is replaced in the variable first with all enabled
68 // languages.
69 static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
70                                 "CMAKE_SHARED_LIBRARY_CREATE_${LANG}_FLAGS",
71                                 "CMAKE_SHARED_MODULE_CREATE_${LANG}_FLAGS",
72                                 "CMAKE_SHARED_MODULE_${LANG}_FLAGS",
73                                 "CMAKE_SHARED_LIBRARY_${LANG}_FLAGS",
74                                 "CMAKE_${LANG}_LINK_FLAGS",
75                                 "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
76                                 "CMAKE_${LANG}_ARCHIVE",
77                                 "CMAKE_AR",
78                                 "CMAKE_CURRENT_SOURCE_DIR",
79                                 "CMAKE_CURRENT_BINARY_DIR",
80                                 "CMAKE_RANLIB",
81                                 "CMAKE_LINKER",
82                                 "CMAKE_MT",
83                                 "CMAKE_CUDA_HOST_COMPILER",
84                                 "CMAKE_CUDA_HOST_LINK_LAUNCHER",
85                                 "CMAKE_CL_SHOWINCLUDES_PREFIX" };
86
87 cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
88   : cmOutputConverter(makefile->GetStateSnapshot())
89   , StateSnapshot(makefile->GetStateSnapshot())
90   , DirectoryBacktrace(makefile->GetBacktrace())
91 {
92   this->GlobalGenerator = gg;
93
94   this->Makefile = makefile;
95
96   this->AliasTargets = makefile->GetAliasTargets();
97
98   this->EmitUniversalBinaryFlags = true;
99   this->BackwardsCompatibility = 0;
100   this->BackwardsCompatibilityFinal = false;
101
102   this->ComputeObjectMaxPath();
103
104   // Canonicalize entries of the CPATH environment variable the same
105   // way detection of CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES does.
106   {
107     std::vector<std::string> cpath;
108     cmSystemTools::GetPath(cpath, "CPATH");
109     for (std::string& cp : cpath) {
110       if (cmSystemTools::FileIsFullPath(cp)) {
111         cp = cmSystemTools::CollapseFullPath(cp);
112         this->EnvCPATH.emplace(std::move(cp));
113       }
114     }
115   }
116
117   std::vector<std::string> enabledLanguages =
118     this->GetState()->GetEnabledLanguages();
119
120   if (const char* sysrootCompile =
121         this->Makefile->GetDefinition("CMAKE_SYSROOT_COMPILE")) {
122     this->CompilerSysroot = sysrootCompile;
123   } else {
124     this->CompilerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
125   }
126
127   if (const char* sysrootLink =
128         this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
129     this->LinkerSysroot = sysrootLink;
130   } else {
131     this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
132   }
133
134   for (std::string const& lang : enabledLanguages) {
135     if (lang == "NONE") {
136       continue;
137     }
138     this->Compilers["CMAKE_" + lang + "_COMPILER"] = lang;
139
140     this->VariableMappings["CMAKE_" + lang + "_COMPILER"] =
141       this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER");
142
143     std::string const& compilerArg1 = "CMAKE_" + lang + "_COMPILER_ARG1";
144     std::string const& compilerTarget = "CMAKE_" + lang + "_COMPILER_TARGET";
145     std::string const& compilerOptionTarget =
146       "CMAKE_" + lang + "_COMPILE_OPTIONS_TARGET";
147     std::string const& compilerExternalToolchain =
148       "CMAKE_" + lang + "_COMPILER_EXTERNAL_TOOLCHAIN";
149     std::string const& compilerOptionExternalToolchain =
150       "CMAKE_" + lang + "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN";
151     std::string const& compilerOptionSysroot =
152       "CMAKE_" + lang + "_COMPILE_OPTIONS_SYSROOT";
153
154     this->VariableMappings[compilerArg1] =
155       this->Makefile->GetSafeDefinition(compilerArg1);
156     this->VariableMappings[compilerTarget] =
157       this->Makefile->GetSafeDefinition(compilerTarget);
158     this->VariableMappings[compilerOptionTarget] =
159       this->Makefile->GetSafeDefinition(compilerOptionTarget);
160     this->VariableMappings[compilerExternalToolchain] =
161       this->Makefile->GetSafeDefinition(compilerExternalToolchain);
162     this->VariableMappings[compilerOptionExternalToolchain] =
163       this->Makefile->GetSafeDefinition(compilerOptionExternalToolchain);
164     this->VariableMappings[compilerOptionSysroot] =
165       this->Makefile->GetSafeDefinition(compilerOptionSysroot);
166
167     for (std::string replaceVar : ruleReplaceVars) {
168       if (replaceVar.find("${LANG}") != std::string::npos) {
169         cmSystemTools::ReplaceString(replaceVar, "${LANG}", lang);
170       }
171
172       this->VariableMappings[replaceVar] =
173         this->Makefile->GetSafeDefinition(replaceVar);
174     }
175   }
176 }
177
178 cmRulePlaceholderExpander* cmLocalGenerator::CreateRulePlaceholderExpander()
179   const
180 {
181   return new cmRulePlaceholderExpander(this->Compilers, this->VariableMappings,
182                                        this->CompilerSysroot,
183                                        this->LinkerSysroot);
184 }
185
186 cmLocalGenerator::~cmLocalGenerator() = default;
187
188 void cmLocalGenerator::IssueMessage(MessageType t,
189                                     std::string const& text) const
190 {
191   this->GetCMakeInstance()->IssueMessage(t, text, this->DirectoryBacktrace);
192 }
193
194 void cmLocalGenerator::ComputeObjectMaxPath()
195 {
196 // Choose a maximum object file name length.
197 #if defined(_WIN32) || defined(__CYGWIN__)
198   this->ObjectPathMax = 250;
199 #else
200   this->ObjectPathMax = 1000;
201 #endif
202   const char* plen = this->Makefile->GetDefinition("CMAKE_OBJECT_PATH_MAX");
203   if (plen && *plen) {
204     unsigned int pmax;
205     if (sscanf(plen, "%u", &pmax) == 1) {
206       if (pmax >= 128) {
207         this->ObjectPathMax = pmax;
208       } else {
209         std::ostringstream w;
210         w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax
211           << ", which is less than the minimum of 128.  "
212           << "The value will be ignored.";
213         this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
214       }
215     } else {
216       std::ostringstream w;
217       w << "CMAKE_OBJECT_PATH_MAX is set to \"" << plen
218         << "\", which fails to parse as a positive integer.  "
219         << "The value will be ignored.";
220       this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
221     }
222   }
223   this->ObjectMaxPathViolations.clear();
224 }
225
226 static void MoveSystemIncludesToEnd(std::vector<std::string>& includeDirs,
227                                     const std::string& config,
228                                     const std::string& lang,
229                                     const cmGeneratorTarget* target)
230 {
231   if (!target) {
232     return;
233   }
234
235   std::stable_sort(
236     includeDirs.begin(), includeDirs.end(),
237     [&target, &config, &lang](std::string const& a, std::string const& b) {
238       return !target->IsSystemIncludeDirectory(a, config, lang) &&
239         target->IsSystemIncludeDirectory(b, config, lang);
240     });
241 }
242
243 static void MoveSystemIncludesToEnd(std::vector<BT<std::string>>& includeDirs,
244                                     const std::string& config,
245                                     const std::string& lang,
246                                     const cmGeneratorTarget* target)
247 {
248   if (!target) {
249     return;
250   }
251
252   std::stable_sort(includeDirs.begin(), includeDirs.end(),
253                    [target, &config, &lang](BT<std::string> const& a,
254                                             BT<std::string> const& b) {
255                      return !target->IsSystemIncludeDirectory(a.Value, config,
256                                                               lang) &&
257                        target->IsSystemIncludeDirectory(b.Value, config, lang);
258                    });
259 }
260
261 void cmLocalGenerator::TraceDependencies()
262 {
263   // Generate the rule files for each target.
264   const auto& targets = this->GetGeneratorTargets();
265   for (const auto& target : targets) {
266     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
267       continue;
268     }
269     target->TraceDependencies();
270   }
271 }
272
273 void cmLocalGenerator::GenerateTestFiles()
274 {
275   if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) {
276     return;
277   }
278
279   // Compute the set of configurations.
280   std::vector<std::string> configurationTypes;
281   const std::string& config =
282     this->Makefile->GetConfigurations(configurationTypes, false);
283
284   std::string file =
285     cmStrCat(this->StateSnapshot.GetDirectory().GetCurrentBinary(),
286              "/CTestTestfile.cmake");
287
288   cmGeneratedFileStream fout(file);
289   fout.SetCopyIfDifferent(true);
290
291   fout << "# CMake generated Testfile for " << std::endl
292        << "# Source directory: "
293        << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
294        << "# Build directory: "
295        << this->StateSnapshot.GetDirectory().GetCurrentBinary() << std::endl
296        << "# " << std::endl
297        << "# This file includes the relevant testing commands "
298        << "required for " << std::endl
299        << "# testing this directory and lists subdirectories to "
300        << "be tested as well." << std::endl;
301
302   const char* testIncludeFile =
303     this->Makefile->GetProperty("TEST_INCLUDE_FILE");
304   if (testIncludeFile) {
305     fout << "include(\"" << testIncludeFile << "\")" << std::endl;
306   }
307
308   const char* testIncludeFiles =
309     this->Makefile->GetProperty("TEST_INCLUDE_FILES");
310   if (testIncludeFiles) {
311     std::vector<std::string> includesList = cmExpandedList(testIncludeFiles);
312     for (std::string const& i : includesList) {
313       fout << "include(\"" << i << "\")" << std::endl;
314     }
315   }
316
317   // Ask each test generator to write its code.
318   for (const auto& tester : this->Makefile->GetTestGenerators()) {
319     tester->Compute(this);
320     tester->Generate(fout, config, configurationTypes);
321   }
322   using vec_t = std::vector<cmStateSnapshot>;
323   vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren();
324   std::string parentBinDir = this->GetCurrentBinaryDirectory();
325   for (cmStateSnapshot const& i : children) {
326     // TODO: Use add_subdirectory instead?
327     std::string outP = i.GetDirectory().GetCurrentBinary();
328     outP = this->MaybeConvertToRelativePath(parentBinDir, outP);
329     outP = cmOutputConverter::EscapeForCMake(outP);
330     fout << "subdirs(" << outP << ")" << std::endl;
331   }
332
333   // Add directory labels property
334   const char* directoryLabels =
335     this->Makefile->GetDefinition("CMAKE_DIRECTORY_LABELS");
336   const char* labels = this->Makefile->GetProperty("LABELS");
337
338   if (labels || directoryLabels) {
339     fout << "set_directory_properties(PROPERTIES LABELS ";
340     if (labels) {
341       fout << cmOutputConverter::EscapeForCMake(labels);
342     }
343     if (labels && directoryLabels) {
344       fout << ";";
345     }
346     if (directoryLabels) {
347       fout << cmOutputConverter::EscapeForCMake(directoryLabels);
348     }
349     fout << ")" << std::endl;
350   }
351 }
352
353 void cmLocalGenerator::CreateEvaluationFileOutputs()
354 {
355   std::vector<std::string> const& configs =
356     this->Makefile->GetGeneratorConfigs();
357   for (std::string const& c : configs) {
358     this->CreateEvaluationFileOutputs(c);
359   }
360 }
361
362 void cmLocalGenerator::CreateEvaluationFileOutputs(std::string const& config)
363 {
364   for (const auto& geef : this->Makefile->GetEvaluationFiles()) {
365     geef->CreateOutputFile(this, config);
366   }
367 }
368
369 void cmLocalGenerator::ProcessEvaluationFiles(
370   std::vector<std::string>& generatedFiles)
371 {
372   for (const auto& geef : this->Makefile->GetEvaluationFiles()) {
373     geef->Generate(this);
374     if (cmSystemTools::GetFatalErrorOccured()) {
375       return;
376     }
377     std::vector<std::string> files = geef->GetFiles();
378     std::sort(files.begin(), files.end());
379
380     std::vector<std::string> intersection;
381     std::set_intersection(files.begin(), files.end(), generatedFiles.begin(),
382                           generatedFiles.end(),
383                           std::back_inserter(intersection));
384     if (!intersection.empty()) {
385       cmSystemTools::Error("Files to be generated by multiple different "
386                            "commands: " +
387                            cmWrap('"', intersection, '"', " "));
388       return;
389     }
390
391     cm::append(generatedFiles, files);
392     std::inplace_merge(generatedFiles.begin(),
393                        generatedFiles.end() - files.size(),
394                        generatedFiles.end());
395   }
396 }
397
398 void cmLocalGenerator::GenerateInstallRules()
399 {
400   // Compute the install prefix.
401   const char* prefix = this->Makefile->GetDefinition("CMAKE_INSTALL_PREFIX");
402
403 #if defined(_WIN32) && !defined(__CYGWIN__)
404   std::string prefix_win32;
405   if (!prefix) {
406     if (!cmSystemTools::GetEnv("SystemDrive", prefix_win32)) {
407       prefix_win32 = "C:";
408     }
409     const char* project_name = this->Makefile->GetDefinition("PROJECT_NAME");
410     if (project_name && project_name[0]) {
411       prefix_win32 += "/Program Files/";
412       prefix_win32 += project_name;
413     } else {
414       prefix_win32 += "/InstalledCMakeProject";
415     }
416     prefix = prefix_win32.c_str();
417   }
418 #elif defined(__HAIKU__)
419   char dir[B_PATH_NAME_LENGTH];
420   if (!prefix) {
421     if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) ==
422         B_OK) {
423       prefix = dir;
424     } else {
425       prefix = "/boot/system";
426     }
427   }
428 #else
429   if (!prefix) {
430     prefix = "/usr/local";
431   }
432 #endif
433   if (const char* stagingPrefix =
434         this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX")) {
435     prefix = stagingPrefix;
436   }
437
438   // Compute the set of configurations.
439   std::vector<std::string> configurationTypes;
440   const std::string& config =
441     this->Makefile->GetConfigurations(configurationTypes, false);
442
443   // Choose a default install configuration.
444   std::string default_config = config;
445   const char* default_order[] = { "RELEASE", "MINSIZEREL", "RELWITHDEBINFO",
446                                   "DEBUG", nullptr };
447   for (const char** c = default_order; *c && default_config.empty(); ++c) {
448     for (std::string const& configurationType : configurationTypes) {
449       if (cmSystemTools::UpperCase(configurationType) == *c) {
450         default_config = configurationType;
451       }
452     }
453   }
454   if (default_config.empty() && !configurationTypes.empty()) {
455     default_config = configurationTypes[0];
456   }
457
458   // Create the install script file.
459   std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary();
460   std::string homedir = this->GetState()->GetBinaryDirectory();
461   int toplevel_install = 0;
462   if (file == homedir) {
463     toplevel_install = 1;
464   }
465   file += "/cmake_install.cmake";
466   cmGeneratedFileStream fout(file);
467   fout.SetCopyIfDifferent(true);
468
469   // Write the header.
470   fout << "# Install script for directory: "
471        << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
472        << std::endl;
473   fout << "# Set the install prefix" << std::endl
474        << "if(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
475        << "  set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
476        << "endif()" << std::endl
477        << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )"
478        << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
479        << std::endl;
480
481   // Write support code for generating per-configuration install rules.
482   /* clang-format off */
483   fout <<
484     "# Set the install configuration name.\n"
485     "if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n"
486     "  if(BUILD_TYPE)\n"
487     "    string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n"
488     "           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n"
489     "  else()\n"
490     "    set(CMAKE_INSTALL_CONFIG_NAME \"" << default_config << "\")\n"
491     "  endif()\n"
492     "  message(STATUS \"Install configuration: "
493     "\\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\n"
494     "endif()\n"
495     "\n";
496   /* clang-format on */
497
498   // Write support code for dealing with component-specific installs.
499   /* clang-format off */
500   fout <<
501     "# Set the component getting installed.\n"
502     "if(NOT CMAKE_INSTALL_COMPONENT)\n"
503     "  if(COMPONENT)\n"
504     "    message(STATUS \"Install component: \\\"${COMPONENT}\\\"\")\n"
505     "    set(CMAKE_INSTALL_COMPONENT \"${COMPONENT}\")\n"
506     "  else()\n"
507     "    set(CMAKE_INSTALL_COMPONENT)\n"
508     "  endif()\n"
509     "endif()\n"
510     "\n";
511   /* clang-format on */
512
513   // Copy user-specified install options to the install code.
514   if (const char* so_no_exe =
515         this->Makefile->GetDefinition("CMAKE_INSTALL_SO_NO_EXE")) {
516     /* clang-format off */
517     fout <<
518       "# Install shared libraries without execute permission?\n"
519       "if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n"
520       "  set(CMAKE_INSTALL_SO_NO_EXE \"" << so_no_exe << "\")\n"
521       "endif()\n"
522       "\n";
523     /* clang-format on */
524   }
525
526   // Copy cmake cross compile state to install code.
527   if (const char* crosscompiling =
528         this->Makefile->GetDefinition("CMAKE_CROSSCOMPILING")) {
529     /* clang-format off */
530     fout <<
531       "# Is this installation the result of a crosscompile?\n"
532       "if(NOT DEFINED CMAKE_CROSSCOMPILING)\n"
533       "  set(CMAKE_CROSSCOMPILING \"" << crosscompiling << "\")\n"
534       "endif()\n"
535       "\n";
536     /* clang-format on */
537   }
538
539   // Write default directory permissions.
540   if (const char* defaultDirPermissions = this->Makefile->GetDefinition(
541         "CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS")) {
542     /* clang-format off */
543     fout <<
544       "# Set default install directory permissions.\n"
545       "if(NOT DEFINED CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS)\n"
546       "  set(CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS \""
547          << defaultDirPermissions << "\")\n"
548       "endif()\n"
549       "\n";
550     /* clang-format on */
551   }
552
553   // Ask each install generator to write its code.
554   cmPolicies::PolicyStatus status = this->GetPolicyStatus(cmPolicies::CMP0082);
555   auto const& installers = this->Makefile->GetInstallGenerators();
556   bool haveSubdirectoryInstall = false;
557   bool haveInstallAfterSubdirectory = false;
558   if (status == cmPolicies::WARN) {
559     for (const auto& installer : installers) {
560       installer->CheckCMP0082(haveSubdirectoryInstall,
561                               haveInstallAfterSubdirectory);
562       installer->Generate(fout, config, configurationTypes);
563     }
564   } else {
565     for (const auto& installer : installers) {
566       installer->Generate(fout, config, configurationTypes);
567     }
568   }
569
570   // Write rules from old-style specification stored in targets.
571   this->GenerateTargetInstallRules(fout, config, configurationTypes);
572
573   // Include install scripts from subdirectories.
574   switch (status) {
575     case cmPolicies::WARN:
576       if (haveInstallAfterSubdirectory &&
577           this->Makefile->PolicyOptionalWarningEnabled(
578             "CMAKE_POLICY_WARNING_CMP0082")) {
579         std::ostringstream e;
580         e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0082) << "\n";
581         this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
582       }
583       CM_FALLTHROUGH;
584     case cmPolicies::OLD: {
585       std::vector<cmStateSnapshot> children =
586         this->Makefile->GetStateSnapshot().GetChildren();
587       if (!children.empty()) {
588         fout << "if(NOT CMAKE_INSTALL_LOCAL_ONLY)\n";
589         fout << "  # Include the install script for each subdirectory.\n";
590         for (cmStateSnapshot const& c : children) {
591           if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
592             std::string odir = c.GetDirectory().GetCurrentBinary();
593             cmSystemTools::ConvertToUnixSlashes(odir);
594             fout << "  include(\"" << odir << "/cmake_install.cmake\")"
595                  << std::endl;
596           }
597         }
598         fout << "\n";
599         fout << "endif()\n\n";
600       }
601     } break;
602
603     case cmPolicies::REQUIRED_IF_USED:
604     case cmPolicies::REQUIRED_ALWAYS:
605     case cmPolicies::NEW:
606       // NEW behavior is handled in
607       // cmInstallSubdirectoryGenerator::GenerateScript()
608       break;
609   }
610
611   // Record the install manifest.
612   if (toplevel_install) {
613     /* clang-format off */
614     fout <<
615       "if(CMAKE_INSTALL_COMPONENT)\n"
616       "  set(CMAKE_INSTALL_MANIFEST \"install_manifest_"
617       "${CMAKE_INSTALL_COMPONENT}.txt\")\n"
618       "else()\n"
619       "  set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\n"
620       "endif()\n"
621       "\n"
622       "string(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n"
623       "       \"${CMAKE_INSTALL_MANIFEST_FILES}\")\n"
624       "file(WRITE \"" << homedir << "/${CMAKE_INSTALL_MANIFEST}\"\n"
625       "     \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n";
626     /* clang-format on */
627   }
628 }
629
630 void cmLocalGenerator::AddGeneratorTarget(
631   std::unique_ptr<cmGeneratorTarget> gt)
632 {
633   cmGeneratorTarget* gt_ptr = gt.get();
634
635   this->GeneratorTargets.push_back(std::move(gt));
636   this->GeneratorTargetSearchIndex.emplace(gt_ptr->GetName(), gt_ptr);
637   this->GlobalGenerator->IndexGeneratorTarget(gt_ptr);
638 }
639
640 void cmLocalGenerator::AddImportedGeneratorTarget(cmGeneratorTarget* gt)
641 {
642   this->ImportedGeneratorTargets.emplace(gt->GetName(), gt);
643   this->GlobalGenerator->IndexGeneratorTarget(gt);
644 }
645
646 void cmLocalGenerator::AddOwnedImportedGeneratorTarget(
647   std::unique_ptr<cmGeneratorTarget> gt)
648 {
649   this->OwnedImportedGeneratorTargets.push_back(std::move(gt));
650 }
651
652 cmGeneratorTarget* cmLocalGenerator::FindLocalNonAliasGeneratorTarget(
653   const std::string& name) const
654 {
655   auto ti = this->GeneratorTargetSearchIndex.find(name);
656   if (ti != this->GeneratorTargetSearchIndex.end()) {
657     return ti->second;
658   }
659   return nullptr;
660 }
661
662 void cmLocalGenerator::ComputeTargetManifest()
663 {
664   // Collect the set of configuration types.
665   std::vector<std::string> configNames;
666   this->Makefile->GetConfigurations(configNames);
667   if (configNames.empty()) {
668     configNames.emplace_back();
669   }
670
671   // Add our targets to the manifest for each configuration.
672   const auto& targets = this->GetGeneratorTargets();
673   for (const auto& target : targets) {
674     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
675       continue;
676     }
677     for (std::string const& c : configNames) {
678       target->ComputeTargetManifest(c);
679     }
680   }
681 }
682
683 bool cmLocalGenerator::ComputeTargetCompileFeatures()
684 {
685   // Collect the set of configuration types.
686   std::vector<std::string> configNames;
687   this->Makefile->GetConfigurations(configNames);
688   if (configNames.empty()) {
689     configNames.emplace_back();
690   }
691
692   using LanguagePair = std::pair<std::string, std::string>;
693   std::vector<LanguagePair> pairedLanguages{ { "OBJC", "C" },
694                                              { "OBJCXX", "CXX" },
695                                              { "CUDA", "CXX" } };
696   std::set<LanguagePair> inferredEnabledLanguages;
697   for (auto const& lang : pairedLanguages) {
698     if (this->Makefile->GetState()->GetLanguageEnabled(lang.first)) {
699       inferredEnabledLanguages.insert(lang);
700     }
701   }
702
703   // Process compile features of all targets.
704   const auto& targets = this->GetGeneratorTargets();
705   for (const auto& target : targets) {
706     for (std::string const& c : configNames) {
707       if (!target->ComputeCompileFeatures(c)) {
708         return false;
709       }
710     }
711
712     // Now that C/C++ _STANDARD values have been computed
713     // set the values to ObjC/ObjCXX _STANDARD variables
714     if (target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
715       auto copyStandardToObjLang = [&](LanguagePair const& lang) -> bool {
716         if (!target->GetProperty(cmStrCat(lang.first, "_STANDARD"))) {
717           auto* standard =
718             target->GetProperty(cmStrCat(lang.second, "_STANDARD"));
719           if (!standard) {
720             standard = this->Makefile->GetDefinition(
721               cmStrCat("CMAKE_", lang.second, "_STANDARD_DEFAULT"));
722           }
723           target->Target->SetProperty(cmStrCat(lang.first, "_STANDARD"),
724                                       standard);
725           return true;
726         }
727         return false;
728       };
729       auto copyPropertyToObjLang = [&](LanguagePair const& lang,
730                                        const char* property) {
731         if (!target->GetProperty(cmStrCat(lang.first, property)) &&
732             target->GetProperty(cmStrCat(lang.second, property))) {
733           target->Target->SetProperty(
734             cmStrCat(lang.first, property),
735             target->GetProperty(cmStrCat(lang.second, property)));
736         }
737       };
738       for (auto const& lang : pairedLanguages) {
739         if (copyStandardToObjLang(lang)) {
740           copyPropertyToObjLang(lang, "_STANDARD_REQUIRED");
741           copyPropertyToObjLang(lang, "_EXTENSIONS");
742         }
743       }
744       if (const char* standard = target->GetProperty("CUDA_STANDARD")) {
745         if (std::string{ standard } == "98") {
746           target->Target->SetProperty("CUDA_STANDARD", "03");
747         }
748       }
749     }
750   }
751
752   return true;
753 }
754
755 bool cmLocalGenerator::IsRootMakefile() const
756 {
757   return !this->StateSnapshot.GetBuildsystemDirectoryParent().IsValid();
758 }
759
760 cmState* cmLocalGenerator::GetState() const
761 {
762   return this->GlobalGenerator->GetCMakeInstance()->GetState();
763 }
764
765 cmStateSnapshot cmLocalGenerator::GetStateSnapshot() const
766 {
767   return this->Makefile->GetStateSnapshot();
768 }
769
770 const char* cmLocalGenerator::GetRuleLauncher(cmGeneratorTarget* target,
771                                               const std::string& prop)
772 {
773   if (target) {
774     return target->GetProperty(prop);
775   }
776   return this->Makefile->GetProperty(prop);
777 }
778
779 std::string cmLocalGenerator::ConvertToIncludeReference(
780   std::string const& path, OutputFormat format, bool forceFullPaths)
781 {
782   static_cast<void>(forceFullPaths);
783   return this->ConvertToOutputForExisting(path, format);
784 }
785
786 std::string cmLocalGenerator::GetIncludeFlags(
787   const std::vector<std::string>& includeDirs, cmGeneratorTarget* target,
788   const std::string& lang, bool forceFullPaths, bool forResponseFile,
789   const std::string& config)
790 {
791   if (lang.empty()) {
792     return "";
793   }
794
795   std::vector<std::string> includes = includeDirs;
796   MoveSystemIncludesToEnd(includes, config, lang, target);
797
798   OutputFormat shellFormat = forResponseFile ? RESPONSE : SHELL;
799   std::ostringstream includeFlags;
800
801   std::string const& includeFlag =
802     this->Makefile->GetSafeDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_", lang));
803   const char* sep =
804     this->Makefile->GetDefinition(cmStrCat("CMAKE_INCLUDE_FLAG_SEP_", lang));
805   bool quotePaths = false;
806   if (this->Makefile->GetDefinition("CMAKE_QUOTE_INCLUDE_PATHS")) {
807     quotePaths = true;
808   }
809   bool repeatFlag = true;
810   // should the include flag be repeated like ie. -IA -IB
811   if (!sep) {
812     sep = " ";
813   } else {
814     // if there is a separator then the flag is not repeated but is only
815     // given once i.e.  -classpath a:b:c
816     repeatFlag = false;
817   }
818
819   // Support special system include flag if it is available and the
820   // normal flag is repeated for each directory.
821   const char* sysIncludeFlag = nullptr;
822   if (repeatFlag) {
823     sysIncludeFlag = this->Makefile->GetDefinition(
824       cmStrCat("CMAKE_INCLUDE_SYSTEM_FLAG_", lang));
825   }
826
827   const char* fwSearchFlag = this->Makefile->GetDefinition(
828     cmStrCat("CMAKE_", lang, "_FRAMEWORK_SEARCH_FLAG"));
829   const char* sysFwSearchFlag = this->Makefile->GetDefinition(
830     cmStrCat("CMAKE_", lang, "_SYSTEM_FRAMEWORK_SEARCH_FLAG"));
831
832   bool flagUsed = false;
833   std::set<std::string> emitted;
834 #ifdef __APPLE__
835   emitted.insert("/System/Library/Frameworks");
836 #endif
837   for (std::string const& i : includes) {
838     if (fwSearchFlag && *fwSearchFlag && this->Makefile->IsOn("APPLE") &&
839         cmSystemTools::IsPathToFramework(i)) {
840       std::string const frameworkDir =
841         cmSystemTools::CollapseFullPath(cmStrCat(i, "/../"));
842       if (emitted.insert(frameworkDir).second) {
843         if (sysFwSearchFlag && target &&
844             target->IsSystemIncludeDirectory(i, config, lang)) {
845           includeFlags << sysFwSearchFlag;
846         } else {
847           includeFlags << fwSearchFlag;
848         }
849         includeFlags << this->ConvertToOutputFormat(frameworkDir, shellFormat)
850                      << " ";
851       }
852       continue;
853     }
854
855     if (!flagUsed || repeatFlag) {
856       if (sysIncludeFlag && target &&
857           target->IsSystemIncludeDirectory(i, config, lang)) {
858         includeFlags << sysIncludeFlag;
859       } else {
860         includeFlags << includeFlag;
861       }
862       flagUsed = true;
863     }
864     std::string includePath =
865       this->ConvertToIncludeReference(i, shellFormat, forceFullPaths);
866     if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
867       includeFlags << "\"";
868     }
869     includeFlags << includePath;
870     if (quotePaths && !includePath.empty() && includePath.front() != '\"') {
871       includeFlags << "\"";
872     }
873     includeFlags << sep;
874   }
875   std::string flags = includeFlags.str();
876   // remove trailing separators
877   if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) {
878     flags.back() = ' ';
879   }
880   return flags;
881 }
882
883 void cmLocalGenerator::AddCompileOptions(std::string& flags,
884                                          cmGeneratorTarget* target,
885                                          const std::string& lang,
886                                          const std::string& config)
887 {
888   std::vector<BT<std::string>> tmpFlags;
889   this->AddCompileOptions(tmpFlags, target, lang, config);
890   this->AppendFlags(flags, tmpFlags);
891 }
892
893 void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags,
894                                          cmGeneratorTarget* target,
895                                          const std::string& lang,
896                                          const std::string& config)
897 {
898   std::string langFlagRegexVar = std::string("CMAKE_") + lang + "_FLAG_REGEX";
899
900   if (const char* langFlagRegexStr =
901         this->Makefile->GetDefinition(langFlagRegexVar)) {
902     // Filter flags acceptable to this language.
903     if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) {
904       std::vector<std::string> opts;
905       cmSystemTools::ParseWindowsCommandLine(targetFlags, opts);
906       // Re-escape these flags since COMPILE_FLAGS were already parsed
907       // as a command line above.
908       std::string compileOpts;
909       this->AppendCompileOptions(compileOpts, opts, langFlagRegexStr);
910       if (!compileOpts.empty()) {
911         flags.emplace_back(std::move(compileOpts));
912       }
913     }
914     std::vector<BT<std::string>> targetCompileOpts =
915       target->GetCompileOptions(config, lang);
916     // COMPILE_OPTIONS are escaped.
917     this->AppendCompileOptions(flags, targetCompileOpts, langFlagRegexStr);
918   } else {
919     // Use all flags.
920     if (const char* targetFlags = target->GetProperty("COMPILE_FLAGS")) {
921       // COMPILE_FLAGS are not escaped for historical reasons.
922       std::string compileFlags;
923       this->AppendFlags(compileFlags, targetFlags);
924       if (!compileFlags.empty()) {
925         flags.emplace_back(std::move(compileFlags));
926       }
927     }
928     std::vector<BT<std::string>> targetCompileOpts =
929       target->GetCompileOptions(config, lang);
930     // COMPILE_OPTIONS are escaped.
931     this->AppendCompileOptions(flags, targetCompileOpts);
932   }
933
934   for (auto const& it : target->GetMaxLanguageStandards()) {
935     const char* standard = target->GetProperty(it.first + "_STANDARD");
936     if (!standard) {
937       continue;
938     }
939     if (this->Makefile->IsLaterStandard(it.first, standard, it.second)) {
940       std::ostringstream e;
941       e << "The COMPILE_FEATURES property of target \"" << target->GetName()
942         << "\" was evaluated when computing the link "
943            "implementation, and the \""
944         << it.first << "_STANDARD\" was \"" << it.second
945         << "\" for that computation.  Computing the "
946            "COMPILE_FEATURES based on the link implementation resulted in a "
947            "higher \""
948         << it.first << "_STANDARD\" \"" << standard
949         << "\".  "
950            "This is not permitted. The COMPILE_FEATURES may not both depend "
951            "on "
952            "and be depended on by the link implementation."
953         << std::endl;
954       this->IssueMessage(MessageType::FATAL_ERROR, e.str());
955       return;
956     }
957   }
958
959   std::string compReqFlag;
960   this->AddCompilerRequirementFlag(compReqFlag, target, lang);
961   if (!compReqFlag.empty()) {
962     flags.emplace_back(std::move(compReqFlag));
963   }
964
965   // Add compile flag for the MSVC compiler only.
966   cmMakefile* mf = this->GetMakefile();
967   if (const char* jmc =
968         mf->GetDefinition("CMAKE_" + lang + "_COMPILE_OPTIONS_JMC")) {
969
970     // Handle Just My Code debugging flags, /JMC.
971     // If the target is a Managed C++ one, /JMC is not compatible.
972     if (target->GetManagedType(config) !=
973         cmGeneratorTarget::ManagedType::Managed) {
974       // add /JMC flags if target property VS_JUST_MY_CODE_DEBUGGING is set
975       // to ON
976       if (char const* jmcExprGen =
977             target->GetProperty("VS_JUST_MY_CODE_DEBUGGING")) {
978         std::string isJMCEnabled =
979           cmGeneratorExpression::Evaluate(jmcExprGen, this, config);
980         if (cmIsOn(isJMCEnabled)) {
981           std::vector<std::string> optVec = cmExpandedList(jmc);
982           std::string jmcFlags;
983           this->AppendCompileOptions(jmcFlags, optVec);
984           if (!jmcFlags.empty()) {
985             flags.emplace_back(std::move(jmcFlags));
986           }
987         }
988       }
989     }
990   }
991 }
992
993 cmTarget* cmLocalGenerator::AddCustomCommandToTarget(
994   const std::string& target, const std::vector<std::string>& byproducts,
995   const std::vector<std::string>& depends,
996   const cmCustomCommandLines& commandLines, cmCustomCommandType type,
997   const char* comment, const char* workingDir, bool escapeOldStyle,
998   bool uses_terminal, const std::string& depfile, const std::string& job_pool,
999   bool command_expand_lists, cmObjectLibraryCommands objLibCommands)
1000 {
1001   cmTarget* t = this->Makefile->GetCustomCommandTarget(
1002     target, objLibCommands, this->DirectoryBacktrace);
1003   if (!t) {
1004     return nullptr;
1005   }
1006
1007   detail::AddCustomCommandToTarget(
1008     *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, t, byproducts,
1009     depends, commandLines, type, comment, workingDir, escapeOldStyle,
1010     uses_terminal, depfile, job_pool, command_expand_lists);
1011
1012   return t;
1013 }
1014
1015 cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
1016   const std::string& output, const std::vector<std::string>& depends,
1017   const std::string& main_dependency, const cmCustomCommandLines& commandLines,
1018   const char* comment, const char* workingDir, bool replace,
1019   bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
1020   const std::string& depfile, const std::string& job_pool)
1021 {
1022   std::vector<std::string> no_byproducts;
1023   cmImplicitDependsList no_implicit_depends;
1024   return this->AddCustomCommandToOutput(
1025     { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
1026     commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
1027     command_expand_lists, depfile, job_pool);
1028 }
1029
1030 cmSourceFile* cmLocalGenerator::AddCustomCommandToOutput(
1031   const std::vector<std::string>& outputs,
1032   const std::vector<std::string>& byproducts,
1033   const std::vector<std::string>& depends, const std::string& main_dependency,
1034   const cmImplicitDependsList& implicit_depends,
1035   const cmCustomCommandLines& commandLines, const char* comment,
1036   const char* workingDir, bool replace, bool escapeOldStyle,
1037   bool uses_terminal, bool command_expand_lists, const std::string& depfile,
1038   const std::string& job_pool)
1039 {
1040   // Make sure there is at least one output.
1041   if (outputs.empty()) {
1042     cmSystemTools::Error("Attempt to add a custom rule with no output!");
1043     return nullptr;
1044   }
1045
1046   return detail::AddCustomCommandToOutput(
1047     *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, outputs,
1048     byproducts, depends, main_dependency, implicit_depends, commandLines,
1049     comment, workingDir, replace, escapeOldStyle, uses_terminal,
1050     command_expand_lists, depfile, job_pool);
1051 }
1052
1053 cmTarget* cmLocalGenerator::AddUtilityCommand(
1054   const std::string& utilityName, bool excludeFromAll, const char* workingDir,
1055   const std::vector<std::string>& byproducts,
1056   const std::vector<std::string>& depends,
1057   const cmCustomCommandLines& commandLines, bool escapeOldStyle,
1058   const char* comment, bool uses_terminal, bool command_expand_lists,
1059   const std::string& job_pool)
1060 {
1061   cmTarget* target =
1062     this->Makefile->AddNewUtilityTarget(utilityName, excludeFromAll);
1063   target->SetIsGeneratorProvided(true);
1064
1065   if (commandLines.empty() && depends.empty()) {
1066     return target;
1067   }
1068
1069   detail::AddUtilityCommand(
1070     *this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target,
1071     this->Makefile->GetUtilityOutput(target), workingDir, byproducts, depends,
1072     commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists,
1073     job_pool);
1074
1075   return target;
1076 }
1077
1078 std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
1079   cmGeneratorTarget const* target, std::string const& lang,
1080   std::string const& config, bool stripImplicitDirs,
1081   bool appendAllImplicitDirs) const
1082 {
1083   std::vector<BT<std::string>> result;
1084   // Do not repeat an include path.
1085   std::set<std::string> emitted;
1086
1087   auto emitDir = [&result, &emitted](std::string const& dir) {
1088     if (emitted.insert(dir).second) {
1089       result.emplace_back(dir);
1090     }
1091   };
1092
1093   auto emitBT = [&result, &emitted](BT<std::string> const& dir) {
1094     if (emitted.insert(dir.Value).second) {
1095       result.emplace_back(dir);
1096     }
1097   };
1098
1099   // When automatic include directories are requested for a build then
1100   // include the source and binary directories at the beginning of the
1101   // include path to approximate include file behavior for an
1102   // in-source build.  This does not account for the case of a source
1103   // file in a subdirectory of the current source directory but we
1104   // cannot fix this because not all native build tools support
1105   // per-source-file include paths.
1106   if (this->Makefile->IsOn("CMAKE_INCLUDE_CURRENT_DIR")) {
1107     // Current binary directory
1108     emitDir(this->StateSnapshot.GetDirectory().GetCurrentBinary());
1109     // Current source directory
1110     emitDir(this->StateSnapshot.GetDirectory().GetCurrentSource());
1111   }
1112
1113   if (!target) {
1114     return result;
1115   }
1116
1117   // Standard include directories to be added unconditionally at the end.
1118   // These are intended to simulate additional implicit include directories.
1119   std::vector<std::string> userStandardDirs;
1120   {
1121     std::string const value = this->Makefile->GetSafeDefinition(
1122       cmStrCat("CMAKE_", lang, "_STANDARD_INCLUDE_DIRECTORIES"));
1123     cmExpandList(value, userStandardDirs);
1124     for (std::string& usd : userStandardDirs) {
1125       cmSystemTools::ConvertToUnixSlashes(usd);
1126     }
1127   }
1128
1129   // Implicit include directories
1130   std::vector<std::string> implicitDirs;
1131   std::set<std::string> implicitSet;
1132   // Include directories to be excluded as if they were implicit.
1133   std::set<std::string> implicitExclude;
1134   {
1135     // Raw list of implicit include directories
1136     // Start with "standard" directories that we unconditionally add below.
1137     std::vector<std::string> impDirVec = userStandardDirs;
1138
1139     // Load implicit include directories for this language.
1140     // We ignore this for Fortran because:
1141     // * There are no standard library headers to avoid overriding.
1142     // * Compilers like gfortran do not search their own implicit include
1143     //   directories for modules ('.mod' files).
1144     if (lang != "Fortran") {
1145       const char* value = this->Makefile->GetDefinition(
1146         cmStrCat("CMAKE_", lang, "_IMPLICIT_INCLUDE_DIRECTORIES"));
1147       if (value != nullptr) {
1148         size_t const impDirVecOldSize = impDirVec.size();
1149         cmExpandList(value, impDirVec);
1150         // FIXME: Use cmRange with 'advance()' when it supports non-const.
1151         for (size_t i = impDirVecOldSize; i < impDirVec.size(); ++i) {
1152           cmSystemTools::ConvertToUnixSlashes(impDirVec[i]);
1153         }
1154       }
1155     }
1156
1157     // The Platform/UnixPaths module used to hard-code /usr/include for C, CXX,
1158     // and CUDA in CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES, but those
1159     // variables are now computed.  On macOS the /usr/include directory is
1160     // inside the platform SDK so the computed value does not contain it
1161     // directly.  In this case adding -I/usr/include can hide SDK headers so we
1162     // must still exclude it.
1163     if ((lang == "C" || lang == "CXX" || lang == "CUDA") &&
1164         !cmContains(impDirVec, "/usr/include") &&
1165         std::find_if(impDirVec.begin(), impDirVec.end(),
1166                      [](std::string const& d) {
1167                        return cmHasLiteralSuffix(d, "/usr/include");
1168                      }) != impDirVec.end()) {
1169       // Only exclude this hard coded path for backwards compatibility.
1170       implicitExclude.emplace("/usr/include");
1171     }
1172
1173     for (std::string const& i : impDirVec) {
1174       if (implicitSet.insert(this->GlobalGenerator->GetRealPath(i)).second) {
1175         implicitDirs.emplace_back(i);
1176       }
1177     }
1178   }
1179
1180   // Checks if this is not an excluded (implicit) include directory.
1181   auto notExcluded = [this, &implicitSet, &implicitExclude,
1182                       &lang](std::string const& dir) {
1183     return (
1184       // Do not exclude directories that are not in an excluded set.
1185       ((!cmContains(implicitSet, this->GlobalGenerator->GetRealPath(dir))) &&
1186        (!cmContains(implicitExclude, dir)))
1187       // Do not exclude entries of the CPATH environment variable even though
1188       // they are implicitly searched by the compiler.  They are meant to be
1189       // user-specified directories that can be re-ordered or converted to
1190       // -isystem without breaking real compiler builtin headers.
1191       || ((lang == "C" || lang == "CXX") && cmContains(this->EnvCPATH, dir)));
1192   };
1193
1194   // Get the target-specific include directories.
1195   std::vector<BT<std::string>> userDirs =
1196     target->GetIncludeDirectories(config, lang);
1197
1198   // Support putting all the in-project include directories first if
1199   // it is requested by the project.
1200   if (this->Makefile->IsOn("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")) {
1201     std::string const& topSourceDir = this->GetState()->GetSourceDirectory();
1202     std::string const& topBinaryDir = this->GetState()->GetBinaryDirectory();
1203     for (BT<std::string> const& udr : userDirs) {
1204       // Emit this directory only if it is a subdirectory of the
1205       // top-level source or binary tree.
1206       if (cmSystemTools::ComparePath(udr.Value, topSourceDir) ||
1207           cmSystemTools::ComparePath(udr.Value, topBinaryDir) ||
1208           cmSystemTools::IsSubDirectory(udr.Value, topSourceDir) ||
1209           cmSystemTools::IsSubDirectory(udr.Value, topBinaryDir)) {
1210         if (notExcluded(udr.Value)) {
1211           emitBT(udr);
1212         }
1213       }
1214     }
1215   }
1216
1217   // Emit remaining non implicit user direcories.
1218   for (BT<std::string> const& udr : userDirs) {
1219     if (notExcluded(udr.Value)) {
1220       emitBT(udr);
1221     }
1222   }
1223
1224   // Sort result
1225   MoveSystemIncludesToEnd(result, config, lang, target);
1226
1227   // Append standard include directories for this language.
1228   userDirs.reserve(userDirs.size() + userStandardDirs.size());
1229   for (std::string& usd : userStandardDirs) {
1230     emitDir(usd);
1231     userDirs.emplace_back(std::move(usd));
1232   }
1233
1234   // Append compiler implicit include directories
1235   if (!stripImplicitDirs) {
1236     // Append implicit directories that were requested by the user only
1237     for (BT<std::string> const& udr : userDirs) {
1238       if (cmContains(implicitSet, cmSystemTools::GetRealPath(udr.Value))) {
1239         emitBT(udr);
1240       }
1241     }
1242     // Append remaining implicit directories (on demand)
1243     if (appendAllImplicitDirs) {
1244       for (std::string& imd : implicitDirs) {
1245         emitDir(imd);
1246       }
1247     }
1248   }
1249
1250   return result;
1251 }
1252
1253 void cmLocalGenerator::GetIncludeDirectoriesImplicit(
1254   std::vector<std::string>& dirs, cmGeneratorTarget const* target,
1255   const std::string& lang, const std::string& config, bool stripImplicitDirs,
1256   bool appendAllImplicitDirs) const
1257 {
1258   std::vector<BT<std::string>> tmp = this->GetIncludeDirectoriesImplicit(
1259     target, lang, config, stripImplicitDirs, appendAllImplicitDirs);
1260   dirs.reserve(dirs.size() + tmp.size());
1261   for (BT<std::string>& v : tmp) {
1262     dirs.emplace_back(std::move(v.Value));
1263   }
1264 }
1265
1266 std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectories(
1267   cmGeneratorTarget const* target, std::string const& lang,
1268   std::string const& config) const
1269 {
1270   return this->GetIncludeDirectoriesImplicit(target, lang, config);
1271 }
1272
1273 void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs,
1274                                              cmGeneratorTarget const* target,
1275                                              const std::string& lang,
1276                                              const std::string& config) const
1277 {
1278   this->GetIncludeDirectoriesImplicit(dirs, target, lang, config);
1279 }
1280
1281 void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags,
1282                                              std::string const& config,
1283                                              std::string const& linkLanguage,
1284                                              cmGeneratorTarget* target)
1285 {
1286   std::vector<BT<std::string>> tmpFlags =
1287     this->GetStaticLibraryFlags(config, linkLanguage, target);
1288   this->AppendFlags(flags, tmpFlags);
1289 }
1290
1291 std::vector<BT<std::string>> cmLocalGenerator::GetStaticLibraryFlags(
1292   std::string const& config, std::string const& linkLanguage,
1293   cmGeneratorTarget* target)
1294 {
1295   std::vector<BT<std::string>> flags;
1296   if (linkLanguage != "Swift") {
1297     std::string staticLibFlags;
1298     this->AppendFlags(
1299       staticLibFlags,
1300       this->Makefile->GetSafeDefinition("CMAKE_STATIC_LINKER_FLAGS"));
1301     if (!config.empty()) {
1302       std::string name = "CMAKE_STATIC_LINKER_FLAGS_" + config;
1303       this->AppendFlags(staticLibFlags,
1304                         this->Makefile->GetSafeDefinition(name));
1305     }
1306     if (!staticLibFlags.empty()) {
1307       flags.emplace_back(std::move(staticLibFlags));
1308     }
1309   }
1310
1311   std::string staticLibFlags;
1312   this->AppendFlags(staticLibFlags,
1313                     target->GetSafeProperty("STATIC_LIBRARY_FLAGS"));
1314   if (!config.empty()) {
1315     std::string name = "STATIC_LIBRARY_FLAGS_" + config;
1316     this->AppendFlags(staticLibFlags, target->GetSafeProperty(name));
1317   }
1318
1319   if (!staticLibFlags.empty()) {
1320     flags.emplace_back(std::move(staticLibFlags));
1321   }
1322
1323   std::vector<BT<std::string>> staticLibOpts =
1324     target->GetStaticLibraryLinkOptions(config, linkLanguage);
1325   // STATIC_LIBRARY_OPTIONS are escaped.
1326   this->AppendCompileOptions(flags, staticLibOpts);
1327
1328   return flags;
1329 }
1330
1331 void cmLocalGenerator::GetTargetFlags(
1332   cmLinkLineComputer* linkLineComputer, const std::string& config,
1333   std::string& linkLibs, std::string& flags, std::string& linkFlags,
1334   std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target)
1335 {
1336   std::vector<BT<std::string>> linkFlagsList;
1337   std::vector<BT<std::string>> linkPathList;
1338   std::vector<BT<std::string>> linkLibsList;
1339   this->GetTargetFlags(linkLineComputer, config, linkLibsList, flags,
1340                        linkFlagsList, frameworkPath, linkPathList, target);
1341   this->AppendFlags(linkFlags, linkFlagsList);
1342   this->AppendFlags(linkPath, linkPathList);
1343   this->AppendFlags(linkLibs, linkLibsList);
1344 }
1345
1346 void cmLocalGenerator::GetTargetFlags(
1347   cmLinkLineComputer* linkLineComputer, const std::string& config,
1348   std::vector<BT<std::string>>& linkLibs, std::string& flags,
1349   std::vector<BT<std::string>>& linkFlags, std::string& frameworkPath,
1350   std::vector<BT<std::string>>& linkPath, cmGeneratorTarget* target)
1351 {
1352   const std::string buildType = cmSystemTools::UpperCase(config);
1353   cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
1354   const char* libraryLinkVariable =
1355     "CMAKE_SHARED_LINKER_FLAGS"; // default to shared library
1356
1357   const std::string linkLanguage =
1358     linkLineComputer->GetLinkerLanguage(target, buildType);
1359
1360   switch (target->GetType()) {
1361     case cmStateEnums::STATIC_LIBRARY:
1362       linkFlags = this->GetStaticLibraryFlags(buildType, linkLanguage, target);
1363       if (pcli && dynamic_cast<cmLinkLineDeviceComputer*>(linkLineComputer)) {
1364         // Compute the required cuda device link libraries when
1365         // resolving cuda device symbols
1366         this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
1367                                   frameworkPath, linkPath);
1368       }
1369       break;
1370     case cmStateEnums::MODULE_LIBRARY:
1371       libraryLinkVariable = "CMAKE_MODULE_LINKER_FLAGS";
1372       CM_FALLTHROUGH;
1373     case cmStateEnums::SHARED_LIBRARY: {
1374       std::string sharedLibFlags;
1375       if (linkLanguage != "Swift") {
1376         sharedLibFlags = cmStrCat(
1377           this->Makefile->GetSafeDefinition(libraryLinkVariable), ' ');
1378         if (!buildType.empty()) {
1379           std::string build = cmStrCat(libraryLinkVariable, '_', buildType);
1380           sharedLibFlags += this->Makefile->GetSafeDefinition(build);
1381           sharedLibFlags += " ";
1382         }
1383         if (this->Makefile->IsOn("WIN32") &&
1384             !(this->Makefile->IsOn("CYGWIN") ||
1385               this->Makefile->IsOn("MINGW"))) {
1386           std::vector<cmSourceFile*> sources;
1387           target->GetSourceFiles(sources, buildType);
1388           std::string defFlag =
1389             this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
1390           for (cmSourceFile* sf : sources) {
1391             if (sf->GetExtension() == "def") {
1392               sharedLibFlags += defFlag;
1393               sharedLibFlags += this->ConvertToOutputFormat(
1394                 cmSystemTools::CollapseFullPath(sf->ResolveFullPath()), SHELL);
1395               sharedLibFlags += " ";
1396             }
1397           }
1398         }
1399       }
1400
1401       const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
1402       if (targetLinkFlags) {
1403         sharedLibFlags += targetLinkFlags;
1404         sharedLibFlags += " ";
1405       }
1406       if (!buildType.empty()) {
1407         targetLinkFlags =
1408           target->GetProperty(cmStrCat("LINK_FLAGS_", buildType));
1409         if (targetLinkFlags) {
1410           sharedLibFlags += targetLinkFlags;
1411           sharedLibFlags += " ";
1412         }
1413       }
1414
1415       if (!sharedLibFlags.empty()) {
1416         linkFlags.emplace_back(std::move(sharedLibFlags));
1417       }
1418
1419       std::vector<BT<std::string>> linkOpts =
1420         target->GetLinkOptions(config, linkLanguage);
1421       // LINK_OPTIONS are escaped.
1422       this->AppendCompileOptions(linkFlags, linkOpts);
1423       if (pcli) {
1424         this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
1425                                   frameworkPath, linkPath);
1426       }
1427     } break;
1428     case cmStateEnums::EXECUTABLE: {
1429       std::string exeFlags;
1430       if (linkLanguage != "Swift") {
1431         exeFlags = this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
1432         exeFlags += " ";
1433         if (!buildType.empty()) {
1434           exeFlags += this->Makefile->GetSafeDefinition(
1435             cmStrCat("CMAKE_EXE_LINKER_FLAGS_", buildType));
1436           exeFlags += " ";
1437         }
1438         if (linkLanguage.empty()) {
1439           cmSystemTools::Error(
1440             "CMake can not determine linker language for target: " +
1441             target->GetName());
1442           return;
1443         }
1444
1445         if (target->GetPropertyAsBool("WIN32_EXECUTABLE")) {
1446           exeFlags +=
1447             this->Makefile->GetSafeDefinition("CMAKE_CREATE_WIN32_EXE");
1448           exeFlags += " ";
1449         } else {
1450           exeFlags +=
1451             this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE");
1452           exeFlags += " ";
1453         }
1454
1455         if (target->IsExecutableWithExports()) {
1456           exeFlags += this->Makefile->GetSafeDefinition(
1457             cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG"));
1458           exeFlags += " ";
1459         }
1460       }
1461
1462       this->AddLanguageFlagsForLinking(flags, target, linkLanguage, buildType);
1463       if (pcli) {
1464         this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
1465                                   frameworkPath, linkPath);
1466       }
1467
1468       if (cmIsOn(this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) {
1469         std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") +
1470           linkLanguage + std::string("_FLAGS");
1471         exeFlags += this->Makefile->GetSafeDefinition(sFlagVar);
1472         exeFlags += " ";
1473       }
1474
1475       std::string cmp0065Flags =
1476         this->GetLinkLibsCMP0065(linkLanguage, *target);
1477       if (!cmp0065Flags.empty()) {
1478         exeFlags += cmp0065Flags;
1479         exeFlags += " ";
1480       }
1481
1482       const char* targetLinkFlags = target->GetProperty("LINK_FLAGS");
1483       if (targetLinkFlags) {
1484         exeFlags += targetLinkFlags;
1485         exeFlags += " ";
1486       }
1487       if (!buildType.empty()) {
1488         targetLinkFlags =
1489           target->GetProperty(cmStrCat("LINK_FLAGS_", buildType));
1490         if (targetLinkFlags) {
1491           exeFlags += targetLinkFlags;
1492           exeFlags += " ";
1493         }
1494       }
1495
1496       if (!exeFlags.empty()) {
1497         linkFlags.emplace_back(std::move(exeFlags));
1498       }
1499
1500       std::vector<BT<std::string>> linkOpts =
1501         target->GetLinkOptions(config, linkLanguage);
1502       // LINK_OPTIONS are escaped.
1503       this->AppendCompileOptions(linkFlags, linkOpts);
1504     } break;
1505     default:
1506       break;
1507   }
1508
1509   std::string extraLinkFlags;
1510   this->AppendPositionIndependentLinkerFlags(extraLinkFlags, target, config,
1511                                              linkLanguage);
1512   this->AppendIPOLinkerFlags(extraLinkFlags, target, config, linkLanguage);
1513
1514   if (!extraLinkFlags.empty()) {
1515     linkFlags.emplace_back(std::move(extraLinkFlags));
1516   }
1517 }
1518
1519 void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target,
1520                                              std::string const& config,
1521                                              std::string const& lang,
1522                                              std::string& flags)
1523 {
1524   std::vector<BT<std::string>> tmpFlags =
1525     this->GetTargetCompileFlags(target, config, lang);
1526   this->AppendFlags(flags, tmpFlags);
1527 }
1528
1529 std::vector<BT<std::string>> cmLocalGenerator::GetTargetCompileFlags(
1530   cmGeneratorTarget* target, std::string const& config,
1531   std::string const& lang)
1532 {
1533   std::vector<BT<std::string>> flags;
1534   std::string compileFlags;
1535
1536   cmMakefile* mf = this->GetMakefile();
1537
1538   // Add language-specific flags.
1539   this->AddLanguageFlags(compileFlags, target, lang, config);
1540
1541   if (target->IsIPOEnabled(lang, config)) {
1542     this->AppendFeatureOptions(compileFlags, lang, "IPO");
1543   }
1544
1545   this->AddArchitectureFlags(compileFlags, target, lang, config);
1546
1547   if (lang == "Fortran") {
1548     this->AppendFlags(compileFlags,
1549                       this->GetTargetFortranFlags(target, config));
1550   }
1551
1552   this->AddCMP0018Flags(compileFlags, target, lang, config);
1553   this->AddVisibilityPresetFlags(compileFlags, target, lang);
1554   this->AppendFlags(compileFlags, mf->GetDefineFlags());
1555   this->AppendFlags(compileFlags,
1556                     this->GetFrameworkFlags(lang, config, target));
1557
1558   if (!compileFlags.empty()) {
1559     flags.emplace_back(std::move(compileFlags));
1560   }
1561   this->AddCompileOptions(flags, target, lang, config);
1562   return flags;
1563 }
1564
1565 static std::string GetFrameworkFlags(const std::string& lang,
1566                                      const std::string& config,
1567                                      cmGeneratorTarget* target)
1568 {
1569   cmLocalGenerator* lg = target->GetLocalGenerator();
1570   cmMakefile* mf = lg->GetMakefile();
1571
1572   if (!mf->IsOn("APPLE")) {
1573     return std::string();
1574   }
1575
1576   std::string fwSearchFlagVar = "CMAKE_" + lang + "_FRAMEWORK_SEARCH_FLAG";
1577   const char* fwSearchFlag = mf->GetDefinition(fwSearchFlagVar);
1578   if (!(fwSearchFlag && *fwSearchFlag)) {
1579     return std::string();
1580   }
1581
1582   std::set<std::string> emitted;
1583 #ifdef __APPLE__ /* don't insert this when crosscompiling e.g. to iphone */
1584   emitted.insert("/System/Library/Frameworks");
1585 #endif
1586   std::vector<std::string> includes;
1587
1588   lg->GetIncludeDirectories(includes, target, "C", config);
1589   // check all include directories for frameworks as this
1590   // will already have added a -F for the framework
1591   for (std::string const& include : includes) {
1592     if (lg->GetGlobalGenerator()->NameResolvesToFramework(include)) {
1593       std::string frameworkDir = cmStrCat(include, "/../");
1594       frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
1595       emitted.insert(frameworkDir);
1596     }
1597   }
1598
1599   std::string flags;
1600   if (cmComputeLinkInformation* cli = target->GetLinkInformation(config)) {
1601     std::vector<std::string> const& frameworks = cli->GetFrameworkPaths();
1602     for (std::string const& framework : frameworks) {
1603       if (emitted.insert(framework).second) {
1604         flags += fwSearchFlag;
1605         flags +=
1606           lg->ConvertToOutputFormat(framework, cmOutputConverter::SHELL);
1607         flags += " ";
1608       }
1609     }
1610   }
1611   return flags;
1612 }
1613
1614 std::string cmLocalGenerator::GetFrameworkFlags(std::string const& l,
1615                                                 std::string const& config,
1616                                                 cmGeneratorTarget* target)
1617 {
1618   return ::GetFrameworkFlags(l, config, target);
1619 }
1620
1621 void cmLocalGenerator::GetTargetDefines(cmGeneratorTarget const* target,
1622                                         std::string const& config,
1623                                         std::string const& lang,
1624                                         std::set<std::string>& defines) const
1625 {
1626   std::set<BT<std::string>> tmp = this->GetTargetDefines(target, config, lang);
1627   for (BT<std::string> const& v : tmp) {
1628     defines.emplace(v.Value);
1629   }
1630 }
1631
1632 std::set<BT<std::string>> cmLocalGenerator::GetTargetDefines(
1633   cmGeneratorTarget const* target, std::string const& config,
1634   std::string const& lang) const
1635 {
1636   std::set<BT<std::string>> defines;
1637
1638   // Add the export symbol definition for shared library objects.
1639   if (const std::string* exportMacro = target->GetExportMacro()) {
1640     this->AppendDefines(defines, *exportMacro);
1641   }
1642
1643   // Add preprocessor definitions for this target and configuration.
1644   std::vector<BT<std::string>> targetDefines =
1645     target->GetCompileDefinitions(config, lang);
1646   this->AppendDefines(defines, targetDefines);
1647
1648   return defines;
1649 }
1650
1651 std::string cmLocalGenerator::GetTargetFortranFlags(
1652   cmGeneratorTarget const* /*unused*/, std::string const& /*unused*/)
1653 {
1654   // Implemented by specific generators that override this.
1655   return std::string();
1656 }
1657
1658 /**
1659  * Output the linking rules on a command line.  For executables,
1660  * targetLibrary should be a NULL pointer.  For libraries, it should point
1661  * to the name of the library.  This will not link a library against itself.
1662  */
1663 void cmLocalGenerator::OutputLinkLibraries(
1664   cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer,
1665   std::string& linkLibraries, std::string& frameworkPath,
1666   std::string& linkPath)
1667 {
1668   std::vector<BT<std::string>> linkLibrariesList;
1669   std::vector<BT<std::string>> linkPathList;
1670   this->OutputLinkLibraries(pcli, linkLineComputer, linkLibrariesList,
1671                             frameworkPath, linkPathList);
1672   pcli->AppendValues(linkLibraries, linkLibrariesList);
1673   pcli->AppendValues(linkPath, linkPathList);
1674 }
1675
1676 void cmLocalGenerator::OutputLinkLibraries(
1677   cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer,
1678   std::vector<BT<std::string>>& linkLibraries, std::string& frameworkPath,
1679   std::vector<BT<std::string>>& linkPath)
1680 {
1681   cmComputeLinkInformation& cli = *pcli;
1682
1683   std::string linkLanguage = cli.GetLinkLanguage();
1684
1685   std::string libPathFlag;
1686   if (const char* value = this->Makefile->GetDefinition(
1687         "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_FLAG")) {
1688     libPathFlag = value;
1689   } else {
1690     libPathFlag =
1691       this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
1692   }
1693
1694   std::string libPathTerminator;
1695   if (const char* value = this->Makefile->GetDefinition(
1696         "CMAKE_" + cli.GetLinkLanguage() + "_LIBRARY_PATH_TERMINATOR")) {
1697     libPathTerminator = value;
1698   } else {
1699     libPathTerminator =
1700       this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
1701   }
1702
1703   // Add standard libraries for this language.
1704   std::string stdLibString = this->Makefile->GetSafeDefinition(
1705     cmStrCat("CMAKE_", cli.GetLinkLanguage(), "_STANDARD_LIBRARIES"));
1706
1707   // Append the framework search path flags.
1708   std::string fwSearchFlag = this->Makefile->GetSafeDefinition(
1709     cmStrCat("CMAKE_", linkLanguage, "_FRAMEWORK_SEARCH_FLAG"));
1710
1711   frameworkPath = linkLineComputer->ComputeFrameworkPath(cli, fwSearchFlag);
1712   linkLineComputer->ComputeLinkPath(cli, libPathFlag, libPathTerminator,
1713                                     linkPath);
1714   linkLineComputer->ComputeLinkLibraries(cli, stdLibString, linkLibraries);
1715 }
1716
1717 std::string cmLocalGenerator::GetLinkLibsCMP0065(
1718   std::string const& linkLanguage, cmGeneratorTarget& tgt) const
1719 {
1720   std::string linkFlags;
1721
1722   // Flags to link an executable to shared libraries.
1723   if (tgt.GetType() == cmStateEnums::EXECUTABLE &&
1724       this->StateSnapshot.GetState()->GetGlobalPropertyAsBool(
1725         "TARGET_SUPPORTS_SHARED_LIBS")) {
1726     bool add_shlib_flags = false;
1727     switch (tgt.GetPolicyStatusCMP0065()) {
1728       case cmPolicies::WARN:
1729         if (!tgt.GetPropertyAsBool("ENABLE_EXPORTS") &&
1730             this->Makefile->PolicyOptionalWarningEnabled(
1731               "CMAKE_POLICY_WARNING_CMP0065")) {
1732           std::ostringstream w;
1733           /* clang-format off */
1734           w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0065) << "\n"
1735             "For compatibility with older versions of CMake, "
1736             "additional flags may be added to export symbols on all "
1737             "executables regardless of their ENABLE_EXPORTS property.";
1738           /* clang-format on */
1739           this->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
1740         }
1741         CM_FALLTHROUGH;
1742       case cmPolicies::OLD:
1743         // OLD behavior is to always add the flags, except on AIX where
1744         // we compute symbol exports if ENABLE_EXPORTS is on.
1745         add_shlib_flags =
1746           !(tgt.Target->IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS"));
1747         break;
1748       case cmPolicies::REQUIRED_IF_USED:
1749       case cmPolicies::REQUIRED_ALWAYS:
1750         this->IssueMessage(
1751           MessageType::FATAL_ERROR,
1752           cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0065));
1753         CM_FALLTHROUGH;
1754       case cmPolicies::NEW:
1755         // NEW behavior is to only add the flags if ENABLE_EXPORTS is on,
1756         // except on AIX where we compute symbol exports.
1757         add_shlib_flags =
1758           !tgt.Target->IsAIX() && tgt.GetPropertyAsBool("ENABLE_EXPORTS");
1759         break;
1760     }
1761
1762     if (add_shlib_flags) {
1763       linkFlags = this->Makefile->GetSafeDefinition(
1764         cmStrCat("CMAKE_SHARED_LIBRARY_LINK_", linkLanguage, "_FLAGS"));
1765     }
1766   }
1767   return linkFlags;
1768 }
1769
1770 void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
1771                                             cmGeneratorTarget const* target,
1772                                             const std::string& lang,
1773                                             const std::string& config)
1774 {
1775   // Only add Apple specific flags on Apple platforms
1776   if (this->Makefile->IsOn("APPLE") && this->EmitUniversalBinaryFlags) {
1777     std::vector<std::string> archs;
1778     target->GetAppleArchs(config, archs);
1779     if (!archs.empty() && !lang.empty() &&
1780         (lang[0] == 'C' || lang[0] == 'F' || lang[0] == 'O')) {
1781       for (std::string const& arch : archs) {
1782         flags += " -arch ";
1783         flags += arch;
1784       }
1785     }
1786
1787     const char* sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
1788     if (sysroot && sysroot[0] == '/' && !sysroot[1]) {
1789       sysroot = nullptr;
1790     }
1791     std::string sysrootFlagVar =
1792       std::string("CMAKE_") + lang + "_SYSROOT_FLAG";
1793     const char* sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
1794     if (sysrootFlag && *sysrootFlag) {
1795       std::vector<std::string> arch_sysroots;
1796       if (const char* arch_sysroots_str =
1797             this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) {
1798         cmExpandList(std::string(arch_sysroots_str), arch_sysroots, true);
1799       }
1800       if (!arch_sysroots.empty()) {
1801         assert(arch_sysroots.size() == archs.size());
1802         for (size_t i = 0; i < archs.size(); ++i) {
1803           if (arch_sysroots[i].empty()) {
1804             continue;
1805           }
1806           flags += " -Xarch_" + archs[i] + " ";
1807           // Combine sysroot flag and path to work with -Xarch
1808           std::string arch_sysroot = sysrootFlag + arch_sysroots[i];
1809           flags += this->ConvertToOutputFormat(arch_sysroot, SHELL);
1810         }
1811       } else if (sysroot && *sysroot) {
1812         flags += " ";
1813         flags += sysrootFlag;
1814         flags += " ";
1815         flags += this->ConvertToOutputFormat(sysroot, SHELL);
1816       }
1817     }
1818
1819     const char* deploymentTarget =
1820       this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
1821     std::string deploymentTargetFlagVar =
1822       std::string("CMAKE_") + lang + "_OSX_DEPLOYMENT_TARGET_FLAG";
1823     const char* deploymentTargetFlag =
1824       this->Makefile->GetDefinition(deploymentTargetFlagVar);
1825     if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget &&
1826         *deploymentTarget) {
1827       flags += " ";
1828       flags += deploymentTargetFlag;
1829       flags += deploymentTarget;
1830     }
1831   }
1832 }
1833
1834 void cmLocalGenerator::AddLanguageFlags(std::string& flags,
1835                                         cmGeneratorTarget const* target,
1836                                         const std::string& lang,
1837                                         const std::string& config)
1838 {
1839   // Add language-specific flags.
1840   this->AddConfigVariableFlags(flags, cmStrCat("CMAKE_", lang, "_FLAGS"),
1841                                config);
1842
1843   if (lang == "Swift") {
1844     if (const char* v = target->GetProperty("Swift_LANGUAGE_VERSION")) {
1845       if (cmSystemTools::VersionCompare(
1846             cmSystemTools::OP_GREATER_EQUAL,
1847             this->Makefile->GetDefinition("CMAKE_Swift_COMPILER_VERSION"),
1848             "4.2")) {
1849         this->AppendFlags(flags, "-swift-version " + std::string(v));
1850       }
1851     }
1852   }
1853
1854   // Add MSVC runtime library flags.  This is activated by the presence
1855   // of a default selection whether or not it is overridden by a property.
1856   const char* msvcRuntimeLibraryDefault =
1857     this->Makefile->GetDefinition("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT");
1858   if (msvcRuntimeLibraryDefault && *msvcRuntimeLibraryDefault) {
1859     const char* msvcRuntimeLibraryValue =
1860       target->GetProperty("MSVC_RUNTIME_LIBRARY");
1861     if (!msvcRuntimeLibraryValue) {
1862       msvcRuntimeLibraryValue = msvcRuntimeLibraryDefault;
1863     }
1864     std::string const msvcRuntimeLibrary = cmGeneratorExpression::Evaluate(
1865       msvcRuntimeLibraryValue, this, config, target);
1866     if (!msvcRuntimeLibrary.empty()) {
1867       if (const char* msvcRuntimeLibraryOptions =
1868             this->Makefile->GetDefinition(
1869               "CMAKE_" + lang + "_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_" +
1870               msvcRuntimeLibrary)) {
1871         this->AppendCompileOptions(flags, msvcRuntimeLibraryOptions);
1872       } else if ((this->Makefile->GetSafeDefinition(
1873                     "CMAKE_" + lang + "_COMPILER_ID") == "MSVC" ||
1874                   this->Makefile->GetSafeDefinition(
1875                     "CMAKE_" + lang + "_SIMULATE_ID") == "MSVC") &&
1876                  !cmSystemTools::GetErrorOccuredFlag()) {
1877         // The compiler uses the MSVC ABI so it needs a known runtime library.
1878         this->IssueMessage(MessageType::FATAL_ERROR,
1879                            "MSVC_RUNTIME_LIBRARY value '" +
1880                              msvcRuntimeLibrary + "' not known for this " +
1881                              lang + " compiler.");
1882       }
1883     }
1884   }
1885 }
1886
1887 void cmLocalGenerator::AddLanguageFlagsForLinking(
1888   std::string& flags, cmGeneratorTarget const* target, const std::string& lang,
1889   const std::string& config)
1890 {
1891   if (this->Makefile->IsOn("CMAKE_" + lang +
1892                            "_LINK_WITH_STANDARD_COMPILE_OPTION")) {
1893     // This toolchain requires use of the language standard flag
1894     // when linking in order to use the matching standard library.
1895     // FIXME: If CMake gains an abstraction for standard library
1896     // selection, this will have to be reconciled with it.
1897     this->AddCompilerRequirementFlag(flags, target, lang);
1898   }
1899
1900   this->AddLanguageFlags(flags, target, lang, config);
1901
1902   if (target->IsIPOEnabled(lang, config)) {
1903     this->AppendFeatureOptions(flags, lang, "IPO");
1904   }
1905 }
1906
1907 cmGeneratorTarget* cmLocalGenerator::FindGeneratorTargetToUse(
1908   const std::string& name) const
1909 {
1910   auto imported = this->ImportedGeneratorTargets.find(name);
1911   if (imported != this->ImportedGeneratorTargets.end()) {
1912     return imported->second;
1913   }
1914
1915   if (cmGeneratorTarget* t = this->FindLocalNonAliasGeneratorTarget(name)) {
1916     return t;
1917   }
1918
1919   return this->GetGlobalGenerator()->FindGeneratorTarget(name);
1920 }
1921
1922 bool cmLocalGenerator::GetRealDependency(const std::string& inName,
1923                                          const std::string& config,
1924                                          std::string& dep)
1925 {
1926   // Older CMake code may specify the dependency using the target
1927   // output file rather than the target name.  Such code would have
1928   // been written before there was support for target properties that
1929   // modify the name so stripping down to just the file name should
1930   // produce the target name in this case.
1931   std::string name = cmSystemTools::GetFilenameName(inName);
1932
1933   // If the input name is the empty string, there is no real
1934   // dependency. Short-circuit the other checks:
1935   if (name.empty()) {
1936     return false;
1937   }
1938
1939   if (cmSystemTools::GetFilenameLastExtension(name) == ".exe") {
1940     name = cmSystemTools::GetFilenameWithoutLastExtension(name);
1941   }
1942
1943   // Look for a CMake target with the given name.
1944   if (cmGeneratorTarget* target = this->FindGeneratorTargetToUse(name)) {
1945     // make sure it is not just a coincidence that the target name
1946     // found is part of the inName
1947     if (cmSystemTools::FileIsFullPath(inName)) {
1948       std::string tLocation;
1949       if (target->GetType() >= cmStateEnums::EXECUTABLE &&
1950           target->GetType() <= cmStateEnums::MODULE_LIBRARY) {
1951         tLocation = target->GetLocation(config);
1952         tLocation = cmSystemTools::GetFilenamePath(tLocation);
1953         tLocation = cmSystemTools::CollapseFullPath(tLocation);
1954       }
1955       std::string depLocation =
1956         cmSystemTools::GetFilenamePath(std::string(inName));
1957       depLocation = cmSystemTools::CollapseFullPath(depLocation);
1958       if (depLocation != tLocation) {
1959         // it is a full path to a depend that has the same name
1960         // as a target but is in a different location so do not use
1961         // the target as the depend
1962         dep = inName;
1963         return true;
1964       }
1965     }
1966     switch (target->GetType()) {
1967       case cmStateEnums::EXECUTABLE:
1968       case cmStateEnums::STATIC_LIBRARY:
1969       case cmStateEnums::SHARED_LIBRARY:
1970       case cmStateEnums::MODULE_LIBRARY:
1971       case cmStateEnums::UNKNOWN_LIBRARY:
1972         dep = target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
1973                                   /*realname=*/true);
1974         return true;
1975       case cmStateEnums::OBJECT_LIBRARY:
1976         // An object library has no single file on which to depend.
1977         // This was listed to get the target-level dependency.
1978         return false;
1979       case cmStateEnums::INTERFACE_LIBRARY:
1980         // An interface library has no file on which to depend.
1981         // This was listed to get the target-level dependency.
1982         return false;
1983       case cmStateEnums::UTILITY:
1984       case cmStateEnums::GLOBAL_TARGET:
1985         // A utility target has no file on which to depend.  This was listed
1986         // only to get the target-level dependency.
1987         return false;
1988     }
1989   }
1990
1991   // The name was not that of a CMake target.  It must name a file.
1992   if (cmSystemTools::FileIsFullPath(inName)) {
1993     // This is a full path.  Return it as given.
1994     dep = inName;
1995     return true;
1996   }
1997
1998   // Check for a source file in this directory that matches the
1999   // dependency.
2000   if (cmSourceFile* sf = this->Makefile->GetSource(inName)) {
2001     dep = sf->ResolveFullPath();
2002     return true;
2003   }
2004
2005   // Treat the name as relative to the source directory in which it
2006   // was given.
2007   dep = cmStrCat(this->GetCurrentSourceDirectory(), '/', inName);
2008
2009   // If the in-source path does not exist, assume it instead lives in the
2010   // binary directory.
2011   if (!cmSystemTools::FileExists(dep)) {
2012     dep = cmStrCat(this->GetCurrentBinaryDirectory(), '/', inName);
2013   }
2014
2015   dep = cmSystemTools::CollapseFullPath(dep, this->GetBinaryDirectory());
2016
2017   return true;
2018 }
2019
2020 void cmLocalGenerator::AddSharedFlags(std::string& flags,
2021                                       const std::string& lang, bool shared)
2022 {
2023   std::string flagsVar;
2024
2025   // Add flags for dealing with shared libraries for this language.
2026   if (shared) {
2027     this->AppendFlags(flags,
2028                       this->Makefile->GetSafeDefinition(
2029                         cmStrCat("CMAKE_SHARED_LIBRARY_", lang, "_FLAGS")));
2030   }
2031 }
2032
2033 void cmLocalGenerator::AddCompilerRequirementFlag(
2034   std::string& flags, cmGeneratorTarget const* target, const std::string& lang)
2035 {
2036   if (lang.empty()) {
2037     return;
2038   }
2039   const char* defaultStd =
2040     this->Makefile->GetDefinition("CMAKE_" + lang + "_STANDARD_DEFAULT");
2041   if (!defaultStd || !*defaultStd) {
2042     // This compiler has no notion of language standard levels.
2043     return;
2044   }
2045   std::string extProp = lang + "_EXTENSIONS";
2046   bool ext = true;
2047   if (const char* extPropValue = target->GetProperty(extProp)) {
2048     if (cmIsOff(extPropValue)) {
2049       ext = false;
2050     }
2051   }
2052   std::string stdProp = lang + "_STANDARD";
2053   const char* standardProp = target->GetProperty(stdProp);
2054   if (!standardProp) {
2055     if (ext) {
2056       // No language standard is specified and extensions are not disabled.
2057       // Check if this compiler needs a flag to enable extensions.
2058       std::string const option_flag =
2059         "CMAKE_" + lang + "_EXTENSION_COMPILE_OPTION";
2060       if (const char* opt =
2061             target->Target->GetMakefile()->GetDefinition(option_flag)) {
2062         std::vector<std::string> optVec = cmExpandedList(opt);
2063         for (std::string const& i : optVec) {
2064           this->AppendFlagEscape(flags, i);
2065         }
2066       }
2067     }
2068     return;
2069   }
2070
2071   std::string const type = ext ? "EXTENSION" : "STANDARD";
2072
2073   if (target->GetPropertyAsBool(lang + "_STANDARD_REQUIRED")) {
2074     std::string option_flag =
2075       "CMAKE_" + lang + standardProp + "_" + type + "_COMPILE_OPTION";
2076
2077     const char* opt =
2078       target->Target->GetMakefile()->GetDefinition(option_flag);
2079     if (!opt) {
2080       std::ostringstream e;
2081       e << "Target \"" << target->GetName()
2082         << "\" requires the language "
2083            "dialect \""
2084         << lang << standardProp << "\" "
2085         << (ext ? "(with compiler extensions)" : "")
2086         << ", but CMake "
2087            "does not know the compile flags to use to enable it.";
2088       this->IssueMessage(MessageType::FATAL_ERROR, e.str());
2089     } else {
2090       std::vector<std::string> optVec = cmExpandedList(opt);
2091       for (std::string const& i : optVec) {
2092         this->AppendFlagEscape(flags, i);
2093       }
2094     }
2095     return;
2096   }
2097
2098   static std::map<std::string, std::vector<std::string>> langStdMap;
2099   if (langStdMap.empty()) {
2100     // Maintain sorted order, most recent first.
2101     langStdMap["CXX"].emplace_back("20");
2102     langStdMap["CXX"].emplace_back("17");
2103     langStdMap["CXX"].emplace_back("14");
2104     langStdMap["CXX"].emplace_back("11");
2105     langStdMap["CXX"].emplace_back("98");
2106
2107     langStdMap["OBJCXX"].emplace_back("20");
2108     langStdMap["OBJCXX"].emplace_back("17");
2109     langStdMap["OBJCXX"].emplace_back("14");
2110     langStdMap["OBJCXX"].emplace_back("11");
2111     langStdMap["OBJCXX"].emplace_back("98");
2112
2113     langStdMap["C"].emplace_back("11");
2114     langStdMap["C"].emplace_back("99");
2115     langStdMap["C"].emplace_back("90");
2116
2117     langStdMap["OBJC"].emplace_back("11");
2118     langStdMap["OBJC"].emplace_back("99");
2119     langStdMap["OBJC"].emplace_back("90");
2120
2121     langStdMap["CUDA"].emplace_back("20");
2122     langStdMap["CUDA"].emplace_back("17");
2123     langStdMap["CUDA"].emplace_back("14");
2124     langStdMap["CUDA"].emplace_back("11");
2125     langStdMap["CUDA"].emplace_back("03");
2126   }
2127
2128   std::string standard(standardProp);
2129   if (lang == "CUDA" && standard == "98") {
2130     standard = "03";
2131   }
2132   std::vector<std::string>& stds = langStdMap[lang];
2133
2134   auto stdIt = std::find(stds.begin(), stds.end(), standard);
2135   if (stdIt == stds.end()) {
2136
2137     std::string e =
2138       lang + "_STANDARD is set to invalid value '" + standard + "'";
2139     this->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
2140       MessageType::FATAL_ERROR, e, target->GetBacktrace());
2141     return;
2142   }
2143
2144   auto defaultStdIt = std::find(stds.begin(), stds.end(), defaultStd);
2145   if (defaultStdIt == stds.end()) {
2146     std::string e = "CMAKE_" + lang +
2147       "_STANDARD_DEFAULT is set to invalid value '" + std::string(defaultStd) +
2148       "'";
2149     this->IssueMessage(MessageType::INTERNAL_ERROR, e);
2150     return;
2151   }
2152
2153   // If the standard requested is older than the compiler's default
2154   // then we need to use a flag to change it.  The comparison is
2155   // greater-or-equal because the standards are stored in backward
2156   // chronological order.
2157   if (stdIt >= defaultStdIt) {
2158     std::string option_flag =
2159       "CMAKE_" + lang + *stdIt + "_" + type + "_COMPILE_OPTION";
2160
2161     std::string const& opt =
2162       target->Target->GetMakefile()->GetRequiredDefinition(option_flag);
2163     std::vector<std::string> optVec = cmExpandedList(opt);
2164     for (std::string const& i : optVec) {
2165       this->AppendFlagEscape(flags, i);
2166     }
2167     return;
2168   }
2169
2170   // The standard requested is at least as new as the compiler's default,
2171   // and the standard request is not required.  Decay to the newest standard
2172   // for which a flag is defined.
2173   for (; stdIt < defaultStdIt; ++stdIt) {
2174     std::string option_flag =
2175       cmStrCat("CMAKE_", lang, *stdIt, "_", type, "_COMPILE_OPTION");
2176
2177     if (const char* opt =
2178           target->Target->GetMakefile()->GetDefinition(option_flag)) {
2179       std::vector<std::string> optVec = cmExpandedList(opt);
2180       for (std::string const& i : optVec) {
2181         this->AppendFlagEscape(flags, i);
2182       }
2183       return;
2184     }
2185   }
2186 }
2187
2188 static void AddVisibilityCompileOption(std::string& flags,
2189                                        cmGeneratorTarget const* target,
2190                                        cmLocalGenerator* lg,
2191                                        const std::string& lang,
2192                                        std::string* warnCMP0063)
2193 {
2194   std::string compileOption = "CMAKE_" + lang + "_COMPILE_OPTIONS_VISIBILITY";
2195   const char* opt = lg->GetMakefile()->GetDefinition(compileOption);
2196   if (!opt) {
2197     return;
2198   }
2199   std::string flagDefine = lang + "_VISIBILITY_PRESET";
2200
2201   const char* prop = target->GetProperty(flagDefine);
2202   if (!prop) {
2203     return;
2204   }
2205   if (warnCMP0063) {
2206     *warnCMP0063 += "  " + flagDefine + "\n";
2207     return;
2208   }
2209   if (strcmp(prop, "hidden") != 0 && strcmp(prop, "default") != 0 &&
2210       strcmp(prop, "protected") != 0 && strcmp(prop, "internal") != 0) {
2211     std::ostringstream e;
2212     e << "Target " << target->GetName() << " uses unsupported value \"" << prop
2213       << "\" for " << flagDefine << "."
2214       << " The supported values are: default, hidden, protected, and "
2215          "internal.";
2216     cmSystemTools::Error(e.str());
2217     return;
2218   }
2219   std::string option = std::string(opt) + prop;
2220   lg->AppendFlags(flags, option);
2221 }
2222
2223 static void AddInlineVisibilityCompileOption(std::string& flags,
2224                                              cmGeneratorTarget const* target,
2225                                              cmLocalGenerator* lg,
2226                                              std::string* warnCMP0063,
2227                                              const std::string& lang)
2228 {
2229   std::string compileOption =
2230     cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN");
2231   const char* opt = lg->GetMakefile()->GetDefinition(compileOption);
2232   if (!opt) {
2233     return;
2234   }
2235
2236   bool prop = target->GetPropertyAsBool("VISIBILITY_INLINES_HIDDEN");
2237   if (!prop) {
2238     return;
2239   }
2240   if (warnCMP0063) {
2241     *warnCMP0063 += "  VISIBILITY_INLINES_HIDDEN\n";
2242     return;
2243   }
2244   lg->AppendFlags(flags, opt);
2245 }
2246
2247 void cmLocalGenerator::AddVisibilityPresetFlags(
2248   std::string& flags, cmGeneratorTarget const* target, const std::string& lang)
2249 {
2250   if (lang.empty()) {
2251     return;
2252   }
2253
2254   std::string warnCMP0063;
2255   std::string* pWarnCMP0063 = nullptr;
2256   if (target->GetType() != cmStateEnums::SHARED_LIBRARY &&
2257       target->GetType() != cmStateEnums::MODULE_LIBRARY &&
2258       !target->IsExecutableWithExports()) {
2259     switch (target->GetPolicyStatusCMP0063()) {
2260       case cmPolicies::OLD:
2261         return;
2262       case cmPolicies::WARN:
2263         pWarnCMP0063 = &warnCMP0063;
2264         break;
2265       default:
2266         break;
2267     }
2268   }
2269
2270   AddVisibilityCompileOption(flags, target, this, lang, pWarnCMP0063);
2271
2272   if (lang == "CXX" || lang == "OBJCXX") {
2273     AddInlineVisibilityCompileOption(flags, target, this, pWarnCMP0063, lang);
2274   }
2275
2276   if (!warnCMP0063.empty() && this->WarnCMP0063.insert(target).second) {
2277     std::ostringstream w;
2278     /* clang-format off */
2279     w <<
2280       cmPolicies::GetPolicyWarning(cmPolicies::CMP0063) << "\n"
2281       "Target \"" << target->GetName() << "\" of "
2282       "type \"" << cmState::GetTargetTypeName(target->GetType()) << "\" "
2283       "has the following visibility properties set for " << lang << ":\n" <<
2284       warnCMP0063 <<
2285       "For compatibility CMake is not honoring them for this target.";
2286     /* clang-format on */
2287     target->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
2288       MessageType::AUTHOR_WARNING, w.str(), target->GetBacktrace());
2289   }
2290 }
2291
2292 void cmLocalGenerator::AddCMP0018Flags(std::string& flags,
2293                                        cmGeneratorTarget const* target,
2294                                        std::string const& lang,
2295                                        const std::string& config)
2296 {
2297   int targetType = target->GetType();
2298
2299   bool shared = ((targetType == cmStateEnums::SHARED_LIBRARY) ||
2300                  (targetType == cmStateEnums::MODULE_LIBRARY));
2301
2302   if (this->GetShouldUseOldFlags(shared, lang)) {
2303     this->AddSharedFlags(flags, lang, shared);
2304   } else {
2305     if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
2306       if (target->GetPropertyAsBool("POSITION_INDEPENDENT_CODE")) {
2307         this->AddPositionIndependentFlags(flags, lang, targetType);
2308       }
2309       return;
2310     }
2311
2312     if (target->GetLinkInterfaceDependentBoolProperty(
2313           "POSITION_INDEPENDENT_CODE", config)) {
2314       this->AddPositionIndependentFlags(flags, lang, targetType);
2315     }
2316     if (shared) {
2317       this->AppendFeatureOptions(flags, lang, "DLL");
2318     }
2319   }
2320 }
2321
2322 bool cmLocalGenerator::GetShouldUseOldFlags(bool shared,
2323                                             const std::string& lang) const
2324 {
2325   std::string originalFlags =
2326     this->GlobalGenerator->GetSharedLibFlagsForLanguage(lang);
2327   if (shared) {
2328     std::string flagsVar = cmStrCat("CMAKE_SHARED_LIBRARY_", lang, "_FLAGS");
2329     std::string const& flags = this->Makefile->GetSafeDefinition(flagsVar);
2330
2331     if (flags != originalFlags) {
2332       switch (this->GetPolicyStatus(cmPolicies::CMP0018)) {
2333         case cmPolicies::WARN: {
2334           std::ostringstream e;
2335           e << "Variable " << flagsVar
2336             << " has been modified. CMake "
2337                "will ignore the POSITION_INDEPENDENT_CODE target property for "
2338                "shared libraries and will use the "
2339             << flagsVar
2340             << " variable "
2341                "instead.  This may cause errors if the original content of "
2342             << flagsVar << " was removed.\n"
2343             << cmPolicies::GetPolicyWarning(cmPolicies::CMP0018);
2344
2345           this->IssueMessage(MessageType::AUTHOR_WARNING, e.str());
2346           CM_FALLTHROUGH;
2347         }
2348         case cmPolicies::OLD:
2349           return true;
2350         case cmPolicies::REQUIRED_IF_USED:
2351         case cmPolicies::REQUIRED_ALWAYS:
2352         case cmPolicies::NEW:
2353           return false;
2354       }
2355     }
2356   }
2357   return false;
2358 }
2359
2360 void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags,
2361                                                    std::string const& lang,
2362                                                    int targetType)
2363 {
2364   std::string picFlags;
2365
2366   if (targetType == cmStateEnums::EXECUTABLE) {
2367     picFlags = this->Makefile->GetSafeDefinition(
2368       cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIE"));
2369   }
2370   if (picFlags.empty()) {
2371     picFlags = this->Makefile->GetSafeDefinition(
2372       cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_PIC"));
2373   }
2374   if (!picFlags.empty()) {
2375     std::vector<std::string> options = cmExpandedList(picFlags);
2376     for (std::string const& o : options) {
2377       this->AppendFlagEscape(flags, o);
2378     }
2379   }
2380 }
2381
2382 void cmLocalGenerator::AddConfigVariableFlags(std::string& flags,
2383                                               const std::string& var,
2384                                               const std::string& config)
2385 {
2386   // Add the flags from the variable itself.
2387   this->AppendFlags(flags, this->Makefile->GetSafeDefinition(var));
2388   // Add the flags from the build-type specific variable.
2389   if (!config.empty()) {
2390     const std::string flagsVar =
2391       cmStrCat(var, '_', cmSystemTools::UpperCase(config));
2392     this->AppendFlags(flags, this->Makefile->GetSafeDefinition(flagsVar));
2393   }
2394 }
2395
2396 void cmLocalGenerator::AppendFlags(std::string& flags,
2397                                    const std::string& newFlags) const
2398 {
2399   if (!newFlags.empty()) {
2400     if (!flags.empty()) {
2401       flags += " ";
2402     }
2403     flags += newFlags;
2404   }
2405 }
2406
2407 void cmLocalGenerator::AppendFlags(
2408   std::string& flags, const std::vector<BT<std::string>>& newFlags) const
2409 {
2410   for (BT<std::string> const& flag : newFlags) {
2411     this->AppendFlags(flags, flag.Value);
2412   }
2413 }
2414
2415 void cmLocalGenerator::AppendFlagEscape(std::string& flags,
2416                                         const std::string& rawFlag) const
2417 {
2418   this->AppendFlags(
2419     flags,
2420     this->EscapeForShell(rawFlag, false, false, false, this->IsNinjaMulti()));
2421 }
2422
2423 void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
2424 {
2425   std::vector<std::string> configsList;
2426   std::string configDefault = this->Makefile->GetConfigurations(configsList);
2427   if (configsList.empty()) {
2428     configsList.push_back(configDefault);
2429   }
2430
2431   for (std::string const& config : configsList) {
2432     const std::string buildType = cmSystemTools::UpperCase(config);
2433
2434     // FIXME: Refactor collection of sources to not evaluate object libraries.
2435     std::vector<cmSourceFile*> sources;
2436     target->GetSourceFiles(sources, buildType);
2437
2438     for (const std::string& lang : { "C", "CXX", "OBJC", "OBJCXX" }) {
2439       auto langSources = std::count_if(
2440         sources.begin(), sources.end(), [lang](cmSourceFile* sf) {
2441           return lang == sf->GetLanguage() &&
2442             !sf->GetProperty("SKIP_PRECOMPILE_HEADERS");
2443         });
2444       if (langSources == 0) {
2445         continue;
2446       }
2447
2448       const std::string pchSource = target->GetPchSource(config, lang);
2449       const std::string pchHeader = target->GetPchHeader(config, lang);
2450
2451       if (pchSource.empty() || pchHeader.empty()) {
2452         continue;
2453       }
2454
2455       const std::string pchExtension =
2456         this->Makefile->GetSafeDefinition("CMAKE_PCH_EXTENSION");
2457
2458       if (pchExtension.empty()) {
2459         continue;
2460       }
2461
2462       const char* pchReuseFrom =
2463         target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
2464
2465       auto pch_sf = this->Makefile->GetOrCreateSource(
2466         pchSource, false, cmSourceFileLocationKind::Known);
2467
2468       if (!this->GetGlobalGenerator()->IsXcode()) {
2469         if (!pchReuseFrom) {
2470           target->AddSource(pchSource, true);
2471         }
2472
2473         const std::string pchFile = target->GetPchFile(config, lang);
2474
2475         // Exclude the pch files from linking
2476         if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
2477           if (!pchReuseFrom) {
2478             pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
2479           } else {
2480             auto reuseTarget =
2481               this->GlobalGenerator->FindGeneratorTarget(pchReuseFrom);
2482
2483             if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
2484
2485               const std::string pdb_prefix =
2486                 this->GetGlobalGenerator()->IsMultiConfig()
2487                 ? cmStrCat(this->GlobalGenerator->GetCMakeCFGIntDir(), "/")
2488                 : "";
2489
2490               const std::string target_compile_pdb_dir = cmStrCat(
2491                 target->GetLocalGenerator()->GetCurrentBinaryDirectory(), "/",
2492                 target->GetName(), ".dir/");
2493
2494               const std::string copy_script =
2495                 cmStrCat(target_compile_pdb_dir, "copy_idb_pdb.cmake");
2496               cmGeneratedFileStream file(copy_script);
2497
2498               file << "# CMake generated file\n";
2499               for (auto extension : { ".pdb", ".idb" }) {
2500                 const std::string from_file =
2501                   cmStrCat(reuseTarget->GetLocalGenerator()
2502                              ->GetCurrentBinaryDirectory(),
2503                            "/", pchReuseFrom, ".dir/${PDB_PREFIX}",
2504                            pchReuseFrom, extension);
2505
2506                 const std::string to_dir = cmStrCat(
2507                   target->GetLocalGenerator()->GetCurrentBinaryDirectory(),
2508                   "/", target->GetName(), ".dir/${PDB_PREFIX}");
2509
2510                 const std::string to_file =
2511                   cmStrCat(to_dir, pchReuseFrom, extension);
2512
2513                 std::string dest_file = to_file;
2514
2515                 const std::string prefix = target->GetSafeProperty("PREFIX");
2516                 if (!prefix.empty()) {
2517                   dest_file =
2518                     cmStrCat(to_dir, prefix, pchReuseFrom, extension);
2519                 }
2520
2521                 file << "if (EXISTS \"" << from_file << "\" AND \""
2522                      << from_file << "\" IS_NEWER_THAN \"" << dest_file
2523                      << "\")\n";
2524                 file << "  file(COPY \"" << from_file << "\""
2525                      << " DESTINATION \"" << to_dir << "\")\n";
2526                 if (!prefix.empty()) {
2527                   file << "  file(REMOVE \"" << dest_file << "\")\n";
2528                   file << "  file(RENAME \"" << to_file << "\" \"" << dest_file
2529                        << "\")\n";
2530                 }
2531                 file << "endif()\n";
2532               }
2533
2534               cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
2535                 { cmSystemTools::GetCMakeCommand(),
2536                   cmStrCat("-DPDB_PREFIX=", pdb_prefix), "-P", copy_script });
2537
2538               const std::string no_main_dependency;
2539               const std::vector<std::string> no_deps;
2540               const char* no_message = "";
2541               const char* no_current_dir = nullptr;
2542               std::vector<std::string> no_byproducts;
2543
2544               std::vector<std::string> outputs;
2545               outputs.push_back(cmStrCat(target_compile_pdb_dir, pdb_prefix,
2546                                          pchReuseFrom, ".pdb"));
2547
2548               if (this->GetGlobalGenerator()->IsVisualStudio()) {
2549                 this->AddCustomCommandToTarget(
2550                   target->GetName(), outputs, no_deps, commandLines,
2551                   cmCustomCommandType::PRE_BUILD, no_message, no_current_dir);
2552               } else {
2553                 cmImplicitDependsList no_implicit_depends;
2554                 cmSourceFile* copy_rule = this->AddCustomCommandToOutput(
2555                   outputs, no_byproducts, no_deps, no_main_dependency,
2556                   no_implicit_depends, commandLines, no_message,
2557                   no_current_dir);
2558
2559                 if (copy_rule) {
2560                   target->AddSource(copy_rule->ResolveFullPath());
2561                 }
2562               }
2563
2564               target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
2565                                           target_compile_pdb_dir);
2566             }
2567
2568             std::string pchSourceObj =
2569               reuseTarget->GetPchFileObject(config, lang);
2570
2571             // Link to the pch object file
2572             target->Target->AppendProperty(
2573               "LINK_FLAGS",
2574               cmStrCat(" ", this->ConvertToOutputFormat(pchSourceObj, SHELL)),
2575               true);
2576           }
2577         } else {
2578           pch_sf->SetProperty("PCH_EXTENSION", pchExtension.c_str());
2579         }
2580
2581         // Add pchHeader to source files, which will
2582         // be grouped as "Precompile Header File"
2583         auto pchHeader_sf = this->Makefile->GetOrCreateSource(
2584           pchHeader, false, cmSourceFileLocationKind::Known);
2585         std::string err;
2586         pchHeader_sf->ResolveFullPath(&err);
2587         target->AddSource(pchHeader);
2588       }
2589     }
2590   }
2591 }
2592
2593 void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target)
2594 {
2595   if (!target->GetPropertyAsBool("UNITY_BUILD")) {
2596     return;
2597   }
2598
2599   // FIXME: Handle all configurations in multi-config generators.
2600   std::string config;
2601   if (!this->GetGlobalGenerator()->IsMultiConfig()) {
2602     config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
2603   }
2604
2605   const std::string buildType = cmSystemTools::UpperCase(config);
2606
2607   std::string filename_base =
2608     cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/",
2609              target->GetName(), ".dir/Unity/");
2610
2611   // FIXME: Refactor collection of sources to not evaluate object libraries.
2612   std::vector<cmSourceFile*> sources;
2613   target->GetSourceFiles(sources, buildType);
2614
2615   auto batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE");
2616   const size_t unityBatchSize =
2617     static_cast<size_t>(std::atoi(batchSizeString));
2618
2619   auto beforeInclude = target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE");
2620   auto afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE");
2621
2622   for (std::string lang : { "C", "CXX" }) {
2623     std::vector<cmSourceFile*> filtered_sources;
2624     std::copy_if(sources.begin(), sources.end(),
2625                  std::back_inserter(filtered_sources), [&](cmSourceFile* sf) {
2626                    return sf->GetLanguage() == lang &&
2627                      !sf->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") &&
2628                      !sf->GetPropertyAsBool("HEADER_FILE_ONLY") &&
2629                      !sf->GetProperty("COMPILE_OPTIONS") &&
2630                      !sf->GetProperty("COMPILE_DEFINITIONS") &&
2631                      !sf->GetProperty("COMPILE_FLAGS") &&
2632                      !sf->GetProperty("INCLUDE_DIRECTORIES");
2633                  });
2634
2635     size_t batchSize = unityBatchSize;
2636     if (unityBatchSize == 0) {
2637       batchSize = filtered_sources.size();
2638     }
2639
2640     for (size_t itemsLeft = filtered_sources.size(), chunk, batch = 0;
2641          itemsLeft > 0; itemsLeft -= chunk, ++batch) {
2642
2643       chunk = std::min(itemsLeft, batchSize);
2644
2645       std::string filename = cmStrCat(filename_base, "unity_", batch,
2646                                       (lang == "C") ? "_c.c" : "_cxx.cxx");
2647
2648       const std::string filename_tmp = cmStrCat(filename, ".tmp");
2649       {
2650         size_t begin = batch * batchSize;
2651         size_t end = begin + chunk;
2652
2653         cmGeneratedFileStream file(
2654           filename_tmp, false,
2655           this->GetGlobalGenerator()->GetMakefileEncoding());
2656         file << "/* generated by CMake */\n\n";
2657
2658         for (; begin != end; ++begin) {
2659           cmSourceFile* sf = filtered_sources[begin];
2660
2661           target->AddSourceFileToUnityBatch(sf->ResolveFullPath());
2662           sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str());
2663
2664           if (beforeInclude) {
2665             file << beforeInclude << "\n";
2666           }
2667
2668           file << "#include \"" << sf->ResolveFullPath() << "\"\n";
2669
2670           if (afterInclude) {
2671             file << afterInclude << "\n";
2672           }
2673         }
2674       }
2675       cmSystemTools::MoveFileIfDifferent(filename_tmp, filename);
2676
2677       target->AddSource(filename, true);
2678
2679       auto unity = this->Makefile->GetOrCreateSource(filename);
2680       unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON");
2681       unity->SetProperty("UNITY_SOURCE_FILE", filename.c_str());
2682     }
2683   }
2684 }
2685
2686 void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
2687                                             cmGeneratorTarget* target,
2688                                             const std::string& config,
2689                                             const std::string& lang)
2690 {
2691   if (!target->IsIPOEnabled(lang, config)) {
2692     return;
2693   }
2694
2695   switch (target->GetType()) {
2696     case cmStateEnums::EXECUTABLE:
2697     case cmStateEnums::SHARED_LIBRARY:
2698     case cmStateEnums::MODULE_LIBRARY:
2699       break;
2700     default:
2701       return;
2702   }
2703
2704   const std::string name = "CMAKE_" + lang + "_LINK_OPTIONS_IPO";
2705   const char* rawFlagsList = this->Makefile->GetDefinition(name);
2706   if (rawFlagsList == nullptr) {
2707     return;
2708   }
2709
2710   std::vector<std::string> flagsList = cmExpandedList(rawFlagsList);
2711   for (std::string const& o : flagsList) {
2712     this->AppendFlagEscape(flags, o);
2713   }
2714 }
2715
2716 void cmLocalGenerator::AppendPositionIndependentLinkerFlags(
2717   std::string& flags, cmGeneratorTarget* target, const std::string& config,
2718   const std::string& lang)
2719 {
2720   // For now, only EXECUTABLE is concerned
2721   if (target->GetType() != cmStateEnums::EXECUTABLE) {
2722     return;
2723   }
2724
2725   const char* PICValue = target->GetLinkPIEProperty(config);
2726   if (PICValue == nullptr) {
2727     // POSITION_INDEPENDENT_CODE is not set
2728     return;
2729   }
2730
2731   const std::string mode = cmIsOn(PICValue) ? "PIE" : "NO_PIE";
2732
2733   std::string supported = "CMAKE_" + lang + "_LINK_" + mode + "_SUPPORTED";
2734   if (cmIsOff(this->Makefile->GetDefinition(supported))) {
2735     return;
2736   }
2737
2738   std::string name = "CMAKE_" + lang + "_LINK_OPTIONS_" + mode;
2739
2740   auto pieFlags = this->Makefile->GetSafeDefinition(name);
2741   if (pieFlags.empty()) {
2742     return;
2743   }
2744
2745   std::vector<std::string> flagsList = cmExpandedList(pieFlags);
2746   for (const auto& flag : flagsList) {
2747     this->AppendFlagEscape(flags, flag);
2748   }
2749 }
2750
2751 void cmLocalGenerator::AppendCompileOptions(std::string& options,
2752                                             std::string const& options_list,
2753                                             const char* regex) const
2754 {
2755   // Short-circuit if there are no options.
2756   if (options_list.empty()) {
2757     return;
2758   }
2759
2760   // Expand the list of options.
2761   std::vector<std::string> options_vec = cmExpandedList(options_list);
2762   this->AppendCompileOptions(options, options_vec, regex);
2763 }
2764
2765 void cmLocalGenerator::AppendCompileOptions(
2766   std::string& options, const std::vector<std::string>& options_vec,
2767   const char* regex) const
2768 {
2769   if (regex != nullptr) {
2770     // Filter flags upon specified reges.
2771     cmsys::RegularExpression r(regex);
2772
2773     for (std::string const& opt : options_vec) {
2774       if (r.find(opt)) {
2775         this->AppendFlagEscape(options, opt);
2776       }
2777     }
2778   } else {
2779     for (std::string const& opt : options_vec) {
2780       this->AppendFlagEscape(options, opt);
2781     }
2782   }
2783 }
2784
2785 void cmLocalGenerator::AppendCompileOptions(
2786   std::vector<BT<std::string>>& options,
2787   const std::vector<BT<std::string>>& options_vec, const char* regex) const
2788 {
2789   if (regex != nullptr) {
2790     // Filter flags upon specified regular expressions.
2791     cmsys::RegularExpression r(regex);
2792
2793     for (BT<std::string> const& opt : options_vec) {
2794       if (r.find(opt.Value)) {
2795         std::string flag;
2796         this->AppendFlagEscape(flag, opt.Value);
2797         options.emplace_back(std::move(flag), opt.Backtrace);
2798       }
2799     }
2800   } else {
2801     for (BT<std::string> const& opt : options_vec) {
2802       std::string flag;
2803       this->AppendFlagEscape(flag, opt.Value);
2804       options.emplace_back(std::move(flag), opt.Backtrace);
2805     }
2806   }
2807 }
2808
2809 void cmLocalGenerator::AppendIncludeDirectories(
2810   std::vector<std::string>& includes, const std::string& includes_list,
2811   const cmSourceFile& sourceFile) const
2812 {
2813   // Short-circuit if there are no includes.
2814   if (includes_list.empty()) {
2815     return;
2816   }
2817
2818   // Expand the list of includes.
2819   std::vector<std::string> includes_vec = cmExpandedList(includes_list);
2820   this->AppendIncludeDirectories(includes, includes_vec, sourceFile);
2821 }
2822
2823 void cmLocalGenerator::AppendIncludeDirectories(
2824   std::vector<std::string>& includes,
2825   const std::vector<std::string>& includes_vec,
2826   const cmSourceFile& sourceFile) const
2827 {
2828   std::unordered_set<std::string> uniqueIncludes;
2829
2830   for (const std::string& include : includes_vec) {
2831     if (!cmSystemTools::FileIsFullPath(include)) {
2832       std::ostringstream e;
2833       e << "Found relative path while evaluating include directories of "
2834            "\""
2835         << sourceFile.GetLocation().GetName() << "\":\n  \"" << include
2836         << "\"\n";
2837
2838       this->IssueMessage(MessageType::FATAL_ERROR, e.str());
2839       return;
2840     }
2841
2842     std::string inc = include;
2843
2844     if (!cmIsOff(inc)) {
2845       cmSystemTools::ConvertToUnixSlashes(inc);
2846     }
2847
2848     if (uniqueIncludes.insert(inc).second) {
2849       includes.push_back(std::move(inc));
2850     }
2851   }
2852 }
2853
2854 void cmLocalGenerator::AppendDefines(std::set<std::string>& defines,
2855                                      std::string const& defines_list) const
2856 {
2857   std::set<BT<std::string>> tmp;
2858   this->AppendDefines(tmp, ExpandListWithBacktrace(defines_list));
2859   for (BT<std::string> const& i : tmp) {
2860     defines.emplace(i.Value);
2861   }
2862 }
2863
2864 void cmLocalGenerator::AppendDefines(std::set<BT<std::string>>& defines,
2865                                      std::string const& defines_list) const
2866 {
2867   // Short-circuit if there are no definitions.
2868   if (defines_list.empty()) {
2869     return;
2870   }
2871
2872   // Expand the list of definitions.
2873   this->AppendDefines(defines, ExpandListWithBacktrace(defines_list));
2874 }
2875
2876 void cmLocalGenerator::AppendDefines(
2877   std::set<BT<std::string>>& defines,
2878   const std::vector<BT<std::string>>& defines_vec) const
2879 {
2880   for (BT<std::string> const& d : defines_vec) {
2881     // Skip unsupported definitions.
2882     if (!this->CheckDefinition(d.Value)) {
2883       continue;
2884     }
2885     defines.insert(d);
2886   }
2887 }
2888
2889 void cmLocalGenerator::JoinDefines(const std::set<std::string>& defines,
2890                                    std::string& definesString,
2891                                    const std::string& lang)
2892 {
2893   // Lookup the define flag for the current language.
2894   std::string dflag = "-D";
2895   if (!lang.empty()) {
2896     const char* df =
2897       this->Makefile->GetDefinition(cmStrCat("CMAKE_", lang, "_DEFINE_FLAG"));
2898     if (df && *df) {
2899       dflag = df;
2900     }
2901   }
2902   const char* itemSeparator = definesString.empty() ? "" : " ";
2903   for (std::string const& define : defines) {
2904     // Append the definition with proper escaping.
2905     std::string def = dflag;
2906     if (this->GetState()->UseWatcomWMake()) {
2907       // The Watcom compiler does its own command line parsing instead
2908       // of using the windows shell rules.  Definitions are one of
2909       //   -DNAME
2910       //   -DNAME=<cpp-token>
2911       //   -DNAME="c-string with spaces and other characters(?@#$)"
2912       //
2913       // Watcom will properly parse each of these cases from the
2914       // command line without any escapes.  However we still have to
2915       // get the '$' and '#' characters through WMake as '$$' and
2916       // '$#'.
2917       for (const char* c = define.c_str(); *c; ++c) {
2918         if (*c == '$' || *c == '#') {
2919           def += '$';
2920         }
2921         def += *c;
2922       }
2923     } else {
2924       // Make the definition appear properly on the command line.  Use
2925       // -DNAME="value" instead of -D"NAME=value" for historical reasons.
2926       std::string::size_type eq = define.find('=');
2927       def += define.substr(0, eq);
2928       if (eq != std::string::npos) {
2929         def += "=";
2930         def += this->EscapeForShell(define.substr(eq + 1), true);
2931       }
2932     }
2933     definesString += itemSeparator;
2934     itemSeparator = " ";
2935     definesString += def;
2936   }
2937 }
2938
2939 void cmLocalGenerator::AppendFeatureOptions(std::string& flags,
2940                                             const std::string& lang,
2941                                             const char* feature)
2942 {
2943   const char* optionList = this->Makefile->GetDefinition(
2944     cmStrCat("CMAKE_", lang, "_COMPILE_OPTIONS_", feature));
2945   if (optionList != nullptr) {
2946     std::vector<std::string> options = cmExpandedList(optionList);
2947     for (std::string const& o : options) {
2948       this->AppendFlagEscape(flags, o);
2949     }
2950   }
2951 }
2952
2953 const char* cmLocalGenerator::GetFeature(const std::string& feature,
2954                                          const std::string& config)
2955 {
2956   std::string featureName = feature;
2957   // TODO: Define accumulation policy for features (prepend, append, replace).
2958   // Currently we always replace.
2959   if (!config.empty()) {
2960     featureName += "_";
2961     featureName += cmSystemTools::UpperCase(config);
2962   }
2963   cmStateSnapshot snp = this->StateSnapshot;
2964   while (snp.IsValid()) {
2965     if (const char* value = snp.GetDirectory().GetProperty(featureName)) {
2966       return value;
2967     }
2968     snp = snp.GetBuildsystemDirectoryParent();
2969   }
2970   return nullptr;
2971 }
2972
2973 std::string cmLocalGenerator::GetProjectName() const
2974 {
2975   return this->StateSnapshot.GetProjectName();
2976 }
2977
2978 std::string cmLocalGenerator::ConstructComment(
2979   cmCustomCommandGenerator const& ccg, const char* default_comment)
2980 {
2981   // Check for a comment provided with the command.
2982   if (ccg.GetComment()) {
2983     return ccg.GetComment();
2984   }
2985
2986   // Construct a reasonable default comment if possible.
2987   if (!ccg.GetOutputs().empty()) {
2988     std::string comment;
2989     comment = "Generating ";
2990     const char* sep = "";
2991     std::string currentBinaryDir = this->GetCurrentBinaryDirectory();
2992     for (std::string const& o : ccg.GetOutputs()) {
2993       comment += sep;
2994       comment += this->MaybeConvertToRelativePath(currentBinaryDir, o);
2995       sep = ", ";
2996     }
2997     return comment;
2998   }
2999
3000   // Otherwise use the provided default.
3001   return default_comment;
3002 }
3003
3004 class cmInstallTargetGeneratorLocal : public cmInstallTargetGenerator
3005 {
3006 public:
3007   cmInstallTargetGeneratorLocal(cmLocalGenerator* lg, std::string const& t,
3008                                 std::string const& dest, bool implib)
3009     : cmInstallTargetGenerator(
3010         t, dest, implib, "", std::vector<std::string>(), "Unspecified",
3011         cmInstallGenerator::SelectMessageLevel(lg->GetMakefile()), false,
3012         false)
3013   {
3014     this->Compute(lg);
3015   }
3016 };
3017
3018 void cmLocalGenerator::GenerateTargetInstallRules(
3019   std::ostream& os, const std::string& config,
3020   std::vector<std::string> const& configurationTypes)
3021 {
3022   // Convert the old-style install specification from each target to
3023   // an install generator and run it.
3024   const auto& tgts = this->GetGeneratorTargets();
3025   for (const auto& l : tgts) {
3026     if (l->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
3027       continue;
3028     }
3029
3030     // Include the user-specified pre-install script for this target.
3031     if (const char* preinstall = l->GetProperty("PRE_INSTALL_SCRIPT")) {
3032       cmInstallScriptGenerator g(preinstall, false, "", false);
3033       g.Generate(os, config, configurationTypes);
3034     }
3035
3036     // Install this target if a destination is given.
3037     if (!l->Target->GetInstallPath().empty()) {
3038       // Compute the full install destination.  Note that converting
3039       // to unix slashes also removes any trailing slash.
3040       // We also skip over the leading slash given by the user.
3041       std::string destination = l->Target->GetInstallPath().substr(1);
3042       cmSystemTools::ConvertToUnixSlashes(destination);
3043       if (destination.empty()) {
3044         destination = ".";
3045       }
3046
3047       // Generate the proper install generator for this target type.
3048       switch (l->GetType()) {
3049         case cmStateEnums::EXECUTABLE:
3050         case cmStateEnums::STATIC_LIBRARY:
3051         case cmStateEnums::MODULE_LIBRARY: {
3052           // Use a target install generator.
3053           cmInstallTargetGeneratorLocal g(this, l->GetName(), destination,
3054                                           false);
3055           g.Generate(os, config, configurationTypes);
3056         } break;
3057         case cmStateEnums::SHARED_LIBRARY: {
3058 #if defined(_WIN32) || defined(__CYGWIN__)
3059           // Special code to handle DLL.  Install the import library
3060           // to the normal destination and the DLL to the runtime
3061           // destination.
3062           cmInstallTargetGeneratorLocal g1(this, l->GetName(), destination,
3063                                            true);
3064           g1.Generate(os, config, configurationTypes);
3065           // We also skip over the leading slash given by the user.
3066           destination = l->Target->GetRuntimeInstallPath().substr(1);
3067           cmSystemTools::ConvertToUnixSlashes(destination);
3068           cmInstallTargetGeneratorLocal g2(this, l->GetName(), destination,
3069                                            false);
3070           g2.Generate(os, config, configurationTypes);
3071 #else
3072           // Use a target install generator.
3073           cmInstallTargetGeneratorLocal g(this, l->GetName(), destination,
3074                                           false);
3075           g.Generate(os, config, configurationTypes);
3076 #endif
3077         } break;
3078         default:
3079           break;
3080       }
3081     }
3082
3083     // Include the user-specified post-install script for this target.
3084     if (const char* postinstall = l->GetProperty("POST_INSTALL_SCRIPT")) {
3085       cmInstallScriptGenerator g(postinstall, false, "", false);
3086       g.Generate(os, config, configurationTypes);
3087     }
3088   }
3089 }
3090
3091 #if defined(CM_LG_ENCODE_OBJECT_NAMES)
3092 static bool cmLocalGeneratorShortenObjectName(std::string& objName,
3093                                               std::string::size_type max_len)
3094 {
3095   // Replace the beginning of the path portion of the object name with
3096   // its own md5 sum.
3097   std::string::size_type pos =
3098     objName.find('/', objName.size() - max_len + 32);
3099   if (pos != std::string::npos) {
3100     cmCryptoHash md5(cmCryptoHash::AlgoMD5);
3101     std::string md5name = cmStrCat(md5.HashString(objName.substr(0, pos)),
3102                                    cm::string_view(objName).substr(pos));
3103     objName = md5name;
3104
3105     // The object name is now short enough.
3106     return true;
3107   }
3108   // The object name could not be shortened enough.
3109   return false;
3110 }
3111
3112 bool cmLocalGeneratorCheckObjectName(std::string& objName,
3113                                      std::string::size_type dir_len,
3114                                      std::string::size_type max_total_len)
3115 {
3116   // Enforce the maximum file name length if possible.
3117   std::string::size_type max_obj_len = max_total_len;
3118   if (dir_len < max_total_len) {
3119     max_obj_len = max_total_len - dir_len;
3120     if (objName.size() > max_obj_len) {
3121       // The current object file name is too long.  Try to shorten it.
3122       return cmLocalGeneratorShortenObjectName(objName, max_obj_len);
3123     }
3124     // The object file name is short enough.
3125     return true;
3126   }
3127   // The build directory in which the object will be stored is
3128   // already too deep.
3129   return false;
3130 }
3131 #endif
3132
3133 std::string& cmLocalGenerator::CreateSafeUniqueObjectFileName(
3134   const std::string& sin, std::string const& dir_max)
3135 {
3136   // Look for an existing mapped name for this object file.
3137   auto it = this->UniqueObjectNamesMap.find(sin);
3138
3139   // If no entry exists create one.
3140   if (it == this->UniqueObjectNamesMap.end()) {
3141     // Start with the original name.
3142     std::string ssin = sin;
3143
3144     // Avoid full paths by removing leading slashes.
3145     ssin.erase(0, ssin.find_first_not_of('/'));
3146
3147     // Avoid full paths by removing colons.
3148     std::replace(ssin.begin(), ssin.end(), ':', '_');
3149
3150     // Avoid relative paths that go up the tree.
3151     cmSystemTools::ReplaceString(ssin, "../", "__/");
3152
3153     // Avoid spaces.
3154     std::replace(ssin.begin(), ssin.end(), ' ', '_');
3155
3156     // Mangle the name if necessary.
3157     if (this->Makefile->IsOn("CMAKE_MANGLE_OBJECT_FILE_NAMES")) {
3158       bool done;
3159       int cc = 0;
3160       char rpstr[100];
3161       sprintf(rpstr, "_p_");
3162       cmSystemTools::ReplaceString(ssin, "+", rpstr);
3163       std::string sssin = sin;
3164       do {
3165         done = true;
3166         for (it = this->UniqueObjectNamesMap.begin();
3167              it != this->UniqueObjectNamesMap.end(); ++it) {
3168           if (it->second == ssin) {
3169             done = false;
3170           }
3171         }
3172         if (done) {
3173           break;
3174         }
3175         sssin = ssin;
3176         cmSystemTools::ReplaceString(ssin, "_p_", rpstr);
3177         sprintf(rpstr, "_p%d_", cc++);
3178       } while (!done);
3179     }
3180
3181 #if defined(CM_LG_ENCODE_OBJECT_NAMES)
3182     if (!cmLocalGeneratorCheckObjectName(ssin, dir_max.size(),
3183                                          this->ObjectPathMax)) {
3184       // Warn if this is the first time the path has been seen.
3185       if (this->ObjectMaxPathViolations.insert(dir_max).second) {
3186         std::ostringstream m;
3187         /* clang-format off */
3188         m << "The object file directory\n"
3189           << "  " << dir_max << "\n"
3190           << "has " << dir_max.size() << " characters.  "
3191           << "The maximum full path to an object file is "
3192           << this->ObjectPathMax << " characters "
3193           << "(see CMAKE_OBJECT_PATH_MAX).  "
3194           << "Object file\n"
3195           << "  " << ssin << "\n"
3196           << "cannot be safely placed under this directory.  "
3197           << "The build may not work correctly.";
3198         /* clang-format on */
3199         this->IssueMessage(MessageType::WARNING, m.str());
3200       }
3201     }
3202 #else
3203     (void)dir_max;
3204 #endif
3205
3206     // Insert the newly mapped object file name.
3207     std::map<std::string, std::string>::value_type e(sin, ssin);
3208     it = this->UniqueObjectNamesMap.insert(e).first;
3209   }
3210
3211   // Return the map entry.
3212   return it->second;
3213 }
3214
3215 void cmLocalGenerator::ComputeObjectFilenames(
3216   std::map<cmSourceFile const*, std::string>& /*unused*/,
3217   cmGeneratorTarget const* /*unused*/)
3218 {
3219 }
3220
3221 bool cmLocalGenerator::IsWindowsShell() const
3222 {
3223   return this->GetState()->UseWindowsShell();
3224 }
3225
3226 bool cmLocalGenerator::IsWatcomWMake() const
3227 {
3228   return this->GetState()->UseWatcomWMake();
3229 }
3230
3231 bool cmLocalGenerator::IsMinGWMake() const
3232 {
3233   return this->GetState()->UseMinGWMake();
3234 }
3235
3236 bool cmLocalGenerator::IsNMake() const
3237 {
3238   return this->GetState()->UseNMake();
3239 }
3240
3241 bool cmLocalGenerator::IsNinjaMulti() const
3242 {
3243   return this->GetState()->UseNinjaMulti();
3244 }
3245
3246 std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
3247   const cmSourceFile& source, std::string const& dir_max,
3248   bool* hasSourceExtension, char const* customOutputExtension)
3249 {
3250   // Construct the object file name using the full path to the source
3251   // file which is its only unique identification.
3252   std::string const& fullPath = source.GetFullPath();
3253
3254   // Try referencing the source relative to the source tree.
3255   std::string relFromSource = this->MaybeConvertToRelativePath(
3256     this->GetCurrentSourceDirectory(), fullPath);
3257   assert(!relFromSource.empty());
3258   bool relSource = !cmSystemTools::FileIsFullPath(relFromSource);
3259   bool subSource = relSource && relFromSource[0] != '.';
3260
3261   // Try referencing the source relative to the binary tree.
3262   std::string relFromBinary = this->MaybeConvertToRelativePath(
3263     this->GetCurrentBinaryDirectory(), fullPath);
3264   assert(!relFromBinary.empty());
3265   bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary);
3266   bool subBinary = relBinary && relFromBinary[0] != '.';
3267
3268   // Select a nice-looking reference to the source file to construct
3269   // the object file name.
3270   std::string objectName;
3271   if ((relSource && !relBinary) || (subSource && !subBinary)) {
3272     objectName = relFromSource;
3273   } else if ((relBinary && !relSource) || (subBinary && !subSource)) {
3274     objectName = relFromBinary;
3275   } else if (relFromBinary.length() < relFromSource.length()) {
3276     objectName = relFromBinary;
3277   } else {
3278     objectName = relFromSource;
3279   }
3280
3281   // if it is still a full path check for the try compile case
3282   // try compile never have in source sources, and should not
3283   // have conflicting source file names in the same target
3284   if (cmSystemTools::FileIsFullPath(objectName)) {
3285     if (this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
3286       objectName = cmSystemTools::GetFilenameName(source.GetFullPath());
3287     }
3288   }
3289
3290   // Ensure that for the CMakeFiles/<target>.dir/generated_source_file
3291   // we don't end up having:
3292   // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj
3293   const char* unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE");
3294   const char* pchExtension = source.GetProperty("PCH_EXTENSION");
3295   const bool isPchObject = objectName.find("cmake_pch") != std::string::npos;
3296   if (unitySourceFile || pchExtension || isPchObject) {
3297     if (pchExtension) {
3298       customOutputExtension = pchExtension;
3299     }
3300
3301     cmsys::RegularExpression var("(CMakeFiles/[^/]+.dir/)");
3302     if (var.find(objectName)) {
3303       objectName.erase(var.start(), var.end() - var.start());
3304     }
3305   }
3306
3307   // Replace the original source file extension with the object file
3308   // extension.
3309   bool keptSourceExtension = true;
3310   if (!source.GetPropertyAsBool("KEEP_EXTENSION")) {
3311     // Decide whether this language wants to replace the source
3312     // extension with the object extension.  For CMake 2.4
3313     // compatibility do this by default.
3314     bool replaceExt = this->NeedBackwardsCompatibility_2_4();
3315     if (!replaceExt) {
3316       std::string lang = source.GetLanguage();
3317       if (!lang.empty()) {
3318         replaceExt = this->Makefile->IsOn(
3319           cmStrCat("CMAKE_", lang, "_OUTPUT_EXTENSION_REPLACE"));
3320       }
3321     }
3322
3323     // Remove the source extension if it is to be replaced.
3324     if (replaceExt || customOutputExtension) {
3325       keptSourceExtension = false;
3326       std::string::size_type dot_pos = objectName.rfind('.');
3327       if (dot_pos != std::string::npos) {
3328         objectName = objectName.substr(0, dot_pos);
3329       }
3330     }
3331
3332     // Store the new extension.
3333     if (customOutputExtension) {
3334       objectName += customOutputExtension;
3335     } else {
3336       objectName += this->GlobalGenerator->GetLanguageOutputExtension(source);
3337     }
3338   }
3339   if (hasSourceExtension) {
3340     *hasSourceExtension = keptSourceExtension;
3341   }
3342
3343   // Convert to a safe name.
3344   return this->CreateSafeUniqueObjectFileName(objectName, dir_max);
3345 }
3346
3347 std::string cmLocalGenerator::GetSourceFileLanguage(const cmSourceFile& source)
3348 {
3349   return source.GetLanguage();
3350 }
3351
3352 cmake* cmLocalGenerator::GetCMakeInstance() const
3353 {
3354   return this->GlobalGenerator->GetCMakeInstance();
3355 }
3356
3357 std::string const& cmLocalGenerator::GetSourceDirectory() const
3358 {
3359   return this->GetCMakeInstance()->GetHomeDirectory();
3360 }
3361
3362 std::string const& cmLocalGenerator::GetBinaryDirectory() const
3363 {
3364   return this->GetCMakeInstance()->GetHomeOutputDirectory();
3365 }
3366
3367 std::string const& cmLocalGenerator::GetCurrentBinaryDirectory() const
3368 {
3369   return this->StateSnapshot.GetDirectory().GetCurrentBinary();
3370 }
3371
3372 std::string const& cmLocalGenerator::GetCurrentSourceDirectory() const
3373 {
3374   return this->StateSnapshot.GetDirectory().GetCurrentSource();
3375 }
3376
3377 std::string cmLocalGenerator::MaybeConvertToRelativePath(
3378   std::string const& local_path, std::string const& remote_path) const
3379 {
3380   return this->StateSnapshot.GetDirectory().ConvertToRelPathIfNotContained(
3381     local_path, remote_path);
3382 }
3383
3384 std::string cmLocalGenerator::GetTargetDirectory(
3385   const cmGeneratorTarget* /*unused*/) const
3386 {
3387   cmSystemTools::Error("GetTargetDirectory"
3388                        " called on cmLocalGenerator");
3389   return "";
3390 }
3391
3392 KWIML_INT_uint64_t cmLocalGenerator::GetBackwardsCompatibility()
3393 {
3394   // The computed version may change until the project is fully
3395   // configured.
3396   if (!this->BackwardsCompatibilityFinal) {
3397     unsigned int major = 0;
3398     unsigned int minor = 0;
3399     unsigned int patch = 0;
3400     if (const char* value =
3401           this->Makefile->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY")) {
3402       switch (sscanf(value, "%u.%u.%u", &major, &minor, &patch)) {
3403         case 2:
3404           patch = 0;
3405           break;
3406         case 1:
3407           minor = 0;
3408           patch = 0;
3409           break;
3410         default:
3411           break;
3412       }
3413     }
3414     this->BackwardsCompatibility = CMake_VERSION_ENCODE(major, minor, patch);
3415     this->BackwardsCompatibilityFinal = true;
3416   }
3417
3418   return this->BackwardsCompatibility;
3419 }
3420
3421 bool cmLocalGenerator::NeedBackwardsCompatibility_2_4()
3422 {
3423   // Check the policy to decide whether to pay attention to this
3424   // variable.
3425   switch (this->GetPolicyStatus(cmPolicies::CMP0001)) {
3426     case cmPolicies::WARN:
3427     // WARN is just OLD without warning because user code does not
3428     // always affect whether this check is done.
3429     case cmPolicies::OLD:
3430       // Old behavior is to check the variable.
3431       break;
3432     case cmPolicies::NEW:
3433       // New behavior is to ignore the variable.
3434       return false;
3435     case cmPolicies::REQUIRED_IF_USED:
3436     case cmPolicies::REQUIRED_ALWAYS:
3437       // This will never be the case because the only way to require
3438       // the setting is to require the user to specify version policy
3439       // 2.6 or higher.  Once we add that requirement then this whole
3440       // method can be removed anyway.
3441       return false;
3442   }
3443
3444   // Compatibility is needed if CMAKE_BACKWARDS_COMPATIBILITY is set
3445   // equal to or lower than the given version.
3446   KWIML_INT_uint64_t actual_compat = this->GetBackwardsCompatibility();
3447   return (actual_compat && actual_compat <= CMake_VERSION_ENCODE(2, 4, 255));
3448 }
3449
3450 cmPolicies::PolicyStatus cmLocalGenerator::GetPolicyStatus(
3451   cmPolicies::PolicyID id) const
3452 {
3453   return this->Makefile->GetPolicyStatus(id);
3454 }
3455
3456 bool cmLocalGenerator::CheckDefinition(std::string const& define) const
3457 {
3458   // Many compilers do not support -DNAME(arg)=sdf so we disable it.
3459   std::string::size_type pos = define.find_first_of("(=");
3460   if (pos != std::string::npos) {
3461     if (define[pos] == '(') {
3462       std::ostringstream e;
3463       /* clang-format off */
3464       e << "WARNING: Function-style preprocessor definitions may not be "
3465         << "passed on the compiler command line because many compilers "
3466         << "do not support it.\n"
3467         << "CMake is dropping a preprocessor definition: " << define << "\n"
3468         << "Consider defining the macro in a (configured) header file.\n";
3469       /* clang-format on */
3470       cmSystemTools::Message(e.str());
3471       return false;
3472     }
3473   }
3474
3475   // Many compilers do not support # in the value so we disable it.
3476   if (define.find_first_of('#') != std::string::npos) {
3477     std::ostringstream e;
3478     /* clang-format off */
3479     e << "WARNING: Preprocessor definitions containing '#' may not be "
3480       << "passed on the compiler command line because many compilers "
3481       << "do not support it.\n"
3482       << "CMake is dropping a preprocessor definition: " << define << "\n"
3483       << "Consider defining the macro in a (configured) header file.\n";
3484     /* clang-format on */
3485     cmSystemTools::Message(e.str());
3486     return false;
3487   }
3488
3489   // Assume it is supported.
3490   return true;
3491 }
3492
3493 static void cmLGInfoProp(cmMakefile* mf, cmGeneratorTarget* target,
3494                          const std::string& prop)
3495 {
3496   if (const char* val = target->GetProperty(prop)) {
3497     mf->AddDefinition(prop, val);
3498   }
3499 }
3500
3501 void cmLocalGenerator::GenerateAppleInfoPList(cmGeneratorTarget* target,
3502                                               const std::string& targetName,
3503                                               const std::string& fname)
3504 {
3505   // Find the Info.plist template.
3506   const char* in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
3507   std::string inFile = (in && *in) ? in : "MacOSXBundleInfo.plist.in";
3508   if (!cmSystemTools::FileIsFullPath(inFile)) {
3509     std::string inMod = this->Makefile->GetModulesFile(inFile);
3510     if (!inMod.empty()) {
3511       inFile = inMod;
3512     }
3513   }
3514   if (!cmSystemTools::FileExists(inFile, true)) {
3515     std::ostringstream e;
3516     e << "Target " << target->GetName() << " Info.plist template \"" << inFile
3517       << "\" could not be found.";
3518     cmSystemTools::Error(e.str());
3519     return;
3520   }
3521
3522   // Convert target properties to variables in an isolated makefile
3523   // scope to configure the file.  If properties are set they will
3524   // override user make variables.  If not the configuration will fall
3525   // back to the directory-level values set by the user.
3526   cmMakefile* mf = this->Makefile;
3527   cmMakefile::ScopePushPop varScope(mf);
3528   mf->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME", targetName);
3529   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_INFO_STRING");
3530   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_ICON_FILE");
3531   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_GUI_IDENTIFIER");
3532   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_LONG_VERSION_STRING");
3533   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_NAME");
3534   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_SHORT_VERSION_STRING");
3535   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_BUNDLE_VERSION");
3536   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_COPYRIGHT");
3537   mf->ConfigureFile(inFile, fname, false, false, false);
3538 }
3539
3540 void cmLocalGenerator::GenerateFrameworkInfoPList(
3541   cmGeneratorTarget* target, const std::string& targetName,
3542   const std::string& fname)
3543 {
3544   // Find the Info.plist template.
3545   const char* in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
3546   std::string inFile = (in && *in) ? in : "MacOSXFrameworkInfo.plist.in";
3547   if (!cmSystemTools::FileIsFullPath(inFile)) {
3548     std::string inMod = this->Makefile->GetModulesFile(inFile);
3549     if (!inMod.empty()) {
3550       inFile = inMod;
3551     }
3552   }
3553   if (!cmSystemTools::FileExists(inFile, true)) {
3554     std::ostringstream e;
3555     e << "Target " << target->GetName() << " Info.plist template \"" << inFile
3556       << "\" could not be found.";
3557     cmSystemTools::Error(e.str());
3558     return;
3559   }
3560
3561   // Convert target properties to variables in an isolated makefile
3562   // scope to configure the file.  If properties are set they will
3563   // override user make variables.  If not the configuration will fall
3564   // back to the directory-level values set by the user.
3565   cmMakefile* mf = this->Makefile;
3566   cmMakefile::ScopePushPop varScope(mf);
3567   mf->AddDefinition("MACOSX_FRAMEWORK_NAME", targetName);
3568   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_ICON_FILE");
3569   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER");
3570   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING");
3571   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_BUNDLE_VERSION");
3572   mf->ConfigureFile(inFile, fname, false, false, false);
3573 }
3574
3575 namespace {
3576 void CreateGeneratedSource(cmLocalGenerator& lg, const std::string& output,
3577                            cmCommandOrigin origin,
3578                            const cmListFileBacktrace& lfbt)
3579 {
3580   if (cmGeneratorExpression::Find(output) == std::string::npos) {
3581     // Outputs without generator expressions from the project are already
3582     // created and marked as generated.  Do not mark them again, because
3583     // other commands might have overwritten the property.
3584     if (origin == cmCommandOrigin::Generator) {
3585       lg.GetMakefile()->GetOrCreateGeneratedSource(output);
3586     }
3587   } else {
3588     lg.GetCMakeInstance()->IssueMessage(
3589       MessageType::FATAL_ERROR,
3590       "Generator expressions in custom command outputs are not implemented!",
3591       lfbt);
3592   }
3593 }
3594
3595 void CreateGeneratedSources(cmLocalGenerator& lg,
3596                             const std::vector<std::string>& outputs,
3597                             cmCommandOrigin origin,
3598                             const cmListFileBacktrace& lfbt)
3599 {
3600   for (std::string const& o : outputs) {
3601     CreateGeneratedSource(lg, o, origin, lfbt);
3602   }
3603 }
3604
3605 cmSourceFile* AddCustomCommand(
3606   cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
3607   const std::vector<std::string>& outputs,
3608   const std::vector<std::string>& byproducts,
3609   const std::vector<std::string>& depends, const std::string& main_dependency,
3610   const cmImplicitDependsList& implicit_depends,
3611   const cmCustomCommandLines& commandLines, const char* comment,
3612   const char* workingDir, bool replace, bool escapeOldStyle,
3613   bool uses_terminal, bool command_expand_lists, const std::string& depfile,
3614   const std::string& job_pool)
3615 {
3616   cmMakefile* mf = lg.GetMakefile();
3617
3618   // Choose a source file on which to store the custom command.
3619   cmSourceFile* file = nullptr;
3620   if (!commandLines.empty() && !main_dependency.empty()) {
3621     // The main dependency was specified.  Use it unless a different
3622     // custom command already used it.
3623     file = mf->GetSource(main_dependency);
3624     if (file && file->GetCustomCommand() && !replace) {
3625       // The main dependency already has a custom command.
3626       if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
3627         // The existing custom command is identical.  Silently ignore
3628         // the duplicate.
3629         return file;
3630       }
3631       // The existing custom command is different.  We need to
3632       // generate a rule file for this new command.
3633       file = nullptr;
3634     } else if (!file) {
3635       file = mf->CreateSource(main_dependency);
3636     }
3637   }
3638
3639   // Generate a rule file if the main dependency is not available.
3640   if (!file) {
3641     cmGlobalGenerator* gg = lg.GetGlobalGenerator();
3642
3643     // Construct a rule file associated with the first output produced.
3644     std::string outName = gg->GenerateRuleFile(outputs[0]);
3645
3646     // Check if the rule file already exists.
3647     file = mf->GetSource(outName, cmSourceFileLocationKind::Known);
3648     if (file && file->GetCustomCommand() && !replace) {
3649       // The rule file already exists.
3650       if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
3651         lg.GetCMakeInstance()->IssueMessage(
3652           MessageType::FATAL_ERROR,
3653           cmStrCat("Attempt to add a custom rule to output\n  ", outName,
3654                    "\nwhich already has a custom rule."),
3655           lfbt);
3656       }
3657       return file;
3658     }
3659
3660     // Create a cmSourceFile for the rule file.
3661     if (!file) {
3662       file = mf->CreateSource(outName, true, cmSourceFileLocationKind::Known);
3663     }
3664     file->SetProperty("__CMAKE_RULE", "1");
3665   }
3666
3667   // Attach the custom command to the file.
3668   if (file) {
3669     // Construct a complete list of dependencies.
3670     std::vector<std::string> depends2(depends);
3671     if (!main_dependency.empty()) {
3672       depends2.push_back(main_dependency);
3673     }
3674
3675     std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>(
3676       outputs, byproducts, depends2, commandLines, lfbt, comment, workingDir);
3677     cc->SetEscapeOldStyle(escapeOldStyle);
3678     cc->SetEscapeAllowMakeVars(true);
3679     cc->SetImplicitDepends(implicit_depends);
3680     cc->SetUsesTerminal(uses_terminal);
3681     cc->SetCommandExpandLists(command_expand_lists);
3682     cc->SetDepfile(depfile);
3683     cc->SetJobPool(job_pool);
3684     file->SetCustomCommand(std::move(cc));
3685
3686     mf->AddSourceOutputs(file, outputs, byproducts);
3687   }
3688   return file;
3689 }
3690 }
3691
3692 namespace detail {
3693 void AddCustomCommandToTarget(cmLocalGenerator& lg,
3694                               const cmListFileBacktrace& lfbt,
3695                               cmCommandOrigin origin, cmTarget* target,
3696                               const std::vector<std::string>& byproducts,
3697                               const std::vector<std::string>& depends,
3698                               const cmCustomCommandLines& commandLines,
3699                               cmCustomCommandType type, const char* comment,
3700                               const char* workingDir, bool escapeOldStyle,
3701                               bool uses_terminal, const std::string& depfile,
3702                               const std::string& job_pool,
3703                               bool command_expand_lists)
3704 {
3705   cmMakefile* mf = lg.GetMakefile();
3706
3707   // Always create the byproduct sources and mark them generated.
3708   CreateGeneratedSources(lg, byproducts, origin, lfbt);
3709
3710   // Add the command to the appropriate build step for the target.
3711   std::vector<std::string> no_output;
3712   cmCustomCommand cc(no_output, byproducts, depends, commandLines, lfbt,
3713                      comment, workingDir);
3714   cc.SetEscapeOldStyle(escapeOldStyle);
3715   cc.SetEscapeAllowMakeVars(true);
3716   cc.SetUsesTerminal(uses_terminal);
3717   cc.SetCommandExpandLists(command_expand_lists);
3718   cc.SetDepfile(depfile);
3719   cc.SetJobPool(job_pool);
3720   switch (type) {
3721     case cmCustomCommandType::PRE_BUILD:
3722       target->AddPreBuildCommand(std::move(cc));
3723       break;
3724     case cmCustomCommandType::PRE_LINK:
3725       target->AddPreLinkCommand(std::move(cc));
3726       break;
3727     case cmCustomCommandType::POST_BUILD:
3728       target->AddPostBuildCommand(std::move(cc));
3729       break;
3730   }
3731
3732   mf->AddTargetByproducts(target, byproducts);
3733 }
3734
3735 cmSourceFile* AddCustomCommandToOutput(
3736   cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
3737   cmCommandOrigin origin, const std::vector<std::string>& outputs,
3738   const std::vector<std::string>& byproducts,
3739   const std::vector<std::string>& depends, const std::string& main_dependency,
3740   const cmImplicitDependsList& implicit_depends,
3741   const cmCustomCommandLines& commandLines, const char* comment,
3742   const char* workingDir, bool replace, bool escapeOldStyle,
3743   bool uses_terminal, bool command_expand_lists, const std::string& depfile,
3744   const std::string& job_pool)
3745 {
3746   // Always create the output sources and mark them generated.
3747   CreateGeneratedSources(lg, outputs, origin, lfbt);
3748   CreateGeneratedSources(lg, byproducts, origin, lfbt);
3749
3750   return AddCustomCommand(
3751     lg, lfbt, outputs, byproducts, depends, main_dependency, implicit_depends,
3752     commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
3753     command_expand_lists, depfile, job_pool);
3754 }
3755
3756 void AppendCustomCommandToOutput(cmLocalGenerator& lg,
3757                                  const cmListFileBacktrace& lfbt,
3758                                  const std::string& output,
3759                                  const std::vector<std::string>& depends,
3760                                  const cmImplicitDependsList& implicit_depends,
3761                                  const cmCustomCommandLines& commandLines)
3762 {
3763   // Lookup an existing command.
3764   if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) {
3765     if (cmCustomCommand* cc = sf->GetCustomCommand()) {
3766       cc->AppendCommands(commandLines);
3767       cc->AppendDepends(depends);
3768       cc->AppendImplicitDepends(implicit_depends);
3769       return;
3770     }
3771   }
3772
3773   // No existing command found.
3774   lg.GetCMakeInstance()->IssueMessage(
3775     MessageType::FATAL_ERROR,
3776     cmStrCat("Attempt to append to output\n  ", output,
3777              "\nwhich is not already a custom command output."),
3778     lfbt);
3779 }
3780
3781 void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
3782                        cmCommandOrigin origin, cmTarget* target,
3783                        const cmUtilityOutput& force, const char* workingDir,
3784                        const std::vector<std::string>& byproducts,
3785                        const std::vector<std::string>& depends,
3786                        const cmCustomCommandLines& commandLines,
3787                        bool escapeOldStyle, const char* comment,
3788                        bool uses_terminal, bool command_expand_lists,
3789                        const std::string& job_pool)
3790 {
3791   // Always create the byproduct sources and mark them generated.
3792   CreateGeneratedSource(lg, force.Name, origin, lfbt);
3793   CreateGeneratedSources(lg, byproducts, origin, lfbt);
3794
3795   // Use an empty comment to avoid generation of default comment.
3796   if (!comment) {
3797     comment = "";
3798   }
3799
3800   std::string no_main_dependency;
3801   cmImplicitDependsList no_implicit_depends;
3802   cmSourceFile* rule = AddCustomCommand(
3803     lg, lfbt, { force.Name }, byproducts, depends, no_main_dependency,
3804     no_implicit_depends, commandLines, comment, workingDir, /*replace=*/false,
3805     escapeOldStyle, uses_terminal, command_expand_lists, /*depfile=*/"",
3806     job_pool);
3807   if (rule) {
3808     lg.GetMakefile()->AddTargetByproducts(target, byproducts);
3809   }
3810
3811   if (!force.NameCMP0049.empty()) {
3812     target->AddSource(force.NameCMP0049);
3813   }
3814 }
3815 }