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