Imported Upstream version 3.17.1
[platform/upstream/cmake.git] / Source / cmLocalUnixMakefileGenerator3.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 "cmLocalUnixMakefileGenerator3.h"
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cstdio>
8 #include <sstream>
9 #include <utility>
10
11 #include <cm/memory>
12 #include <cm/vector>
13 #include <cmext/algorithm>
14
15 #include "cmsys/FStream.hxx"
16 #include "cmsys/Terminal.h"
17
18 #include "cmCustomCommand.h" // IWYU pragma: keep
19 #include "cmCustomCommandGenerator.h"
20 #include "cmFileTimeCache.h"
21 #include "cmGeneratedFileStream.h"
22 #include "cmGeneratorExpression.h"
23 #include "cmGeneratorTarget.h"
24 #include "cmGlobalGenerator.h"
25 #include "cmGlobalUnixMakefileGenerator3.h"
26 #include "cmListFileCache.h"
27 #include "cmLocalGenerator.h"
28 #include "cmMakefile.h"
29 #include "cmMakefileTargetGenerator.h"
30 #include "cmOutputConverter.h"
31 #include "cmRange.h"
32 #include "cmRulePlaceholderExpander.h"
33 #include "cmSourceFile.h"
34 #include "cmState.h"
35 #include "cmStateDirectory.h"
36 #include "cmStateSnapshot.h"
37 #include "cmStateTypes.h"
38 #include "cmStringAlgorithms.h"
39 #include "cmSystemTools.h"
40 #include "cmVersion.h"
41 #include "cmake.h"
42
43 // Include dependency scanners for supported languages.  Only the
44 // C/C++ scanner is needed for bootstrapping CMake.
45 #include "cmDependsC.h"
46 #ifndef CMAKE_BOOTSTRAP
47 #  include "cmDependsFortran.h"
48 #  include "cmDependsJava.h"
49 #endif
50
51 // Escape special characters in Makefile dependency lines
52 class cmMakeSafe
53 {
54 public:
55   cmMakeSafe(const char* s)
56     : Data(s)
57   {
58   }
59   cmMakeSafe(std::string const& s)
60     : Data(s.c_str())
61   {
62   }
63
64 private:
65   const char* Data;
66   friend std::ostream& operator<<(std::ostream& os, cmMakeSafe const& self)
67   {
68     for (const char* c = self.Data; *c; ++c) {
69       switch (*c) {
70         case '=':
71           os << "$(EQUALS)";
72           break;
73         default:
74           os << *c;
75           break;
76       }
77     }
78     return os;
79   }
80 };
81
82 // Helper function used below.
83 static std::string cmSplitExtension(std::string const& in, std::string& base)
84 {
85   std::string ext;
86   std::string::size_type dot_pos = in.rfind('.');
87   if (dot_pos != std::string::npos) {
88     // Remove the extension first in case &base == &in.
89     ext = in.substr(dot_pos);
90     base = in.substr(0, dot_pos);
91   } else {
92     base = in;
93   }
94   return ext;
95 }
96
97 cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3(
98   cmGlobalGenerator* gg, cmMakefile* mf)
99   : cmLocalCommonGenerator(gg, mf, mf->GetCurrentBinaryDirectory())
100 {
101   this->MakefileVariableSize = 0;
102   this->ColorMakefile = false;
103   this->SkipPreprocessedSourceRules = false;
104   this->SkipAssemblySourceRules = false;
105   this->MakeCommandEscapeTargetTwice = false;
106   this->BorlandMakeCurlyHack = false;
107 }
108
109 cmLocalUnixMakefileGenerator3::~cmLocalUnixMakefileGenerator3() = default;
110
111 std::string cmLocalUnixMakefileGenerator3::GetConfigName() const
112 {
113   auto const& configNames = this->GetConfigNames();
114   assert(configNames.size() == 1);
115   return configNames.front();
116 }
117
118 void cmLocalUnixMakefileGenerator3::Generate()
119 {
120   // Record whether some options are enabled to avoid checking many
121   // times later.
122   if (!this->GetGlobalGenerator()->GetCMakeInstance()->GetIsInTryCompile()) {
123     this->ColorMakefile = this->Makefile->IsOn("CMAKE_COLOR_MAKEFILE");
124   }
125   this->SkipPreprocessedSourceRules =
126     this->Makefile->IsOn("CMAKE_SKIP_PREPROCESSED_SOURCE_RULES");
127   this->SkipAssemblySourceRules =
128     this->Makefile->IsOn("CMAKE_SKIP_ASSEMBLY_SOURCE_RULES");
129
130   // Generate the rule files for each target.
131   cmGlobalUnixMakefileGenerator3* gg =
132     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
133   for (const auto& target : this->GetGeneratorTargets()) {
134     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
135       continue;
136     }
137     std::unique_ptr<cmMakefileTargetGenerator> tg(
138       cmMakefileTargetGenerator::New(target.get()));
139     if (tg) {
140       tg->WriteRuleFiles();
141       gg->RecordTargetProgress(tg.get());
142     }
143   }
144
145   // write the local Makefile
146   this->WriteLocalMakefile();
147
148   // Write the cmake file with information for this directory.
149   this->WriteDirectoryInformationFile();
150 }
151
152 void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath()
153 {
154   // Compute the path to use when referencing the current output
155   // directory from the top output directory.
156   this->HomeRelativeOutputPath = this->MaybeConvertToRelativePath(
157     this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory());
158   if (this->HomeRelativeOutputPath == ".") {
159     this->HomeRelativeOutputPath.clear();
160   }
161   if (!this->HomeRelativeOutputPath.empty()) {
162     this->HomeRelativeOutputPath += "/";
163   }
164 }
165
166 void cmLocalUnixMakefileGenerator3::GetLocalObjectFiles(
167   std::map<std::string, LocalObjectInfo>& localObjectFiles)
168 {
169   for (const auto& gt : this->GetGeneratorTargets()) {
170     if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
171       continue;
172     }
173     std::vector<cmSourceFile const*> objectSources;
174     gt->GetObjectSources(objectSources, this->GetConfigName());
175     // Compute full path to object file directory for this target.
176     std::string dir = cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(),
177                                '/', this->GetTargetDirectory(gt.get()), '/');
178     // Compute the name of each object file.
179     for (cmSourceFile const* sf : objectSources) {
180       bool hasSourceExtension = true;
181       std::string objectName =
182         this->GetObjectFileNameWithoutTarget(*sf, dir, &hasSourceExtension);
183       if (cmSystemTools::FileIsFullPath(objectName)) {
184         objectName = cmSystemTools::GetFilenameName(objectName);
185       }
186       LocalObjectInfo& info = localObjectFiles[objectName];
187       info.HasSourceExtension = hasSourceExtension;
188       info.emplace_back(gt.get(), sf->GetLanguage());
189     }
190   }
191 }
192
193 void cmLocalUnixMakefileGenerator3::GetIndividualFileTargets(
194   std::vector<std::string>& targets)
195 {
196   std::map<std::string, LocalObjectInfo> localObjectFiles;
197   this->GetLocalObjectFiles(localObjectFiles);
198   for (auto const& localObjectFile : localObjectFiles) {
199     targets.push_back(localObjectFile.first);
200
201     std::string::size_type dot_pos = localObjectFile.first.rfind(".");
202     std::string base = localObjectFile.first.substr(0, dot_pos);
203     if (localObjectFile.second.HasPreprocessRule) {
204       targets.push_back(base + ".i");
205     }
206
207     if (localObjectFile.second.HasAssembleRule) {
208       targets.push_back(base + ".s");
209     }
210   }
211 }
212
213 void cmLocalUnixMakefileGenerator3::WriteLocalMakefile()
214 {
215   // generate the includes
216   std::string ruleFileName = "Makefile";
217
218   // Open the rule file.  This should be copy-if-different because the
219   // rules may depend on this file itself.
220   std::string ruleFileNameFull = this->ConvertToFullPath(ruleFileName);
221   cmGeneratedFileStream ruleFileStream(
222     ruleFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
223   if (!ruleFileStream) {
224     return;
225   }
226   // always write the top makefile
227   if (!this->IsRootMakefile()) {
228     ruleFileStream.SetCopyIfDifferent(true);
229   }
230
231   // write the all rules
232   this->WriteLocalAllRules(ruleFileStream);
233
234   // only write local targets unless at the top Keep track of targets already
235   // listed.
236   std::set<std::string> emittedTargets;
237   if (!this->IsRootMakefile()) {
238     // write our targets, and while doing it collect up the object
239     // file rules
240     this->WriteLocalMakefileTargets(ruleFileStream, emittedTargets);
241   } else {
242     cmGlobalUnixMakefileGenerator3* gg =
243       static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
244     gg->WriteConvenienceRules(ruleFileStream, emittedTargets);
245   }
246
247   bool do_preprocess_rules = this->GetCreatePreprocessedSourceRules();
248   bool do_assembly_rules = this->GetCreateAssemblySourceRules();
249
250   std::map<std::string, LocalObjectInfo> localObjectFiles;
251   this->GetLocalObjectFiles(localObjectFiles);
252
253   // now write out the object rules
254   // for each object file name
255   for (auto& localObjectFile : localObjectFiles) {
256     // Add a convenience rule for building the object file.
257     this->WriteObjectConvenienceRule(
258       ruleFileStream, "target to build an object file", localObjectFile.first,
259       localObjectFile.second);
260
261     // Check whether preprocessing and assembly rules make sense.
262     // They make sense only for C and C++ sources.
263     bool lang_has_preprocessor = false;
264     bool lang_has_assembly = false;
265
266     for (LocalObjectEntry const& entry : localObjectFile.second) {
267       if (entry.Language == "C" || entry.Language == "CXX" ||
268           entry.Language == "CUDA" || entry.Language == "Fortran") {
269         // Right now, C, C++, Fortran and CUDA have both a preprocessor and the
270         // ability to generate assembly code
271         lang_has_preprocessor = true;
272         lang_has_assembly = true;
273         break;
274       }
275     }
276
277     // Add convenience rules for preprocessed and assembly files.
278     if (lang_has_preprocessor && do_preprocess_rules) {
279       std::string::size_type dot_pos = localObjectFile.first.rfind(".");
280       std::string base = localObjectFile.first.substr(0, dot_pos);
281       this->WriteObjectConvenienceRule(ruleFileStream,
282                                        "target to preprocess a source file",
283                                        (base + ".i"), localObjectFile.second);
284       localObjectFile.second.HasPreprocessRule = true;
285     }
286
287     if (lang_has_assembly && do_assembly_rules) {
288       std::string::size_type dot_pos = localObjectFile.first.rfind(".");
289       std::string base = localObjectFile.first.substr(0, dot_pos);
290       this->WriteObjectConvenienceRule(
291         ruleFileStream, "target to generate assembly for a file",
292         (base + ".s"), localObjectFile.second);
293       localObjectFile.second.HasAssembleRule = true;
294     }
295   }
296
297   // add a help target as long as there isn;t a real target named help
298   if (emittedTargets.insert("help").second) {
299     cmGlobalUnixMakefileGenerator3* gg =
300       static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
301     gg->WriteHelpRule(ruleFileStream, this);
302   }
303
304   this->WriteSpecialTargetsBottom(ruleFileStream);
305 }
306
307 void cmLocalUnixMakefileGenerator3::WriteObjectConvenienceRule(
308   std::ostream& ruleFileStream, const char* comment, const std::string& output,
309   LocalObjectInfo const& info)
310 {
311   // If the rule includes the source file extension then create a
312   // version that has the extension removed.  The help should include
313   // only the version without source extension.
314   bool inHelp = true;
315   if (info.HasSourceExtension) {
316     // Remove the last extension.  This should be kept.
317     std::string outBase1 = output;
318     std::string outExt1 = cmSplitExtension(outBase1, outBase1);
319
320     // Now remove the source extension and put back the last
321     // extension.
322     std::string outNoExt;
323     cmSplitExtension(outBase1, outNoExt);
324     outNoExt += outExt1;
325
326     // Add a rule to drive the rule below.
327     std::vector<std::string> depends;
328     depends.emplace_back(output);
329     std::vector<std::string> no_commands;
330     this->WriteMakeRule(ruleFileStream, nullptr, outNoExt, depends,
331                         no_commands, true, true);
332     inHelp = false;
333   }
334
335   // Recursively make the rule for each target using the object file.
336   std::vector<std::string> commands;
337   for (LocalObjectEntry const& t : info) {
338     std::string tgtMakefileName = this->GetRelativeTargetDirectory(t.Target);
339     std::string targetName = tgtMakefileName;
340     tgtMakefileName += "/build.make";
341     targetName += "/";
342     targetName += output;
343     commands.push_back(
344       this->GetRecursiveMakeCall(tgtMakefileName, targetName));
345   }
346   this->CreateCDCommand(commands, this->GetBinaryDirectory(),
347                         this->GetCurrentBinaryDirectory());
348
349   // Write the rule to the makefile.
350   std::vector<std::string> no_depends;
351   this->WriteMakeRule(ruleFileStream, comment, output, no_depends, commands,
352                       true, inHelp);
353 }
354
355 void cmLocalUnixMakefileGenerator3::WriteLocalMakefileTargets(
356   std::ostream& ruleFileStream, std::set<std::string>& emitted)
357 {
358   std::vector<std::string> depends;
359   std::vector<std::string> commands;
360
361   // for each target we just provide a rule to cd up to the top and do a make
362   // on the target
363   std::string localName;
364   for (const auto& target : this->GetGeneratorTargets()) {
365     if ((target->GetType() == cmStateEnums::EXECUTABLE) ||
366         (target->GetType() == cmStateEnums::STATIC_LIBRARY) ||
367         (target->GetType() == cmStateEnums::SHARED_LIBRARY) ||
368         (target->GetType() == cmStateEnums::MODULE_LIBRARY) ||
369         (target->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
370         (target->GetType() == cmStateEnums::UTILITY)) {
371       emitted.insert(target->GetName());
372
373       // for subdirs add a rule to build this specific target by name.
374       localName =
375         cmStrCat(this->GetRelativeTargetDirectory(target.get()), "/rule");
376       commands.clear();
377       depends.clear();
378
379       // Build the target for this pass.
380       std::string makefile2 = "CMakeFiles/Makefile2";
381       commands.push_back(this->GetRecursiveMakeCall(makefile2, localName));
382       this->CreateCDCommand(commands, this->GetBinaryDirectory(),
383                             this->GetCurrentBinaryDirectory());
384       this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
385                           localName, depends, commands, true);
386
387       // Add a target with the canonical name (no prefix, suffix or path).
388       if (localName != target->GetName()) {
389         commands.clear();
390         depends.push_back(localName);
391         this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
392                             target->GetName(), depends, commands, true);
393       }
394
395       // Add a fast rule to build the target
396       std::string makefileName = cmStrCat(
397         this->GetRelativeTargetDirectory(target.get()), "/build.make");
398       // make sure the makefile name is suitable for a makefile
399       std::string makeTargetName =
400         cmStrCat(this->GetRelativeTargetDirectory(target.get()), "/build");
401       localName = cmStrCat(target->GetName(), "/fast");
402       depends.clear();
403       commands.clear();
404       commands.push_back(
405         this->GetRecursiveMakeCall(makefileName, makeTargetName));
406       this->CreateCDCommand(commands, this->GetBinaryDirectory(),
407                             this->GetCurrentBinaryDirectory());
408       this->WriteMakeRule(ruleFileStream, "fast build rule for target.",
409                           localName, depends, commands, true);
410
411       // Add a local name for the rule to relink the target before
412       // installation.
413       if (target->NeedRelinkBeforeInstall(this->GetConfigName())) {
414         makeTargetName = cmStrCat(
415           this->GetRelativeTargetDirectory(target.get()), "/preinstall");
416         localName = cmStrCat(target->GetName(), "/preinstall");
417         depends.clear();
418         commands.clear();
419         commands.push_back(
420           this->GetRecursiveMakeCall(makefile2, makeTargetName));
421         this->CreateCDCommand(commands, this->GetBinaryDirectory(),
422                               this->GetCurrentBinaryDirectory());
423         this->WriteMakeRule(ruleFileStream,
424                             "Manual pre-install relink rule for target.",
425                             localName, depends, commands, true);
426       }
427     }
428   }
429 }
430
431 void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile()
432 {
433   std::string infoFileName =
434     cmStrCat(this->GetCurrentBinaryDirectory(),
435              "/CMakeFiles/CMakeDirectoryInformation.cmake");
436
437   // Open the output file.
438   cmGeneratedFileStream infoFileStream(infoFileName);
439   if (!infoFileStream) {
440     return;
441   }
442
443   infoFileStream.SetCopyIfDifferent(true);
444   // Write the do not edit header.
445   this->WriteDisclaimer(infoFileStream);
446
447   // Setup relative path conversion tops.
448   /* clang-format off */
449   infoFileStream
450     << "# Relative path conversion top directories.\n"
451     << "set(CMAKE_RELATIVE_PATH_TOP_SOURCE \""
452     << this->StateSnapshot.GetDirectory().GetRelativePathTopSource()
453     << "\")\n"
454     << "set(CMAKE_RELATIVE_PATH_TOP_BINARY \""
455     << this->StateSnapshot.GetDirectory().GetRelativePathTopBinary()
456     << "\")\n"
457     << "\n";
458   /* clang-format on */
459
460   // Tell the dependency scanner to use unix paths if necessary.
461   if (cmSystemTools::GetForceUnixPaths()) {
462     /* clang-format off */
463     infoFileStream
464       << "# Force unix paths in dependencies.\n"
465       << "set(CMAKE_FORCE_UNIX_PATHS 1)\n"
466       << "\n";
467     /* clang-format on */
468   }
469
470   // Store the include regular expressions for this directory.
471   infoFileStream << "\n"
472                  << "# The C and CXX include file regular expressions for "
473                  << "this directory.\n";
474   infoFileStream << "set(CMAKE_C_INCLUDE_REGEX_SCAN ";
475   cmLocalUnixMakefileGenerator3::WriteCMakeArgument(
476     infoFileStream, this->Makefile->GetIncludeRegularExpression());
477   infoFileStream << ")\n";
478   infoFileStream << "set(CMAKE_C_INCLUDE_REGEX_COMPLAIN ";
479   cmLocalUnixMakefileGenerator3::WriteCMakeArgument(
480     infoFileStream, this->Makefile->GetComplainRegularExpression());
481   infoFileStream << ")\n";
482   infoFileStream
483     << "set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN})\n";
484   infoFileStream << "set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN "
485                     "${CMAKE_C_INCLUDE_REGEX_COMPLAIN})\n";
486 }
487
488 std::string cmLocalUnixMakefileGenerator3::ConvertToFullPath(
489   const std::string& localPath)
490 {
491   std::string dir =
492     cmStrCat(this->GetCurrentBinaryDirectory(), '/', localPath);
493   return dir;
494 }
495
496 const std::string& cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath()
497 {
498   return this->HomeRelativeOutputPath;
499 }
500
501 void cmLocalUnixMakefileGenerator3::WriteMakeRule(
502   std::ostream& os, const char* comment, const std::string& target,
503   const std::vector<std::string>& depends,
504   const std::vector<std::string>& commands, bool symbolic, bool in_help)
505 {
506   // Make sure there is a target.
507   if (target.empty()) {
508     std::string err("No target for WriteMakeRule! called with comment: ");
509     if (comment) {
510       err += comment;
511     }
512     cmSystemTools::Error(err);
513     return;
514   }
515
516   std::string replace;
517
518   // Write the comment describing the rule in the makefile.
519   if (comment) {
520     replace = comment;
521     std::string::size_type lpos = 0;
522     std::string::size_type rpos;
523     while ((rpos = replace.find('\n', lpos)) != std::string::npos) {
524       os << "# " << replace.substr(lpos, rpos - lpos) << "\n";
525       lpos = rpos + 1;
526     }
527     os << "# " << replace.substr(lpos) << "\n";
528   }
529
530   // Construct the left hand side of the rule.
531   std::string tgt = cmSystemTools::ConvertToOutputPath(
532     this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target));
533
534   const char* space = "";
535   if (tgt.size() == 1) {
536     // Add a space before the ":" to avoid drive letter confusion on
537     // Windows.
538     space = " ";
539   }
540
541   // Mark the rule as symbolic if requested.
542   if (symbolic) {
543     if (const char* sym =
544           this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) {
545       os << cmMakeSafe(tgt) << space << ": " << sym << "\n";
546     }
547   }
548
549   // Write the rule.
550   if (depends.empty()) {
551     // No dependencies.  The commands will always run.
552     os << cmMakeSafe(tgt) << space << ":\n";
553   } else {
554     // Split dependencies into multiple rule lines.  This allows for
555     // very long dependency lists even on older make implementations.
556     std::string binDir = this->GetBinaryDirectory();
557     for (std::string const& depend : depends) {
558       replace = depend;
559       replace = cmSystemTools::ConvertToOutputPath(
560         this->MaybeConvertToRelativePath(binDir, replace));
561       os << cmMakeSafe(tgt) << space << ": " << cmMakeSafe(replace) << "\n";
562     }
563   }
564
565   // Write the list of commands.
566   os << cmWrap("\t", commands, "", "\n") << "\n";
567   if (symbolic && !this->IsWatcomWMake()) {
568     os << ".PHONY : " << cmMakeSafe(tgt) << "\n";
569   }
570   os << "\n";
571   // Add the output to the local help if requested.
572   if (in_help) {
573     this->LocalHelp.push_back(target);
574   }
575 }
576
577 std::string cmLocalUnixMakefileGenerator3::MaybeConvertWatcomShellCommand(
578   std::string const& cmd)
579 {
580   if (this->IsWatcomWMake() && cmSystemTools::FileIsFullPath(cmd) &&
581       cmd.find_first_of("( )") != std::string::npos) {
582     // On Watcom WMake use the windows short path for the command
583     // name.  This is needed to avoid funny quoting problems on
584     // lines with shell redirection operators.
585     std::string scmd;
586     if (cmSystemTools::GetShortPath(cmd, scmd)) {
587       return this->ConvertToOutputFormat(scmd, cmOutputConverter::SHELL);
588     }
589   }
590   return std::string();
591 }
592
593 void cmLocalUnixMakefileGenerator3::WriteMakeVariables(
594   std::ostream& makefileStream)
595 {
596   this->WriteDivider(makefileStream);
597   makefileStream << "# Set environment variables for the build.\n"
598                  << "\n";
599   cmGlobalUnixMakefileGenerator3* gg =
600     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
601   if (gg->DefineWindowsNULL) {
602     makefileStream << "!IF \"$(OS)\" == \"Windows_NT\"\n"
603                    << "NULL=\n"
604                    << "!ELSE\n"
605                    << "NULL=nul\n"
606                    << "!ENDIF\n";
607   }
608   if (this->IsWindowsShell()) {
609     makefileStream << "SHELL = cmd.exe\n"
610                    << "\n";
611   } else {
612 #if !defined(__VMS)
613     /* clang-format off */
614       makefileStream
615         << "# The shell in which to execute make rules.\n"
616         << "SHELL = /bin/sh\n"
617         << "\n";
618 /* clang-format on */
619 #endif
620   }
621
622   std::string cmakeShellCommand =
623     this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand());
624   if (cmakeShellCommand.empty()) {
625     cmakeShellCommand = this->ConvertToOutputFormat(
626       cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()),
627       cmOutputConverter::SHELL);
628   }
629
630   /* clang-format off */
631   makefileStream
632     << "# The CMake executable.\n"
633     << "CMAKE_COMMAND = "
634     << cmakeShellCommand
635     << "\n"
636     << "\n";
637   makefileStream
638     << "# The command to remove a file.\n"
639     << "RM = "
640     << cmakeShellCommand
641     << " -E rm -f\n"
642     << "\n";
643   makefileStream
644     << "# Escaping for special characters.\n"
645     << "EQUALS = =\n"
646     << "\n";
647   makefileStream
648     << "# The top-level source directory on which CMake was run.\n"
649     << "CMAKE_SOURCE_DIR = "
650     << this->ConvertToOutputFormat(
651       cmSystemTools::CollapseFullPath(this->GetSourceDirectory()),
652                      cmOutputConverter::SHELL)
653     << "\n"
654     << "\n";
655   makefileStream
656     << "# The top-level build directory on which CMake was run.\n"
657     << "CMAKE_BINARY_DIR = "
658     << this->ConvertToOutputFormat(
659       cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()),
660                      cmOutputConverter::SHELL)
661     << "\n"
662     << "\n";
663   /* clang-format on */
664 }
665
666 void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsTop(
667   std::ostream& makefileStream)
668 {
669   this->WriteDivider(makefileStream);
670   makefileStream << "# Special targets provided by cmake.\n"
671                  << "\n";
672
673   std::vector<std::string> no_commands;
674   std::vector<std::string> no_depends;
675
676   // Special target to cleanup operation of make tool.
677   // This should be the first target except for the default_target in
678   // the interface Makefile.
679   this->WriteMakeRule(makefileStream,
680                       "Disable implicit rules so canonical targets will work.",
681                       ".SUFFIXES", no_depends, no_commands, false);
682
683   if (!this->IsNMake() && !this->IsWatcomWMake() &&
684       !this->BorlandMakeCurlyHack) {
685     // turn off RCS and SCCS automatic stuff from gmake
686     constexpr const char* vcs_rules[] = {
687       "%,v", "RCS/%", "RCS/%,v", "SCCS/s.%", "s.%",
688     };
689     for (auto vcs_rule : vcs_rules) {
690       std::vector<std::string> vcs_depend;
691       vcs_depend.emplace_back(vcs_rule);
692       this->WriteMakeRule(makefileStream, "Disable VCS-based implicit rules.",
693                           "%", vcs_depend, no_commands, false);
694     }
695   }
696   // Add a fake suffix to keep HP happy.  Must be max 32 chars for SGI make.
697   std::vector<std::string> depends;
698   depends.emplace_back(".hpux_make_needs_suffix_list");
699   this->WriteMakeRule(makefileStream, nullptr, ".SUFFIXES", depends,
700                       no_commands, false);
701   if (this->IsWatcomWMake()) {
702     // Switch on WMake feature, if an error or interrupt occurs during
703     // makefile processing, the current target being made may be deleted
704     // without prompting (the same as command line -e option).
705     /* clang-format off */
706     makefileStream <<
707       "\n"
708       ".ERASE\n"
709       "\n"
710       ;
711     /* clang-format on */
712   }
713   if (this->Makefile->IsOn("CMAKE_VERBOSE_MAKEFILE")) {
714     /* clang-format off */
715     makefileStream
716       << "# Produce verbose output by default.\n"
717       << "VERBOSE = 1\n"
718       << "\n";
719     /* clang-format on */
720   }
721   if (this->IsWatcomWMake()) {
722     /* clang-format off */
723     makefileStream <<
724       "!ifndef VERBOSE\n"
725       ".SILENT\n"
726       "!endif\n"
727       "\n"
728       ;
729     /* clang-format on */
730   } else {
731     makefileStream << "# Command-line flag to silence nested $(MAKE).\n"
732                       "$(VERBOSE)MAKESILENT = -s\n"
733                       "\n";
734
735     // Write special target to silence make output.  This must be after
736     // the default target in case VERBOSE is set (which changes the
737     // name).  The setting of CMAKE_VERBOSE_MAKEFILE to ON will cause a
738     // "VERBOSE=1" to be added as a make variable which will change the
739     // name of this special target.  This gives a make-time choice to
740     // the user.
741     this->WriteMakeRule(makefileStream,
742                         "Suppress display of executed commands.",
743                         "$(VERBOSE).SILENT", no_depends, no_commands, false);
744   }
745
746   // Work-around for makes that drop rules that have no dependencies
747   // or commands.
748   cmGlobalUnixMakefileGenerator3* gg =
749     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
750   std::string hack = gg->GetEmptyRuleHackDepends();
751   if (!hack.empty()) {
752     no_depends.push_back(std::move(hack));
753   }
754   std::string hack_cmd = gg->GetEmptyRuleHackCommand();
755   if (!hack_cmd.empty()) {
756     no_commands.push_back(std::move(hack_cmd));
757   }
758
759   // Special symbolic target that never exists to force dependers to
760   // run their rules.
761   this->WriteMakeRule(makefileStream, "A target that is always out of date.",
762                       "cmake_force", no_depends, no_commands, true);
763
764   // Variables for reference by other rules.
765   this->WriteMakeVariables(makefileStream);
766 }
767
768 void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
769   std::ostream& makefileStream)
770 {
771   this->WriteDivider(makefileStream);
772   makefileStream << "# Special targets to cleanup operation of make.\n"
773                  << "\n";
774
775   // Write special "cmake_check_build_system" target to run cmake with
776   // the --check-build-system flag.
777   if (!this->GlobalGenerator->GlobalSettingIsOn(
778         "CMAKE_SUPPRESS_REGENERATION")) {
779     // Build command to run CMake to check if anything needs regenerating.
780     std::vector<std::string> commands;
781     cmake* cm = this->GlobalGenerator->GetCMakeInstance();
782     if (cm->DoWriteGlobVerifyTarget()) {
783       std::string rescanRule =
784         cmStrCat("$(CMAKE_COMMAND) -P ",
785                  this->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
786                                              cmOutputConverter::SHELL));
787       commands.push_back(rescanRule);
788     }
789     std::string cmakefileName = "CMakeFiles/Makefile.cmake";
790     std::string runRule = cmStrCat(
791       "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) "
792       "--check-build-system ",
793       this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
794       " 0");
795
796     std::vector<std::string> no_depends;
797     commands.push_back(std::move(runRule));
798     if (!this->IsRootMakefile()) {
799       this->CreateCDCommand(commands, this->GetBinaryDirectory(),
800                             this->GetCurrentBinaryDirectory());
801     }
802     this->WriteMakeRule(makefileStream,
803                         "Special rule to run CMake to check the build system "
804                         "integrity.\n"
805                         "No rule that depends on this can have "
806                         "commands that come from listfiles\n"
807                         "because they might be regenerated.",
808                         "cmake_check_build_system", no_depends, commands,
809                         true);
810   }
811 }
812
813 void cmLocalUnixMakefileGenerator3::WriteConvenienceRule(
814   std::ostream& ruleFileStream, const std::string& realTarget,
815   const std::string& helpTarget)
816 {
817   // A rule is only needed if the names are different.
818   if (realTarget != helpTarget) {
819     // The helper target depends on the real target.
820     std::vector<std::string> depends;
821     depends.push_back(realTarget);
822
823     // There are no commands.
824     std::vector<std::string> no_commands;
825
826     // Write the rule.
827     this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
828                         helpTarget, depends, no_commands, true);
829   }
830 }
831
832 std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory(
833   cmGeneratorTarget const* target) const
834 {
835   std::string dir =
836     cmStrCat(this->HomeRelativeOutputPath, this->GetTargetDirectory(target));
837   return dir;
838 }
839
840 void cmLocalUnixMakefileGenerator3::AppendFlags(
841   std::string& flags, const std::string& newFlags) const
842 {
843   if (this->IsWatcomWMake() && !newFlags.empty()) {
844     std::string newf = newFlags;
845     if (newf.find("\\\"") != std::string::npos) {
846       cmSystemTools::ReplaceString(newf, "\\\"", "\"");
847       this->cmLocalGenerator::AppendFlags(flags, newf);
848       return;
849     }
850   }
851   this->cmLocalGenerator::AppendFlags(flags, newFlags);
852 }
853
854 void cmLocalUnixMakefileGenerator3::AppendRuleDepend(
855   std::vector<std::string>& depends, const char* ruleFileName)
856 {
857   // Add a dependency on the rule file itself unless an option to skip
858   // it is specifically enabled by the user or project.
859   const char* nodep =
860     this->Makefile->GetDefinition("CMAKE_SKIP_RULE_DEPENDENCY");
861   if (!nodep || cmIsOff(nodep)) {
862     depends.emplace_back(ruleFileName);
863   }
864 }
865
866 void cmLocalUnixMakefileGenerator3::AppendRuleDepends(
867   std::vector<std::string>& depends, std::vector<std::string> const& ruleFiles)
868 {
869   // Add a dependency on the rule file itself unless an option to skip
870   // it is specifically enabled by the user or project.
871   if (!this->Makefile->IsOn("CMAKE_SKIP_RULE_DEPENDENCY")) {
872     cm::append(depends, ruleFiles);
873   }
874 }
875
876 void cmLocalUnixMakefileGenerator3::AppendCustomDepends(
877   std::vector<std::string>& depends, const std::vector<cmCustomCommand>& ccs)
878 {
879   for (cmCustomCommand const& cc : ccs) {
880     cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this);
881     this->AppendCustomDepend(depends, ccg);
882   }
883 }
884
885 void cmLocalUnixMakefileGenerator3::AppendCustomDepend(
886   std::vector<std::string>& depends, cmCustomCommandGenerator const& ccg)
887 {
888   for (std::string const& d : ccg.GetDepends()) {
889     // Lookup the real name of the dependency in case it is a CMake target.
890     std::string dep;
891     if (this->GetRealDependency(d, this->GetConfigName(), dep)) {
892       depends.push_back(std::move(dep));
893     }
894   }
895 }
896
897 void cmLocalUnixMakefileGenerator3::AppendCustomCommands(
898   std::vector<std::string>& commands, const std::vector<cmCustomCommand>& ccs,
899   cmGeneratorTarget* target, std::string const& relative)
900 {
901   for (cmCustomCommand const& cc : ccs) {
902     cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this);
903     this->AppendCustomCommand(commands, ccg, target, relative, true);
904   }
905 }
906
907 void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
908   std::vector<std::string>& commands, cmCustomCommandGenerator const& ccg,
909   cmGeneratorTarget* target, std::string const& relative, bool echo_comment,
910   std::ostream* content)
911 {
912   // Optionally create a command to display the custom command's
913   // comment text.  This is used for pre-build, pre-link, and
914   // post-build command comments.  Custom build step commands have
915   // their comments generated elsewhere.
916   if (echo_comment) {
917     const char* comment = ccg.GetComment();
918     if (comment && *comment) {
919       this->AppendEcho(commands, comment,
920                        cmLocalUnixMakefileGenerator3::EchoGenerate);
921     }
922   }
923
924   // if the command specified a working directory use it.
925   std::string dir = this->GetCurrentBinaryDirectory();
926   std::string workingDir = ccg.GetWorkingDirectory();
927   if (!workingDir.empty()) {
928     dir = workingDir;
929   }
930   if (content) {
931     *content << dir;
932   }
933
934   std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
935     this->CreateRulePlaceholderExpander());
936
937   // Add each command line to the set of commands.
938   std::vector<std::string> commands1;
939   std::string currentBinDir = this->GetCurrentBinaryDirectory();
940   for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
941     // Build the command line in a single string.
942     std::string cmd = ccg.GetCommand(c);
943     if (!cmd.empty()) {
944       // Use "call " before any invocations of .bat or .cmd files
945       // invoked as custom commands in the WindowsShell.
946       //
947       bool useCall = false;
948
949       if (this->IsWindowsShell()) {
950         std::string suffix;
951         if (cmd.size() > 4) {
952           suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
953           if (suffix == ".bat" || suffix == ".cmd") {
954             useCall = true;
955           }
956         }
957       }
958
959       cmSystemTools::ReplaceString(cmd, "/./", "/");
960       // Convert the command to a relative path only if the current
961       // working directory will be the start-output directory.
962       bool had_slash = cmd.find('/') != std::string::npos;
963       if (workingDir.empty()) {
964         cmd = this->MaybeConvertToRelativePath(currentBinDir, cmd);
965       }
966       bool has_slash = cmd.find('/') != std::string::npos;
967       if (had_slash && !has_slash) {
968         // This command was specified as a path to a file in the
969         // current directory.  Add a leading "./" so it can run
970         // without the current directory being in the search path.
971         cmd = cmStrCat("./", cmd);
972       }
973
974       std::string launcher;
975       // Short-circuit if there is no launcher.
976       const char* val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM");
977       if (val && *val) {
978         // Expand rule variables referenced in the given launcher command.
979         cmRulePlaceholderExpander::RuleVariables vars;
980         vars.CMTargetName = target->GetName().c_str();
981         vars.CMTargetType = cmState::GetTargetTypeName(target->GetType());
982         std::string output;
983         const std::vector<std::string>& outputs = ccg.GetOutputs();
984         if (!outputs.empty()) {
985           output = outputs[0];
986           if (workingDir.empty()) {
987             output = this->MaybeConvertToRelativePath(
988               this->GetCurrentBinaryDirectory(), output);
989           }
990           output =
991             this->ConvertToOutputFormat(output, cmOutputConverter::SHELL);
992         }
993         vars.Output = output.c_str();
994
995         launcher = val;
996         rulePlaceholderExpander->ExpandRuleVariables(this, launcher, vars);
997         if (!launcher.empty()) {
998           launcher += " ";
999         }
1000       }
1001
1002       std::string shellCommand = this->MaybeConvertWatcomShellCommand(cmd);
1003       if (shellCommand.empty()) {
1004         shellCommand =
1005           this->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL);
1006       }
1007       cmd = launcher + shellCommand;
1008
1009       ccg.AppendArguments(c, cmd);
1010       if (content) {
1011         // Rule content does not include the launcher.
1012         *content << (cmd.c_str() + launcher.size());
1013       }
1014       if (this->BorlandMakeCurlyHack) {
1015         // Borland Make has a very strange bug.  If the first curly
1016         // brace anywhere in the command string is a left curly, it
1017         // must be written {{} instead of just {.  Otherwise some
1018         // curly braces are removed.  The hack can be skipped if the
1019         // first curly brace is the last character.
1020         std::string::size_type lcurly = cmd.find('{');
1021         if (lcurly != std::string::npos && lcurly < (cmd.size() - 1)) {
1022           std::string::size_type rcurly = cmd.find('}');
1023           if (rcurly == std::string::npos || rcurly > lcurly) {
1024             // The first curly is a left curly.  Use the hack.
1025             cmd =
1026               cmStrCat(cmd.substr(0, lcurly), "{{}", cmd.substr(lcurly + 1));
1027           }
1028         }
1029       }
1030       if (launcher.empty()) {
1031         if (useCall) {
1032           cmd = cmStrCat("call ", cmd);
1033         } else if (this->IsNMake() && cmd[0] == '"') {
1034           cmd = cmStrCat("echo >nul && ", cmd);
1035         }
1036       }
1037       commands1.push_back(std::move(cmd));
1038     }
1039   }
1040
1041   // Setup the proper working directory for the commands.
1042   this->CreateCDCommand(commands1, dir, relative);
1043
1044   // push back the custom commands
1045   cm::append(commands, commands1);
1046 }
1047
1048 void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
1049   std::vector<std::string>& commands, const std::set<std::string>& files,
1050   cmGeneratorTarget* target, const char* filename)
1051 {
1052   std::string currentBinDir = this->GetCurrentBinaryDirectory();
1053   std::string cleanfile = cmStrCat(
1054     currentBinDir, '/', this->GetTargetDirectory(target), "/cmake_clean");
1055   if (filename) {
1056     cleanfile += "_";
1057     cleanfile += filename;
1058   }
1059   cleanfile += ".cmake";
1060   std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
1061   cmsys::ofstream fout(cleanfilePath.c_str());
1062   if (!fout) {
1063     cmSystemTools::Error("Could not create " + cleanfilePath);
1064   }
1065   if (!files.empty()) {
1066     fout << "file(REMOVE_RECURSE\n";
1067     for (std::string const& file : files) {
1068       std::string fc = this->MaybeConvertToRelativePath(currentBinDir, file);
1069       fout << "  " << cmOutputConverter::EscapeForCMake(fc) << "\n";
1070     }
1071     fout << ")\n";
1072   }
1073   {
1074     std::string remove =
1075       cmStrCat("$(CMAKE_COMMAND) -P ",
1076                this->ConvertToOutputFormat(
1077                  this->MaybeConvertToRelativePath(
1078                    this->GetCurrentBinaryDirectory(), cleanfile),
1079                  cmOutputConverter::SHELL));
1080     commands.push_back(std::move(remove));
1081   }
1082
1083   // For the main clean rule add per-language cleaning.
1084   if (!filename) {
1085     // Get the set of source languages in the target.
1086     std::set<std::string> languages;
1087     target->GetLanguages(
1088       languages, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
1089     /* clang-format off */
1090     fout << "\n"
1091          << "# Per-language clean rules from dependency scanning.\n"
1092          << "foreach(lang " << cmJoin(languages, " ") << ")\n"
1093          << "  include(" << this->GetTargetDirectory(target)
1094          << "/cmake_clean_${lang}.cmake OPTIONAL)\n"
1095          << "endforeach()\n";
1096     /* clang-format on */
1097   }
1098 }
1099
1100 void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand(
1101   std::vector<std::string>& commands)
1102 {
1103   std::vector<std::string> cleanFiles;
1104   // Look for additional files registered for cleaning in this directory.
1105   if (const char* prop_value =
1106         this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
1107     cmExpandList(cmGeneratorExpression::Evaluate(
1108                    prop_value, this,
1109                    this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")),
1110                  cleanFiles);
1111   }
1112   if (cleanFiles.empty()) {
1113     return;
1114   }
1115
1116   const auto& rootLG = this->GetGlobalGenerator()->GetLocalGenerators().at(0);
1117   std::string const& binaryDir = rootLG->GetCurrentBinaryDirectory();
1118   std::string const& currentBinaryDir = this->GetCurrentBinaryDirectory();
1119   std::string cleanfile =
1120     cmStrCat(currentBinaryDir, "/CMakeFiles/cmake_directory_clean.cmake");
1121   // Write clean script
1122   {
1123     std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
1124     cmsys::ofstream fout(cleanfilePath.c_str());
1125     if (!fout) {
1126       cmSystemTools::Error("Could not create " + cleanfilePath);
1127       return;
1128     }
1129     fout << "file(REMOVE_RECURSE\n";
1130     for (std::string const& cfl : cleanFiles) {
1131       std::string fc = rootLG->MaybeConvertToRelativePath(
1132         binaryDir, cmSystemTools::CollapseFullPath(cfl, currentBinaryDir));
1133       fout << "  " << cmOutputConverter::EscapeForCMake(fc) << "\n";
1134     }
1135     fout << ")\n";
1136   }
1137   // Create command
1138   {
1139     std::string remove =
1140       cmStrCat("$(CMAKE_COMMAND) -P ",
1141                this->ConvertToOutputFormat(
1142                  rootLG->MaybeConvertToRelativePath(binaryDir, cleanfile),
1143                  cmOutputConverter::SHELL));
1144     commands.push_back(std::move(remove));
1145   }
1146 }
1147
1148 void cmLocalUnixMakefileGenerator3::AppendEcho(
1149   std::vector<std::string>& commands, std::string const& text, EchoColor color,
1150   EchoProgress const* progress)
1151 {
1152   // Choose the color for the text.
1153   std::string color_name;
1154   if (this->GlobalGenerator->GetToolSupportsColor() && this->ColorMakefile) {
1155     // See cmake::ExecuteEchoColor in cmake.cxx for these options.
1156     // This color set is readable on both black and white backgrounds.
1157     switch (color) {
1158       case EchoNormal:
1159         break;
1160       case EchoDepend:
1161         color_name = "--magenta --bold ";
1162         break;
1163       case EchoBuild:
1164         color_name = "--green ";
1165         break;
1166       case EchoLink:
1167         color_name = "--green --bold ";
1168         break;
1169       case EchoGenerate:
1170         color_name = "--blue --bold ";
1171         break;
1172       case EchoGlobal:
1173         color_name = "--cyan ";
1174         break;
1175     }
1176   }
1177
1178   // Echo one line at a time.
1179   std::string line;
1180   line.reserve(200);
1181   for (const char* c = text.c_str();; ++c) {
1182     if (*c == '\n' || *c == '\0') {
1183       // Avoid writing a blank last line on end-of-string.
1184       if (*c != '\0' || !line.empty()) {
1185         // Add a command to echo this line.
1186         std::string cmd;
1187         if (color_name.empty() && !progress) {
1188           // Use the native echo command.
1189           cmd = cmStrCat("@echo ", this->EscapeForShell(line, false, true));
1190         } else {
1191           // Use cmake to echo the text in color.
1192           cmd = cmStrCat(
1193             "@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) ",
1194             color_name);
1195           if (progress) {
1196             cmd += "--progress-dir=";
1197             cmd += this->ConvertToOutputFormat(
1198               cmSystemTools::CollapseFullPath(progress->Dir),
1199               cmOutputConverter::SHELL);
1200             cmd += " ";
1201             cmd += "--progress-num=";
1202             cmd += progress->Arg;
1203             cmd += " ";
1204           }
1205           cmd += this->EscapeForShell(line);
1206         }
1207         commands.push_back(std::move(cmd));
1208       }
1209
1210       // Reset the line to empty.
1211       line.clear();
1212
1213       // Progress appears only on first line.
1214       progress = nullptr;
1215
1216       // Terminate on end-of-string.
1217       if (*c == '\0') {
1218         return;
1219       }
1220     } else if (*c != '\r') {
1221       // Append this character to the current line.
1222       line += *c;
1223     }
1224   }
1225 }
1226
1227 std::string cmLocalUnixMakefileGenerator3::CreateMakeVariable(
1228   std::string const& s, std::string const& s2)
1229 {
1230   std::string unmodified = cmStrCat(s, s2);
1231   // if there is no restriction on the length of make variables
1232   // and there are no "." characters in the string, then return the
1233   // unmodified combination.
1234   if ((!this->MakefileVariableSize &&
1235        unmodified.find('.') == std::string::npos) &&
1236       (!this->MakefileVariableSize &&
1237        unmodified.find('+') == std::string::npos) &&
1238       (!this->MakefileVariableSize &&
1239        unmodified.find('-') == std::string::npos)) {
1240     return unmodified;
1241   }
1242
1243   // see if the variable has been defined before and return
1244   // the modified version of the variable
1245   auto i = this->MakeVariableMap.find(unmodified);
1246   if (i != this->MakeVariableMap.end()) {
1247     return i->second;
1248   }
1249   // start with the unmodified variable
1250   std::string ret = unmodified;
1251   // if this there is no value for this->MakefileVariableSize then
1252   // the string must have bad characters in it
1253   if (!this->MakefileVariableSize) {
1254     std::replace(ret.begin(), ret.end(), '.', '_');
1255     cmSystemTools::ReplaceString(ret, "-", "__");
1256     cmSystemTools::ReplaceString(ret, "+", "___");
1257     int ni = 0;
1258     char buffer[5];
1259     // make sure the _ version is not already used, if
1260     // it is used then add number to the end of the variable
1261     while (this->ShortMakeVariableMap.count(ret) && ni < 1000) {
1262       ++ni;
1263       sprintf(buffer, "%04d", ni);
1264       ret = unmodified + buffer;
1265     }
1266     this->ShortMakeVariableMap[ret] = "1";
1267     this->MakeVariableMap[unmodified] = ret;
1268     return ret;
1269   }
1270
1271   // if the string is greater than 32 chars it is an invalid variable name
1272   // for borland make
1273   if (static_cast<int>(ret.size()) > this->MakefileVariableSize) {
1274     int keep = this->MakefileVariableSize - 8;
1275     int size = keep + 3;
1276     std::string str1 = s;
1277     std::string str2 = s2;
1278     // we must shorten the combined string by 4 characters
1279     // keep no more than 24 characters from the second string
1280     if (static_cast<int>(str2.size()) > keep) {
1281       str2 = str2.substr(0, keep);
1282     }
1283     if (static_cast<int>(str1.size()) + static_cast<int>(str2.size()) > size) {
1284       str1 = str1.substr(0, size - str2.size());
1285     }
1286     char buffer[5];
1287     int ni = 0;
1288     sprintf(buffer, "%04d", ni);
1289     ret = str1 + str2 + buffer;
1290     while (this->ShortMakeVariableMap.count(ret) && ni < 1000) {
1291       ++ni;
1292       sprintf(buffer, "%04d", ni);
1293       ret = str1 + str2 + buffer;
1294     }
1295     if (ni == 1000) {
1296       cmSystemTools::Error("Borland makefile variable length too long");
1297       return unmodified;
1298     }
1299     // once an unused variable is found
1300     this->ShortMakeVariableMap[ret] = "1";
1301   }
1302   // always make an entry into the unmodified to variable map
1303   this->MakeVariableMap[unmodified] = ret;
1304   return ret;
1305 }
1306
1307 bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
1308   const std::string& tgtInfo, bool verbose, bool color)
1309 {
1310   // read in the target info file
1311   if (!this->Makefile->ReadListFile(tgtInfo) ||
1312       cmSystemTools::GetErrorOccuredFlag()) {
1313     cmSystemTools::Error("Target DependInfo.cmake file not found");
1314   }
1315
1316   // Check if any multiple output pairs have a missing file.
1317   this->CheckMultipleOutputs(verbose);
1318
1319   std::string const targetDir = cmSystemTools::GetFilenamePath(tgtInfo);
1320   std::string const internalDependFile = targetDir + "/depend.internal";
1321   std::string const dependFile = targetDir + "/depend.make";
1322
1323   // If the target DependInfo.cmake file has changed since the last
1324   // time dependencies were scanned then force rescanning.  This may
1325   // happen when a new source file is added and CMake regenerates the
1326   // project but no other sources were touched.
1327   bool needRescanDependInfo = false;
1328   cmFileTimeCache* ftc =
1329     this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
1330   {
1331     int result;
1332     if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
1333       if (verbose) {
1334         std::ostringstream msg;
1335         msg << "Dependee \"" << tgtInfo << "\" is newer than depender \""
1336             << internalDependFile << "\"." << std::endl;
1337         cmSystemTools::Stdout(msg.str());
1338       }
1339       needRescanDependInfo = true;
1340     }
1341   }
1342
1343   // If the directory information is newer than depend.internal, include dirs
1344   // may have changed. In this case discard all old dependencies.
1345   bool needRescanDirInfo = false;
1346   {
1347     std::string dirInfoFile =
1348       cmStrCat(this->GetCurrentBinaryDirectory(),
1349                "/CMakeFiles/CMakeDirectoryInformation.cmake");
1350     int result;
1351     if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
1352         result < 0) {
1353       if (verbose) {
1354         std::ostringstream msg;
1355         msg << "Dependee \"" << dirInfoFile << "\" is newer than depender \""
1356             << internalDependFile << "\"." << std::endl;
1357         cmSystemTools::Stdout(msg.str());
1358       }
1359       needRescanDirInfo = true;
1360     }
1361   }
1362
1363   // Check the implicit dependencies to see if they are up to date.
1364   // The build.make file may have explicit dependencies for the object
1365   // files but these will not affect the scanning process so they need
1366   // not be considered.
1367   cmDepends::DependencyMap validDependencies;
1368   bool needRescanDependencies = false;
1369   if (!needRescanDirInfo) {
1370     cmDependsC checker;
1371     checker.SetVerbose(verbose);
1372     checker.SetFileTimeCache(ftc);
1373     // cmDependsC::Check() fills the vector validDependencies() with the
1374     // dependencies for those files where they are still valid, i.e. neither
1375     // the files themselves nor any files they depend on have changed.
1376     // We don't do that if the CMakeDirectoryInformation.cmake file has
1377     // changed, because then potentially all dependencies have changed.
1378     // This information is given later on to cmDependsC, which then only
1379     // rescans the files where it did not get valid dependencies via this
1380     // dependency vector. This means that in the normal case, when only
1381     // few or one file have been edited, then also only this one file is
1382     // actually scanned again, instead of all files for this target.
1383     needRescanDependencies =
1384       !checker.Check(dependFile, internalDependFile, validDependencies);
1385   }
1386
1387   if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
1388     // The dependencies must be regenerated.
1389     std::string targetName = cmSystemTools::GetFilenameName(targetDir);
1390     targetName = targetName.substr(0, targetName.length() - 4);
1391     std::string message =
1392       cmStrCat("Scanning dependencies of target ", targetName);
1393     cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
1394                                        cmsysTerminal_Color_ForegroundBold,
1395                                      message.c_str(), true, color);
1396
1397     return this->ScanDependencies(targetDir, dependFile, internalDependFile,
1398                                   validDependencies);
1399   }
1400
1401   // The dependencies are already up-to-date.
1402   return true;
1403 }
1404
1405 bool cmLocalUnixMakefileGenerator3::ScanDependencies(
1406   std::string const& targetDir, std::string const& dependFile,
1407   std::string const& internalDependFile, cmDepends::DependencyMap& validDeps)
1408 {
1409   // Read the directory information file.
1410   cmMakefile* mf = this->Makefile;
1411   bool haveDirectoryInfo = false;
1412   {
1413     std::string dirInfoFile =
1414       cmStrCat(this->GetCurrentBinaryDirectory(),
1415                "/CMakeFiles/CMakeDirectoryInformation.cmake");
1416     if (mf->ReadListFile(dirInfoFile) &&
1417         !cmSystemTools::GetErrorOccuredFlag()) {
1418       haveDirectoryInfo = true;
1419     }
1420   }
1421
1422   // Lookup useful directory information.
1423   if (haveDirectoryInfo) {
1424     // Test whether we need to force Unix paths.
1425     if (const char* force = mf->GetDefinition("CMAKE_FORCE_UNIX_PATHS")) {
1426       if (!cmIsOff(force)) {
1427         cmSystemTools::SetForceUnixPaths(true);
1428       }
1429     }
1430
1431     // Setup relative path top directories.
1432     if (const char* relativePathTopSource =
1433           mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_SOURCE")) {
1434       this->StateSnapshot.GetDirectory().SetRelativePathTopSource(
1435         relativePathTopSource);
1436     }
1437     if (const char* relativePathTopBinary =
1438           mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_BINARY")) {
1439       this->StateSnapshot.GetDirectory().SetRelativePathTopBinary(
1440         relativePathTopBinary);
1441     }
1442   } else {
1443     cmSystemTools::Error("Directory Information file not found");
1444   }
1445
1446   // Open the make depends file.  This should be copy-if-different
1447   // because the make tool may try to reload it needlessly otherwise.
1448   cmGeneratedFileStream ruleFileStream(
1449     dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
1450   ruleFileStream.SetCopyIfDifferent(true);
1451   if (!ruleFileStream) {
1452     return false;
1453   }
1454
1455   // Open the cmake dependency tracking file.  This should not be
1456   // copy-if-different because dependencies are re-scanned when it is
1457   // older than the DependInfo.cmake.
1458   cmGeneratedFileStream internalRuleFileStream(
1459     internalDependFile, false, this->GlobalGenerator->GetMakefileEncoding());
1460   if (!internalRuleFileStream) {
1461     return false;
1462   }
1463
1464   this->WriteDisclaimer(ruleFileStream);
1465   this->WriteDisclaimer(internalRuleFileStream);
1466
1467   // for each language we need to scan, scan it
1468   std::vector<std::string> langs =
1469     cmExpandedList(mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"));
1470   for (std::string const& lang : langs) {
1471     // construct the checker
1472     // Create the scanner for this language
1473     std::unique_ptr<cmDepends> scanner;
1474     if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" ||
1475         lang == "CUDA") {
1476       // TODO: Handle RC (resource files) dependencies correctly.
1477       scanner = cm::make_unique<cmDependsC>(this, targetDir, lang, &validDeps);
1478     }
1479 #ifndef CMAKE_BOOTSTRAP
1480     else if (lang == "Fortran") {
1481       ruleFileStream << "# Note that incremental build could trigger "
1482                      << "a call to cmake_copy_f90_mod on each re-build\n";
1483       scanner = cm::make_unique<cmDependsFortran>(this);
1484     } else if (lang == "Java") {
1485       scanner = cm::make_unique<cmDependsJava>();
1486     }
1487 #endif
1488
1489     if (scanner) {
1490       scanner->SetLocalGenerator(this);
1491       scanner->SetFileTimeCache(
1492         this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache());
1493       scanner->SetLanguage(lang);
1494       scanner->SetTargetDirectory(targetDir);
1495       scanner->Write(ruleFileStream, internalRuleFileStream);
1496     }
1497   }
1498
1499   return true;
1500 }
1501
1502 void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose)
1503 {
1504   cmMakefile* mf = this->Makefile;
1505
1506   // Get the string listing the multiple output pairs.
1507   const char* pairs_string = mf->GetDefinition("CMAKE_MULTIPLE_OUTPUT_PAIRS");
1508   if (!pairs_string) {
1509     return;
1510   }
1511
1512   // Convert the string to a list and preserve empty entries.
1513   std::vector<std::string> pairs = cmExpandedList(pairs_string, true);
1514   for (auto i = pairs.begin(); i != pairs.end() && (i + 1) != pairs.end();) {
1515     const std::string& depender = *i++;
1516     const std::string& dependee = *i++;
1517
1518     // If the depender is missing then delete the dependee to make
1519     // sure both will be regenerated.
1520     if (cmSystemTools::FileExists(dependee) &&
1521         !cmSystemTools::FileExists(depender)) {
1522       if (verbose) {
1523         std::ostringstream msg;
1524         msg << "Deleting primary custom command output \"" << dependee
1525             << "\" because another output \"" << depender
1526             << "\" does not exist." << std::endl;
1527         cmSystemTools::Stdout(msg.str());
1528       }
1529       cmSystemTools::RemoveFile(dependee);
1530     }
1531   }
1532 }
1533
1534 void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
1535   std::ostream& ruleFileStream)
1536 {
1537   this->WriteDisclaimer(ruleFileStream);
1538
1539   // Write the main entry point target.  This must be the VERY first
1540   // target so that make with no arguments will run it.
1541   {
1542     // Just depend on the all target to drive the build.
1543     std::vector<std::string> depends;
1544     std::vector<std::string> no_commands;
1545     depends.emplace_back("all");
1546
1547     // Write the rule.
1548     this->WriteMakeRule(ruleFileStream,
1549                         "Default target executed when no arguments are "
1550                         "given to make.",
1551                         "default_target", depends, no_commands, true);
1552
1553     // Help out users that try "gmake target1 target2 -j".
1554     cmGlobalUnixMakefileGenerator3* gg =
1555       static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
1556     if (gg->AllowNotParallel()) {
1557       std::vector<std::string> no_depends;
1558       this->WriteMakeRule(ruleFileStream,
1559                           "Allow only one \"make -f "
1560                           "Makefile2\" at a time, but pass "
1561                           "parallelism.",
1562                           ".NOTPARALLEL", no_depends, no_commands, false);
1563     }
1564   }
1565
1566   this->WriteSpecialTargetsTop(ruleFileStream);
1567
1568   // Include the progress variables for the target.
1569   // Write all global targets
1570   this->WriteDivider(ruleFileStream);
1571   ruleFileStream << "# Targets provided globally by CMake.\n"
1572                  << "\n";
1573   const auto& targets = this->GetGeneratorTargets();
1574   for (const auto& gt : targets) {
1575     if (gt->GetType() == cmStateEnums::GLOBAL_TARGET) {
1576       std::string targetString =
1577         "Special rule for the target " + gt->GetName();
1578       std::vector<std::string> commands;
1579       std::vector<std::string> depends;
1580
1581       const char* text = gt->GetProperty("EchoString");
1582       if (!text) {
1583         text = "Running external command ...";
1584       }
1585       depends.reserve(gt->GetUtilities().size());
1586       for (BT<std::pair<std::string, bool>> const& u : gt->GetUtilities()) {
1587         depends.push_back(u.Value.first);
1588       }
1589       this->AppendEcho(commands, text,
1590                        cmLocalUnixMakefileGenerator3::EchoGlobal);
1591
1592       // Global targets store their rules in pre- and post-build commands.
1593       this->AppendCustomDepends(depends, gt->GetPreBuildCommands());
1594       this->AppendCustomDepends(depends, gt->GetPostBuildCommands());
1595       this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt.get(),
1596                                  this->GetCurrentBinaryDirectory());
1597       this->AppendCustomCommands(commands, gt->GetPostBuildCommands(),
1598                                  gt.get(), this->GetCurrentBinaryDirectory());
1599       std::string targetName = gt->GetName();
1600       this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
1601                           depends, commands, true);
1602
1603       // Provide a "/fast" version of the target.
1604       depends.clear();
1605       if ((targetName == "install") || (targetName == "install/local") ||
1606           (targetName == "install/strip")) {
1607         // Provide a fast install target that does not depend on all
1608         // but has the same command.
1609         depends.emplace_back("preinstall/fast");
1610       } else {
1611         // Just forward to the real target so at least it will work.
1612         depends.push_back(targetName);
1613         commands.clear();
1614       }
1615       targetName += "/fast";
1616       this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
1617                           depends, commands, true);
1618     }
1619   }
1620
1621   std::vector<std::string> depends;
1622   std::vector<std::string> commands;
1623
1624   // Write the all rule.
1625   std::string recursiveTarget =
1626     cmStrCat(this->GetCurrentBinaryDirectory(), "/all");
1627
1628   bool regenerate =
1629     !this->GlobalGenerator->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
1630   if (regenerate) {
1631     depends.emplace_back("cmake_check_build_system");
1632   }
1633
1634   std::string progressDir =
1635     cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles");
1636   {
1637     std::ostringstream progCmd;
1638     progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
1639     progCmd << this->ConvertToOutputFormat(
1640       cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL);
1641
1642     std::string progressFile = "/CMakeFiles/progress.marks";
1643     std::string progressFileNameFull = this->ConvertToFullPath(progressFile);
1644     progCmd << " "
1645             << this->ConvertToOutputFormat(
1646                  cmSystemTools::CollapseFullPath(progressFileNameFull),
1647                  cmOutputConverter::SHELL);
1648     commands.push_back(progCmd.str());
1649   }
1650   std::string mf2Dir = "CMakeFiles/Makefile2";
1651   commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
1652   this->CreateCDCommand(commands, this->GetBinaryDirectory(),
1653                         this->GetCurrentBinaryDirectory());
1654   {
1655     std::ostringstream progCmd;
1656     progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
1657     progCmd << this->ConvertToOutputFormat(
1658       cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL);
1659     progCmd << " 0";
1660     commands.push_back(progCmd.str());
1661   }
1662   this->WriteMakeRule(ruleFileStream, "The main all target", "all", depends,
1663                       commands, true);
1664
1665   // Write the clean rule.
1666   recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/clean");
1667   commands.clear();
1668   depends.clear();
1669   commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
1670   this->CreateCDCommand(commands, this->GetBinaryDirectory(),
1671                         this->GetCurrentBinaryDirectory());
1672   this->WriteMakeRule(ruleFileStream, "The main clean target", "clean",
1673                       depends, commands, true);
1674   commands.clear();
1675   depends.clear();
1676   depends.emplace_back("clean");
1677   this->WriteMakeRule(ruleFileStream, "The main clean target", "clean/fast",
1678                       depends, commands, true);
1679
1680   // Write the preinstall rule.
1681   recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/preinstall");
1682   commands.clear();
1683   depends.clear();
1684   const char* noall =
1685     this->Makefile->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
1686   if (!noall || cmIsOff(noall)) {
1687     // Drive the build before installing.
1688     depends.emplace_back("all");
1689   } else if (regenerate) {
1690     // At least make sure the build system is up to date.
1691     depends.emplace_back("cmake_check_build_system");
1692   }
1693   commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
1694   this->CreateCDCommand(commands, this->GetBinaryDirectory(),
1695                         this->GetCurrentBinaryDirectory());
1696   this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
1697                       "preinstall", depends, commands, true);
1698   depends.clear();
1699   this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
1700                       "preinstall/fast", depends, commands, true);
1701
1702   if (regenerate) {
1703     // write the depend rule, really a recompute depends rule
1704     depends.clear();
1705     commands.clear();
1706     cmake* cm = this->GlobalGenerator->GetCMakeInstance();
1707     if (cm->DoWriteGlobVerifyTarget()) {
1708       std::string rescanRule =
1709         cmStrCat("$(CMAKE_COMMAND) -P ",
1710                  this->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
1711                                              cmOutputConverter::SHELL));
1712       commands.push_back(rescanRule);
1713     }
1714     std::string cmakefileName = "CMakeFiles/Makefile.cmake";
1715     {
1716       std::string runRule = cmStrCat(
1717         "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) "
1718         "--check-build-system ",
1719         this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
1720         " 1");
1721       commands.push_back(std::move(runRule));
1722     }
1723     this->CreateCDCommand(commands, this->GetBinaryDirectory(),
1724                           this->GetCurrentBinaryDirectory());
1725     this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends,
1726                         commands, true);
1727   }
1728 }
1729
1730 void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
1731                                                       bool verbose)
1732 {
1733   // Get the list of target files to check
1734   const char* infoDef = mf->GetDefinition("CMAKE_DEPEND_INFO_FILES");
1735   if (!infoDef) {
1736     return;
1737   }
1738   std::vector<std::string> files = cmExpandedList(infoDef);
1739
1740   // Each depend information file corresponds to a target.  Clear the
1741   // dependencies for that target.
1742   cmDepends clearer;
1743   clearer.SetVerbose(verbose);
1744   for (std::string const& file : files) {
1745     std::string dir = cmSystemTools::GetFilenamePath(file);
1746
1747     // Clear the implicit dependency makefile.
1748     std::string dependFile = dir + "/depend.make";
1749     clearer.Clear(dependFile);
1750
1751     // Remove the internal dependency check file to force
1752     // regeneration.
1753     std::string internalDependFile = dir + "/depend.internal";
1754     cmSystemTools::RemoveFile(internalDependFile);
1755   }
1756 }
1757
1758 namespace {
1759 // Helper predicate for removing absolute paths that don't point to the
1760 // source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
1761 // is set ON, to only consider in-project dependencies during the build.
1762 class NotInProjectDir
1763 {
1764 public:
1765   // Constructor with the source and binary directory's path
1766   NotInProjectDir(std::string sourceDir, std::string binaryDir)
1767     : SourceDir(std::move(sourceDir))
1768     , BinaryDir(std::move(binaryDir))
1769   {
1770   }
1771
1772   // Operator evaluating the predicate
1773   bool operator()(const std::string& path) const
1774   {
1775     // Keep all relative paths:
1776     if (!cmSystemTools::FileIsFullPath(path)) {
1777       return false;
1778     }
1779     // If it's an absolute path, check if it starts with the source
1780     // direcotory:
1781     return (
1782       !(IsInDirectory(SourceDir, path) || IsInDirectory(BinaryDir, path)));
1783   }
1784
1785 private:
1786   // Helper function used by the predicate
1787   static bool IsInDirectory(const std::string& baseDir,
1788                             const std::string& testDir)
1789   {
1790     // First check if the test directory "starts with" the base directory:
1791     if (testDir.find(baseDir) != 0) {
1792       return false;
1793     }
1794     // If it does, then check that it's either the same string, or that the
1795     // next character is a slash:
1796     return ((testDir.size() == baseDir.size()) ||
1797             (testDir[baseDir.size()] == '/'));
1798   }
1799
1800   // The path to the source directory
1801   std::string SourceDir;
1802   // The path to the binary directory
1803   std::string BinaryDir;
1804 };
1805 }
1806
1807 void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
1808   std::ostream& cmakefileStream, cmGeneratorTarget* target)
1809 {
1810   ImplicitDependLanguageMap const& implicitLangs =
1811     this->GetImplicitDepends(target);
1812
1813   // list the languages
1814   cmakefileStream
1815     << "# The set of languages for which implicit dependencies are needed:\n";
1816   cmakefileStream << "set(CMAKE_DEPENDS_LANGUAGES\n";
1817   for (auto const& implicitLang : implicitLangs) {
1818     cmakefileStream << "  \"" << implicitLang.first << "\"\n";
1819   }
1820   cmakefileStream << "  )\n";
1821
1822   // now list the files for each language
1823   cmakefileStream
1824     << "# The set of files for implicit dependencies of each language:\n";
1825   for (auto const& implicitLang : implicitLangs) {
1826     cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << implicitLang.first
1827                     << "\n";
1828     ImplicitDependFileMap const& implicitPairs = implicitLang.second;
1829
1830     // for each file pair
1831     for (auto const& implicitPair : implicitPairs) {
1832       for (auto const& di : implicitPair.second) {
1833         cmakefileStream << "  \"" << di << "\" ";
1834         cmakefileStream << "\"" << implicitPair.first << "\"\n";
1835       }
1836     }
1837     cmakefileStream << "  )\n";
1838
1839     // Tell the dependency scanner what compiler is used.
1840     std::string cidVar =
1841       cmStrCat("CMAKE_", implicitLang.first, "_COMPILER_ID");
1842     const char* cid = this->Makefile->GetDefinition(cidVar);
1843     if (cid && *cid) {
1844       cmakefileStream << "set(CMAKE_" << implicitLang.first
1845                       << "_COMPILER_ID \"" << cid << "\")\n";
1846     }
1847
1848     if (implicitLang.first == "Fortran") {
1849       std::string smodSep =
1850         this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
1851       std::string smodExt =
1852         this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
1853       cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep
1854                       << "\")\n";
1855       cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt
1856                       << "\")\n";
1857     }
1858
1859     // Build a list of preprocessor definitions for the target.
1860     std::set<std::string> defines;
1861     this->GetTargetDefines(target, this->GetConfigName(), implicitLang.first,
1862                            defines);
1863     if (!defines.empty()) {
1864       /* clang-format off */
1865       cmakefileStream
1866         << "\n"
1867         << "# Preprocessor definitions for this target.\n"
1868         << "set(CMAKE_TARGET_DEFINITIONS_" << implicitLang.first << "\n";
1869       /* clang-format on */
1870       for (std::string const& define : defines) {
1871         cmakefileStream << "  " << cmOutputConverter::EscapeForCMake(define)
1872                         << "\n";
1873       }
1874       cmakefileStream << "  )\n";
1875     }
1876
1877     // Target-specific include directories:
1878     cmakefileStream << "\n"
1879                     << "# The include file search paths:\n";
1880     cmakefileStream << "set(CMAKE_" << implicitLang.first
1881                     << "_TARGET_INCLUDE_PATH\n";
1882     std::vector<std::string> includes;
1883
1884     this->GetIncludeDirectories(includes, target, implicitLang.first,
1885                                 this->GetConfigName());
1886     std::string binaryDir = this->GetState()->GetBinaryDirectory();
1887     if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
1888       std::string const& sourceDir = this->GetState()->GetSourceDirectory();
1889       cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir));
1890     }
1891     for (std::string const& include : includes) {
1892       cmakefileStream << "  \""
1893                       << this->MaybeConvertToRelativePath(binaryDir, include)
1894                       << "\"\n";
1895     }
1896     cmakefileStream << "  )\n";
1897   }
1898
1899   // Store include transform rule properties.  Write the directory
1900   // rules first because they may be overridden by later target rules.
1901   std::vector<std::string> transformRules;
1902   if (const char* xform =
1903         this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
1904     cmExpandList(xform, transformRules);
1905   }
1906   if (const char* xform =
1907         target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
1908     cmExpandList(xform, transformRules);
1909   }
1910   if (!transformRules.empty()) {
1911     cmakefileStream << "set(CMAKE_INCLUDE_TRANSFORMS\n";
1912     for (std::string const& tr : transformRules) {
1913       cmakefileStream << "  " << cmOutputConverter::EscapeForCMake(tr) << "\n";
1914     }
1915     cmakefileStream << "  )\n";
1916   }
1917 }
1918
1919 void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os)
1920 {
1921   os << "# CMAKE generated file: DO NOT EDIT!\n"
1922      << "# Generated by \"" << this->GlobalGenerator->GetName() << "\""
1923      << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
1924      << cmVersion::GetMinorVersion() << "\n\n";
1925 }
1926
1927 std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall(
1928   const std::string& makefile, const std::string& tgt)
1929 {
1930   // Call make on the given file.
1931   std::string cmd = cmStrCat(
1932     "$(MAKE) $(MAKESILENT) -f ",
1933     this->ConvertToOutputFormat(makefile, cmOutputConverter::SHELL), ' ');
1934
1935   cmGlobalUnixMakefileGenerator3* gg =
1936     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
1937   // Pass down verbosity level.
1938   if (!gg->MakeSilentFlag.empty()) {
1939     cmd += gg->MakeSilentFlag;
1940     cmd += " ";
1941   }
1942
1943   // Most unix makes will pass the command line flags to make down to
1944   // sub-invoked makes via an environment variable.  However, some
1945   // makes do not support that, so you have to pass the flags
1946   // explicitly.
1947   if (gg->PassMakeflags) {
1948     cmd += "-$(MAKEFLAGS) ";
1949   }
1950
1951   // Add the target.
1952   if (!tgt.empty()) {
1953     // The make target is always relative to the top of the build tree.
1954     std::string tgt2 =
1955       this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), tgt);
1956
1957     // The target may have been written with windows paths.
1958     cmSystemTools::ConvertToOutputSlashes(tgt2);
1959
1960     // Escape one extra time if the make tool requires it.
1961     if (this->MakeCommandEscapeTargetTwice) {
1962       tgt2 = this->EscapeForShell(tgt2, true, false);
1963     }
1964
1965     // The target name is now a string that should be passed verbatim
1966     // on the command line.
1967     cmd += this->EscapeForShell(tgt2, true, false);
1968   }
1969   return cmd;
1970 }
1971
1972 void cmLocalUnixMakefileGenerator3::WriteDivider(std::ostream& os)
1973 {
1974   os << "#======================================"
1975      << "=======================================\n";
1976 }
1977
1978 void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os,
1979                                                        const std::string& s)
1980 {
1981   // Write the given string to the stream with escaping to get it back
1982   // into CMake through the lexical scanner.
1983   os << "\"";
1984   for (char c : s) {
1985     if (c == '\\') {
1986       os << "\\\\";
1987     } else if (c == '"') {
1988       os << "\\\"";
1989     } else {
1990       os << c;
1991     }
1992   }
1993   os << "\"";
1994 }
1995
1996 std::string cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
1997   const std::string& p, bool useWatcomQuote)
1998 {
1999   // Split the path into its components.
2000   std::vector<std::string> components;
2001   cmSystemTools::SplitPath(p, components);
2002
2003   // Open the quoted result.
2004   std::string result;
2005   if (useWatcomQuote) {
2006 #if defined(_WIN32) && !defined(__CYGWIN__)
2007     result = "'";
2008 #else
2009     result = "\"'";
2010 #endif
2011   } else {
2012     result = "\"";
2013   }
2014
2015   // Return an empty path if there are no components.
2016   if (!components.empty()) {
2017     // Choose a slash direction and fix root component.
2018     const char* slash = "/";
2019 #if defined(_WIN32) && !defined(__CYGWIN__)
2020     if (!cmSystemTools::GetForceUnixPaths()) {
2021       slash = "\\";
2022       for (char& i : components[0]) {
2023         if (i == '/') {
2024           i = '\\';
2025         }
2026       }
2027     }
2028 #endif
2029
2030     // Begin the quoted result with the root component.
2031     result += components[0];
2032
2033     if (components.size() > 1) {
2034       // Now add the rest of the components separated by the proper slash
2035       // direction for this platform.
2036       auto compEnd = std::remove(components.begin() + 1, components.end() - 1,
2037                                  std::string());
2038       auto compStart = components.begin() + 1;
2039       result += cmJoin(cmMakeRange(compStart, compEnd), slash);
2040       // Only the last component can be empty to avoid double slashes.
2041       result += slash;
2042       result += components.back();
2043     }
2044   }
2045
2046   // Close the quoted result.
2047   if (useWatcomQuote) {
2048 #if defined(_WIN32) && !defined(__CYGWIN__)
2049     result += "'";
2050 #else
2051     result += "'\"";
2052 #endif
2053   } else {
2054     result += "\"";
2055   }
2056
2057   return result;
2058 }
2059
2060 std::string cmLocalUnixMakefileGenerator3::GetTargetDirectory(
2061   cmGeneratorTarget const* target) const
2062 {
2063   std::string dir = cmStrCat("CMakeFiles/", target->GetName());
2064 #if defined(__VMS)
2065   dir += "_dir";
2066 #else
2067   dir += ".dir";
2068 #endif
2069   return dir;
2070 }
2071
2072 cmLocalUnixMakefileGenerator3::ImplicitDependLanguageMap const&
2073 cmLocalUnixMakefileGenerator3::GetImplicitDepends(const cmGeneratorTarget* tgt)
2074 {
2075   return this->ImplicitDepends[tgt->GetName()];
2076 }
2077
2078 void cmLocalUnixMakefileGenerator3::AddImplicitDepends(
2079   const cmGeneratorTarget* tgt, const std::string& lang,
2080   const std::string& obj, const std::string& src)
2081 {
2082   this->ImplicitDepends[tgt->GetName()][lang][obj].push_back(src);
2083 }
2084
2085 void cmLocalUnixMakefileGenerator3::CreateCDCommand(
2086   std::vector<std::string>& commands, std::string const& tgtDir,
2087   std::string const& relDir)
2088 {
2089   // do we need to cd?
2090   if (tgtDir == relDir) {
2091     return;
2092   }
2093
2094   // In a Windows shell we must change drive letter too.  The shell
2095   // used by NMake and Borland make does not support "cd /d" so this
2096   // feature simply cannot work with them (Borland make does not even
2097   // support changing the drive letter with just "d:").
2098   const char* cd_cmd = this->IsMinGWMake() ? "cd /d " : "cd ";
2099
2100   cmGlobalUnixMakefileGenerator3* gg =
2101     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
2102   if (!gg->UnixCD) {
2103     // On Windows we must perform each step separately and then change
2104     // back because the shell keeps the working directory between
2105     // commands.
2106     std::string cmd =
2107       cmStrCat(cd_cmd, this->ConvertToOutputForExisting(tgtDir));
2108     commands.insert(commands.begin(), cmd);
2109
2110     // Change back to the starting directory.
2111     cmd = cmStrCat(cd_cmd, this->ConvertToOutputForExisting(relDir));
2112     commands.push_back(std::move(cmd));
2113   } else {
2114     // On UNIX we must construct a single shell command to change
2115     // directory and build because make resets the directory between
2116     // each command.
2117     std::string outputForExisting = this->ConvertToOutputForExisting(tgtDir);
2118     std::string prefix = cd_cmd + outputForExisting + " && ";
2119     std::transform(commands.begin(), commands.end(), commands.begin(),
2120                    [&prefix](std::string const& s) { return prefix + s; });
2121   }
2122 }