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"
11 #include <cmext/algorithm>
12 #include <cmext/memory>
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"
24 #include "cmStateTypes.h"
25 #include "cmStringAlgorithms.h"
26 #include "cmSystemTools.h"
27 #include "cmTargetDepend.h"
31 cmGlobalUnixMakefileGenerator3::cmGlobalUnixMakefileGenerator3(cmake* cm)
32 : cmGlobalCommonGenerator(cm)
34 // This type of makefile always requires unix style paths
35 this->ForceUnixPaths = true;
36 this->FindMakeProgramFile = "CMakeUnixFindMake.cmake";
37 this->ToolSupportsColor = true;
39 #if defined(_WIN32) || defined(__VMS)
40 this->UseLinkScript = false;
42 this->UseLinkScript = true;
45 this->IncludeDirective = "include";
46 this->LineContinueDirective = "\\\n";
47 this->DefineWindowsNULL = false;
48 this->PassMakeflags = false;
52 cmGlobalUnixMakefileGenerator3::~cmGlobalUnixMakefileGenerator3() = default;
54 void cmGlobalUnixMakefileGenerator3::EnableLanguage(
55 std::vector<std::string> const& languages, cmMakefile* mf, bool optional)
57 this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
58 for (std::string const& language : languages) {
59 if (language == "NONE") {
62 this->ResolveLanguageCompiler(language, mf, optional);
66 //! Create a local generator appropriate to this Global Generator
67 std::unique_ptr<cmLocalGenerator>
68 cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(cmMakefile* mf)
70 return std::unique_ptr<cmLocalGenerator>(
71 cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf));
74 void cmGlobalUnixMakefileGenerator3::GetDocumentation(
75 cmDocumentationEntry& entry)
77 entry.Name = cmGlobalUnixMakefileGenerator3::GetActualName();
78 entry.Brief = "Generates standard UNIX makefiles.";
81 void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
82 cmGeneratorTarget* gt) const
84 // Compute full path to object file directory for this target.
86 cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/',
87 gt->LocalGenerator->GetTargetDirectory(gt), '/');
88 gt->ObjectDirectory = dir;
91 bool cmGlobalUnixMakefileGenerator3::CanEscapeOctothorpe() const
93 // Make tools that use UNIX-style '/' paths also support '\' escaping.
94 return this->ForceUnixPaths;
97 void cmGlobalUnixMakefileGenerator3::Configure()
99 // Initialize CMAKE_EDIT_COMMAND cache entry.
100 this->GetEditCacheCommand();
102 this->cmGlobalGenerator::Configure();
105 void cmGlobalUnixMakefileGenerator3::Generate()
107 // first do superclass method
108 this->cmGlobalGenerator::Generate();
110 // initialize progress
111 unsigned long total = 0;
112 for (auto const& pmi : this->ProgressMap) {
113 total += pmi.second.NumberOfActions;
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);
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";
134 // write the main makefile
135 this->WriteMainMakefile2();
136 this->WriteMainCMakefile();
138 if (this->CommandDatabase) {
139 *this->CommandDatabase << "\n]";
140 this->CommandDatabase.reset();
144 void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand(
145 const std::string& sourceFile, const std::string& workingDirectory,
146 const std::string& compileCommand)
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";
156 *this->CommandDatabase << ",\n";
158 *this->CommandDatabase << "{\n"
159 << R"( "directory": ")"
160 << cmGlobalGenerator::EscapeJSON(workingDirectory)
162 << R"( "command": ")"
163 << cmGlobalGenerator::EscapeJSON(compileCommand)
166 << cmGlobalGenerator::EscapeJSON(sourceFile)
170 void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
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) {
184 // The global dependency graph is expressed via the root local generator.
185 auto& rootLG = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
186 this->LocalGenerators[0]);
188 // Write the do not edit header.
189 rootLG.WriteDisclaimer(makefileStream);
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");
199 rootLG.WriteMakeRule(makefileStream,
200 "Default target executed when no arguments are "
202 "default_target", depends, no_commands, true);
206 // The all and preinstall rules might never have any dependencies
208 if (!this->EmptyRuleHackDepends.empty()) {
209 depends.push_back(this->EmptyRuleHackDepends);
212 // Write out the "special" stuff
213 rootLG.WriteSpecialTargetsTop(makefileStream);
215 // Write the directory level rules.
216 for (auto const& it : this->ComputeDirectoryTargets()) {
217 this->WriteDirectoryRules2(makefileStream, rootLG, it.second);
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));
227 // Write special bottom targets
228 rootLG.WriteSpecialTargetsBottom(makefileStream);
231 void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile()
233 if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
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) {
248 std::string makefileName =
249 cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(), "/Makefile");
252 // get a local generator for some useful methods
253 auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
254 this->LocalGenerators[0]);
256 // Write the do not edit header.
257 lg.WriteDisclaimer(cmakefileStream);
260 // Save the generator name
261 cmakefileStream << "# The generator used is:\n"
262 << "set(CMAKE_DEPENDS_GENERATOR \"" << this->GetName()
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());
272 cmake* cm = this->GetCMakeInstance();
273 if (cm->DoWriteGlobVerifyTarget()) {
274 lfiles.push_back(cm->GetGlobVerifyScript());
275 lfiles.push_back(cm->GetGlobVerifyStamp());
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());
286 // reset lg to the first makefile
287 const auto& lg = cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(
288 this->LocalGenerators[0]);
290 // Save the list to the cmake file.
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";
298 cmakefileStream << " )\n\n";
300 // Build the path to the cache check file.
302 cmStrCat(this->GetCMakeInstance()->GetHomeOutputDirectory(),
303 "/CMakeFiles/cmake.check_cache");
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)
310 << " \"" << lg.MaybeRelativeToCurBinDir(check) << "\"\n";
311 cmakefileStream << " )\n\n";
313 // CMake must rerun if a byproduct is missing.
314 cmakefileStream << "# Byproducts of CMake generate step:\n"
315 << "set(CMAKE_MAKEFILE_PRODUCTS\n";
317 // add in any byproducts and all the directory information files
319 for (const auto& localGen : this->LocalGenerators) {
320 for (std::string const& outfile :
321 localGen->GetMakefile()->GetOutputFiles()) {
322 cmakefileStream << " \"" << lg.MaybeRelativeToTopBinDir(outfile)
325 tmpStr = cmStrCat(localGen->GetCurrentBinaryDirectory(),
326 "/CMakeFiles/CMakeDirectoryInformation.cmake");
327 cmakefileStream << " \"" << localGen->MaybeRelativeToTopBinDir(tmpStr)
330 cmakefileStream << " )\n\n";
333 this->WriteMainCMakefileLanguageRules(cmakefileStream,
334 this->LocalGenerators);
337 void cmGlobalUnixMakefileGenerator3::WriteMainCMakefileLanguageRules(
338 cmGeneratedFileStream& cmakefileStream,
339 std::vector<std::unique_ptr<cmLocalGenerator>>& lGenerators)
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) {
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";
358 cmakefileStream << " )\n";
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)
366 auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
367 std::string makeTarget =
368 cmStrCat(lg->GetCurrentBinaryDirectory(), '/', pass);
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()) &&
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());
382 cmStrCat(tlg->GetRelativeTargetDirectory(t.GT), '/', pass);
383 depends.push_back(std::move(tname));
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) {
393 std::string subdir = cmStrCat(d.Path, '/', pass);
394 depends.push_back(std::move(subdir));
397 // Work-around for makes that drop rules that have no dependencies
399 if (depends.empty() && !this->EmptyRuleHackDepends.empty()) {
400 depends.push_back(this->EmptyRuleHackDepends);
405 if (lg->IsRootMakefile()) {
406 doc = cmStrCat("The main recursive \"", pass, "\" target.");
408 doc = cmStrCat("Recursive \"", pass, "\" directory target.");
411 rootLG.WriteMakeRule(ruleFileStream, doc.c_str(), makeTarget, depends,
415 void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
416 std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& rootLG,
417 DirectoryTarget const& dt)
419 auto* lg = static_cast<cmLocalUnixMakefileGenerator3*>(dt.LG);
420 // Begin the directory-level rules section.
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";
428 ruleFileStream << "# Directory level rules for directory " << dir;
430 ruleFileStream << "\n\n";
433 // Write directory-level rules for "all".
434 this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "all", true, false);
436 // Write directory-level rules for "preinstall".
437 this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "preinstall", true,
440 // Write directory-level rules for "clean".
442 std::vector<std::string> cmds;
443 lg->AppendDirectoryCleanCommand(cmds);
444 this->WriteDirectoryRule2(ruleFileStream, rootLG, dt, "clean", false,
450 std::string ConvertToMakefilePathForUnix(std::string const& path)
453 result.reserve(path.size());
454 for (char c : path) {
457 // We provide 'EQUALS = =' to encode '=' in a non-assignment case.
458 result.append("$(EQUALS)");
466 result.push_back('\\');
476 #if defined(_WIN32) && !defined(__CYGWIN__)
477 std::string ConvertToMakefilePathForWindows(std::string const& path)
479 bool const quote = path.find_first_of(" #") != std::string::npos;
481 result.reserve(path.size() + (quote ? 2 : 0));
483 result.push_back('"');
485 for (char c : path) {
488 // We provide 'EQUALS = =' to encode '=' in a non-assignment case.
489 result.append("$(EQUALS)");
495 result.push_back('\\');
503 result.push_back('"');
510 std::string cmGlobalUnixMakefileGenerator3::ConvertToMakefilePath(
511 std::string const& path) const
513 #if defined(_WIN32) && !defined(__CYGWIN__)
514 if (!this->ForceUnixPaths) {
515 return ConvertToMakefilePathForWindows(path);
518 return ConvertToMakefilePathForUnix(path);
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)
529 GeneratedMakeCommand makeCommand;
531 // Make it possible to set verbosity also from command line
533 makeCommand.Add(cmSystemTools::GetCMakeCommand());
534 makeCommand.Add("-E");
535 makeCommand.Add("env");
536 makeCommand.Add("VERBOSE=1");
538 makeCommand.Add(this->SelectMakeProgram(makeProgram));
540 // Explicitly tell the make tool to use the Makefile written by
541 // cmLocalUnixMakefileGenerator3::WriteLocalMakefile
542 makeCommand.Add("-f");
543 makeCommand.Add("Makefile");
545 if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
546 if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
547 makeCommand.Add("-j");
549 makeCommand.Add("-j" + std::to_string(jobs));
553 makeCommand.Add(makeOptions.begin(), makeOptions.end());
554 for (auto tname : targetNames) {
555 if (!tname.empty()) {
556 if (buildOptions.Fast) {
559 cmSystemTools::ConvertToOutputSlashes(tname);
560 makeCommand.Add(std::move(tname));
563 return { std::move(makeCommand) };
566 void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules(
567 std::ostream& ruleFileStream, std::set<std::string>& emitted)
569 std::vector<std::string> depends;
570 std::vector<std::string> commands;
572 bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
574 depends.emplace_back("cmake_check_build_system");
577 // write the target convenience rules
578 for (const auto& localGen : this->LocalGenerators) {
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
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
598 std::string tmp = "CMakeFiles/Makefile2";
599 commands.push_back(lg.GetRecursiveMakeCall(tmp, name));
602 depends.emplace_back("cmake_check_build_system");
604 lg.WriteMakeRule(ruleFileStream, "Build rule for target.", name,
605 depends, commands, true);
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");
613 std::string makeTargetName = cmStrCat(localName, "/build");
614 localName = cmStrCat(name, "/fast");
616 lg.GetRecursiveMakeCall(makefileName, makeTargetName));
617 lg.WriteMakeRule(ruleFileStream, "fast build rule for target.",
618 localName, depends, commands, true);
620 // Add a local name for the rule to relink the target before
622 if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
623 makeTargetName = cmStrCat(
624 lg.GetRelativeTargetDirectory(gtarget.get()), "/preinstall");
625 localName = cmStrCat(name, "/preinstall");
629 lg.GetRecursiveMakeCall(makefileName, makeTargetName));
630 lg.WriteMakeRule(ruleFileStream,
631 "Manual pre-install relink rule for target.",
632 localName, depends, commands, true);
639 void cmGlobalUnixMakefileGenerator3::WriteConvenienceRules2(
640 std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3& rootLG,
641 cmLocalUnixMakefileGenerator3& lg)
643 std::vector<std::string> depends;
644 std::vector<std::string> commands;
645 std::string localName;
646 std::string makeTargetName;
648 bool regenerate = !this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION");
650 depends.emplace_back("cmake_check_build_system");
653 // for each target Generate the rule files for each target.
654 for (const auto& gtarget : lg.GetGeneratorTargets()) {
655 std::string name = gtarget->GetName();
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");
664 lg.WriteDivider(ruleFileStream);
665 ruleFileStream << "# Target rules for target " << localName << "\n\n";
668 makeTargetName = cmStrCat(localName, "/depend");
670 lg.GetRecursiveMakeCall(makefileName, makeTargetName));
672 makeTargetName = cmStrCat(localName, "/build");
674 lg.GetRecursiveMakeCall(makefileName, makeTargetName));
680 cmLocalUnixMakefileGenerator3::EchoProgress progress;
681 progress.Dir = cmStrCat(lg.GetBinaryDirectory(), "/CMakeFiles");
683 std::ostringstream progressArg;
684 const char* sep = "";
685 for (unsigned long progFile : this->ProgressMap[gtarget.get()].Marks) {
686 progressArg << sep << progFile;
689 progress.Arg = progressArg.str();
692 bool targetMessages = true;
694 this->GetCMakeInstance()->GetState()->GetGlobalProperty(
695 "TARGET_MESSAGES")) {
696 targetMessages = cmIsOn(*tgtMsg);
699 if (targetMessages) {
700 lg.AppendEcho(commands, "Built target " + name,
701 cmLocalUnixMakefileGenerator3::EchoNormal, &progress);
704 this->AppendGlobalTargetDepends(depends, gtarget.get());
705 rootLG.WriteMakeRule(ruleFileStream, "All Build rule for target.",
706 localName, depends, commands, true);
712 // TODO: Convert the total progress count to a make variable.
713 std::ostringstream progCmd;
714 progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
716 progCmd << lg.ConvertToOutputFormat(progress.Dir,
717 cmOutputConverter::SHELL);
719 std::set<cmGeneratorTarget const*> emitted;
721 << this->CountProgressMarksInTarget(gtarget.get(), emitted);
722 commands.push_back(progCmd.str());
724 std::string tmp = "CMakeFiles/Makefile2";
725 commands.push_back(lg.GetRecursiveMakeCall(tmp, localName));
727 std::ostringstream progCmd;
728 progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
729 progCmd << lg.ConvertToOutputFormat(progress.Dir,
730 cmOutputConverter::SHELL);
732 commands.push_back(progCmd.str());
736 depends.emplace_back("cmake_check_build_system");
739 cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()), "/rule");
740 rootLG.WriteMakeRule(ruleFileStream,
741 "Build rule for subdir invocation for target.",
742 localName, depends, commands, true);
744 // Add a target with the canonical name (no prefix, suffix or path).
747 depends.push_back(localName);
748 rootLG.WriteMakeRule(ruleFileStream, "Convenience name for target.",
749 name, depends, commands, true);
751 // Add rules to prepare the target for installation.
752 if (gtarget->NeedRelinkBeforeInstall(lg.GetConfigName())) {
753 localName = cmStrCat(lg.GetRelativeTargetDirectory(gtarget.get()),
757 commands.push_back(lg.GetRecursiveMakeCall(makefileName, localName));
758 rootLG.WriteMakeRule(ruleFileStream,
759 "Pre-install relink rule for target.", localName,
760 depends, commands, true);
763 // add the clean rule
764 localName = lg.GetRelativeTargetDirectory(gtarget.get());
765 makeTargetName = cmStrCat(localName, "/clean");
769 lg.GetRecursiveMakeCall(makefileName, makeTargetName));
770 rootLG.WriteMakeRule(ruleFileStream, "clean rule for target.",
771 makeTargetName, depends, commands, true);
777 // Build a map that contains the set of targets used by each local
778 // generator directory level.
779 void cmGlobalUnixMakefileGenerator3::InitializeProgressMarks()
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();
787 if (!gt->IsInBuildSystem() || this->IsExcluded(lg.get(), gt.get())) {
791 cmStateSnapshot csnp = lg->GetStateSnapshot();
792 cmStateSnapshot tsnp = tlg->GetStateSnapshot();
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());
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);
815 size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInTarget(
816 cmGeneratorTarget const* target, std::set<cmGeneratorTarget const*>& emitted)
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()) {
825 count += this->CountProgressMarksInTarget(depend, emitted);
831 size_t cmGlobalUnixMakefileGenerator3::CountProgressMarksInAll(
832 const cmLocalGenerator& lg)
835 std::set<cmGeneratorTarget const*> emitted;
836 for (cmGeneratorTarget const* target :
837 this->DirectoryTargetsMap[lg.GetStateSnapshot()]) {
838 count += this->CountProgressMarksInTarget(target, emitted);
843 void cmGlobalUnixMakefileGenerator3::RecordTargetProgress(
844 cmMakefileTargetGenerator* tg)
846 TargetProgress& tp = this->ProgressMap[tg->GetGeneratorTarget()];
847 tp.NumberOfActions = tg->GetNumberOfProgressActions();
848 tp.VariableFile = tg->GetProgressFileNameFull();
851 void cmGlobalUnixMakefileGenerator3::TargetProgress::WriteProgressVariables(
852 unsigned long total, unsigned long& current)
854 cmGeneratedFileStream fout(this->VariableFile);
855 for (unsigned long i = 1; i <= this->NumberOfActions; ++i) {
856 fout << "CMAKE_PROGRESS_" << i << " = ";
858 unsigned long num = i + current;
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;
865 this->Marks.push_back(num);
870 current += this->NumberOfActions;
873 void cmGlobalUnixMakefileGenerator3::AppendGlobalTargetDepends(
874 std::vector<std::string>& depends, cmGeneratorTarget* target)
876 for (cmTargetDepend const& i : this->GetTargetDirectDepends(target)) {
877 // Create the target-level dependency.
878 cmGeneratorTarget const* dep = i;
879 if (!dep->IsInBuildSystem()) {
882 cmLocalUnixMakefileGenerator3* lg3 =
883 static_cast<cmLocalUnixMakefileGenerator3*>(dep->GetLocalGenerator());
884 std::string tgtName = cmStrCat(
885 lg3->GetRelativeTargetDirectory(const_cast<cmGeneratorTarget*>(dep)),
887 depends.push_back(tgtName);
891 void cmGlobalUnixMakefileGenerator3::WriteHelpRule(
892 std::ostream& ruleFileStream, cmLocalUnixMakefileGenerator3* lg)
894 // add the help target
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");
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;
913 // for each local generator
914 for (const auto& localGen : this->LocalGenerators) {
916 cm::static_reference_cast<cmLocalUnixMakefileGenerator3>(localGen);
917 // for the passed in makefile or if this is the top Makefile wripte out
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());
940 for (std::string const& name : globals_targets) {
941 path = cmStrCat("... ", name);
942 lg->AppendEcho(commands, path);
944 for (std::string const& name : utility_targets) {
945 path = cmStrCat("... ", name);
946 lg->AppendEcho(commands, path);
948 for (std::string const& name : project_targets) {
949 path = cmStrCat("... ", name);
950 lg->AppendEcho(commands, path);
953 for (std::string const& o : lg->GetLocalHelp()) {
954 path = cmStrCat("... ", o);
955 lg->AppendEcho(commands, path);
957 lg->WriteMakeRule(ruleFileStream, "Help Target", "help", no_depends,
959 ruleFileStream << "\n\n";