diff options
Diffstat (limited to 'Source/cmGlobalNinjaGenerator.h')
-rw-r--r-- | Source/cmGlobalNinjaGenerator.h | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h new file mode 100644 index 0000000..69ec6ca --- /dev/null +++ b/Source/cmGlobalNinjaGenerator.h @@ -0,0 +1,418 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmGlobalNinjaGenerator_h +#define cmGlobalNinjaGenerator_h + +#include "cmGlobalCommonGenerator.h" + +#include "cmGlobalGeneratorFactory.h" +#include "cmNinjaTypes.h" + +//#define NINJA_GEN_VERBOSE_FILES + +class cmLocalGenerator; +class cmGeneratedFileStream; +class cmGeneratorTarget; + +/** + * \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 don't care about generating a clean target since Ninja already have + * a clean tool. + * - 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; + + /// 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 EncodeIdent(const std::string& ident, std::ostream& vars); + static std::string EncodeLiteral(const std::string& lit); + std::string EncodePath(const std::string& path); + static std::string EncodeDepfileSpace(const std::string& path); + + /** + * 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; } + + /** + * Write a build statement to @a os with the @a comment using + * the @a rule the list of @a outputs files and inputs. + * It also writes the variables bound to this build statement. + * @warning no escaping of any kind is done here. + */ + void WriteBuild(std::ostream& os, const std::string& comment, + const std::string& rule, const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps, + const cmNinjaDeps& orderOnlyDeps, + const cmNinjaVars& variables, + const std::string& rspfile = std::string(), + int cmdLineLimit = 0, bool* usedResponseFile = CM_NULLPTR); + + /** + * Helper to write a build statement with the special 'phony' rule. + */ + void WritePhonyBuild(std::ostream& os, const std::string& comment, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps = cmNinjaDeps(), + const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(), + const cmNinjaVars& variables = cmNinjaVars()); + + void WriteCustomCommandBuild(const std::string& command, + const std::string& description, + const std::string& comment, bool uses_terminal, + bool restat, const cmNinjaDeps& outputs, + const cmNinjaDeps& deps = cmNinjaDeps(), + const cmNinjaDeps& orderOnly = cmNinjaDeps()); + void WriteMacOSXContentBuild(const std::string& input, + const std::string& output); + + /** + * Write a rule statement named @a name to @a os with the @a comment, + * the mandatory @a command, the @a depfile and the @a description. + * It also writes the variables bound to this rule statement. + * @warning no escaping of any kind is done here. + */ + static void WriteRule(std::ostream& os, const std::string& name, + const std::string& command, + const std::string& description, + const std::string& comment, const std::string& depfile, + const std::string& deptype, const std::string& rspfile, + const std::string& rspcontent, + const std::string& restat, bool generator); + + /** + * 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>(); + } + + ~cmGlobalNinjaGenerator() CM_OVERRIDE {} + + cmLocalGenerator* CreateLocalGenerator(cmMakefile* mf) CM_OVERRIDE; + + std::string GetName() const CM_OVERRIDE + { + return cmGlobalNinjaGenerator::GetActualName(); + } + + static std::string GetActualName() { return "Ninja"; } + + static void GetDocumentation(cmDocumentationEntry& entry); + + void EnableLanguage(std::vector<std::string> const& languages, + cmMakefile* mf, bool optional) CM_OVERRIDE; + + void GenerateBuildCommand(std::vector<std::string>& makeCommand, + const std::string& makeProgram, + const std::string& projectName, + const std::string& projectDir, + const std::string& targetName, + const std::string& config, bool fast, bool verbose, + std::vector<std::string> const& makeOptions = + std::vector<std::string>()) CM_OVERRIDE; + + // Setup target names + const char* GetAllTargetName() const CM_OVERRIDE { return "all"; } + const char* GetInstallTargetName() const CM_OVERRIDE { return "install"; } + const char* GetInstallLocalTargetName() const CM_OVERRIDE + { + return "install/local"; + } + const char* GetInstallStripTargetName() const CM_OVERRIDE + { + return "install/strip"; + } + const char* GetTestTargetName() const CM_OVERRIDE { return "test"; } + const char* GetPackageTargetName() const CM_OVERRIDE { return "package"; } + const char* GetPackageSourceTargetName() const CM_OVERRIDE + { + return "package_source"; + } + const char* GetEditCacheTargetName() const CM_OVERRIDE + { + return "edit_cache"; + } + const char* GetRebuildCacheTargetName() const CM_OVERRIDE + { + return "rebuild_cache"; + } + const char* GetCleanTargetName() const CM_OVERRIDE { return "clean"; } + + cmGeneratedFileStream* GetBuildFileStream() const + { + return this->BuildFileStream; + } + + cmGeneratedFileStream* GetRulesFileStream() const + { + return this->RulesFileStream; + } + + std::string ConvertToNinjaPath(const std::string& path); + std::string ConvertToNinjaFolderRule(const std::string& path); + + struct MapToNinjaPathImpl + { + cmGlobalNinjaGenerator* GG; + MapToNinjaPathImpl(cmGlobalNinjaGenerator* gg) + : GG(gg) + { + } + std::string operator()(std::string const& path) + { + return this->GG->ConvertToNinjaPath(path); + } + }; + MapToNinjaPathImpl MapToNinjaPath() { return MapToNinjaPathImpl(this); } + + 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(const std::string& name, const std::string& command, + const std::string& description, const std::string& comment, + const std::string& depfile, const std::string& deptype, + const std::string& rspfile, const std::string& rspcontent, + const std::string& restat, bool generator); + + 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); + void AppendTargetDepends(cmGeneratorTarget const* target, + cmNinjaDeps& outputs); + void AddDependencyToAll(cmGeneratorTarget* target); + void AddDependencyToAll(const std::string& input); + + const std::vector<cmLocalGenerator*>& GetLocalGenerators() const + { + return LocalGenerators; + } + + bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) + { + return cmGlobalGenerator::IsExcluded(root, target); + } + + int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; } + + void AddTargetAlias(const std::string& alias, cmGeneratorTarget* target); + + void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const CM_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"; } + bool SupportsConsolePool() const; + + std::string NinjaOutputPath(std::string const& path); + bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); } + void StripNinjaOutputPathPrefixAsSuffix(std::string& path); + +protected: + void Generate() CM_OVERRIDE; + + bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const CM_OVERRIDE { return true; } + +private: + std::string GetEditCacheCommand() const CM_OVERRIDE; + void FindMakeProgram(cmMakefile* mf) CM_OVERRIDE; + + void OpenBuildFileStream(); + void CloseBuildFileStream(); + + void CloseCompileCommandsStream(); + + void 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 WriteTargetAll(std::ostream& os); + void WriteTargetRebuildManifest(std::ostream& os); + void WriteTargetClean(std::ostream& os); + void WriteTargetHelp(std::ostream& os); + + std::string ninjaCmd() const; + + /// The file containing the build statement. (the relationship of the + /// compilation DAG). + cmGeneratedFileStream* BuildFileStream; + /// The file containing the rule statements. (The action attached to each + /// edge of the compilation DAG). + cmGeneratedFileStream* RulesFileStream; + cmGeneratedFileStream* CompileCommandsStream; + + /// The type used to store the set of rules added to the generated build + /// system. + typedef std::set<std::string> RulesSetType; + + /// The set of rules added to the generated build system. + RulesSetType Rules; + + /// Length of rule command, used by rsp file evaluation + std::map<std::string, int> RuleCmdLength; + + /// The set of dependencies to add to the "all" target. + cmNinjaDeps AllDependencies; + + bool UsingGCCOnWindows; + + /// 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; + cmPolicies::PolicyStatus PolicyCMP0058; + + /// 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; + + typedef std::map<std::string, cmGeneratorTarget*> TargetAliasMap; + TargetAliasMap TargetAliases; + + std::string NinjaCommand; + std::string NinjaVersion; + +private: + void InitOutputPathPrefix(); + + std::string OutputPathPrefix; + std::string TargetAll; + std::string CMakeCacheFile; +}; + +#endif // ! cmGlobalNinjaGenerator_h |