1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
5 #include "cmConfigure.h" // IWYU pragma: keep
12 #include <unordered_map>
13 #include <unordered_set>
17 #include <cm/optional>
19 #include "cm_codecvt.hxx"
21 #include "cmBuildOptions.h"
22 #include "cmGeneratedFileStream.h"
23 #include "cmGlobalCommonGenerator.h"
24 #include "cmGlobalGeneratorFactory.h"
25 #include "cmNinjaTypes.h"
26 #include "cmPolicies.h"
27 #include "cmStringAlgorithms.h"
28 #include "cmTransformDepfile.h"
30 class cmCustomCommand;
31 class cmGeneratorTarget;
32 class cmLinkLineComputer;
33 class cmLocalGenerator;
35 class cmOutputConverter;
36 class cmStateDirectory;
38 struct cmDocumentationEntry;
41 * \class cmGlobalNinjaGenerator
42 * \brief Write a build.ninja file.
44 * The main differences between this generator and the UnixMakefile
45 * generator family are:
46 * - We don't care about VERBOSE variable or RULE_MESSAGES property since
47 * it is handle by Ninja's -v option.
48 * - We don't care about computing any progress status since Ninja manages
50 * - We generate one build.ninja and one rules.ninja per project.
51 * - We try to minimize the number of generated rules: one per target and
53 * - We use Ninja special variable $in and $out to produce nice output.
54 * - We extensively use Ninja variable overloading system to minimize the
55 * number of generated rules.
57 class cmGlobalNinjaGenerator : public cmGlobalCommonGenerator
60 /// The default name of Ninja's build file. Typically: build.ninja.
61 static const char* NINJA_BUILD_FILE;
63 /// The default name of Ninja's rules file. Typically: rules.ninja.
64 /// It is included in the main build.ninja file.
65 static const char* NINJA_RULES_FILE;
67 /// The indentation string used when generating Ninja's build file.
68 static const char* INDENT;
70 /// The shell command used for a no-op.
71 static std::string const SHELL_NOOP;
73 /// Write @a count times INDENT level to output stream @a os.
74 static void Indent(std::ostream& os, int count);
76 /// Write a divider in the given output stream @a os.
77 static void WriteDivider(std::ostream& os);
79 static std::string EncodeRuleName(std::string const& name);
80 std::string EncodeLiteral(const std::string& lit);
81 void EncodeLiteralInplace(std::string& lit);
82 std::string EncodePath(const std::string& path);
84 std::unique_ptr<cmLinkLineComputer> CreateLinkLineComputer(
85 cmOutputConverter* outputConverter,
86 cmStateDirectory const& stateDir) const override;
89 * Write the given @a comment to the output stream @a os. It
90 * handles new line character properly.
92 static void WriteComment(std::ostream& os, const std::string& comment);
95 * Utilized by the generator factory to determine if this generator
98 static bool SupportsToolset() { return false; }
101 * Utilized by the generator factory to determine if this generator
102 * supports platforms.
104 static bool SupportsPlatform() { return false; }
106 bool IsIPOSupported() const override { return true; }
109 * Write a build statement @a build to @a os.
110 * @warning no escaping of any kind is done here.
112 void WriteBuild(std::ostream& os, cmNinjaBuild const& build,
113 int cmdLineLimit = 0, bool* usedResponseFile = nullptr);
117 cmGlobalNinjaGenerator* GG;
120 CCOutputs(cmGlobalNinjaGenerator* gg)
124 void Add(std::vector<std::string> const& outputs);
125 cmNinjaDeps ExplicitOuts;
126 cmNinjaDeps WorkDirOuts;
129 void WriteCustomCommandBuild(std::string const& command,
130 std::string const& description,
131 std::string const& comment,
132 std::string const& depfile,
133 std::string const& pool, bool uses_terminal,
134 bool restat, std::string const& config,
136 cmNinjaDeps explicitDeps = cmNinjaDeps(),
137 cmNinjaDeps orderOnlyDeps = cmNinjaDeps());
139 void WriteMacOSXContentBuild(std::string input, std::string output,
140 const std::string& config);
143 * Write a rule statement to @a os.
144 * @warning no escaping of any kind is done here.
146 static void WriteRule(std::ostream& os, cmNinjaRule const& rule);
149 * Write a variable named @a name to @a os with value @a value and an
150 * optional @a comment. An @a indent level can be specified.
151 * @warning no escaping of any kind is done here.
153 static void WriteVariable(std::ostream& os, const std::string& name,
154 const std::string& value,
155 const std::string& comment = "", int indent = 0);
158 * Write an include statement including @a filename with an optional
159 * @a comment to the @a os stream.
161 static void WriteInclude(std::ostream& os, const std::string& filename,
162 const std::string& comment = "");
165 * Write a default target statement specifying @a targets as
166 * the default targets.
168 static void WriteDefault(std::ostream& os, const cmNinjaDeps& targets,
169 const std::string& comment = "");
171 bool IsGCCOnWindows() const { return this->UsingGCCOnWindows; }
173 cmGlobalNinjaGenerator(cmake* cm);
175 static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
177 return std::unique_ptr<cmGlobalGeneratorFactory>(
178 new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>());
181 std::unique_ptr<cmLocalGenerator> CreateLocalGenerator(
182 cmMakefile* mf) override;
184 std::string GetName() const override
186 return cmGlobalNinjaGenerator::GetActualName();
189 static std::string GetActualName() { return "Ninja"; }
191 bool IsNinja() const override { return true; }
193 /** Get encoding used by generator for ninja files */
194 codecvt::Encoding GetMakefileEncoding() const override;
196 static void GetDocumentation(cmDocumentationEntry& entry);
198 void EnableLanguage(std::vector<std::string> const& languages,
199 cmMakefile* mf, bool optional) override;
201 std::vector<GeneratedMakeCommand> GenerateBuildCommand(
202 const std::string& makeProgram, const std::string& projectName,
203 const std::string& projectDir, std::vector<std::string> const& targetNames,
204 const std::string& config, int jobs, bool verbose,
205 const cmBuildOptions& buildOptions = cmBuildOptions(),
206 std::vector<std::string> const& makeOptions =
207 std::vector<std::string>()) override;
209 // Setup target names
210 const char* GetAllTargetName() const override { return "all"; }
211 const char* GetInstallTargetName() const override { return "install"; }
212 const char* GetInstallLocalTargetName() const override
214 return "install/local";
216 const char* GetInstallStripTargetName() const override
218 return "install/strip";
220 const char* GetTestTargetName() const override { return "test"; }
221 const char* GetPackageTargetName() const override { return "package"; }
222 const char* GetPackageSourceTargetName() const override
224 return "package_source";
226 const char* GetRebuildCacheTargetName() const override
228 return "rebuild_cache";
230 const char* GetCleanTargetName() const override { return "clean"; }
232 bool SupportsCustomCommandDepfile() const override { return true; }
233 cm::optional<cmDepfileFormat> DepfileFormat() const override
235 return cmDepfileFormat::GccDepfile;
238 virtual cmGeneratedFileStream* GetImplFileStream(
239 const std::string& /*config*/) const
241 return this->BuildFileStream.get();
244 virtual cmGeneratedFileStream* GetConfigFileStream(
245 const std::string& /*config*/) const
247 return this->BuildFileStream.get();
250 virtual cmGeneratedFileStream* GetDefaultFileStream() const
252 return this->BuildFileStream.get();
255 virtual cmGeneratedFileStream* GetCommonFileStream() const
257 return this->BuildFileStream.get();
260 cmGeneratedFileStream* GetRulesFileStream() const
262 return this->RulesFileStream.get();
265 std::string const& ConvertToNinjaPath(const std::string& path) const;
266 std::string ConvertToNinjaAbsPath(std::string path) const;
268 struct MapToNinjaPathImpl
270 cmGlobalNinjaGenerator* GG;
271 MapToNinjaPathImpl(cmGlobalNinjaGenerator* gg)
275 std::string operator()(std::string const& path) const
277 return this->GG->ConvertToNinjaPath(path);
280 MapToNinjaPathImpl MapToNinjaPath() { return { this }; }
282 // -- Additional clean files
283 void AddAdditionalCleanFile(std::string fileName, const std::string& config);
284 const char* GetAdditionalCleanTargetName() const
286 return "CMakeFiles/clean.additional";
289 static const char* GetByproductsForCleanTargetName()
291 return "CMakeFiles/cmake_byproducts_for_clean_target";
294 void AddCXXCompileCommand(const std::string& commandLine,
295 const std::string& sourceFile);
298 * Add a rule to the generated build system.
299 * Call WriteRule() behind the scene but perform some check before like:
300 * - Do not add twice the same rule.
302 void AddRule(cmNinjaRule const& rule);
304 bool HasRule(const std::string& name);
306 void AddCustomCommandRule();
307 void AddMacOSXContentRule();
309 bool HasCustomCommandOutput(const std::string& output)
311 return this->CustomCommandOutputs.find(output) !=
312 this->CustomCommandOutputs.end();
315 /// Called when we have seen the given custom command. Returns true
316 /// if we has seen it before.
317 bool SeenCustomCommand(cmCustomCommand const* cc, const std::string& config)
319 return !this->Configs[config].CustomCommands.insert(cc).second;
322 /// Called when we have seen the given custom command output.
323 void SeenCustomCommandOutput(const std::string& output)
325 this->CustomCommandOutputs.insert(output);
326 // We don't need the assumed dependencies anymore, because we have
328 this->AssumedSourceDependencies.erase(output);
331 void AddAssumedSourceDependencies(const std::string& source,
332 const cmNinjaDeps& deps)
334 std::set<std::string>& ASD = this->AssumedSourceDependencies[source];
335 // Because we may see the same source file multiple times (same source
336 // specified in multiple targets), compute the union of any assumed
338 ASD.insert(deps.begin(), deps.end());
341 virtual std::string OrderDependsTargetForTarget(
342 cmGeneratorTarget const* target, const std::string& config) const;
344 void AppendTargetOutputs(cmGeneratorTarget const* target,
345 cmNinjaDeps& outputs, const std::string& config,
346 cmNinjaTargetDepends depends) const;
347 void AppendTargetDepends(cmGeneratorTarget const* target,
348 cmNinjaDeps& outputs, const std::string& config,
349 const std::string& fileConfig,
350 cmNinjaTargetDepends depends);
351 void AppendTargetDependsClosure(cmGeneratorTarget const* target,
352 cmNinjaDeps& outputs,
353 const std::string& config,
354 const std::string& fileConfig,
356 void AppendTargetDependsClosure(cmGeneratorTarget const* target,
357 cmNinjaOuts& outputs,
358 const std::string& config,
359 const std::string& fileConfig,
360 bool genexOutput, bool omit_self);
362 void AppendDirectoryForConfig(const std::string& prefix,
363 const std::string& config,
364 const std::string& suffix,
365 std::string& dir) override;
367 virtual void AppendNinjaFileArgument(GeneratedMakeCommand& /*command*/,
368 const std::string& /*config*/) const
372 virtual void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const
374 outputs.push_back(this->NinjaOutputPath(NINJA_BUILD_FILE));
377 int GetRuleCmdLength(const std::string& name)
379 return this->RuleCmdLength[name];
382 void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target,
383 const std::string& config);
385 void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
387 // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3
388 static std::string RequiredNinjaVersion() { return "1.3"; }
389 static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; }
390 static std::string RequiredNinjaVersionForImplicitOuts() { return "1.7"; }
391 static std::string RequiredNinjaVersionForManifestRestat() { return "1.8"; }
392 static std::string RequiredNinjaVersionForMultilineDepfile()
396 static std::string RequiredNinjaVersionForDyndeps() { return "1.10"; }
397 static std::string RequiredNinjaVersionForRestatTool() { return "1.10"; }
398 static std::string RequiredNinjaVersionForUnconditionalRecompactTool()
402 static std::string RequiredNinjaVersionForMultipleOutputs()
406 static std::string RequiredNinjaVersionForMetadataOnRegeneration()
410 static std::string RequiredNinjaVersionForCodePage() { return "1.11"; }
411 bool SupportsDirectConsole() const override;
412 bool SupportsImplicitOuts() const;
413 bool SupportsManifestRestat() const;
414 bool SupportsMultilineDepfile() const;
416 std::string NinjaOutputPath(std::string const& path) const;
417 bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
418 void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
420 struct CxxModuleExportInfo;
421 bool WriteDyndepFile(
422 std::string const& dir_top_src, std::string const& dir_top_bld,
423 std::string const& dir_cur_src, std::string const& dir_cur_bld,
424 std::string const& arg_dd, std::vector<std::string> const& arg_ddis,
425 std::string const& module_dir,
426 std::vector<std::string> const& linked_target_dirs,
427 std::string const& arg_lang, std::string const& arg_modmapfmt,
428 CxxModuleExportInfo const& export_info);
430 virtual std::string BuildAlias(const std::string& alias,
431 const std::string& /*config*/) const
436 virtual std::string ConfigDirectory(const std::string& /*config*/) const
441 cmNinjaDeps& GetByproductsForCleanTarget()
443 return this->ByproductsForCleanTarget;
446 cmNinjaDeps& GetByproductsForCleanTarget(const std::string& config)
448 return this->Configs[config].ByproductsForCleanTarget;
451 bool EnableCrossConfigBuild() const;
453 std::set<std::string> GetCrossConfigs(const std::string& config) const;
455 const std::set<std::string>& GetDefaultConfigs() const
457 return this->DefaultConfigs;
460 const std::set<std::string>& GetPerConfigUtilityTargets() const
462 return this->PerConfigUtilityTargets;
465 void AddPerConfigUtilityTarget(const std::string& name)
467 this->PerConfigUtilityTargets.insert(name);
470 bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
472 bool CheckCxxModuleSupport();
475 void Generate() override;
477 bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; }
479 virtual bool OpenBuildFileStreams();
480 virtual void CloseBuildFileStreams();
482 bool OpenFileStream(std::unique_ptr<cmGeneratedFileStream>& stream,
483 const std::string& name);
485 static cm::optional<std::set<std::string>> ListSubsetWithAll(
486 const std::set<std::string>& all, const std::set<std::string>& defaults,
487 const std::vector<std::string>& items);
489 std::set<std::string> CrossConfigs;
490 std::set<std::string> DefaultConfigs;
491 std::string DefaultFileConfig;
494 bool FindMakeProgram(cmMakefile* mf) override;
495 void CheckNinjaFeatures();
496 void CheckNinjaCodePage();
497 bool CheckLanguages(std::vector<std::string> const& languages,
498 cmMakefile* mf) const override;
499 bool CheckFortran(cmMakefile* mf) const;
500 bool CheckISPC(cmMakefile* mf) const;
502 void CloseCompileCommandsStream();
504 bool OpenRulesFileStream();
505 void CloseRulesFileStream();
506 void CleanMetaData();
508 /// Write the common disclaimer text at the top of each build file.
509 void WriteDisclaimer(std::ostream& os) const;
511 void WriteAssumedSourceDependencies();
513 void WriteTargetAliases(std::ostream& os);
514 void WriteFolderTargets(std::ostream& os);
515 void WriteUnknownExplicitDependencies(std::ostream& os);
517 void WriteBuiltinTargets(std::ostream& os);
518 void WriteTargetDefault(std::ostream& os);
519 void WriteTargetRebuildManifest(std::ostream& os);
520 bool WriteTargetCleanAdditional(std::ostream& os);
521 void WriteTargetClean(std::ostream& os);
522 void WriteTargetHelp(std::ostream& os);
524 void ComputeTargetDependsClosure(
525 cmGeneratorTarget const* target,
526 std::set<cmGeneratorTarget const*>& depends);
528 std::string CMakeCmd() const;
529 std::string NinjaCmd() const;
531 /// The file containing the build statement. (the relationship of the
532 /// compilation DAG).
533 std::unique_ptr<cmGeneratedFileStream> BuildFileStream;
534 /// The file containing the rule statements. (The action attached to each
535 /// edge of the compilation DAG).
536 std::unique_ptr<cmGeneratedFileStream> RulesFileStream;
537 std::unique_ptr<cmGeneratedFileStream> CompileCommandsStream;
539 /// The set of rules added to the generated build system.
540 std::unordered_set<std::string> Rules;
542 /// Length of rule command, used by rsp file evaluation
543 std::unordered_map<std::string, int> RuleCmdLength;
545 bool UsingGCCOnWindows = false;
547 /// The set of custom command outputs we have seen.
548 std::set<std::string> CustomCommandOutputs;
550 /// Whether we are collecting known build outputs and needed
551 /// dependencies to determine unknown dependencies.
552 bool ComputingUnknownDependencies = false;
553 cmPolicies::PolicyStatus PolicyCMP0058 = cmPolicies::WARN;
555 /// The combined explicit dependencies of custom build commands
556 std::set<std::string> CombinedCustomCommandExplicitDependencies;
558 /// When combined with CombinedCustomCommandExplicitDependencies it allows
559 /// us to detect the set of explicit dependencies that have
560 std::set<std::string> CombinedBuildOutputs;
562 /// The mapping from source file to assumed dependencies.
563 std::map<std::string, std::set<std::string>> AssumedSourceDependencies;
565 /// Utility targets which have per-config outputs
566 std::set<std::string> PerConfigUtilityTargets;
570 cmGeneratorTarget* GeneratorTarget;
573 using TargetAliasMap = std::map<std::string, TargetAlias>;
574 TargetAliasMap TargetAliases;
575 TargetAliasMap DefaultTargetAliases;
577 /// the local cache for calls to ConvertToNinjaPath
578 mutable std::unordered_map<std::string, std::string> ConvertToNinjaPathCache;
580 std::string NinjaCommand;
581 std::string NinjaVersion;
582 bool NinjaSupportsConsolePool = false;
583 bool NinjaSupportsImplicitOuts = false;
584 bool NinjaSupportsManifestRestat = false;
585 bool NinjaSupportsMultilineDepfile = false;
586 bool NinjaSupportsDyndeps = false;
587 bool NinjaSupportsRestatTool = false;
588 bool NinjaSupportsUnconditionalRecompactTool = false;
589 bool NinjaSupportsMultipleOutputs = false;
590 bool NinjaSupportsMetadataOnRegeneration = false;
591 bool NinjaSupportsCodePage = false;
593 codecvt::Encoding NinjaExpectedEncoding = codecvt::None;
595 bool DiagnosedCxxModuleSupport = false;
597 void InitOutputPathPrefix();
599 std::string OutputPathPrefix;
600 std::string TargetAll;
601 std::string CMakeCacheFile;
602 bool DisableCleandead = false;
606 std::set<std::string> AdditionalCleanFiles;
608 /// The set of custom commands we have seen.
609 std::set<cmCustomCommand const*> CustomCommands;
611 struct TargetDependsClosureKey
613 cmGeneratorTarget const* Target;
618 std::map<TargetDependsClosureKey, cmNinjaOuts> TargetDependsClosures;
620 TargetAliasMap TargetAliases;
622 cmNinjaDeps ByproductsForCleanTarget;
624 std::map<std::string, ByConfig> Configs;
626 cmNinjaDeps ByproductsForCleanTarget;
628 friend bool operator==(const ByConfig::TargetDependsClosureKey& lhs,
629 const ByConfig::TargetDependsClosureKey& rhs);
630 friend bool operator!=(const ByConfig::TargetDependsClosureKey& lhs,
631 const ByConfig::TargetDependsClosureKey& rhs);
632 friend bool operator<(const ByConfig::TargetDependsClosureKey& lhs,
633 const ByConfig::TargetDependsClosureKey& rhs);
634 friend bool operator>(const ByConfig::TargetDependsClosureKey& lhs,
635 const ByConfig::TargetDependsClosureKey& rhs);
636 friend bool operator<=(const ByConfig::TargetDependsClosureKey& lhs,
637 const ByConfig::TargetDependsClosureKey& rhs);
638 friend bool operator>=(const ByConfig::TargetDependsClosureKey& lhs,
639 const ByConfig::TargetDependsClosureKey& rhs);
642 class cmGlobalNinjaMultiGenerator : public cmGlobalNinjaGenerator
645 /// The default name of Ninja's common file. Typically: common.ninja.
646 static const char* NINJA_COMMON_FILE;
647 /// The default file extension to use for per-config Ninja files.
648 static const char* NINJA_FILE_EXTENSION;
650 cmGlobalNinjaMultiGenerator(cmake* cm);
651 bool IsMultiConfig() const override { return true; }
652 static std::unique_ptr<cmGlobalGeneratorFactory> NewFactory()
654 return std::unique_ptr<cmGlobalGeneratorFactory>(
655 new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaMultiGenerator>());
658 static void GetDocumentation(cmDocumentationEntry& entry);
660 std::string GetName() const override
662 return cmGlobalNinjaMultiGenerator::GetActualName();
665 static std::string GetActualName() { return "Ninja Multi-Config"; }
667 std::string BuildAlias(const std::string& alias,
668 const std::string& config) const override
670 if (config.empty()) {
673 return cmStrCat(alias, ":", config);
676 std::string ConfigDirectory(const std::string& config) const override
678 if (!config.empty()) {
679 return cmStrCat('/', config);
684 const char* GetCMakeCFGIntDir() const override { return "${CONFIGURATION}"; }
686 std::string ExpandCFGIntDir(const std::string& str,
687 const std::string& config) const override;
689 cmGeneratedFileStream* GetImplFileStream(
690 const std::string& config) const override
692 return this->ImplFileStreams.at(config).get();
695 cmGeneratedFileStream* GetConfigFileStream(
696 const std::string& config) const override
698 return this->ConfigFileStreams.at(config).get();
701 cmGeneratedFileStream* GetDefaultFileStream() const override
703 return this->DefaultFileStream.get();
706 cmGeneratedFileStream* GetCommonFileStream() const override
708 return this->CommonFileStream.get();
711 void AppendNinjaFileArgument(GeneratedMakeCommand& command,
712 const std::string& config) const override;
714 static std::string GetNinjaImplFilename(const std::string& config);
715 static std::string GetNinjaConfigFilename(const std::string& config);
717 void AddRebuildManifestOutputs(cmNinjaDeps& outputs) const override;
719 void GetQtAutoGenConfigs(std::vector<std::string>& configs) const override;
721 bool InspectConfigTypeVariables() override;
723 std::string GetDefaultBuildConfig() const override;
725 bool SupportsDefaultBuildType() const override { return true; }
726 bool SupportsCrossConfigs() const override { return true; }
727 bool SupportsDefaultConfigs() const override { return true; }
729 std::string OrderDependsTargetForTarget(
730 cmGeneratorTarget const* target, const std::string& config) const override;
733 bool OpenBuildFileStreams() override;
734 void CloseBuildFileStreams() override;
737 std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>
739 std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>
741 std::unique_ptr<cmGeneratedFileStream> CommonFileStream;
742 std::unique_ptr<cmGeneratedFileStream> DefaultFileStream;