resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmGlobalUnixMakefileGenerator3.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 "cmGlobalUnixMakefileGenerator3.h"
4
5 #include <algorithm>
6 #include <functional>
7 #include <sstream>
8 #include <utility>
9
10 #include <cm/memory>
11 #include <cmext/algorithm>
12 #include <cmext/memory>
13
14 #include "cmDocumentationEntry.h"
15 #include "cmGeneratedFileStream.h"
16 #include "cmGeneratorTarget.h"
17 #include "cmGlobalGenerator.h"
18 #include "cmLocalGenerator.h"
19 #include "cmLocalUnixMakefileGenerator3.h"
20 #include "cmMakefile.h"
21 #include "cmMakefileTargetGenerator.h"
22 #include "cmOutputConverter.h"
23 #include "cmState.h"
24 #include "cmStateTypes.h"
25 #include "cmStringAlgorithms.h"
26 #include "cmSystemTools.h"
27 #include "cmTargetDepend.h"
28 #include "cmValue.h"
29 #include "cmake.h"
30
31 cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm)
32   : cmGlobalCommonGenerator(cm)
33 {
34   // This type of makefile always requires unix style paths
35   this->ForceUnixPaths = true;
36   this->FindMakeProgramFile = "CMakeUnixFindMake.cmake";
37   this->ToolSupportsColor = true;
38
39 #if defined(_WIN32) || defined(__VMS)
40   this->UseLinkScript = false;
41 #else
42   this->UseLinkScript = true;
43 #endif
44
45   this->IncludeDirective = "include";
46   this->LineContinueDirective = "\\\n";
47   this->DefineWindowsNULL = false;
48   this->PassMakeflags = false;
49   this->UnixCD = true;
50 }
51
52 cmGlobalUnixMakefileGenerator3::~cmGlobalUnixMakefileGenerator3() = default;
53
54 void cmGlobalUnixMakefileGenerator3::EnableLanguage(
55   std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
56 {
57   this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
58   for (std::string const& language : languages) {
59     if (language == "NONE") {
60       continue;
61     }
62     this->ResolveLanguageCompiler(language, mf, optional);
63   }
64 }
65
66 //! Create a local generator appropriate to this Global Generator
67 std::unique_ptr<cmLocalGenerator>
68 cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(cmMakefile* mf)
69 {
70   return std::unique_ptr<cmLocalGenerator>(
71     cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf));
72 }
73
74 void cmGlobalUnixMakefileGenerator3::GetDocumentation(
75   cmDocumentationEntry& entry)
76 {
77   entry.Name = cmGlobalUnixMakefileGenerator3::GetActualName();
78   entry.Brief = "Generates standard UNIX makefiles.";
79 }
80
81 void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
82   cmGeneratorTarget* gt) const
83 {
84   // Compute full path to object file directory for this target.
85   std::string dir =
86     cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/',
87              gt->LocalGenerator->GetTargetDirectory(gt), '/');
88   gt->ObjectDirectory = dir;
89 }
90
91 bool cmGlobalUnixMakefileGenerator3::CanEscapeOctothorpe() const
92 {
93   // Make tools that use UNIX-style '/' paths also support '\' escaping.
94   return this->ForceUnixPaths;
95 }
96
97 void cmGlobalUnixMakefileGenerator3::Configure()
98 {
99   // Initialize CMAKE_EDIT_COMMAND cache entry.
100   this->GetEditCacheCommand();
101
102   this->cmGlobalGenerator::Configure();
103 }
104
105 void cmGlobalUnixMakefileGenerator3::Generate()
106 {
107   // first do superclass method
108   this->cmGlobalGenerator::Generate();
109
110   // initialize progress
111   unsigned long total = 0;
112   for (auto const& pmi : this->ProgressMap) {
113     total += pmi.second.NumberOfActions;
114   }
115
116   // write each target's progress.make this loop is done twice. Basically the
117   // Generate pass counts all the actions, the first loop below determines
118   // how many actions have progress updates for each target and writes to
119   // correct variable values for everything except the all targets. The
120   // second loop actually writes out correct values for the all targets as
121   // well. This is because the all targets require more information that is
122   // computed in the first loop.
123   unsigned long current = 0;
124   for (auto& pmi : this->ProgressMap) {
125     pmi.second.WriteProgressVariables(total, current);
126   }
127   for (const auto& lg : this->LocalGenerators) {
128     std::string markFileName =
129       cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/progress.marks");
130     cmGeneratedFileStream markFile(markFileName);
131     markFile << this->CountProgressMarksInAll(*lg) << "\n";
132   }
133
134   // write the main makefile
135   this->WriteMainMakefile2();
136   this->WriteMainCMakefile();
137
138   if (this->CommandDatabase) {
139     *this->CommandDatabase << "\n]";
140     this->CommandDatabase.reset();
141   }
142 }
143
144 void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
145   const std::string& sourceFile, const std::string& workingDirectory,
146   const std::string& compileCommand)
147 {
148   if (!this->CommandDatabase) {
149     std::string commandDatabaseName =
150       this->GetCMakeInstance()->GetHomeOutputDirectory() +
151       "/compile_commands.json";
152     this->CommandDatabase =
153       cm::make_unique<cmGeneratedFileStream>(commandDatabaseName);
154     *this->CommandDatabase << "[\n";
155   } else {
156     *this->CommandDatabase << ",\n";
157   }
158   *this->CommandDatabase << "{\n"
159                          << R"(  "directory": ")"
160                          << cmGlobalGenerator::EscapeJSON(workingDirectory)
161                          << "\",\n"
162                          << R"(  "command": ")"
163                          << cmGlobalGenerator::EscapeJSON(compileCommand)
164                          << "\",\n"
165                          << R"(  "file": ")"
166                          << cmGlobalGenerator::EscapeJSON(sourceFile)
167                          << "\"\n}";
168 }
169
170 void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
171 {
172   // Open the output file.  This should not be copy-if-different
173   // because the check-build-system step compares the makefile time to
174   // see if the build system must be regenerated.
175   std::string makefileName =
176     cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
177              "/CMakeFiles/Makefile2");
178   cmGeneratedFileStream makefileStream(makefileName, false,
179                                        this->GetMakefileEncoding());
180   if (!makefileStream) {
181     return;
182   }
183
184   // The global dependency graph is expressed via the root local generator.
185   auto& rootLG = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
186     this->LocalGenerators[0]);
187
188   // Write the do not edit header.
189   rootLG.WriteDisclaimer(makefileStream);
190
191   // Write the main entry point target.  This must be the VERY first
192   // target so that make with no arguments will run it.
193   // Just depend on the all target to drive the build.
194   std::vector<std::string> depends;
195   std::vector<std::string> no_commands;
196   depends.emplace_back("all");
197
198   // Write the rule.
199   rootLG.WriteMakeRule(makefileStream,
200                        "Default target executed when no arguments are "
201                        "given to make.",
202                        "default_target", depends, no_commands, true);
203
204   depends.clear();
205
206   // The all and preinstall rules might never have any dependencies
207   // added to them.
208   if (!this->EmptyRuleHackDepends.empty()) {
209     depends.push_back(this->EmptyRuleHackDepends);
210   }
211
212   // Write out the "special" stuff
213   rootLG.WriteSpecialTargetsTop(makefileStream);
214
215   // Write the directory level rules.
216   for (auto const& it : this->ComputeDirectoryTargets()) {
217     this->WriteDirectoryRules2(makefileStream, rootLG, it.second);
218   }
219
220   // Write the target convenience rules
221   for (const auto& localGen : this->LocalGenerators) {
222     this->WriteConvenienceRules2(
223       makefileStream, rootLG,
224       cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen));
225   }
226
227   // Write special bottom targets
228   rootLG.WriteSpecialTargetsBottom(makefileStream);
229 }
230
231 void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
232 {
233   if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
234     return;
235   }
236
237   // Open the output file.  This should not be copy-if-different
238   // because the check-build-system step compares the makefile time to
239   // see if the build system must be regenerated.
240   std::string cmakefileName =
241     cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
242              "/CMakeFiles/Makefile.cmake");
243   cmGeneratedFileStream cmakefileStream(cmakefileName);
244   if (!cmakefileStream) {
245     return;
246   }
247
248   std::string makefileName =
249     cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), "/Makefile");
250
251   {
252     // get a local generator for some useful methods
253     auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
254       this->LocalGenerators[0]);
255
256     // Write the do not edit header.
257     lg.WriteDisclaimer(cmakefileStream);
258   }
259
260   // Save the generator name
261   cmakefileStream << "# The generator used is:\n"
262                   << "set(CMAKE_DEPENDS_GENERATOR \"" << this->GetName()
263                   << "\")\n\n";
264
265   // for each cmMakefile get its list of dependencies
266   std::vector<std::string> lfiles;
267   for (const auto& localGen : this->LocalGenerators) {
268     // Get the list of files contributing to this generation step.
269     cm::append(lfiles, localGen->GetMakefile()->GetListFiles());
270   }
271
272   cmake* cm = this->GetCMakeInstance();
273   if (cm->DoWriteGlobVerifyTarget()) {
274     lfiles.push_back(cm->GetGlobVerifyScript());
275     lfiles.push_back(cm->GetGlobVerifyStamp());
276   }
277
278   // Sort the list and remove duplicates.
279   std::sort(lfiles.begin(), lfiles.end(), std::less<std::string>());
280 #if !defined(__VMS) // The Compaq STL on VMS crashes, so accept duplicates.
281   auto new_end = std::unique(lfiles.begin(), lfiles.end());
282   lfiles.erase(new_end, lfiles.end());
283 #endif
284
285   {
286     // reset lg to the first makefile
287     const auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
288       this->LocalGenerators[0]);
289
290     // Save the list to the cmake file.
291     cmakefileStream
292       << "# The top level Makefile was generated from the following files:\n"
293       << "set(CMAKE_MAKEFILE_DEPENDS\n"
294       << "  \"CMakeCache.txt\"\n";
295     for (std::string const& f : lfiles) {
296       cmakefileStream << "  \"" << lg.MaybeRelativeToCurBinDir(f) << "\"\n";
297     }
298     cmakefileStream << "  )\n\n";
299
300     // Build the path to the cache check file.
301     std::string check =
302       cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
303                "/CMakeFiles/cmake.check_cache");
304
305     // Set the corresponding makefile in the cmake file.
306     cmakefileStream << "# The corresponding makefile is:\n"
307                     << "set(CMAKE_MAKEFILE_OUTPUTS\n"
308                     << "  \"" << lg.MaybeRelativeToCurBinDir(makefileName)
309                     << "\"\n"
310                     << "  \"" << lg.MaybeRelativeToCurBinDir(check) << "\"\n";
311     cmakefileStream << "  )\n\n";
312
313     // CMake must rerun if a byproduct is missing.
314     cmakefileStream << "# Byproducts of CMake generate step:\n"
315                     << "set(CMAKE_MAKEFILE_PRODUCTS\n";
316
317     // add in any byproducts and all the directory information files
318     std::string tmpStr;
319     for (const auto& localGen : this->LocalGenerators) {
320       for (std::string const& outfile :
321            localGen->GetMakefile()->GetOutputFiles()) {
322         cmakefileStream << "  \"" << lg.MaybeRelativeToTopBinDir(outfile)
323                         << "\"\n";
324       }
325       tmpStr = cmStrCat(localGen->GetCurrentBinaryDirectory(),
326                         "/CMakeFiles/CMakeDirectoryInformation.cmake");
327       cmakefileStream << "  \"" << localGen->MaybeRelativeToTopBinDir(tmpStr)
328                       << "\"\n";
329     }
330     cmakefileStream << "  )\n\n";
331   }
332
333   this->WriteMainCMakefileLanguageRules(cmakefileStream,
334                                         this->LocalGenerators);
335 }
336
337 void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
338   cmGeneratedFileStream& cmakefileStream,
339   std::vector<std::unique_ptr<cmLocalGenerator>>& lGenerators)
340 {
341   // now list all the target info files
342   cmakefileStream << "# Dependency information for all targets:\n";
343   cmakefileStream << "set(CMAKE_DEPEND_INFO_FILES\n";
344   for (const auto& lGenerator : lGenerators) {
345     const auto& lg =
346       cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(lGenerator);
347     // for all of out targets
348     for (const auto& tgt : lg.GetGeneratorTargets()) {
349       if (tgt->IsInBuildSystem() &&
350           tgt->GetType() != cmStateEnums::GLOBAL_TARGET) {
351         std::string tname = cmStrCat(lg.GetRelativeTargetDirectory(tgt.get()),
352                                      "/DependInfo.cmake");
353         cmSystemTools::ConvertToUnixSlashes(tname);
354         cmakefileStream << "  \"" << tname << "\"\n";
355       }
356     }
357   }
358   cmakefileStream << "  )\n";
359 }
360
361 void cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2(
362   std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& rootLG,
363   DirectoryTarget const& dt, const char* pass, bool check_all,
364   bool check_relink, std::vector<std::string> const& commands)
365 {
366   auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
367   std::string makeTarget =
368     cmStrCat(lg->GetCurrentBinaryDirectory(), '/', pass);
369
370   // The directory-level rule should depend on the target-level rules
371   // for all targets in the directory.
372   std::vector<std::string> depends;
373   for (DirectoryTarget::Target const& t : dt.Targets) {
374     // Add this to the list of depends rules in this directory.
375     if ((!check_all || t.ExcludedFromAllInConfigs.empty()) &&
376         (!check_relink ||
377          t.GT->NeedRelinkBeforeInstall(lg->GetConfigName()))) {
378       // The target may be from a different directory; use its local gen.
379       auto const* tlg = static_cast<cmLocalUnixMakefileGenerator3 const*>(
380         t.GT->GetLocalGenerator());
381       std::string tname =
382         cmStrCat(tlg->GetRelativeTargetDirectory(t.GT), '/', pass);
383       depends.push_back(std::move(tname));
384     }
385   }
386
387   // The directory-level rule should depend on the directory-level
388   // rules of the subdirectories.
389   for (DirectoryTarget::Dir const& d : dt.Children) {
390     if (check_all && d.ExcludeFromAll) {
391       continue;
392     }
393     std::string subdir = cmStrCat(d.Path, '/', pass);
394     depends.push_back(std::move(subdir));
395   }
396
397   // Work-around for makes that drop rules that have no dependencies
398   // or commands.
399   if (depends.empty() && !this->EmptyRuleHackDepends.empty()) {
400     depends.push_back(this->EmptyRuleHackDepends);
401   }
402
403   // Write the rule.
404   std::string doc;
405   if (lg->IsRootMakefile()) {
406     doc = cmStrCat("The main recursive \"", pass, "\" target.");
407   } else {
408     doc = cmStrCat("Recursive \"", pass, "\" directory target.");
409   }
410
411   rootLG.WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends,
412                        commands, true);
413 }
414
415 void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
416   std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& rootLG,
417   DirectoryTarget const& dt)
418 {
419   auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
420   // Begin the directory-level rules section.
421   {
422     std::string dir = cmSystemTools::ConvertToOutputPath(
423       rootLG.MaybeRelativeToTopBinDir(lg->GetCurrentBinaryDirectory()));
424     rootLG.WriteDivider(ruleFileStream);
425     if (lg->IsRootMakefile()) {
426       ruleFileStream << "# Directory level rules for the build root directory";
427     } else {
428       ruleFileStream << "# Directory level rules for directory " << dir;
429     }
430     ruleFileStream << "\n\n";
431   }
432
433   // Write directory-level rules for "all".
434   this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "all", true, false);
435
436   // Write directory-level rules for "preinstall".
437   this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "preinstall", true,
438                             true);
439
440   // Write directory-level rules for "clean".
441   {
442     std::vector<std::string> cmds;
443     lg->AppendDirectoryCleanCommand(cmds);
444     this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "clean", false,
445                               false, cmds);
446   }
447 }
448
449 namespace {
450 std::string ConvertToMakefilePathForUnix(std::string const& path)
451 {
452   std::string result;
453   result.reserve(path.size());
454   for (char c : path) {
455     switch (c) {
456       case '=':
457         // We provide 'EQUALS = =' to encode '=' in a non-assignment case.
458         result.append("$(EQUALS)");
459         break;
460       case '$':
461         result.append("$$");
462         break;
463       case '\\':
464       case ' ':
465       case '#':
466         result.push_back('\\');
467         CM_FALLTHROUGH;
468       default:
469         result.push_back(c);
470         break;
471     }
472   }
473   return result;
474 }
475
476 #if defined(_WIN32) && !defined(__CYGWIN__)
477 std::string ConvertToMakefilePathForWindows(std::string const& path)
478 {
479   bool const quote = path.find_first_of(" #") != std::string::npos;
480   std::string result;
481   result.reserve(path.size() + (quote ? 2 : 0));
482   if (quote) {
483     result.push_back('"');
484   }
485   for (char c : path) {
486     switch (c) {
487       case '=':
488         // We provide 'EQUALS = =' to encode '=' in a non-assignment case.
489         result.append("$(EQUALS)");
490         break;
491       case '$':
492         result.append("$$");
493         break;
494       case '/':
495         result.push_back('\\');
496         break;
497       default:
498         result.push_back(c);
499         break;
500     }
501   }
502   if (quote) {
503     result.push_back('"');
504   }
505   return result;
506 }
507 #endif
508 }
509
510 std::string cmGlobalUnixMakefileGenerator3::ConvertToMakefilePath(
511   std::string const& path) const
512 {
513 #if defined(_WIN32) && !defined(__CYGWIN__)
514   if (!this->ForceUnixPaths) {
515     return ConvertToMakefilePathForWindows(path);
516   }
517 #endif
518   return ConvertToMakefilePathForUnix(path);
519 }
520
521 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
522 cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
523   const std::string& makeProgram, const std::string& /*projectName*/,
524   const std::string& /*projectDir*/,
525   std::vector<std::string> const& targetNames, const std::string& /*config*/,
526   int jobs, bool verbose, const cmBuildOptions& buildOptions,
527   std::vector<std::string> const& makeOptions)
528 {
529   GeneratedMakeCommand makeCommand;
530
531   // Make it possible to set verbosity also from command line
532   if (verbose) {
533     makeCommand.Add(cmSystemTools::GetCMakeCommand());
534     makeCommand.Add("-E");
535     makeCommand.Add("env");
536     makeCommand.Add("VERBOSE=1");
537   }
538   makeCommand.Add(this->SelectMakeProgram(makeProgram));
539
540   // Explicitly tell the make tool to use the Makefile written by
541   // cmLocalUnixMakefileGenerator3::WriteLocalMakefile
542   makeCommand.Add("-f");
543   makeCommand.Add("Makefile");
544
545   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
546     if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
547       makeCommand.Add("-j");
548     } else {
549       makeCommand.Add("-j" + std::to_string(jobs));
550     }
551   }
552
553   makeCommand.Add(makeOptions.begin(), makeOptions.end());
554   for (auto tname : targetNames) {
555     if (!tname.empty()) {
556       if (buildOptions.Fast) {
557         tname += "/fast";
558       }
559       cmSystemTools::ConvertToOutputSlashes(tname);
560       makeCommand.Add(std::move(tname));
561     }
562   }
563   return { std::move(makeCommand) };
564 }
565
566 void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
567   std::ostream& ruleFileStream, std::set<std::string>& emitted)
568 {
569   std::vector<std::string> depends;
570   std::vector<std::string> commands;
571
572   bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
573   if (regenerate) {
574     depends.emplace_back("cmake_check_build_system");
575   }
576
577   // write the target convenience rules
578   for (const auto& localGen : this->LocalGenerators) {
579     auto& lg =
580       cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen);
581     // for each target Generate the rule files for each target.
582     for (const auto& gtarget : lg.GetGeneratorTargets()) {
583       // Don't emit the same rule twice (e.g. two targets with the same
584       // simple name)
585       std::string name = gtarget->GetName();
586       if (!name.empty() && emitted.insert(name).second &&
587           // Handle user targets here.  Global targets are handled in
588           // the local generator on a per-directory basis.
589           (gtarget->IsInBuildSystem() &&
590            gtarget->GetType() != cmStateEnums::GLOBAL_TARGET)) {
591         // Add a rule to build the target by name.
592         lg.WriteDivider(ruleFileStream);
593         ruleFileStream << "# Target rules for targets named " << name
594                        << "\n\n";
595
596         // Write the rule.
597         commands.clear();
598         std::string tmp = "CMakeFiles/Makefile2";
599         commands.push_back(lg.GetRecursiveMakeCall(tmp, name));
600         depends.clear();
601         if (regenerate) {
602           depends.emplace_back("cmake_check_build_system");
603         }
604         lg.WriteMakeRule(ruleFileStream, "Build rule for target.", name,
605                          depends, commands, true);
606
607         // Add a fast rule to build the target
608         std::string localName = lg.GetRelativeTargetDirectory(gtarget.get());
609         std::string makefileName;
610         makefileName = cmStrCat(localName, "/build.make");
611         depends.clear();
612         commands.clear();
613         std::string makeTargetName = cmStrCat(localName, "/build");
614         localName = cmStrCat(name, "/fast");
615         commands.push_back(
616           lg.GetRecursiveMakeCall(makefileName, makeTargetName));
617         lg.WriteMakeRule(ruleFileStream, "fast build rule for target.",
618                          localName, depends, commands, true);
619
620         // Add a local name for the rule to relink the target before
621         // installation.
622         if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
623           makeTargetName = cmStrCat(
624             lg.GetRelativeTargetDirectory(gtarget.get()), "/preinstall");
625           localName = cmStrCat(name, "/preinstall");
626           depends.clear();
627           commands.clear();
628           commands.push_back(
629             lg.GetRecursiveMakeCall(makefileName, makeTargetName));
630           lg.WriteMakeRule(ruleFileStream,
631                            "Manual pre-install relink rule for target.",
632                            localName, depends, commands, true);
633         }
634       }
635     }
636   }
637 }
638
639 void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
640   std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& rootLG,
641   cmLocalUnixMakefileGenerator3& lg)
642 {
643   std::vector<std::string> depends;
644   std::vector<std::string> commands;
645   std::string localName;
646   std::string makeTargetName;
647
648   bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
649   if (regenerate) {
650     depends.emplace_back("cmake_check_build_system");
651   }
652
653   // for each target Generate the rule files for each target.
654   for (const auto& gtarget : lg.GetGeneratorTargets()) {
655     std::string name = gtarget->GetName();
656     if (!name.empty() &&
657         (gtarget->IsInBuildSystem() &&
658          gtarget->GetType() != cmStateEnums::GLOBAL_TARGET)) {
659       std::string makefileName;
660       // Add a rule to build the target by name.
661       localName = lg.GetRelativeTargetDirectory(gtarget.get());
662       makefileName = cmStrCat(localName, "/build.make");
663
664       lg.WriteDivider(ruleFileStream);
665       ruleFileStream << "# Target rules for target " << localName << "\n\n";
666
667       commands.clear();
668       makeTargetName = cmStrCat(localName, "/depend");
669       commands.push_back(
670         lg.GetRecursiveMakeCall(makefileName, makeTargetName));
671
672       makeTargetName = cmStrCat(localName, "/build");
673       commands.push_back(
674         lg.GetRecursiveMakeCall(makefileName, makeTargetName));
675
676       // Write the rule.
677       localName += "/all";
678       depends.clear();
679
680       cmLocalUnixMakefileGenerator3::EchoProgress progress;
681       progress.Dir = cmStrCat(lg.GetBinaryDirectory(), "/CMakeFiles");
682       {
683         std::ostringstream progressArg;
684         const char* sep = "";
685         for (unsigned long progFile : this->ProgressMap[gtarget.get()].Marks) {
686           progressArg << sep << progFile;
687           sep = ",";
688         }
689         progress.Arg = progressArg.str();
690       }
691
692       bool targetMessages = true;
693       if (cmValue tgtMsg =
694             this->GetCMakeInstance()->GetState()->GetGlobalProperty(
695               "TARGET_MESSAGES")) {
696         targetMessages = cmIsOn(*tgtMsg);
697       }
698
699       if (targetMessages) {
700         lg.AppendEcho(commands, "Built target " + name,
701                       cmLocalUnixMakefileGenerator3::EchoNormal, &progress);
702       }
703
704       this->AppendGlobalTargetDepends(depends, gtarget.get());
705       rootLG.WriteMakeRule(ruleFileStream, "All Build rule for target.",
706                            localName, depends, commands, true);
707
708       // Write the rule.
709       commands.clear();
710
711       {
712         // TODO: Convert the total progress count to a make variable.
713         std::ostringstream progCmd;
714         progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
715         // # in target
716         progCmd << lg.ConvertToOutputFormat(progress.Dir,
717                                             cmOutputConverter::SHELL);
718         //
719         std::set<cmGeneratorTarget const*> emitted;
720         progCmd << " "
721                 << this->CountProgressMarksInTarget(gtarget.get(), emitted);
722         commands.push_back(progCmd.str());
723       }
724       std::string tmp = "CMakeFiles/Makefile2";
725       commands.push_back(lg.GetRecursiveMakeCall(tmp, localName));
726       {
727         std::ostringstream progCmd;
728         progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
729         progCmd << lg.ConvertToOutputFormat(progress.Dir,
730                                             cmOutputConverter::SHELL);
731         progCmd << " 0";
732         commands.push_back(progCmd.str());
733       }
734       depends.clear();
735       if (regenerate) {
736         depends.emplace_back("cmake_check_build_system");
737       }
738       localName =
739         cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()), "/rule");
740       rootLG.WriteMakeRule(ruleFileStream,
741                            "Build rule for subdir invocation for target.",
742                            localName, depends, commands, true);
743
744       // Add a target with the canonical name (no prefix, suffix or path).
745       commands.clear();
746       depends.clear();
747       depends.push_back(localName);
748       rootLG.WriteMakeRule(ruleFileStream, "Convenience name for target.",
749                            name, depends, commands, true);
750
751       // Add rules to prepare the target for installation.
752       if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
753         localName = cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()),
754                              "/preinstall");
755         depends.clear();
756         commands.clear();
757         commands.push_back(lg.GetRecursiveMakeCall(makefileName, localName));
758         rootLG.WriteMakeRule(ruleFileStream,
759                              "Pre-install relink rule for target.", localName,
760                              depends, commands, true);
761       }
762
763       // add the clean rule
764       localName = lg.GetRelativeTargetDirectory(gtarget.get());
765       makeTargetName = cmStrCat(localName, "/clean");
766       depends.clear();
767       commands.clear();
768       commands.push_back(
769         lg.GetRecursiveMakeCall(makefileName, makeTargetName));
770       rootLG.WriteMakeRule(ruleFileStream, "clean rule for target.",
771                            makeTargetName, depends, commands, true);
772       commands.clear();
773     }
774   }
775 }
776
777 // Build a map that contains the set of targets used by each local
778 // generator directory level.
779 void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
780 {
781   this->DirectoryTargetsMap.clear();
782   // Loop over all targets in all local generators.
783   for (const auto& lg : this->LocalGenerators) {
784     for (const auto& gt : lg->GetGeneratorTargets()) {
785       cmLocalGenerator* tlg = gt->GetLocalGenerator();
786
787       if (!gt->IsInBuildSystem() || this->IsExcluded(lg.get(), gt.get())) {
788         continue;
789       }
790
791       cmStateSnapshot csnp = lg->GetStateSnapshot();
792       cmStateSnapshot tsnp = tlg->GetStateSnapshot();
793
794       // Consider the directory containing the target and all its
795       // parents until something excludes the target.
796       for (; csnp.IsValid() && !this->IsExcluded(csnp, tsnp);
797            csnp = csnp.GetBuildsystemDirectoryParent()) {
798         // This local generator includes the target.
799         std::set<cmGeneratorTarget const*>& targetSet =
800           this->DirectoryTargetsMap[csnp];
801         targetSet.insert(gt.get());
802
803         // Add dependencies of the included target.  An excluded
804         // target may still be included if it is a dependency of a
805         // non-excluded target.
806         for (cmTargetDepend const& tgtdep :
807              this->GetTargetDirectDepends(gt.get())) {
808           targetSet.insert(tgtdep);
809         }
810       }
811     }
812   }
813 }
814
815 size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget(
816   cmGeneratorTarget const* target, std::set<cmGeneratorTarget const*>& emitted)
817 {
818   size_t count = 0;
819   if (emitted.insert(target).second) {
820     count = this->ProgressMap[target].Marks.size();
821     for (cmTargetDepend const& depend : this->GetTargetDirectDepends(target)) {
822       if (!depend->IsInBuildSystem()) {
823         continue;
824       }
825       count += this->CountProgressMarksInTarget(depend, emitted);
826     }
827   }
828   return count;
829 }
830
831 size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll(
832   const cmLocalGenerator& lg)
833 {
834   size_t count = 0;
835   std::set<cmGeneratorTarget const*> emitted;
836   for (cmGeneratorTarget const* target :
837        this->DirectoryTargetsMap[lg.GetStateSnapshot()]) {
838     count += this->CountProgressMarksInTarget(target, emitted);
839   }
840   return count;
841 }
842
843 void cmGlobalUnixMakefileGenerator3::RecordTargetProgress(
844   cmMakefileTargetGenerator* tg)
845 {
846   TargetProgress& tp = this->ProgressMap[tg->GetGeneratorTarget()];
847   tp.NumberOfActions = tg->GetNumberOfProgressActions();
848   tp.VariableFile = tg->GetProgressFileNameFull();
849 }
850
851 void cmGlobalUnixMakefileGenerator3::TargetProgress::WriteProgressVariables(
852   unsigned long total, unsigned long& current)
853 {
854   cmGeneratedFileStream fout(this->VariableFile);
855   for (unsigned long i = 1; i <= this->NumberOfActions; ++i) {
856     fout << "CMAKE_PROGRESS_" << i << " = ";
857     if (total <= 100) {
858       unsigned long num = i + current;
859       fout << num;
860       this->Marks.push_back(num);
861     } else if (((i + current) * 100) / total >
862                ((i - 1 + current) * 100) / total) {
863       unsigned long num = ((i + current) * 100) / total;
864       fout << num;
865       this->Marks.push_back(num);
866     }
867     fout << "\n";
868   }
869   fout << "\n";
870   current += this->NumberOfActions;
871 }
872
873 void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends(
874   std::vector<std::string>& depends, cmGeneratorTarget* target)
875 {
876   for (cmTargetDepend const& i : this->GetTargetDirectDepends(target)) {
877     // Create the target-level dependency.
878     cmGeneratorTarget const* dep = i;
879     if (!dep->IsInBuildSystem()) {
880       continue;
881     }
882     cmLocalUnixMakefileGenerator3* lg3 =
883       static_cast<cmLocalUnixMakefileGenerator3*>(dep->GetLocalGenerator());
884     std::string tgtName = cmStrCat(
885       lg3->GetRelativeTargetDirectory(const_cast<cmGeneratorTarget*>(dep)),
886       "/all");
887     depends.push_back(tgtName);
888   }
889 }
890
891 void cmGlobalUnixMakefileGenerator3::WriteHelpRule(
892   std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
893 {
894   // add the help target
895   std::string path;
896   std::vector<std::string> no_depends;
897   std::vector<std::string> commands;
898   lg->AppendEcho(commands,
899                  "The following are some of the valid targets "
900                  "for this Makefile:");
901   lg->AppendEcho(commands, "... all (the default if no target is provided)");
902   lg->AppendEcho(commands, "... clean");
903   if (!this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
904     lg->AppendEcho(commands, "... depend");
905   }
906
907   // Keep track of targets already listed.
908   std::set<std::string> emittedTargets;
909   std::set<std::string> utility_targets;
910   std::set<std::string> globals_targets;
911   std::set<std::string> project_targets;
912
913   // for each local generator
914   for (const auto& localGen : this->LocalGenerators) {
915     const auto& lg2 =
916       cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen);
917     // for the passed in makefile or if this is the top Makefile wripte out
918     // the targets
919     if (&lg2 == lg || lg->IsRootMakefile()) {
920       // for each target Generate the rule files for each target.
921       for (const auto& target : lg2.GetGeneratorTargets()) {
922         cmStateEnums::TargetType type = target->GetType();
923         if ((type == cmStateEnums::EXECUTABLE) ||
924             (type == cmStateEnums::STATIC_LIBRARY) ||
925             (type == cmStateEnums::SHARED_LIBRARY) ||
926             (type == cmStateEnums::MODULE_LIBRARY) ||
927             (type == cmStateEnums::OBJECT_LIBRARY) ||
928             (type == cmStateEnums::INTERFACE_LIBRARY &&
929              target->IsInBuildSystem())) {
930           project_targets.insert(target->GetName());
931         } else if (type == cmStateEnums::GLOBAL_TARGET) {
932           globals_targets.insert(target->GetName());
933         } else if (type == cmStateEnums::UTILITY) {
934           utility_targets.insert(target->GetName());
935         }
936       }
937     }
938   }
939
940   for (std::string const& name : globals_targets) {
941     path = cmStrCat("... ", name);
942     lg->AppendEcho(commands, path);
943   }
944   for (std::string const& name : utility_targets) {
945     path = cmStrCat("... ", name);
946     lg->AppendEcho(commands, path);
947   }
948   for (std::string const& name : project_targets) {
949     path = cmStrCat("... ", name);
950     lg->AppendEcho(commands, path);
951   }
952
953   for (std::string const& o : lg->GetLocalHelp()) {
954     path = cmStrCat("... ", o);
955     lg->AppendEcho(commands, path);
956   }
957   lg->WriteMakeRule(ruleFileStream, "Help Target", "help", no_depends,
958                     commands, true);
959   ruleFileStream << "\n\n";
960 }