1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2011 Peter Collingbourne <peter@pcc.me.uk>
4 Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com>
6 Distributed under the OSI-approved BSD License (the "License");
7 see accompanying file Copyright.txt for details.
9 This software is distributed WITHOUT ANY WARRANTY; without even the
10 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 See the License for more information.
12 ============================================================================*/
13 #ifndef cmGlobalNinjaGenerator_h
14 # define cmGlobalNinjaGenerator_h
16 # include "cmGlobalGenerator.h"
17 # include "cmGlobalGeneratorFactory.h"
18 # include "cmNinjaTypes.h"
20 //#define NINJA_GEN_VERBOSE_FILES
22 class cmLocalGenerator;
23 class cmGeneratedFileStream;
24 class cmGeneratorTarget;
27 * \class cmGlobalNinjaGenerator
28 * \brief Write a build.ninja file.
30 * The main differences between this generator and the UnixMakefile
31 * generator family are:
32 * - We don't care about VERBOSE variable or RULE_MESSAGES property since
33 * it is handle by Ninja's -v option.
34 * - We don't care about computing any progress status since Ninja manages
36 * - We don't care about generating a clean target since Ninja already have
38 * - We generate one build.ninja and one rules.ninja per project.
39 * - We try to minimize the number of generated rules: one per target and
41 * - We use Ninja special variable $in and $out to produce nice output.
42 * - We extensively use Ninja variable overloading system to minimize the
43 * number of generated rules.
45 class cmGlobalNinjaGenerator : public cmGlobalGenerator
48 /// The default name of Ninja's build file. Typically: build.ninja.
49 static const char* NINJA_BUILD_FILE;
51 /// The default name of Ninja's rules file. Typically: rules.ninja.
52 /// It is included in the main build.ninja file.
53 static const char* NINJA_RULES_FILE;
55 /// The indentation string used when generating Ninja's build file.
56 static const char* INDENT;
58 /// Write @a count times INDENT level to output stream @a os.
59 static void Indent(std::ostream& os, int count);
61 /// Write a divider in the given output stream @a os.
62 static void WriteDivider(std::ostream& os);
64 static std::string EncodeIdent(const std::string &ident, std::ostream &vars);
65 static std::string EncodeLiteral(const std::string &lit);
66 static std::string EncodePath(const std::string &path);
69 * Write the given @a comment to the output stream @a os. It
70 * handles new line character properly.
72 static void WriteComment(std::ostream& os, const std::string& comment);
75 * Write a build statement to @a os with the @a comment using
76 * the @a rule the list of @a outputs files and inputs.
77 * It also writes the variables bound to this build statement.
78 * @warning no escaping of any kind is done here.
80 static void WriteBuild(std::ostream& os,
81 const std::string& comment,
82 const std::string& rule,
83 const cmNinjaDeps& outputs,
84 const cmNinjaDeps& explicitDeps,
85 const cmNinjaDeps& implicitDeps,
86 const cmNinjaDeps& orderOnlyDeps,
87 const cmNinjaVars& variables,
88 const std::string& rspfile = std::string(),
89 int cmdLineLimit = -1);
92 * Helper to write a build statement with the special 'phony' rule.
94 static void WritePhonyBuild(std::ostream& os,
95 const std::string& comment,
96 const cmNinjaDeps& outputs,
97 const cmNinjaDeps& explicitDeps,
98 const cmNinjaDeps& implicitDeps = cmNinjaDeps(),
99 const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(),
100 const cmNinjaVars& variables = cmNinjaVars());
102 void WriteCustomCommandBuild(const std::string& command,
103 const std::string& description,
104 const std::string& comment,
105 const cmNinjaDeps& outputs,
106 const cmNinjaDeps& deps = cmNinjaDeps(),
107 const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps());
108 void WriteMacOSXContentBuild(const std::string& input,
109 const std::string& output);
112 * Write a rule statement named @a name to @a os with the @a comment,
113 * the mandatory @a command, the @a depfile and the @a description.
114 * It also writes the variables bound to this rule statement.
115 * @warning no escaping of any kind is done here.
117 static void WriteRule(std::ostream& os,
118 const std::string& name,
119 const std::string& command,
120 const std::string& description,
121 const std::string& comment,
122 const std::string& depfile,
123 const std::string& rspfile,
124 const std::string& rspcontent,
129 * Write a variable named @a name to @a os with value @a value and an
130 * optional @a comment. An @a indent level can be specified.
131 * @warning no escaping of any kind is done here.
133 static void WriteVariable(std::ostream& os,
134 const std::string& name,
135 const std::string& value,
136 const std::string& comment = "",
140 * Write an include statement including @a filename with an optional
141 * @a comment to the @a os stream.
143 static void WriteInclude(std::ostream& os,
144 const std::string& filename,
145 const std::string& comment = "");
148 * Write a default target statement specifying @a targets as
149 * the default targets.
151 static void WriteDefault(std::ostream& os,
152 const cmNinjaDeps& targets,
153 const std::string& comment = "");
156 static bool IsMinGW() { return UsingMinGW; }
160 /// Default constructor.
161 cmGlobalNinjaGenerator();
163 /// Convenience method for creating an instance of this class.
164 static cmGlobalGeneratorFactory* NewFactory() {
165 return new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaGenerator>(); }
168 virtual ~cmGlobalNinjaGenerator() { }
170 /// Overloaded methods. @see cmGlobalGenerator::CreateLocalGenerator()
171 virtual cmLocalGenerator* CreateLocalGenerator();
173 /// Overloaded methods. @see cmGlobalGenerator::GetName().
174 virtual const char* GetName() const {
175 return cmGlobalNinjaGenerator::GetActualName(); }
177 /// @return the name of this generator.
178 static const char* GetActualName() { return "Ninja"; }
180 /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
181 static void GetDocumentation(cmDocumentationEntry& entry);
183 /// Overloaded methods. @see cmGlobalGenerator::Generate()
184 virtual void Generate();
186 /// Overloaded methods. @see cmGlobalGenerator::EnableLanguage()
187 virtual void EnableLanguage(std::vector<std::string>const& languages,
191 /// Overloaded methods. @see cmGlobalGenerator::GenerateBuildCommand()
192 virtual std::string GenerateBuildCommand(const char* makeProgram,
193 const char* projectName,
194 const char* additionalOptions,
195 const char* targetName,
200 // Setup target names
201 virtual const char* GetAllTargetName() const { return "all"; }
202 virtual const char* GetInstallTargetName() const { return "install"; }
203 virtual const char* GetInstallLocalTargetName() const {
204 return "install/local";
206 virtual const char* GetInstallStripTargetName() const {
207 return "install/strip";
209 virtual const char* GetTestTargetName() const { return "test"; }
210 virtual const char* GetPackageTargetName() const { return "package"; }
211 virtual const char* GetPackageSourceTargetName() const {
212 return "package_source";
214 virtual const char* GetEditCacheTargetName() const {
217 virtual const char* GetRebuildCacheTargetName() const {
218 return "rebuild_cache";
220 virtual const char* GetCleanTargetName() const { return "clean"; }
223 cmGeneratedFileStream* GetBuildFileStream() const {
224 return this->BuildFileStream; }
226 cmGeneratedFileStream* GetRulesFileStream() const {
227 return this->RulesFileStream; }
229 void AddCXXCompileCommand(const std::string &commandLine,
230 const std::string &sourceFile);
233 * Add a rule to the generated build system.
234 * Call WriteRule() behind the scene but perform some check before like:
235 * - Do not add twice the same rule.
237 void AddRule(const std::string& name,
238 const std::string& command,
239 const std::string& description,
240 const std::string& comment,
241 const std::string& depfile = "",
242 const std::string& rspfile = "",
243 const std::string& rspcontent = "",
245 bool generator = false);
247 bool HasRule(const std::string& name);
249 void AddCustomCommandRule();
250 void AddMacOSXContentRule();
252 bool HasCustomCommandOutput(const std::string &output) {
253 return this->CustomCommandOutputs.find(output) !=
254 this->CustomCommandOutputs.end();
257 /// Called when we have seen the given custom command. Returns true
258 /// if we has seen it before.
259 bool SeenCustomCommand(cmCustomCommand const *cc) {
260 return !this->CustomCommands.insert(cc).second;
263 /// Called when we have seen the given custom command output.
264 void SeenCustomCommandOutput(const std::string &output) {
265 this->CustomCommandOutputs.insert(output);
266 // We don't need the assumed dependencies anymore, because we have
268 this->AssumedSourceDependencies.erase(output);
271 void AddAssumedSourceDependencies(const std::string &source,
272 const cmNinjaDeps &deps) {
273 std::set<std::string> &ASD = this->AssumedSourceDependencies[source];
274 // Because we may see the same source file multiple times (same source
275 // specified in multiple targets), compute the union of any assumed
277 ASD.insert(deps.begin(), deps.end());
280 void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs);
281 void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs);
282 void AddDependencyToAll(cmTarget* target);
283 void AddDependencyToAll(const std::string& input);
285 const std::vector<cmLocalGenerator*>& GetLocalGenerators() const {
286 return LocalGenerators; }
288 bool IsExcluded(cmLocalGenerator* root, cmTarget& target) {
289 return cmGlobalGenerator::IsExcluded(root, target); }
291 int GetRuleCmdLength(const std::string& name) {
292 return RuleCmdLength[name]; }
294 void AddTargetAlias(const std::string& alias, cmTarget* target);
299 /// Overloaded methods.
300 /// @see cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
301 virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { return true; }
306 /// @see cmGlobalGenerator::ComputeTargetObjects
307 virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
309 void OpenBuildFileStream();
310 void CloseBuildFileStream();
312 void CloseCompileCommandsStream();
314 void OpenRulesFileStream();
315 void CloseRulesFileStream();
317 /// Write the common disclaimer text at the top of each build file.
318 void WriteDisclaimer(std::ostream& os);
320 void WriteAssumedSourceDependencies();
322 void WriteTargetAliases(std::ostream& os);
324 void WriteBuiltinTargets(std::ostream& os);
325 void WriteTargetAll(std::ostream& os);
326 void WriteTargetRebuildManifest(std::ostream& os);
327 void WriteTargetClean(std::ostream& os);
328 void WriteTargetHelp(std::ostream& os);
330 std::string ninjaCmd() const;
333 /// The file containing the build statement. (the relation ship of the
334 /// compilation DAG).
335 cmGeneratedFileStream* BuildFileStream;
336 /// The file containing the rule statements. (The action attached to each
337 /// edge of the compilation DAG).
338 cmGeneratedFileStream* RulesFileStream;
339 cmGeneratedFileStream* CompileCommandsStream;
341 /// The type used to store the set of rules added to the generated build
343 typedef std::set<std::string> RulesSetType;
345 /// The set of rules added to the generated build system.
348 /// Length of rule command, used by rsp file evaluation
349 std::map<std::string, int> RuleCmdLength;
351 /// The set of dependencies to add to the "all" target.
352 cmNinjaDeps AllDependencies;
354 /// The set of custom commands we have seen.
355 std::set<cmCustomCommand const*> CustomCommands;
357 /// The set of custom command outputs we have seen.
358 std::set<std::string> CustomCommandOutputs;
360 /// The mapping from source file to assumed dependencies.
361 std::map<std::string, std::set<std::string> > AssumedSourceDependencies;
363 typedef std::map<std::string, cmTarget*> TargetAliasMap;
364 TargetAliasMap TargetAliases;
366 static cmLocalGenerator* LocalGenerator;
368 static bool UsingMinGW;
372 #endif // ! cmGlobalNinjaGenerator_h