63c6680b1f4c946e8cb92b60a0f9833eb435c1ff
[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     // Write special target to silence make output.  This must be after
732     // the default target in case VERBOSE is set (which changes the
733     // name).  The setting of CMAKE_VERBOSE_MAKEFILE to ON will cause a
734     // "VERBOSE=1" to be added as a make variable which will change the
735     // name of this special target.  This gives a make-time choice to
736     // the user.
737     this->WriteMakeRule(makefileStream,
738                         "Suppress display of executed commands.",
739                         "$(VERBOSE).SILENT", no_depends, no_commands, false);
740   }
741
742   // Work-around for makes that drop rules that have no dependencies
743   // or commands.
744   cmGlobalUnixMakefileGenerator3* gg =
745     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
746   std::string hack = gg->GetEmptyRuleHackDepends();
747   if (!hack.empty()) {
748     no_depends.push_back(std::move(hack));
749   }
750   std::string hack_cmd = gg->GetEmptyRuleHackCommand();
751   if (!hack_cmd.empty()) {
752     no_commands.push_back(std::move(hack_cmd));
753   }
754
755   // Special symbolic target that never exists to force dependers to
756   // run their rules.
757   this->WriteMakeRule(makefileStream, "A target that is always out of date.",
758                       "cmake_force", no_depends, no_commands, true);
759
760   // Variables for reference by other rules.
761   this->WriteMakeVariables(makefileStream);
762 }
763
764 void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom(
765   std::ostream& makefileStream)
766 {
767   this->WriteDivider(makefileStream);
768   makefileStream << "# Special targets to cleanup operation of make.\n"
769                  << "\n";
770
771   // Write special "cmake_check_build_system" target to run cmake with
772   // the --check-build-system flag.
773   if (!this->GlobalGenerator->GlobalSettingIsOn(
774         "CMAKE_SUPPRESS_REGENERATION")) {
775     // Build command to run CMake to check if anything needs regenerating.
776     std::vector<std::string> commands;
777     cmake* cm = this->GlobalGenerator->GetCMakeInstance();
778     if (cm->DoWriteGlobVerifyTarget()) {
779       std::string rescanRule =
780         cmStrCat("$(CMAKE_COMMAND) -P ",
781                  this->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
782                                              cmOutputConverter::SHELL));
783       commands.push_back(rescanRule);
784     }
785     std::string cmakefileName = "CMakeFiles/Makefile.cmake";
786     std::string runRule = cmStrCat(
787       "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) "
788       "--check-build-system ",
789       this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
790       " 0");
791
792     std::vector<std::string> no_depends;
793     commands.push_back(std::move(runRule));
794     if (!this->IsRootMakefile()) {
795       this->CreateCDCommand(commands, this->GetBinaryDirectory(),
796                             this->GetCurrentBinaryDirectory());
797     }
798     this->WriteMakeRule(makefileStream,
799                         "Special rule to run CMake to check the build system "
800                         "integrity.\n"
801                         "No rule that depends on this can have "
802                         "commands that come from listfiles\n"
803                         "because they might be regenerated.",
804                         "cmake_check_build_system", no_depends, commands,
805                         true);
806   }
807 }
808
809 void cmLocalUnixMakefileGenerator3::WriteConvenienceRule(
810   std::ostream& ruleFileStream, const std::string& realTarget,
811   const std::string& helpTarget)
812 {
813   // A rule is only needed if the names are different.
814   if (realTarget != helpTarget) {
815     // The helper target depends on the real target.
816     std::vector<std::string> depends;
817     depends.push_back(realTarget);
818
819     // There are no commands.
820     std::vector<std::string> no_commands;
821
822     // Write the rule.
823     this->WriteMakeRule(ruleFileStream, "Convenience name for target.",
824                         helpTarget, depends, no_commands, true);
825   }
826 }
827
828 std::string cmLocalUnixMakefileGenerator3::GetRelativeTargetDirectory(
829   cmGeneratorTarget const* target) const
830 {
831   std::string dir =
832     cmStrCat(this->HomeRelativeOutputPath, this->GetTargetDirectory(target));
833   return dir;
834 }
835
836 void cmLocalUnixMakefileGenerator3::AppendFlags(
837   std::string& flags, const std::string& newFlags) const
838 {
839   if (this->IsWatcomWMake() && !newFlags.empty()) {
840     std::string newf = newFlags;
841     if (newf.find("\\\"") != std::string::npos) {
842       cmSystemTools::ReplaceString(newf, "\\\"", "\"");
843       this->cmLocalGenerator::AppendFlags(flags, newf);
844       return;
845     }
846   }
847   this->cmLocalGenerator::AppendFlags(flags, newFlags);
848 }
849
850 void cmLocalUnixMakefileGenerator3::AppendRuleDepend(
851   std::vector<std::string>& depends, const char* ruleFileName)
852 {
853   // Add a dependency on the rule file itself unless an option to skip
854   // it is specifically enabled by the user or project.
855   const char* nodep =
856     this->Makefile->GetDefinition("CMAKE_SKIP_RULE_DEPENDENCY");
857   if (!nodep || cmIsOff(nodep)) {
858     depends.emplace_back(ruleFileName);
859   }
860 }
861
862 void cmLocalUnixMakefileGenerator3::AppendRuleDepends(
863   std::vector<std::string>& depends, std::vector<std::string> const& ruleFiles)
864 {
865   // Add a dependency on the rule file itself unless an option to skip
866   // it is specifically enabled by the user or project.
867   if (!this->Makefile->IsOn("CMAKE_SKIP_RULE_DEPENDENCY")) {
868     cm::append(depends, ruleFiles);
869   }
870 }
871
872 void cmLocalUnixMakefileGenerator3::AppendCustomDepends(
873   std::vector<std::string>& depends, const std::vector<cmCustomCommand>& ccs)
874 {
875   for (cmCustomCommand const& cc : ccs) {
876     cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this);
877     this->AppendCustomDepend(depends, ccg);
878   }
879 }
880
881 void cmLocalUnixMakefileGenerator3::AppendCustomDepend(
882   std::vector<std::string>& depends, cmCustomCommandGenerator const& ccg)
883 {
884   for (std::string const& d : ccg.GetDepends()) {
885     // Lookup the real name of the dependency in case it is a CMake target.
886     std::string dep;
887     if (this->GetRealDependency(d, this->GetConfigName(), dep)) {
888       depends.push_back(std::move(dep));
889     }
890   }
891 }
892
893 void cmLocalUnixMakefileGenerator3::AppendCustomCommands(
894   std::vector<std::string>& commands, const std::vector<cmCustomCommand>& ccs,
895   cmGeneratorTarget* target, std::string const& relative)
896 {
897   for (cmCustomCommand const& cc : ccs) {
898     cmCustomCommandGenerator ccg(cc, this->GetConfigName(), this);
899     this->AppendCustomCommand(commands, ccg, target, relative, true);
900   }
901 }
902
903 void cmLocalUnixMakefileGenerator3::AppendCustomCommand(
904   std::vector<std::string>& commands, cmCustomCommandGenerator const& ccg,
905   cmGeneratorTarget* target, std::string const& relative, bool echo_comment,
906   std::ostream* content)
907 {
908   // Optionally create a command to display the custom command's
909   // comment text.  This is used for pre-build, pre-link, and
910   // post-build command comments.  Custom build step commands have
911   // their comments generated elsewhere.
912   if (echo_comment) {
913     const char* comment = ccg.GetComment();
914     if (comment && *comment) {
915       this->AppendEcho(commands, comment,
916                        cmLocalUnixMakefileGenerator3::EchoGenerate);
917     }
918   }
919
920   // if the command specified a working directory use it.
921   std::string dir = this->GetCurrentBinaryDirectory();
922   std::string workingDir = ccg.GetWorkingDirectory();
923   if (!workingDir.empty()) {
924     dir = workingDir;
925   }
926   if (content) {
927     *content << dir;
928   }
929
930   std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
931     this->CreateRulePlaceholderExpander());
932
933   // Add each command line to the set of commands.
934   std::vector<std::string> commands1;
935   std::string currentBinDir = this->GetCurrentBinaryDirectory();
936   for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
937     // Build the command line in a single string.
938     std::string cmd = ccg.GetCommand(c);
939     if (!cmd.empty()) {
940       // Use "call " before any invocations of .bat or .cmd files
941       // invoked as custom commands in the WindowsShell.
942       //
943       bool useCall = false;
944
945       if (this->IsWindowsShell()) {
946         std::string suffix;
947         if (cmd.size() > 4) {
948           suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
949           if (suffix == ".bat" || suffix == ".cmd") {
950             useCall = true;
951           }
952         }
953       }
954
955       cmSystemTools::ReplaceString(cmd, "/./", "/");
956       // Convert the command to a relative path only if the current
957       // working directory will be the start-output directory.
958       bool had_slash = cmd.find('/') != std::string::npos;
959       if (workingDir.empty()) {
960         cmd = this->MaybeConvertToRelativePath(currentBinDir, cmd);
961       }
962       bool has_slash = cmd.find('/') != std::string::npos;
963       if (had_slash && !has_slash) {
964         // This command was specified as a path to a file in the
965         // current directory.  Add a leading "./" so it can run
966         // without the current directory being in the search path.
967         cmd = cmStrCat("./", cmd);
968       }
969
970       std::string launcher;
971       // Short-circuit if there is no launcher.
972       const char* val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM");
973       if (val && *val) {
974         // Expand rule variables referenced in the given launcher command.
975         cmRulePlaceholderExpander::RuleVariables vars;
976         vars.CMTargetName = target->GetName().c_str();
977         vars.CMTargetType = cmState::GetTargetTypeName(target->GetType());
978         std::string output;
979         const std::vector<std::string>& outputs = ccg.GetOutputs();
980         if (!outputs.empty()) {
981           output = outputs[0];
982           if (workingDir.empty()) {
983             output = this->MaybeConvertToRelativePath(
984               this->GetCurrentBinaryDirectory(), output);
985           }
986           output =
987             this->ConvertToOutputFormat(output, cmOutputConverter::SHELL);
988         }
989         vars.Output = output.c_str();
990
991         launcher = val;
992         rulePlaceholderExpander->ExpandRuleVariables(this, launcher, vars);
993         if (!launcher.empty()) {
994           launcher += " ";
995         }
996       }
997
998       std::string shellCommand = this->MaybeConvertWatcomShellCommand(cmd);
999       if (shellCommand.empty()) {
1000         shellCommand =
1001           this->ConvertToOutputFormat(cmd, cmOutputConverter::SHELL);
1002       }
1003       cmd = launcher + shellCommand;
1004
1005       ccg.AppendArguments(c, cmd);
1006       if (content) {
1007         // Rule content does not include the launcher.
1008         *content << (cmd.c_str() + launcher.size());
1009       }
1010       if (this->BorlandMakeCurlyHack) {
1011         // Borland Make has a very strange bug.  If the first curly
1012         // brace anywhere in the command string is a left curly, it
1013         // must be written {{} instead of just {.  Otherwise some
1014         // curly braces are removed.  The hack can be skipped if the
1015         // first curly brace is the last character.
1016         std::string::size_type lcurly = cmd.find('{');
1017         if (lcurly != std::string::npos && lcurly < (cmd.size() - 1)) {
1018           std::string::size_type rcurly = cmd.find('}');
1019           if (rcurly == std::string::npos || rcurly > lcurly) {
1020             // The first curly is a left curly.  Use the hack.
1021             cmd =
1022               cmStrCat(cmd.substr(0, lcurly), "{{}", cmd.substr(lcurly + 1));
1023           }
1024         }
1025       }
1026       if (launcher.empty()) {
1027         if (useCall) {
1028           cmd = cmStrCat("call ", cmd);
1029         } else if (this->IsNMake() && cmd[0] == '"') {
1030           cmd = cmStrCat("echo >nul && ", cmd);
1031         }
1032       }
1033       commands1.push_back(std::move(cmd));
1034     }
1035   }
1036
1037   // Setup the proper working directory for the commands.
1038   this->CreateCDCommand(commands1, dir, relative);
1039
1040   // push back the custom commands
1041   cm::append(commands, commands1);
1042 }
1043
1044 void cmLocalUnixMakefileGenerator3::AppendCleanCommand(
1045   std::vector<std::string>& commands, const std::set<std::string>& files,
1046   cmGeneratorTarget* target, const char* filename)
1047 {
1048   std::string currentBinDir = this->GetCurrentBinaryDirectory();
1049   std::string cleanfile = cmStrCat(
1050     currentBinDir, '/', this->GetTargetDirectory(target), "/cmake_clean");
1051   if (filename) {
1052     cleanfile += "_";
1053     cleanfile += filename;
1054   }
1055   cleanfile += ".cmake";
1056   std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
1057   cmsys::ofstream fout(cleanfilePath.c_str());
1058   if (!fout) {
1059     cmSystemTools::Error("Could not create " + cleanfilePath);
1060   }
1061   if (!files.empty()) {
1062     fout << "file(REMOVE_RECURSE\n";
1063     for (std::string const& file : files) {
1064       std::string fc = this->MaybeConvertToRelativePath(currentBinDir, file);
1065       fout << "  " << cmOutputConverter::EscapeForCMake(fc) << "\n";
1066     }
1067     fout << ")\n";
1068   }
1069   {
1070     std::string remove =
1071       cmStrCat("$(CMAKE_COMMAND) -P ",
1072                this->ConvertToOutputFormat(
1073                  this->MaybeConvertToRelativePath(
1074                    this->GetCurrentBinaryDirectory(), cleanfile),
1075                  cmOutputConverter::SHELL));
1076     commands.push_back(std::move(remove));
1077   }
1078
1079   // For the main clean rule add per-language cleaning.
1080   if (!filename) {
1081     // Get the set of source languages in the target.
1082     std::set<std::string> languages;
1083     target->GetLanguages(
1084       languages, this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
1085     /* clang-format off */
1086     fout << "\n"
1087          << "# Per-language clean rules from dependency scanning.\n"
1088          << "foreach(lang " << cmJoin(languages, " ") << ")\n"
1089          << "  include(" << this->GetTargetDirectory(target)
1090          << "/cmake_clean_${lang}.cmake OPTIONAL)\n"
1091          << "endforeach()\n";
1092     /* clang-format on */
1093   }
1094 }
1095
1096 void cmLocalUnixMakefileGenerator3::AppendDirectoryCleanCommand(
1097   std::vector<std::string>& commands)
1098 {
1099   std::vector<std::string> cleanFiles;
1100   // Look for additional files registered for cleaning in this directory.
1101   if (const char* prop_value =
1102         this->Makefile->GetProperty("ADDITIONAL_CLEAN_FILES")) {
1103     cmExpandList(cmGeneratorExpression::Evaluate(
1104                    prop_value, this,
1105                    this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")),
1106                  cleanFiles);
1107   }
1108   if (cleanFiles.empty()) {
1109     return;
1110   }
1111
1112   const auto& rootLG = this->GetGlobalGenerator()->GetLocalGenerators().at(0);
1113   std::string const& binaryDir = rootLG->GetCurrentBinaryDirectory();
1114   std::string const& currentBinaryDir = this->GetCurrentBinaryDirectory();
1115   std::string cleanfile =
1116     cmStrCat(currentBinaryDir, "/CMakeFiles/cmake_directory_clean.cmake");
1117   // Write clean script
1118   {
1119     std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
1120     cmsys::ofstream fout(cleanfilePath.c_str());
1121     if (!fout) {
1122       cmSystemTools::Error("Could not create " + cleanfilePath);
1123       return;
1124     }
1125     fout << "file(REMOVE_RECURSE\n";
1126     for (std::string const& cfl : cleanFiles) {
1127       std::string fc = rootLG->MaybeConvertToRelativePath(
1128         binaryDir, cmSystemTools::CollapseFullPath(cfl, currentBinaryDir));
1129       fout << "  " << cmOutputConverter::EscapeForCMake(fc) << "\n";
1130     }
1131     fout << ")\n";
1132   }
1133   // Create command
1134   {
1135     std::string remove =
1136       cmStrCat("$(CMAKE_COMMAND) -P ",
1137                this->ConvertToOutputFormat(
1138                  rootLG->MaybeConvertToRelativePath(binaryDir, cleanfile),
1139                  cmOutputConverter::SHELL));
1140     commands.push_back(std::move(remove));
1141   }
1142 }
1143
1144 void cmLocalUnixMakefileGenerator3::AppendEcho(
1145   std::vector<std::string>& commands, std::string const& text, EchoColor color,
1146   EchoProgress const* progress)
1147 {
1148   // Choose the color for the text.
1149   std::string color_name;
1150   if (this->GlobalGenerator->GetToolSupportsColor() && this->ColorMakefile) {
1151     // See cmake::ExecuteEchoColor in cmake.cxx for these options.
1152     // This color set is readable on both black and white backgrounds.
1153     switch (color) {
1154       case EchoNormal:
1155         break;
1156       case EchoDepend:
1157         color_name = "--magenta --bold ";
1158         break;
1159       case EchoBuild:
1160         color_name = "--green ";
1161         break;
1162       case EchoLink:
1163         color_name = "--green --bold ";
1164         break;
1165       case EchoGenerate:
1166         color_name = "--blue --bold ";
1167         break;
1168       case EchoGlobal:
1169         color_name = "--cyan ";
1170         break;
1171     }
1172   }
1173
1174   // Echo one line at a time.
1175   std::string line;
1176   line.reserve(200);
1177   for (const char* c = text.c_str();; ++c) {
1178     if (*c == '\n' || *c == '\0') {
1179       // Avoid writing a blank last line on end-of-string.
1180       if (*c != '\0' || !line.empty()) {
1181         // Add a command to echo this line.
1182         std::string cmd;
1183         if (color_name.empty() && !progress) {
1184           // Use the native echo command.
1185           cmd = cmStrCat("@echo ", this->EscapeForShell(line, false, true));
1186         } else {
1187           // Use cmake to echo the text in color.
1188           cmd = cmStrCat(
1189             "@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) ",
1190             color_name);
1191           if (progress) {
1192             cmd += "--progress-dir=";
1193             cmd += this->ConvertToOutputFormat(
1194               cmSystemTools::CollapseFullPath(progress->Dir),
1195               cmOutputConverter::SHELL);
1196             cmd += " ";
1197             cmd += "--progress-num=";
1198             cmd += progress->Arg;
1199             cmd += " ";
1200           }
1201           cmd += this->EscapeForShell(line);
1202         }
1203         commands.push_back(std::move(cmd));
1204       }
1205
1206       // Reset the line to empty.
1207       line.clear();
1208
1209       // Progress appears only on first line.
1210       progress = nullptr;
1211
1212       // Terminate on end-of-string.
1213       if (*c == '\0') {
1214         return;
1215       }
1216     } else if (*c != '\r') {
1217       // Append this character to the current line.
1218       line += *c;
1219     }
1220   }
1221 }
1222
1223 std::string cmLocalUnixMakefileGenerator3::CreateMakeVariable(
1224   std::string const& s, std::string const& s2)
1225 {
1226   std::string unmodified = cmStrCat(s, s2);
1227   // if there is no restriction on the length of make variables
1228   // and there are no "." characters in the string, then return the
1229   // unmodified combination.
1230   if ((!this->MakefileVariableSize &&
1231        unmodified.find('.') == std::string::npos) &&
1232       (!this->MakefileVariableSize &&
1233        unmodified.find('+') == std::string::npos) &&
1234       (!this->MakefileVariableSize &&
1235        unmodified.find('-') == std::string::npos)) {
1236     return unmodified;
1237   }
1238
1239   // see if the variable has been defined before and return
1240   // the modified version of the variable
1241   auto i = this->MakeVariableMap.find(unmodified);
1242   if (i != this->MakeVariableMap.end()) {
1243     return i->second;
1244   }
1245   // start with the unmodified variable
1246   std::string ret = unmodified;
1247   // if this there is no value for this->MakefileVariableSize then
1248   // the string must have bad characters in it
1249   if (!this->MakefileVariableSize) {
1250     std::replace(ret.begin(), ret.end(), '.', '_');
1251     cmSystemTools::ReplaceString(ret, "-", "__");
1252     cmSystemTools::ReplaceString(ret, "+", "___");
1253     int ni = 0;
1254     char buffer[5];
1255     // make sure the _ version is not already used, if
1256     // it is used then add number to the end of the variable
1257     while (this->ShortMakeVariableMap.count(ret) && ni < 1000) {
1258       ++ni;
1259       sprintf(buffer, "%04d", ni);
1260       ret = unmodified + buffer;
1261     }
1262     this->ShortMakeVariableMap[ret] = "1";
1263     this->MakeVariableMap[unmodified] = ret;
1264     return ret;
1265   }
1266
1267   // if the string is greater than 32 chars it is an invalid variable name
1268   // for borland make
1269   if (static_cast<int>(ret.size()) > this->MakefileVariableSize) {
1270     int keep = this->MakefileVariableSize - 8;
1271     int size = keep + 3;
1272     std::string str1 = s;
1273     std::string str2 = s2;
1274     // we must shorten the combined string by 4 characters
1275     // keep no more than 24 characters from the second string
1276     if (static_cast<int>(str2.size()) > keep) {
1277       str2 = str2.substr(0, keep);
1278     }
1279     if (static_cast<int>(str1.size()) + static_cast<int>(str2.size()) > size) {
1280       str1 = str1.substr(0, size - str2.size());
1281     }
1282     char buffer[5];
1283     int ni = 0;
1284     sprintf(buffer, "%04d", ni);
1285     ret = str1 + str2 + buffer;
1286     while (this->ShortMakeVariableMap.count(ret) && ni < 1000) {
1287       ++ni;
1288       sprintf(buffer, "%04d", ni);
1289       ret = str1 + str2 + buffer;
1290     }
1291     if (ni == 1000) {
1292       cmSystemTools::Error("Borland makefile variable length too long");
1293       return unmodified;
1294     }
1295     // once an unused variable is found
1296     this->ShortMakeVariableMap[ret] = "1";
1297   }
1298   // always make an entry into the unmodified to variable map
1299   this->MakeVariableMap[unmodified] = ret;
1300   return ret;
1301 }
1302
1303 bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
1304   const std::string& tgtInfo, bool verbose, bool color)
1305 {
1306   // read in the target info file
1307   if (!this->Makefile->ReadListFile(tgtInfo) ||
1308       cmSystemTools::GetErrorOccuredFlag()) {
1309     cmSystemTools::Error("Target DependInfo.cmake file not found");
1310   }
1311
1312   // Check if any multiple output pairs have a missing file.
1313   this->CheckMultipleOutputs(verbose);
1314
1315   std::string const targetDir = cmSystemTools::GetFilenamePath(tgtInfo);
1316   std::string const internalDependFile = targetDir + "/depend.internal";
1317   std::string const dependFile = targetDir + "/depend.make";
1318
1319   // If the target DependInfo.cmake file has changed since the last
1320   // time dependencies were scanned then force rescanning.  This may
1321   // happen when a new source file is added and CMake regenerates the
1322   // project but no other sources were touched.
1323   bool needRescanDependInfo = false;
1324   cmFileTimeCache* ftc =
1325     this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache();
1326   {
1327     int result;
1328     if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
1329       if (verbose) {
1330         std::ostringstream msg;
1331         msg << "Dependee \"" << tgtInfo << "\" is newer than depender \""
1332             << internalDependFile << "\"." << std::endl;
1333         cmSystemTools::Stdout(msg.str());
1334       }
1335       needRescanDependInfo = true;
1336     }
1337   }
1338
1339   // If the directory information is newer than depend.internal, include dirs
1340   // may have changed. In this case discard all old dependencies.
1341   bool needRescanDirInfo = false;
1342   {
1343     std::string dirInfoFile =
1344       cmStrCat(this->GetCurrentBinaryDirectory(),
1345                "/CMakeFiles/CMakeDirectoryInformation.cmake");
1346     int result;
1347     if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
1348         result < 0) {
1349       if (verbose) {
1350         std::ostringstream msg;
1351         msg << "Dependee \"" << dirInfoFile << "\" is newer than depender \""
1352             << internalDependFile << "\"." << std::endl;
1353         cmSystemTools::Stdout(msg.str());
1354       }
1355       needRescanDirInfo = true;
1356     }
1357   }
1358
1359   // Check the implicit dependencies to see if they are up to date.
1360   // The build.make file may have explicit dependencies for the object
1361   // files but these will not affect the scanning process so they need
1362   // not be considered.
1363   cmDepends::DependencyMap validDependencies;
1364   bool needRescanDependencies = false;
1365   if (!needRescanDirInfo) {
1366     cmDependsC checker;
1367     checker.SetVerbose(verbose);
1368     checker.SetFileTimeCache(ftc);
1369     // cmDependsC::Check() fills the vector validDependencies() with the
1370     // dependencies for those files where they are still valid, i.e. neither
1371     // the files themselves nor any files they depend on have changed.
1372     // We don't do that if the CMakeDirectoryInformation.cmake file has
1373     // changed, because then potentially all dependencies have changed.
1374     // This information is given later on to cmDependsC, which then only
1375     // rescans the files where it did not get valid dependencies via this
1376     // dependency vector. This means that in the normal case, when only
1377     // few or one file have been edited, then also only this one file is
1378     // actually scanned again, instead of all files for this target.
1379     needRescanDependencies =
1380       !checker.Check(dependFile, internalDependFile, validDependencies);
1381   }
1382
1383   if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
1384     // The dependencies must be regenerated.
1385     std::string targetName = cmSystemTools::GetFilenameName(targetDir);
1386     targetName = targetName.substr(0, targetName.length() - 4);
1387     std::string message =
1388       cmStrCat("Scanning dependencies of target ", targetName);
1389     cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundMagenta |
1390                                        cmsysTerminal_Color_ForegroundBold,
1391                                      message.c_str(), true, color);
1392
1393     return this->ScanDependencies(targetDir, dependFile, internalDependFile,
1394                                   validDependencies);
1395   }
1396
1397   // The dependencies are already up-to-date.
1398   return true;
1399 }
1400
1401 bool cmLocalUnixMakefileGenerator3::ScanDependencies(
1402   std::string const& targetDir, std::string const& dependFile,
1403   std::string const& internalDependFile, cmDepends::DependencyMap& validDeps)
1404 {
1405   // Read the directory information file.
1406   cmMakefile* mf = this->Makefile;
1407   bool haveDirectoryInfo = false;
1408   {
1409     std::string dirInfoFile =
1410       cmStrCat(this->GetCurrentBinaryDirectory(),
1411                "/CMakeFiles/CMakeDirectoryInformation.cmake");
1412     if (mf->ReadListFile(dirInfoFile) &&
1413         !cmSystemTools::GetErrorOccuredFlag()) {
1414       haveDirectoryInfo = true;
1415     }
1416   }
1417
1418   // Lookup useful directory information.
1419   if (haveDirectoryInfo) {
1420     // Test whether we need to force Unix paths.
1421     if (const char* force = mf->GetDefinition("CMAKE_FORCE_UNIX_PATHS")) {
1422       if (!cmIsOff(force)) {
1423         cmSystemTools::SetForceUnixPaths(true);
1424       }
1425     }
1426
1427     // Setup relative path top directories.
1428     if (const char* relativePathTopSource =
1429           mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_SOURCE")) {
1430       this->StateSnapshot.GetDirectory().SetRelativePathTopSource(
1431         relativePathTopSource);
1432     }
1433     if (const char* relativePathTopBinary =
1434           mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_BINARY")) {
1435       this->StateSnapshot.GetDirectory().SetRelativePathTopBinary(
1436         relativePathTopBinary);
1437     }
1438   } else {
1439     cmSystemTools::Error("Directory Information file not found");
1440   }
1441
1442   // Open the make depends file.  This should be copy-if-different
1443   // because the make tool may try to reload it needlessly otherwise.
1444   cmGeneratedFileStream ruleFileStream(
1445     dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
1446   ruleFileStream.SetCopyIfDifferent(true);
1447   if (!ruleFileStream) {
1448     return false;
1449   }
1450
1451   // Open the cmake dependency tracking file.  This should not be
1452   // copy-if-different because dependencies are re-scanned when it is
1453   // older than the DependInfo.cmake.
1454   cmGeneratedFileStream internalRuleFileStream(
1455     internalDependFile, false, this->GlobalGenerator->GetMakefileEncoding());
1456   if (!internalRuleFileStream) {
1457     return false;
1458   }
1459
1460   this->WriteDisclaimer(ruleFileStream);
1461   this->WriteDisclaimer(internalRuleFileStream);
1462
1463   // for each language we need to scan, scan it
1464   std::vector<std::string> langs =
1465     cmExpandedList(mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"));
1466   for (std::string const& lang : langs) {
1467     // construct the checker
1468     // Create the scanner for this language
1469     std::unique_ptr<cmDepends> scanner;
1470     if (lang == "C" || lang == "CXX" || lang == "RC" || lang == "ASM" ||
1471         lang == "CUDA") {
1472       // TODO: Handle RC (resource files) dependencies correctly.
1473       scanner = cm::make_unique<cmDependsC>(this, targetDir, lang, &validDeps);
1474     }
1475 #ifndef CMAKE_BOOTSTRAP
1476     else if (lang == "Fortran") {
1477       ruleFileStream << "# Note that incremental build could trigger "
1478                      << "a call to cmake_copy_f90_mod on each re-build\n";
1479       scanner = cm::make_unique<cmDependsFortran>(this);
1480     } else if (lang == "Java") {
1481       scanner = cm::make_unique<cmDependsJava>();
1482     }
1483 #endif
1484
1485     if (scanner) {
1486       scanner->SetLocalGenerator(this);
1487       scanner->SetFileTimeCache(
1488         this->GlobalGenerator->GetCMakeInstance()->GetFileTimeCache());
1489       scanner->SetLanguage(lang);
1490       scanner->SetTargetDirectory(targetDir);
1491       scanner->Write(ruleFileStream, internalRuleFileStream);
1492     }
1493   }
1494
1495   return true;
1496 }
1497
1498 void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose)
1499 {
1500   cmMakefile* mf = this->Makefile;
1501
1502   // Get the string listing the multiple output pairs.
1503   const char* pairs_string = mf->GetDefinition("CMAKE_MULTIPLE_OUTPUT_PAIRS");
1504   if (!pairs_string) {
1505     return;
1506   }
1507
1508   // Convert the string to a list and preserve empty entries.
1509   std::vector<std::string> pairs = cmExpandedList(pairs_string, true);
1510   for (auto i = pairs.begin(); i != pairs.end() && (i + 1) != pairs.end();) {
1511     const std::string& depender = *i++;
1512     const std::string& dependee = *i++;
1513
1514     // If the depender is missing then delete the dependee to make
1515     // sure both will be regenerated.
1516     if (cmSystemTools::FileExists(dependee) &&
1517         !cmSystemTools::FileExists(depender)) {
1518       if (verbose) {
1519         std::ostringstream msg;
1520         msg << "Deleting primary custom command output \"" << dependee
1521             << "\" because another output \"" << depender
1522             << "\" does not exist." << std::endl;
1523         cmSystemTools::Stdout(msg.str());
1524       }
1525       cmSystemTools::RemoveFile(dependee);
1526     }
1527   }
1528 }
1529
1530 void cmLocalUnixMakefileGenerator3::WriteLocalAllRules(
1531   std::ostream& ruleFileStream)
1532 {
1533   this->WriteDisclaimer(ruleFileStream);
1534
1535   // Write the main entry point target.  This must be the VERY first
1536   // target so that make with no arguments will run it.
1537   {
1538     // Just depend on the all target to drive the build.
1539     std::vector<std::string> depends;
1540     std::vector<std::string> no_commands;
1541     depends.emplace_back("all");
1542
1543     // Write the rule.
1544     this->WriteMakeRule(ruleFileStream,
1545                         "Default target executed when no arguments are "
1546                         "given to make.",
1547                         "default_target", depends, no_commands, true);
1548
1549     // Help out users that try "gmake target1 target2 -j".
1550     cmGlobalUnixMakefileGenerator3* gg =
1551       static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
1552     if (gg->AllowNotParallel()) {
1553       std::vector<std::string> no_depends;
1554       this->WriteMakeRule(ruleFileStream,
1555                           "Allow only one \"make -f "
1556                           "Makefile2\" at a time, but pass "
1557                           "parallelism.",
1558                           ".NOTPARALLEL", no_depends, no_commands, false);
1559     }
1560   }
1561
1562   this->WriteSpecialTargetsTop(ruleFileStream);
1563
1564   // Include the progress variables for the target.
1565   // Write all global targets
1566   this->WriteDivider(ruleFileStream);
1567   ruleFileStream << "# Targets provided globally by CMake.\n"
1568                  << "\n";
1569   const auto& targets = this->GetGeneratorTargets();
1570   for (const auto& gt : targets) {
1571     if (gt->GetType() == cmStateEnums::GLOBAL_TARGET) {
1572       std::string targetString =
1573         "Special rule for the target " + gt->GetName();
1574       std::vector<std::string> commands;
1575       std::vector<std::string> depends;
1576
1577       const char* text = gt->GetProperty("EchoString");
1578       if (!text) {
1579         text = "Running external command ...";
1580       }
1581       depends.reserve(gt->GetUtilities().size());
1582       for (BT<std::pair<std::string, bool>> const& u : gt->GetUtilities()) {
1583         depends.push_back(u.Value.first);
1584       }
1585       this->AppendEcho(commands, text,
1586                        cmLocalUnixMakefileGenerator3::EchoGlobal);
1587
1588       // Global targets store their rules in pre- and post-build commands.
1589       this->AppendCustomDepends(depends, gt->GetPreBuildCommands());
1590       this->AppendCustomDepends(depends, gt->GetPostBuildCommands());
1591       this->AppendCustomCommands(commands, gt->GetPreBuildCommands(), gt.get(),
1592                                  this->GetCurrentBinaryDirectory());
1593       this->AppendCustomCommands(commands, gt->GetPostBuildCommands(),
1594                                  gt.get(), this->GetCurrentBinaryDirectory());
1595       std::string targetName = gt->GetName();
1596       this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
1597                           depends, commands, true);
1598
1599       // Provide a "/fast" version of the target.
1600       depends.clear();
1601       if ((targetName == "install") || (targetName == "install/local") ||
1602           (targetName == "install/strip")) {
1603         // Provide a fast install target that does not depend on all
1604         // but has the same command.
1605         depends.emplace_back("preinstall/fast");
1606       } else {
1607         // Just forward to the real target so at least it will work.
1608         depends.push_back(targetName);
1609         commands.clear();
1610       }
1611       targetName += "/fast";
1612       this->WriteMakeRule(ruleFileStream, targetString.c_str(), targetName,
1613                           depends, commands, true);
1614     }
1615   }
1616
1617   std::vector<std::string> depends;
1618   std::vector<std::string> commands;
1619
1620   // Write the all rule.
1621   std::string recursiveTarget =
1622     cmStrCat(this->GetCurrentBinaryDirectory(), "/all");
1623
1624   bool regenerate =
1625     !this->GlobalGenerator->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
1626   if (regenerate) {
1627     depends.emplace_back("cmake_check_build_system");
1628   }
1629
1630   std::string progressDir =
1631     cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles");
1632   {
1633     std::ostringstream progCmd;
1634     progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
1635     progCmd << this->ConvertToOutputFormat(
1636       cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL);
1637
1638     std::string progressFile = "/CMakeFiles/progress.marks";
1639     std::string progressFileNameFull = this->ConvertToFullPath(progressFile);
1640     progCmd << " "
1641             << this->ConvertToOutputFormat(
1642                  cmSystemTools::CollapseFullPath(progressFileNameFull),
1643                  cmOutputConverter::SHELL);
1644     commands.push_back(progCmd.str());
1645   }
1646   std::string mf2Dir = "CMakeFiles/Makefile2";
1647   commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
1648   this->CreateCDCommand(commands, this->GetBinaryDirectory(),
1649                         this->GetCurrentBinaryDirectory());
1650   {
1651     std::ostringstream progCmd;
1652     progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
1653     progCmd << this->ConvertToOutputFormat(
1654       cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL);
1655     progCmd << " 0";
1656     commands.push_back(progCmd.str());
1657   }
1658   this->WriteMakeRule(ruleFileStream, "The main all target", "all", depends,
1659                       commands, true);
1660
1661   // Write the clean rule.
1662   recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/clean");
1663   commands.clear();
1664   depends.clear();
1665   commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
1666   this->CreateCDCommand(commands, this->GetBinaryDirectory(),
1667                         this->GetCurrentBinaryDirectory());
1668   this->WriteMakeRule(ruleFileStream, "The main clean target", "clean",
1669                       depends, commands, true);
1670   commands.clear();
1671   depends.clear();
1672   depends.emplace_back("clean");
1673   this->WriteMakeRule(ruleFileStream, "The main clean target", "clean/fast",
1674                       depends, commands, true);
1675
1676   // Write the preinstall rule.
1677   recursiveTarget = cmStrCat(this->GetCurrentBinaryDirectory(), "/preinstall");
1678   commands.clear();
1679   depends.clear();
1680   const char* noall =
1681     this->Makefile->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
1682   if (!noall || cmIsOff(noall)) {
1683     // Drive the build before installing.
1684     depends.emplace_back("all");
1685   } else if (regenerate) {
1686     // At least make sure the build system is up to date.
1687     depends.emplace_back("cmake_check_build_system");
1688   }
1689   commands.push_back(this->GetRecursiveMakeCall(mf2Dir, recursiveTarget));
1690   this->CreateCDCommand(commands, this->GetBinaryDirectory(),
1691                         this->GetCurrentBinaryDirectory());
1692   this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
1693                       "preinstall", depends, commands, true);
1694   depends.clear();
1695   this->WriteMakeRule(ruleFileStream, "Prepare targets for installation.",
1696                       "preinstall/fast", depends, commands, true);
1697
1698   if (regenerate) {
1699     // write the depend rule, really a recompute depends rule
1700     depends.clear();
1701     commands.clear();
1702     cmake* cm = this->GlobalGenerator->GetCMakeInstance();
1703     if (cm->DoWriteGlobVerifyTarget()) {
1704       std::string rescanRule =
1705         cmStrCat("$(CMAKE_COMMAND) -P ",
1706                  this->ConvertToOutputFormat(cm->GetGlobVerifyScript(),
1707                                              cmOutputConverter::SHELL));
1708       commands.push_back(rescanRule);
1709     }
1710     std::string cmakefileName = "CMakeFiles/Makefile.cmake";
1711     {
1712       std::string runRule = cmStrCat(
1713         "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) "
1714         "--check-build-system ",
1715         this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
1716         " 1");
1717       commands.push_back(std::move(runRule));
1718     }
1719     this->CreateCDCommand(commands, this->GetBinaryDirectory(),
1720                           this->GetCurrentBinaryDirectory());
1721     this->WriteMakeRule(ruleFileStream, "clear depends", "depend", depends,
1722                         commands, true);
1723   }
1724 }
1725
1726 void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
1727                                                       bool verbose)
1728 {
1729   // Get the list of target files to check
1730   const char* infoDef = mf->GetDefinition("CMAKE_DEPEND_INFO_FILES");
1731   if (!infoDef) {
1732     return;
1733   }
1734   std::vector<std::string> files = cmExpandedList(infoDef);
1735
1736   // Each depend information file corresponds to a target.  Clear the
1737   // dependencies for that target.
1738   cmDepends clearer;
1739   clearer.SetVerbose(verbose);
1740   for (std::string const& file : files) {
1741     std::string dir = cmSystemTools::GetFilenamePath(file);
1742
1743     // Clear the implicit dependency makefile.
1744     std::string dependFile = dir + "/depend.make";
1745     clearer.Clear(dependFile);
1746
1747     // Remove the internal dependency check file to force
1748     // regeneration.
1749     std::string internalDependFile = dir + "/depend.internal";
1750     cmSystemTools::RemoveFile(internalDependFile);
1751   }
1752 }
1753
1754 namespace {
1755 // Helper predicate for removing absolute paths that don't point to the
1756 // source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
1757 // is set ON, to only consider in-project dependencies during the build.
1758 class NotInProjectDir
1759 {
1760 public:
1761   // Constructor with the source and binary directory's path
1762   NotInProjectDir(std::string sourceDir, std::string binaryDir)
1763     : SourceDir(std::move(sourceDir))
1764     , BinaryDir(std::move(binaryDir))
1765   {
1766   }
1767
1768   // Operator evaluating the predicate
1769   bool operator()(const std::string& path) const
1770   {
1771     // Keep all relative paths:
1772     if (!cmSystemTools::FileIsFullPath(path)) {
1773       return false;
1774     }
1775     // If it's an absolute path, check if it starts with the source
1776     // direcotory:
1777     return (
1778       !(IsInDirectory(SourceDir, path) || IsInDirectory(BinaryDir, path)));
1779   }
1780
1781 private:
1782   // Helper function used by the predicate
1783   static bool IsInDirectory(const std::string& baseDir,
1784                             const std::string& testDir)
1785   {
1786     // First check if the test directory "starts with" the base directory:
1787     if (testDir.find(baseDir) != 0) {
1788       return false;
1789     }
1790     // If it does, then check that it's either the same string, or that the
1791     // next character is a slash:
1792     return ((testDir.size() == baseDir.size()) ||
1793             (testDir[baseDir.size()] == '/'));
1794   }
1795
1796   // The path to the source directory
1797   std::string SourceDir;
1798   // The path to the binary directory
1799   std::string BinaryDir;
1800 };
1801 }
1802
1803 void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
1804   std::ostream& cmakefileStream, cmGeneratorTarget* target)
1805 {
1806   ImplicitDependLanguageMap const& implicitLangs =
1807     this->GetImplicitDepends(target);
1808
1809   // list the languages
1810   cmakefileStream
1811     << "# The set of languages for which implicit dependencies are needed:\n";
1812   cmakefileStream << "set(CMAKE_DEPENDS_LANGUAGES\n";
1813   for (auto const& implicitLang : implicitLangs) {
1814     cmakefileStream << "  \"" << implicitLang.first << "\"\n";
1815   }
1816   cmakefileStream << "  )\n";
1817
1818   // now list the files for each language
1819   cmakefileStream
1820     << "# The set of files for implicit dependencies of each language:\n";
1821   for (auto const& implicitLang : implicitLangs) {
1822     cmakefileStream << "set(CMAKE_DEPENDS_CHECK_" << implicitLang.first
1823                     << "\n";
1824     ImplicitDependFileMap const& implicitPairs = implicitLang.second;
1825
1826     // for each file pair
1827     for (auto const& implicitPair : implicitPairs) {
1828       for (auto const& di : implicitPair.second) {
1829         cmakefileStream << "  \"" << di << "\" ";
1830         cmakefileStream << "\"" << implicitPair.first << "\"\n";
1831       }
1832     }
1833     cmakefileStream << "  )\n";
1834
1835     // Tell the dependency scanner what compiler is used.
1836     std::string cidVar =
1837       cmStrCat("CMAKE_", implicitLang.first, "_COMPILER_ID");
1838     const char* cid = this->Makefile->GetDefinition(cidVar);
1839     if (cid && *cid) {
1840       cmakefileStream << "set(CMAKE_" << implicitLang.first
1841                       << "_COMPILER_ID \"" << cid << "\")\n";
1842     }
1843
1844     if (implicitLang.first == "Fortran") {
1845       std::string smodSep =
1846         this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_SEP");
1847       std::string smodExt =
1848         this->Makefile->GetSafeDefinition("CMAKE_Fortran_SUBMODULE_EXT");
1849       cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_SEP \"" << smodSep
1850                       << "\")\n";
1851       cmakefileStream << "set(CMAKE_Fortran_SUBMODULE_EXT \"" << smodExt
1852                       << "\")\n";
1853     }
1854
1855     // Build a list of preprocessor definitions for the target.
1856     std::set<std::string> defines;
1857     this->GetTargetDefines(target, this->GetConfigName(), implicitLang.first,
1858                            defines);
1859     if (!defines.empty()) {
1860       /* clang-format off */
1861       cmakefileStream
1862         << "\n"
1863         << "# Preprocessor definitions for this target.\n"
1864         << "set(CMAKE_TARGET_DEFINITIONS_" << implicitLang.first << "\n";
1865       /* clang-format on */
1866       for (std::string const& define : defines) {
1867         cmakefileStream << "  " << cmOutputConverter::EscapeForCMake(define)
1868                         << "\n";
1869       }
1870       cmakefileStream << "  )\n";
1871     }
1872
1873     // Target-specific include directories:
1874     cmakefileStream << "\n"
1875                     << "# The include file search paths:\n";
1876     cmakefileStream << "set(CMAKE_" << implicitLang.first
1877                     << "_TARGET_INCLUDE_PATH\n";
1878     std::vector<std::string> includes;
1879
1880     this->GetIncludeDirectories(includes, target, implicitLang.first,
1881                                 this->GetConfigName());
1882     std::string binaryDir = this->GetState()->GetBinaryDirectory();
1883     if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) {
1884       std::string const& sourceDir = this->GetState()->GetSourceDirectory();
1885       cm::erase_if(includes, ::NotInProjectDir(sourceDir, binaryDir));
1886     }
1887     for (std::string const& include : includes) {
1888       cmakefileStream << "  \""
1889                       << this->MaybeConvertToRelativePath(binaryDir, include)
1890                       << "\"\n";
1891     }
1892     cmakefileStream << "  )\n";
1893   }
1894
1895   // Store include transform rule properties.  Write the directory
1896   // rules first because they may be overridden by later target rules.
1897   std::vector<std::string> transformRules;
1898   if (const char* xform =
1899         this->Makefile->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
1900     cmExpandList(xform, transformRules);
1901   }
1902   if (const char* xform =
1903         target->GetProperty("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")) {
1904     cmExpandList(xform, transformRules);
1905   }
1906   if (!transformRules.empty()) {
1907     cmakefileStream << "set(CMAKE_INCLUDE_TRANSFORMS\n";
1908     for (std::string const& tr : transformRules) {
1909       cmakefileStream << "  " << cmOutputConverter::EscapeForCMake(tr) << "\n";
1910     }
1911     cmakefileStream << "  )\n";
1912   }
1913 }
1914
1915 void cmLocalUnixMakefileGenerator3::WriteDisclaimer(std::ostream& os)
1916 {
1917   os << "# CMAKE generated file: DO NOT EDIT!\n"
1918      << "# Generated by \"" << this->GlobalGenerator->GetName() << "\""
1919      << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
1920      << cmVersion::GetMinorVersion() << "\n\n";
1921 }
1922
1923 std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall(
1924   const std::string& makefile, const std::string& tgt)
1925 {
1926   // Call make on the given file.
1927   std::string cmd = cmStrCat(
1928     "$(MAKE) -f ",
1929     this->ConvertToOutputFormat(makefile, cmOutputConverter::SHELL), ' ');
1930
1931   cmGlobalUnixMakefileGenerator3* gg =
1932     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
1933   // Pass down verbosity level.
1934   if (!gg->MakeSilentFlag.empty()) {
1935     cmd += gg->MakeSilentFlag;
1936     cmd += " ";
1937   }
1938
1939   // Most unix makes will pass the command line flags to make down to
1940   // sub-invoked makes via an environment variable.  However, some
1941   // makes do not support that, so you have to pass the flags
1942   // explicitly.
1943   if (gg->PassMakeflags) {
1944     cmd += "-$(MAKEFLAGS) ";
1945   }
1946
1947   // Add the target.
1948   if (!tgt.empty()) {
1949     // The make target is always relative to the top of the build tree.
1950     std::string tgt2 =
1951       this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), tgt);
1952
1953     // The target may have been written with windows paths.
1954     cmSystemTools::ConvertToOutputSlashes(tgt2);
1955
1956     // Escape one extra time if the make tool requires it.
1957     if (this->MakeCommandEscapeTargetTwice) {
1958       tgt2 = this->EscapeForShell(tgt2, true, false);
1959     }
1960
1961     // The target name is now a string that should be passed verbatim
1962     // on the command line.
1963     cmd += this->EscapeForShell(tgt2, true, false);
1964   }
1965   return cmd;
1966 }
1967
1968 void cmLocalUnixMakefileGenerator3::WriteDivider(std::ostream& os)
1969 {
1970   os << "#======================================"
1971      << "=======================================\n";
1972 }
1973
1974 void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os,
1975                                                        const std::string& s)
1976 {
1977   // Write the given string to the stream with escaping to get it back
1978   // into CMake through the lexical scanner.
1979   os << "\"";
1980   for (char c : s) {
1981     if (c == '\\') {
1982       os << "\\\\";
1983     } else if (c == '"') {
1984       os << "\\\"";
1985     } else {
1986       os << c;
1987     }
1988   }
1989   os << "\"";
1990 }
1991
1992 std::string cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
1993   const std::string& p, bool useWatcomQuote)
1994 {
1995   // Split the path into its components.
1996   std::vector<std::string> components;
1997   cmSystemTools::SplitPath(p, components);
1998
1999   // Open the quoted result.
2000   std::string result;
2001   if (useWatcomQuote) {
2002 #if defined(_WIN32) && !defined(__CYGWIN__)
2003     result = "'";
2004 #else
2005     result = "\"'";
2006 #endif
2007   } else {
2008     result = "\"";
2009   }
2010
2011   // Return an empty path if there are no components.
2012   if (!components.empty()) {
2013     // Choose a slash direction and fix root component.
2014     const char* slash = "/";
2015 #if defined(_WIN32) && !defined(__CYGWIN__)
2016     if (!cmSystemTools::GetForceUnixPaths()) {
2017       slash = "\\";
2018       for (char& i : components[0]) {
2019         if (i == '/') {
2020           i = '\\';
2021         }
2022       }
2023     }
2024 #endif
2025
2026     // Begin the quoted result with the root component.
2027     result += components[0];
2028
2029     if (components.size() > 1) {
2030       // Now add the rest of the components separated by the proper slash
2031       // direction for this platform.
2032       auto compEnd = std::remove(components.begin() + 1, components.end() - 1,
2033                                  std::string());
2034       auto compStart = components.begin() + 1;
2035       result += cmJoin(cmMakeRange(compStart, compEnd), slash);
2036       // Only the last component can be empty to avoid double slashes.
2037       result += slash;
2038       result += components.back();
2039     }
2040   }
2041
2042   // Close the quoted result.
2043   if (useWatcomQuote) {
2044 #if defined(_WIN32) && !defined(__CYGWIN__)
2045     result += "'";
2046 #else
2047     result += "'\"";
2048 #endif
2049   } else {
2050     result += "\"";
2051   }
2052
2053   return result;
2054 }
2055
2056 std::string cmLocalUnixMakefileGenerator3::GetTargetDirectory(
2057   cmGeneratorTarget const* target) const
2058 {
2059   std::string dir = cmStrCat("CMakeFiles/", target->GetName());
2060 #if defined(__VMS)
2061   dir += "_dir";
2062 #else
2063   dir += ".dir";
2064 #endif
2065   return dir;
2066 }
2067
2068 cmLocalUnixMakefileGenerator3::ImplicitDependLanguageMap const&
2069 cmLocalUnixMakefileGenerator3::GetImplicitDepends(const cmGeneratorTarget* tgt)
2070 {
2071   return this->ImplicitDepends[tgt->GetName()];
2072 }
2073
2074 void cmLocalUnixMakefileGenerator3::AddImplicitDepends(
2075   const cmGeneratorTarget* tgt, const std::string& lang,
2076   const std::string& obj, const std::string& src)
2077 {
2078   this->ImplicitDepends[tgt->GetName()][lang][obj].push_back(src);
2079 }
2080
2081 void cmLocalUnixMakefileGenerator3::CreateCDCommand(
2082   std::vector<std::string>& commands, std::string const& tgtDir,
2083   std::string const& relDir)
2084 {
2085   // do we need to cd?
2086   if (tgtDir == relDir) {
2087     return;
2088   }
2089
2090   // In a Windows shell we must change drive letter too.  The shell
2091   // used by NMake and Borland make does not support "cd /d" so this
2092   // feature simply cannot work with them (Borland make does not even
2093   // support changing the drive letter with just "d:").
2094   const char* cd_cmd = this->IsMinGWMake() ? "cd /d " : "cd ";
2095
2096   cmGlobalUnixMakefileGenerator3* gg =
2097     static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
2098   if (!gg->UnixCD) {
2099     // On Windows we must perform each step separately and then change
2100     // back because the shell keeps the working directory between
2101     // commands.
2102     std::string cmd =
2103       cmStrCat(cd_cmd, this->ConvertToOutputForExisting(tgtDir));
2104     commands.insert(commands.begin(), cmd);
2105
2106     // Change back to the starting directory.
2107     cmd = cmStrCat(cd_cmd, this->ConvertToOutputForExisting(relDir));
2108     commands.push_back(std::move(cmd));
2109   } else {
2110     // On UNIX we must construct a single shell command to change
2111     // directory and build because make resets the directory between
2112     // each command.
2113     std::string outputForExisting = this->ConvertToOutputForExisting(tgtDir);
2114     std::string prefix = cd_cmd + outputForExisting + " && ";
2115     std::transform(commands.begin(), commands.end(), commands.begin(),
2116                    [&prefix](std::string const& s) { return prefix + s; });
2117   }
2118 }