| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #ifndef cmGlobalNinjaGenerator_h |
| #define cmGlobalNinjaGenerator_h |
| |
| #include "cmConfigure.h" // IWYU pragma: keep |
| |
| #include <iosfwd> |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <unordered_map> |
| #include <unordered_set> |
| #include <utility> |
| #include <vector> |
| |
| #include "cm_codecvt.hxx" |
| |
| #include "cmGeneratedFileStream.h" |
| #include "cmGlobalCommonGenerator.h" |
| #include "cmGlobalGeneratorFactory.h" |
| #include "cmNinjaTypes.h" |
| #include "cmPolicies.h" |
| |
| class cmCustomCommand; |
| class cmGeneratorTarget; |
| class cmLinkLineComputer; |
| class cmLocalGenerator; |
| class cmMakefile; |
| class cmOutputConverter; |
| class cmStateDirectory; |
| class cmake; |
| struct cmDocumentationEntry; |
| |
| /** |
| * \class cmGlobalNinjaGenerator |
| * \brief Write a build.ninja file. |
| * |
| * The main differences between this generator and the UnixMakefile |
| * generator family are: |
| * - We don't care about VERBOSE variable or RULE_MESSAGES property since |
| * it is handle by Ninja's -v option. |
| * - We don't care about computing any progress status since Ninja manages |
| * it itself. |
| * - We generate one build.ninja and one rules.ninja per project. |
| * - We try to minimize the number of generated rules: one per target and |
| * language. |
| * - We use Ninja special variable $in and $out to produce nice output. |
| * - We extensively use Ninja variable overloading system to minimize the |
| * number of generated rules. |
| */ |
| class cmGlobalNinjaGenerator : public cmGlobalCommonGenerator |
| { |
| public: |
| /// The default name of Ninja's build file. Typically: build.ninja. |
| static const char* NINJA_BUILD_FILE; |
| |
| /// The default name of Ninja's rules file. Typically: rules.ninja. |
| /// It is included in the main build.ninja file. |
| static const char* NINJA_RULES_FILE; |
| |
| /// The indentation string used when generating Ninja's build file. |
| static const char* INDENT; |
| |
| /// The shell command used for a no-op. |
| static std::string const SHELL_NOOP; |
| |
| /// Write @a count times INDENT level to output stream @a os. |
| static void Indent(std::ostream& os, int count); |
| |
| /// Write a divider in the given output stream @a os. |
| static void WriteDivider(std::ostream& os); |
| |
| static std::string EncodeRuleName(std::string const& name); |
| static std::string EncodeLiteral(const std::string& lit); |
| std::string EncodePath(const std::string& path); |
| |
| cmLinkLineComputer* CreateLinkLineComputer( |
| cmOutputConverter* outputConverter, |
| cmStateDirectory const& stateDir) const override; |
| |
| /** |
| * Write the given @a comment to the output stream @a os. It |
| * handles new line character properly. |
| */ |
| static void WriteComment(std::ostream& os, const std::string& comment); |
| |
| /** |
| * Utilized by the generator factory to determine if this generator |
| * supports toolsets. |
| */ |
| static bool SupportsToolset() { return false; } |
| |
| /** |
| * Utilized by the generator factory to determine if this generator |
| * supports platforms. |
| */ |
| static bool SupportsPlatform() { return false; } |
| |
| bool IsIPOSupported() const override { return true; } |
| |
| /** |
| * Write a build statement @a build to @a os. |
| * @warning no escaping of any kind is done here. |
| */ |
| void WriteBuild(std::ostream& os, cmNinjaBuild const& build, |
| int cmdLineLimit = 0, bool* usedResponseFile = nullptr); |
| |
| void WriteCustomCommandBuild( |
| const std::string& command, const std::string& description, |
| const std::string& comment, const std::string& depfile, |
| const std::string& pool, bool uses_terminal, bool restat, |
| const cmNinjaDeps& outputs, |
| const cmNinjaDeps& explicitDeps = cmNinjaDeps(), |
| const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps()); |
| |
| void WriteMacOSXContentBuild(std::string input, std::string output); |
| |
| /** |
| * Write a rule statement to @a os. |
| * @warning no escaping of any kind is done here. |
| */ |
| static void WriteRule(std::ostream& os, cmNinjaRule const& rule); |
| |
| /** |
| * Write a variable named @a name to @a os with value @a value and an |
| * optional @a comment. An @a indent level can be specified. |
| * @warning no escaping of any kind is done here. |
| */ |
| static void WriteVariable(std::ostream& os, const std::string& name, |
| const std::string& value, |
| const std::string& comment = "", int indent = 0); |
| |
| /** |
| * Write an include statement including @a filename with an optional |
| * @a comment to the @a os stream. |
| */ |
| static void WriteInclude(std::ostream& os, const std::string& filename, |
| const std::string& comment = ""); |
| |
| /** |
| * Write a default target statement specifying @a targets as |
| * the default targets. |
| */ |
| static void WriteDefault(std::ostream& os, const cmNinjaDeps& targets, |
| const std::string& comment = ""); |
| |
| bool IsGCCOnWindows() const { return UsingGCCOnWindows; } |
| |
| public: |
| cmGlobalNinjaGenerator(cmake* cm); |
| |
| static cmGlobalGeneratorFactory* NewFactory() |
| { |
| return new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>(); |
| } |
| |
| cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) override; |
| |
| std::string GetName() const override |
| { |
| return cmGlobalNinjaGenerator::GetActualName(); |
| } |
| |
| static std::string GetActualName() { return "Ninja"; } |
| |
| /** Get encoding used by generator for ninja files */ |
| codecvt::Encoding GetMakefileEncoding() const override; |
| |
| static void GetDocumentation(cmDocumentationEntry& entry); |
| |
| void EnableLanguage(std::vector<std::string> const& languages, |
| cmMakefile* mf, bool optional) override; |
| |
| std::vector<GeneratedMakeCommand> GenerateBuildCommand( |
| const std::string& makeProgram, const std::string& projectName, |
| const std::string& projectDir, std::vector<std::string> const& targetNames, |
| const std::string& config, bool fast, int jobs, bool verbose, |
| std::vector<std::string> const& makeOptions = |
| std::vector<std::string>()) override; |
| |
| // Setup target names |
| const char* GetAllTargetName() const override { return "all"; } |
| const char* GetInstallTargetName() const override { return "install"; } |
| const char* GetInstallLocalTargetName() const override |
| { |
| return "install/local"; |
| } |
| const char* GetInstallStripTargetName() const override |
| { |
| return "install/strip"; |
| } |
| const char* GetTestTargetName() const override { return "test"; } |
| const char* GetPackageTargetName() const override { return "package"; } |
| const char* GetPackageSourceTargetName() const override |
| { |
| return "package_source"; |
| } |
| const char* GetEditCacheTargetName() const override { return "edit_cache"; } |
| const char* GetRebuildCacheTargetName() const override |
| { |
| return "rebuild_cache"; |
| } |
| const char* GetCleanTargetName() const override { return "clean"; } |
| |
| cmGeneratedFileStream* GetBuildFileStream() const |
| { |
| return this->BuildFileStream.get(); |
| } |
| |
| cmGeneratedFileStream* GetRulesFileStream() const |
| { |
| return this->RulesFileStream.get(); |
| } |
| |
| std::string const& ConvertToNinjaPath(const std::string& path) const; |
| |
| struct MapToNinjaPathImpl |
| { |
| cmGlobalNinjaGenerator* GG; |
| MapToNinjaPathImpl(cmGlobalNinjaGenerator* gg) |
| : GG(gg) |
| { |
| } |
| std::string operator()(std::string const& path) |
| { |
| return this->GG->ConvertToNinjaPath(path); |
| } |
| }; |
| MapToNinjaPathImpl MapToNinjaPath() { return { this }; } |
| |
| // -- Additional clean files |
| void AddAdditionalCleanFile(std::string fileName); |
| const char* GetAdditionalCleanTargetName() const |
| { |
| return "CMakeFiles/clean.additional"; |
| } |
| |
| void AddCXXCompileCommand(const std::string& commandLine, |
| const std::string& sourceFile); |
| |
| /** |
| * Add a rule to the generated build system. |
| * Call WriteRule() behind the scene but perform some check before like: |
| * - Do not add twice the same rule. |
| */ |
| void AddRule(cmNinjaRule const& rule); |
| |
| bool HasRule(const std::string& name); |
| |
| void AddCustomCommandRule(); |
| void AddMacOSXContentRule(); |
| |
| bool HasCustomCommandOutput(const std::string& output) |
| { |
| return this->CustomCommandOutputs.find(output) != |
| this->CustomCommandOutputs.end(); |
| } |
| |
| /// Called when we have seen the given custom command. Returns true |
| /// if we has seen it before. |
| bool SeenCustomCommand(cmCustomCommand const* cc) |
| { |
| return !this->CustomCommands.insert(cc).second; |
| } |
| |
| /// Called when we have seen the given custom command output. |
| void SeenCustomCommandOutput(const std::string& output) |
| { |
| this->CustomCommandOutputs.insert(output); |
| // We don't need the assumed dependencies anymore, because we have |
| // an output. |
| this->AssumedSourceDependencies.erase(output); |
| } |
| |
| void AddAssumedSourceDependencies(const std::string& source, |
| const cmNinjaDeps& deps) |
| { |
| std::set<std::string>& ASD = this->AssumedSourceDependencies[source]; |
| // Because we may see the same source file multiple times (same source |
| // specified in multiple targets), compute the union of any assumed |
| // dependencies. |
| ASD.insert(deps.begin(), deps.end()); |
| } |
| |
| void AppendTargetOutputs( |
| cmGeneratorTarget const* target, cmNinjaDeps& outputs, |
| cmNinjaTargetDepends depends = DependOnTargetArtifact); |
| void AppendTargetDepends( |
| cmGeneratorTarget const* target, cmNinjaDeps& outputs, |
| cmNinjaTargetDepends depends = DependOnTargetArtifact); |
| void AppendTargetDependsClosure(cmGeneratorTarget const* target, |
| cmNinjaDeps& outputs); |
| void AppendTargetDependsClosure(cmGeneratorTarget const* target, |
| cmNinjaOuts& outputs, bool omit_self); |
| |
| const std::vector<cmLocalGenerator*>& GetLocalGenerators() const |
| { |
| return LocalGenerators; |
| } |
| |
| int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; } |
| |
| void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target); |
| |
| void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override; |
| |
| // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3 |
| static std::string RequiredNinjaVersion() { return "1.3"; } |
| static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; } |
| static std::string RequiredNinjaVersionForImplicitOuts() { return "1.7"; } |
| static std::string RequiredNinjaVersionForManifestRestat() { return "1.8"; } |
| static std::string RequiredNinjaVersionForMultilineDepfile() |
| { |
| return "1.9"; |
| } |
| static std::string RequiredNinjaVersionForDyndeps() { return "1.10"; } |
| bool SupportsConsolePool() const; |
| bool SupportsImplicitOuts() const; |
| bool SupportsManifestRestat() const; |
| bool SupportsMultilineDepfile() const; |
| |
| std::string NinjaOutputPath(std::string const& path) const; |
| bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); } |
| void StripNinjaOutputPathPrefixAsSuffix(std::string& path); |
| |
| bool WriteDyndepFile(std::string const& dir_top_src, |
| std::string const& dir_top_bld, |
| std::string const& dir_cur_src, |
| std::string const& dir_cur_bld, |
| std::string const& arg_dd, |
| std::vector<std::string> const& arg_ddis, |
| std::string const& module_dir, |
| std::vector<std::string> const& linked_target_dirs, |
| std::string const& arg_lang); |
| |
| protected: |
| void Generate() override; |
| |
| bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const override { return true; } |
| |
| private: |
| std::string GetEditCacheCommand() const override; |
| bool FindMakeProgram(cmMakefile* mf) override; |
| void CheckNinjaFeatures(); |
| bool CheckLanguages(std::vector<std::string> const& languages, |
| cmMakefile* mf) const override; |
| bool CheckFortran(cmMakefile* mf) const; |
| |
| bool OpenBuildFileStream(); |
| void CloseBuildFileStream(); |
| |
| void CloseCompileCommandsStream(); |
| |
| bool OpenRulesFileStream(); |
| void CloseRulesFileStream(); |
| |
| /// Write the common disclaimer text at the top of each build file. |
| void WriteDisclaimer(std::ostream& os); |
| |
| void WriteAssumedSourceDependencies(); |
| |
| void WriteTargetAliases(std::ostream& os); |
| void WriteFolderTargets(std::ostream& os); |
| void WriteUnknownExplicitDependencies(std::ostream& os); |
| |
| void WriteBuiltinTargets(std::ostream& os); |
| void WriteTargetDefault(std::ostream& os); |
| void WriteTargetRebuildManifest(std::ostream& os); |
| bool WriteTargetCleanAdditional(std::ostream& os); |
| void WriteTargetClean(std::ostream& os); |
| void WriteTargetHelp(std::ostream& os); |
| |
| void ComputeTargetDependsClosure( |
| cmGeneratorTarget const* target, |
| std::set<cmGeneratorTarget const*>& depends); |
| |
| std::string CMakeCmd() const; |
| std::string NinjaCmd() const; |
| |
| /// The file containing the build statement. (the relationship of the |
| /// compilation DAG). |
| std::unique_ptr<cmGeneratedFileStream> BuildFileStream; |
| /// The file containing the rule statements. (The action attached to each |
| /// edge of the compilation DAG). |
| std::unique_ptr<cmGeneratedFileStream> RulesFileStream; |
| std::unique_ptr<cmGeneratedFileStream> CompileCommandsStream; |
| |
| /// The set of rules added to the generated build system. |
| std::unordered_set<std::string> Rules; |
| |
| /// Length of rule command, used by rsp file evaluation |
| std::unordered_map<std::string, int> RuleCmdLength; |
| |
| bool UsingGCCOnWindows = false; |
| |
| /// The set of custom commands we have seen. |
| std::set<cmCustomCommand const*> CustomCommands; |
| |
| /// The set of custom command outputs we have seen. |
| std::set<std::string> CustomCommandOutputs; |
| |
| /// Whether we are collecting known build outputs and needed |
| /// dependencies to determine unknown dependencies. |
| bool ComputingUnknownDependencies = false; |
| cmPolicies::PolicyStatus PolicyCMP0058 = cmPolicies::WARN; |
| |
| /// The combined explicit dependencies of custom build commands |
| std::set<std::string> CombinedCustomCommandExplicitDependencies; |
| |
| /// When combined with CombinedCustomCommandExplicitDependencies it allows |
| /// us to detect the set of explicit dependencies that have |
| std::set<std::string> CombinedBuildOutputs; |
| |
| /// The mapping from source file to assumed dependencies. |
| std::map<std::string, std::set<std::string>> AssumedSourceDependencies; |
| |
| using TargetAliasMap = std::map<std::string, cmGeneratorTarget*>; |
| TargetAliasMap TargetAliases; |
| |
| std::map<cmGeneratorTarget const*, cmNinjaOuts> TargetDependsClosures; |
| |
| /// the local cache for calls to ConvertToNinjaPath |
| mutable std::unordered_map<std::string, std::string> ConvertToNinjaPathCache; |
| |
| std::string NinjaCommand; |
| std::string NinjaVersion; |
| bool NinjaSupportsConsolePool = false; |
| bool NinjaSupportsImplicitOuts = false; |
| bool NinjaSupportsManifestRestat = false; |
| bool NinjaSupportsMultilineDepfile = false; |
| bool NinjaSupportsDyndeps = false; |
| |
| private: |
| void InitOutputPathPrefix(); |
| |
| std::string OutputPathPrefix; |
| std::string TargetAll; |
| std::string CMakeCacheFile; |
| std::set<std::string> AdditionalCleanFiles; |
| }; |
| |
| #endif // ! cmGlobalNinjaGenerator_h |