packaging: Initial packaging
[platform/upstream/cmake.git] / Source / cmGlobalNinjaGenerator.cxx
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>
5
6   Distributed under the OSI-approved BSD License (the "License");
7   see accompanying file Copyright.txt for details.
8
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 #include "cmGeneratedFileStream.h"
14 #include "cmGeneratorExpressionEvaluationFile.h"
15 #include "cmGeneratorTarget.h"
16 #include "cmGlobalNinjaGenerator.h"
17 #include "cmLocalNinjaGenerator.h"
18 #include "cmMakefile.h"
19 #include "cmVersion.h"
20
21 #include <algorithm>
22
23 const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
24 const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.ninja";
25 const char* cmGlobalNinjaGenerator::INDENT = "  ";
26
27 void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count)
28 {
29   for(int i = 0; i < count; ++i)
30     os << cmGlobalNinjaGenerator::INDENT;
31 }
32
33 void cmGlobalNinjaGenerator::WriteDivider(std::ostream& os)
34 {
35   os
36     << "# ======================================"
37     << "=======================================\n";
38 }
39
40 void cmGlobalNinjaGenerator::WriteComment(std::ostream& os,
41                                           const std::string& comment)
42 {
43   if (comment.empty())
44     return;
45
46   std::string replace = comment;
47   std::string::size_type lpos = 0;
48   std::string::size_type rpos;
49   os << "\n#############################################\n";
50   while((rpos = replace.find('\n', lpos)) != std::string::npos)
51     {
52     os << "# " << replace.substr(lpos, rpos - lpos) << "\n";
53     lpos = rpos + 1;
54     }
55   os << "# " << replace.substr(lpos) << "\n\n";
56 }
57
58 static bool IsIdentChar(char c)
59 {
60   return
61     ('a' <= c && c <= 'z') ||
62     ('+' <= c && c <= '9') ||  // +,-./ and numbers
63     ('A' <= c && c <= 'Z') ||
64     (c == '_') || (c == '$') || (c == '\\') ||
65     (c == ' ') || (c == ':');
66 }
67
68 std::string cmGlobalNinjaGenerator::EncodeIdent(const std::string &ident,
69                                                 std::ostream &vars) {
70   if (std::find_if(ident.begin(), ident.end(),
71                    std::not1(std::ptr_fun(IsIdentChar))) != ident.end()) {
72     static unsigned VarNum = 0;
73     cmOStringStream names;
74     names << "ident" << VarNum++;
75     vars << names.str() << " = " << ident << "\n";
76     return "$" + names.str();
77   } else {
78     std::string result = ident;
79     cmSystemTools::ReplaceString(result, " ", "$ ");
80     cmSystemTools::ReplaceString(result, ":", "$:");
81     return result;
82   }
83 }
84
85 std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string &lit)
86 {
87   std::string result = lit;
88   cmSystemTools::ReplaceString(result, "$", "$$");
89   cmSystemTools::ReplaceString(result, "\n", "$\n");
90   return result;
91 }
92
93 std::string cmGlobalNinjaGenerator::EncodePath(const std::string &path)
94 {
95   std::string result = path;
96 #ifdef _WIN32
97   if(UsingMinGW)
98     cmSystemTools::ReplaceString(result, "\\", "/");
99   else
100     cmSystemTools::ReplaceString(result, "/", "\\");
101 #endif
102   return EncodeLiteral(result);
103 }
104
105 void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
106                                         const std::string& comment,
107                                         const std::string& rule,
108                                         const cmNinjaDeps& outputs,
109                                         const cmNinjaDeps& explicitDeps,
110                                         const cmNinjaDeps& implicitDeps,
111                                         const cmNinjaDeps& orderOnlyDeps,
112                                         const cmNinjaVars& variables,
113                                         const std::string& rspfile,
114                                         int cmdLineLimit)
115 {
116   // Make sure there is a rule.
117   if(rule.empty())
118     {
119     cmSystemTools::Error("No rule for WriteBuildStatement! called "
120                          "with comment: ",
121                          comment.c_str());
122     return;
123     }
124
125   // Make sure there is at least one output file.
126   if(outputs.empty())
127     {
128     cmSystemTools::Error("No output files for WriteBuildStatement! called "
129                          "with comment: ",
130                          comment.c_str());
131     return;
132     }
133
134   cmGlobalNinjaGenerator::WriteComment(os, comment);
135
136   cmOStringStream arguments;
137
138   // TODO: Better formatting for when there are multiple input/output files.
139
140   // Write explicit dependencies.
141   for(cmNinjaDeps::const_iterator i = explicitDeps.begin();
142       i != explicitDeps.end();
143       ++i)
144     {
145     arguments  << " " << EncodeIdent(EncodePath(*i), os);
146
147     //we need to track every dependency that comes in, since we are trying
148     //to find dependencies that are side effects of build commands
149     //
150     this->CombinedBuildExplicitDependencies.insert( EncodePath(*i) );
151     }
152
153   // Write implicit dependencies.
154   if(!implicitDeps.empty())
155     {
156     arguments << " |";
157     for(cmNinjaDeps::const_iterator i = implicitDeps.begin();
158         i != implicitDeps.end();
159         ++i)
160       arguments  << " " << EncodeIdent(EncodePath(*i), os);
161     }
162
163   // Write order-only dependencies.
164   if(!orderOnlyDeps.empty())
165     {
166     arguments << " ||";
167     for(cmNinjaDeps::const_iterator i = orderOnlyDeps.begin();
168         i != orderOnlyDeps.end();
169         ++i)
170       arguments  << " " << EncodeIdent(EncodePath(*i), os);
171     }
172
173   arguments << "\n";
174
175   cmOStringStream build;
176
177   // Write outputs files.
178   build << "build";
179   for(cmNinjaDeps::const_iterator i = outputs.begin();
180       i != outputs.end(); ++i)
181     {
182     build << " " << EncodeIdent(EncodePath(*i), os);
183     this->CombinedBuildOutputs.insert( EncodePath(*i) );
184     }
185   build << ":";
186
187   // Write the rule.
188   build << " " << rule;
189
190   // Write the variables bound to this build statement.
191   cmOStringStream variable_assignments;
192   for(cmNinjaVars::const_iterator i = variables.begin();
193       i != variables.end(); ++i)
194     cmGlobalNinjaGenerator::WriteVariable(variable_assignments,
195                                           i->first, i->second, "", 1);
196
197   // check if a response file rule should be used
198   std::string buildstr = build.str();
199   std::string assignments = variable_assignments.str();
200   const std::string args = arguments.str();
201   if (cmdLineLimit > 0
202       && args.size() + buildstr.size() + assignments.size()
203                                                     > (size_t) cmdLineLimit) {
204     buildstr += "_RSP_FILE";
205     variable_assignments.clear();
206     cmGlobalNinjaGenerator::WriteVariable(variable_assignments,
207                                           "RSP_FILE", rspfile, "", 1);
208     assignments += variable_assignments.str();
209   }
210
211   os << buildstr << args << assignments;
212 }
213
214 void cmGlobalNinjaGenerator::WritePhonyBuild(std::ostream& os,
215                                              const std::string& comment,
216                                              const cmNinjaDeps& outputs,
217                                              const cmNinjaDeps& explicitDeps,
218                                              const cmNinjaDeps& implicitDeps,
219                                              const cmNinjaDeps& orderOnlyDeps,
220                                              const cmNinjaVars& variables)
221 {
222   this->WriteBuild(os,
223                    comment,
224                    "phony",
225                    outputs,
226                    explicitDeps,
227                    implicitDeps,
228                    orderOnlyDeps,
229                    variables);
230 }
231
232 void cmGlobalNinjaGenerator::AddCustomCommandRule()
233 {
234   this->AddRule("CUSTOM_COMMAND",
235                 "$COMMAND",
236                 "$DESC",
237                 "Rule for running custom commands.",
238                 /*depfile*/ "",
239                 /*rspfile*/ "",
240                 /*rspcontent*/ "",
241                 /*restat*/ true);
242 }
243
244 void
245 cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command,
246                                                 const std::string& description,
247                                                 const std::string& comment,
248                                                 const cmNinjaDeps& outputs,
249                                                 const cmNinjaDeps& deps,
250                                               const cmNinjaDeps& orderOnlyDeps)
251 {
252   std::string cmd = command;
253 #ifdef _WIN32
254    if (cmd.empty())
255       // TODO Shouldn't an empty command be handled by ninja?
256       cmd = "cmd.exe /c";
257 #endif
258
259   this->AddCustomCommandRule();
260
261   cmNinjaVars vars;
262   vars["COMMAND"] = cmd;
263   vars["DESC"] = EncodeLiteral(description);
264
265   this->WriteBuild(*this->BuildFileStream,
266                    comment,
267                    "CUSTOM_COMMAND",
268                    outputs,
269                    deps,
270                    cmNinjaDeps(),
271                    orderOnlyDeps,
272                    vars);
273 }
274
275 void
276 cmGlobalNinjaGenerator::AddMacOSXContentRule()
277 {
278   cmLocalGenerator *lg = this->LocalGenerators[0];
279   cmMakefile* mfRoot = lg->GetMakefile();
280
281   cmOStringStream cmd;
282   cmd << lg->ConvertToOutputFormat(
283            mfRoot->GetRequiredDefinition("CMAKE_COMMAND"),
284            cmLocalGenerator::SHELL)
285       << " -E copy $in $out";
286
287   this->AddRule("COPY_OSX_CONTENT",
288                 cmd.str(),
289                 "Copying OS X Content $out",
290                 "Rule for copying OS X bundle content file."
291                 /*depfile*/ "",
292                 /*rspfile*/ "");
293 }
294
295 void
296 cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input,
297                                                 const std::string& output)
298 {
299   this->AddMacOSXContentRule();
300
301   cmNinjaDeps outputs;
302   outputs.push_back(output);
303   cmNinjaDeps deps;
304   deps.push_back(input);
305   cmNinjaVars vars;
306
307   this->WriteBuild(*this->BuildFileStream,
308                    "",
309                    "COPY_OSX_CONTENT",
310                    outputs,
311                    deps,
312                    cmNinjaDeps(),
313                    cmNinjaDeps(),
314                    cmNinjaVars());
315 }
316
317 void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
318                                        const std::string& name,
319                                        const std::string& command,
320                                        const std::string& description,
321                                        const std::string& comment,
322                                        const std::string& depfile,
323                                        const std::string& rspfile,
324                                        const std::string& rspcontent,
325                                        bool restat,
326                                        bool generator)
327 {
328   // Make sure the rule has a name.
329   if(name.empty())
330     {
331     cmSystemTools::Error("No name given for WriteRuleStatement! called "
332                          "with comment: ",
333                          comment.c_str());
334     return;
335     }
336
337   // Make sure a command is given.
338   if(command.empty())
339     {
340     cmSystemTools::Error("No command given for WriteRuleStatement! called "
341                          "with comment: ",
342                          comment.c_str());
343     return;
344     }
345
346   cmGlobalNinjaGenerator::WriteComment(os, comment);
347
348   // Write the rule.
349   os << "rule " << name << "\n";
350
351   // Write the depfile if any.
352   if(!depfile.empty())
353     {
354     cmGlobalNinjaGenerator::Indent(os, 1);
355     os << "depfile = " << depfile << "\n";
356     }
357
358   // Write the command.
359   cmGlobalNinjaGenerator::Indent(os, 1);
360   os << "command = " << command << "\n";
361
362   // Write the description if any.
363   if(!description.empty())
364     {
365     cmGlobalNinjaGenerator::Indent(os, 1);
366     os << "description = " << description << "\n";
367     }
368
369   if(!rspfile.empty())
370     {
371     if (rspcontent.empty())
372       {
373       cmSystemTools::Error("No rspfile_content given!", comment.c_str());
374       return;
375       }
376     cmGlobalNinjaGenerator::Indent(os, 1);
377     os << "rspfile = " << rspfile << "\n";
378     cmGlobalNinjaGenerator::Indent(os, 1);
379     os << "rspfile_content = " << rspcontent << "\n";
380     }
381
382   if(restat)
383     {
384     cmGlobalNinjaGenerator::Indent(os, 1);
385     os << "restat = 1\n";
386     }
387
388   if(generator)
389     {
390     cmGlobalNinjaGenerator::Indent(os, 1);
391     os << "generator = 1\n";
392     }
393
394   os << "\n";
395 }
396
397 void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
398                                            const std::string& name,
399                                            const std::string& value,
400                                            const std::string& comment,
401                                            int indent)
402 {
403   // Make sure we have a name.
404   if(name.empty())
405     {
406     cmSystemTools::Error("No name given for WriteVariable! called "
407                          "with comment: ",
408                          comment.c_str());
409     return;
410     }
411
412   // Do not add a variable if the value is empty.
413   std::string val = cmSystemTools::TrimWhitespace(value);
414   if(val.empty())
415     {
416     return;
417     }
418
419   cmGlobalNinjaGenerator::WriteComment(os, comment);
420   cmGlobalNinjaGenerator::Indent(os, indent);
421   os << name << " = " << val << "\n";
422 }
423
424 void cmGlobalNinjaGenerator::WriteInclude(std::ostream& os,
425                                           const std::string& filename,
426                                           const std::string& comment)
427 {
428   cmGlobalNinjaGenerator::WriteComment(os, comment);
429   os << "include " << filename << "\n";
430 }
431
432 void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os,
433                                           const cmNinjaDeps& targets,
434                                           const std::string& comment)
435 {
436   cmGlobalNinjaGenerator::WriteComment(os, comment);
437   os << "default";
438   for(cmNinjaDeps::const_iterator i = targets.begin(); i != targets.end(); ++i)
439     os << " " << *i;
440   os << "\n";
441 }
442
443
444 cmGlobalNinjaGenerator::cmGlobalNinjaGenerator()
445   : cmGlobalGenerator()
446   , BuildFileStream(0)
447   , RulesFileStream(0)
448   , CompileCommandsStream(0)
449   , Rules()
450   , AllDependencies()
451 {
452   // // Ninja is not ported to non-Unix OS yet.
453   // this->ForceUnixPaths = true;
454   this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake";
455 }
456
457
458 //----------------------------------------------------------------------------
459 // Virtual public methods.
460
461 cmLocalGenerator* cmGlobalNinjaGenerator::CreateLocalGenerator()
462 {
463   cmLocalGenerator* lg = new cmLocalNinjaGenerator;
464   lg->SetGlobalGenerator(this);
465   return lg;
466 }
467
468 void cmGlobalNinjaGenerator
469 ::GetDocumentation(cmDocumentationEntry& entry)
470 {
471   entry.Name = cmGlobalNinjaGenerator::GetActualName();
472   entry.Brief = "Generates build.ninja files (experimental).";
473   entry.Full =
474     "A build.ninja file is generated into the build tree. Recent "
475     "versions of the ninja program can build the project through the "
476     "\"all\" target.  An \"install\" target is also provided.";
477 }
478
479 // Implemented in all cmGlobaleGenerator sub-classes.
480 // Used in:
481 //   Source/cmLocalGenerator.cxx
482 //   Source/cmake.cxx
483 void cmGlobalNinjaGenerator::Generate()
484 {
485   this->OpenBuildFileStream();
486   this->OpenRulesFileStream();
487
488   this->cmGlobalGenerator::Generate();
489
490   this->WriteAssumedSourceDependencies();
491   this->WriteTargetAliases(*this->BuildFileStream);
492   this->WriteUnknownExplicitDependencies(*this->BuildFileStream);
493   this->WriteBuiltinTargets(*this->BuildFileStream);
494
495   if (cmSystemTools::GetErrorOccuredFlag()) {
496     this->RulesFileStream->setstate(std::ios_base::failbit);
497     this->BuildFileStream->setstate(std::ios_base::failbit);
498   }
499
500   this->CloseCompileCommandsStream();
501   this->CloseRulesFileStream();
502   this->CloseBuildFileStream();
503 }
504
505 // Implemented in all cmGlobaleGenerator sub-classes.
506 // Used in:
507 //   Source/cmMakefile.cxx:
508 void cmGlobalNinjaGenerator
509 ::EnableLanguage(std::vector<std::string>const& langs,
510                  cmMakefile* makefile,
511                  bool optional)
512 {
513   if (makefile->IsOn("CMAKE_COMPILER_IS_MINGW"))
514     {
515     UsingMinGW = true;
516     this->EnableMinGWLanguage(makefile);
517     }
518   if (std::find(langs.begin(), langs.end(), "Fortran") != langs.end())
519     {
520     cmSystemTools::Error("The Ninja generator does not support Fortran yet.");
521     }
522   this->cmGlobalGenerator::EnableLanguage(langs, makefile, optional);
523 }
524
525 bool cmGlobalNinjaGenerator::UsingMinGW = false;
526
527 // Implemented by:
528 //   cmGlobalUnixMakefileGenerator3
529 //   cmGlobalVisualStudio10Generator
530 //   cmGlobalVisualStudio6Generator
531 //   cmGlobalVisualStudio7Generator
532 //   cmGlobalXCodeGenerator
533 // Called by:
534 //   cmGlobalGenerator::Build()
535 std::string cmGlobalNinjaGenerator
536 ::GenerateBuildCommand(const char* makeProgram,
537                        const char* projectName,
538                        const char* projectDir,
539                        const char* additionalOptions,
540                        const char* targetName,
541                        const char* config,
542                        bool ignoreErrors,
543                        bool fast)
544 {
545   // Project name & dir and config are not used yet.
546   (void)projectName;
547   (void)projectDir;
548   (void)config;
549   // Ninja does not have -i equivalent option yet.
550   (void)ignoreErrors;
551   // We do not handle fast build yet.
552   (void)fast;
553
554   std::string makeCommand =
555     cmSystemTools::ConvertToUnixOutputPath(makeProgram);
556
557   if(additionalOptions)
558     {
559     makeCommand += " ";
560     makeCommand += additionalOptions;
561     }
562   if(targetName)
563     {
564     if(strcmp(targetName, "clean") == 0)
565       {
566       makeCommand += " -t clean";
567       }
568     else
569       {
570       makeCommand += " ";
571       makeCommand += targetName;
572       }
573     }
574
575   return makeCommand;
576 }
577
578 //----------------------------------------------------------------------------
579 // Non-virtual public methods.
580
581 void cmGlobalNinjaGenerator::AddRule(const std::string& name,
582                                      const std::string& command,
583                                      const std::string& description,
584                                      const std::string& comment,
585                                      const std::string& depfile,
586                                      const std::string& rspfile,
587                                      const std::string& rspcontent,
588                                      bool restat,
589                                      bool generator)
590 {
591   // Do not add the same rule twice.
592   if (this->HasRule(name))
593     {
594     return;
595     }
596
597   this->Rules.insert(name);
598   cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream,
599                                     name,
600                                     command,
601                                     description,
602                                     comment,
603                                     depfile,
604                                     rspfile,
605                                     rspcontent,
606                                     restat,
607                                     generator);
608
609   this->RuleCmdLength[name] = (int) command.size();
610 }
611
612 bool cmGlobalNinjaGenerator::HasRule(const std::string &name)
613 {
614   RulesSetType::const_iterator rule = this->Rules.find(name);
615   return (rule != this->Rules.end());
616 }
617
618 //----------------------------------------------------------------------------
619 // Private virtual overrides
620
621 // TODO: Refactor to combine with cmGlobalUnixMakefileGenerator3 impl.
622 void cmGlobalNinjaGenerator::ComputeTargetObjects(cmGeneratorTarget* gt) const
623 {
624   cmTarget* target = gt->Target;
625
626   // Compute full path to object file directory for this target.
627   std::string dir_max;
628   dir_max += gt->Makefile->GetCurrentOutputDirectory();
629   dir_max += "/";
630   dir_max += gt->LocalGenerator->GetTargetDirectory(*target);
631   dir_max += "/";
632   gt->ObjectDirectory = dir_max;
633
634   // Compute the name of each object file.
635   for(std::vector<cmSourceFile*>::iterator
636         si = gt->ObjectSources.begin();
637       si != gt->ObjectSources.end(); ++si)
638     {
639     cmSourceFile* sf = *si;
640     std::string objectName = gt->LocalGenerator
641       ->GetObjectFileNameWithoutTarget(*sf, dir_max);
642     gt->Objects[sf] = objectName;
643     }
644 }
645
646 //----------------------------------------------------------------------------
647 // Private methods
648
649 void cmGlobalNinjaGenerator::OpenBuildFileStream()
650 {
651   // Compute Ninja's build file path.
652   std::string buildFilePath =
653     this->GetCMakeInstance()->GetHomeOutputDirectory();
654   buildFilePath += "/";
655   buildFilePath += cmGlobalNinjaGenerator::NINJA_BUILD_FILE;
656
657   // Get a stream where to generate things.
658   if (!this->BuildFileStream)
659     {
660     this->BuildFileStream = new cmGeneratedFileStream(buildFilePath.c_str());
661     if (!this->BuildFileStream)
662       {
663       // An error message is generated by the constructor if it cannot
664       // open the file.
665       return;
666       }
667     }
668
669   // Write the do not edit header.
670   this->WriteDisclaimer(*this->BuildFileStream);
671
672   // Write a comment about this file.
673   *this->BuildFileStream
674     << "# This file contains all the build statements describing the\n"
675     << "# compilation DAG.\n\n"
676     ;
677 }
678
679 void cmGlobalNinjaGenerator::CloseBuildFileStream()
680 {
681   if (this->BuildFileStream)
682     {
683     delete this->BuildFileStream;
684     this->BuildFileStream = 0;
685     }
686   else
687     {
688     cmSystemTools::Error("Build file stream was not open.");
689    }
690 }
691
692 void cmGlobalNinjaGenerator::OpenRulesFileStream()
693 {
694   // Compute Ninja's build file path.
695   std::string rulesFilePath =
696     this->GetCMakeInstance()->GetHomeOutputDirectory();
697   rulesFilePath += "/";
698   rulesFilePath += cmGlobalNinjaGenerator::NINJA_RULES_FILE;
699
700   // Get a stream where to generate things.
701   if (!this->RulesFileStream)
702     {
703     this->RulesFileStream = new cmGeneratedFileStream(rulesFilePath.c_str());
704     if (!this->RulesFileStream)
705       {
706       // An error message is generated by the constructor if it cannot
707       // open the file.
708       return;
709       }
710     }
711
712   // Write the do not edit header.
713   this->WriteDisclaimer(*this->RulesFileStream);
714
715   // Write comment about this file.
716   *this->RulesFileStream
717     << "# This file contains all the rules used to get the outputs files\n"
718     << "# built from the input files.\n"
719     << "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
720     ;
721 }
722
723 void cmGlobalNinjaGenerator::CloseRulesFileStream()
724 {
725   if (this->RulesFileStream)
726     {
727     delete this->RulesFileStream;
728     this->RulesFileStream = 0;
729     }
730   else
731     {
732     cmSystemTools::Error("Rules file stream was not open.");
733    }
734 }
735
736 void cmGlobalNinjaGenerator::AddCXXCompileCommand(
737                                       const std::string &commandLine,
738                                       const std::string &sourceFile)
739 {
740   // Compute Ninja's build file path.
741   std::string buildFileDir =
742     this->GetCMakeInstance()->GetHomeOutputDirectory();
743   if (!this->CompileCommandsStream)
744     {
745     std::string buildFilePath = buildFileDir + "/compile_commands.json";
746
747     // Get a stream where to generate things.
748     this->CompileCommandsStream =
749       new cmGeneratedFileStream(buildFilePath.c_str());
750     *this->CompileCommandsStream << "[";
751     } else {
752     *this->CompileCommandsStream << "," << std::endl;
753     }
754
755   std::string sourceFileName = sourceFile;
756   if (!cmSystemTools::FileIsFullPath(sourceFileName.c_str()))
757     {
758     sourceFileName = cmSystemTools::CollapseFullPath(
759       sourceFileName.c_str(),
760       this->GetCMakeInstance()->GetHomeOutputDirectory());
761     }
762
763
764   *this->CompileCommandsStream << "\n{\n"
765      << "  \"directory\": \""
766      << cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n"
767      << "  \"command\": \""
768      << cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n"
769      << "  \"file\": \""
770      << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n"
771      << "}";
772 }
773
774 void cmGlobalNinjaGenerator::CloseCompileCommandsStream()
775 {
776   if (this->CompileCommandsStream)
777     {
778     *this->CompileCommandsStream << "\n]";
779     delete this->CompileCommandsStream;
780     this->CompileCommandsStream = 0;
781     }
782
783 }
784
785 void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os)
786 {
787   os
788     << "# CMAKE generated file: DO NOT EDIT!\n"
789     << "# Generated by \"" << this->GetName() << "\""
790     << " Generator, CMake Version "
791     << cmVersion::GetMajorVersion() << "."
792     << cmVersion::GetMinorVersion() << "\n\n";
793 }
794
795 void cmGlobalNinjaGenerator::AddDependencyToAll(cmTarget* target)
796 {
797   this->AppendTargetOutputs(target, this->AllDependencies);
798 }
799
800 void cmGlobalNinjaGenerator::AddDependencyToAll(const std::string& input)
801 {
802   this->AllDependencies.push_back(input);
803 }
804
805 void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
806 {
807   for (std::map<std::string, std::set<std::string> >::iterator
808        i = this->AssumedSourceDependencies.begin();
809        i != this->AssumedSourceDependencies.end(); ++i) {
810     cmNinjaDeps deps;
811     std::copy(i->second.begin(), i->second.end(), std::back_inserter(deps));
812     WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
813                             "Assume dependencies for generated source file.",
814                             cmNinjaDeps(1, i->first), deps);
815   }
816 }
817
818 void
819 cmGlobalNinjaGenerator
820 ::AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs)
821 {
822   const char* configName =
823     target->GetMakefile()->GetDefinition("CMAKE_BUILD_TYPE");
824   cmLocalNinjaGenerator *ng =
825     static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0]);
826
827   // for frameworks, we want the real name, not smple name
828   // frameworks always appear versioned, and the build.ninja
829   // will always attempt to manage symbolic links instead
830   // of letting cmOSXBundleGenerator do it.
831   bool realname = target->IsFrameworkOnApple();
832
833   switch (target->GetType()) {
834   case cmTarget::EXECUTABLE:
835   case cmTarget::SHARED_LIBRARY:
836   case cmTarget::STATIC_LIBRARY:
837   case cmTarget::MODULE_LIBRARY:
838     outputs.push_back(ng->ConvertToNinjaPath(
839       target->GetFullPath(configName, false, realname).c_str()));
840     break;
841
842   case cmTarget::OBJECT_LIBRARY:
843   case cmTarget::UTILITY: {
844     std::string path = ng->ConvertToNinjaPath(
845       target->GetMakefile()->GetStartOutputDirectory());
846     if (path.empty() || path == ".")
847       outputs.push_back(target->GetName());
848     else {
849       path += "/";
850       path += target->GetName();
851       outputs.push_back(path);
852     }
853     break;
854   }
855
856   case cmTarget::GLOBAL_TARGET:
857     // Always use the target in HOME instead of an unused duplicate in a
858     // subdirectory.
859     outputs.push_back(target->GetName());
860     break;
861
862   default:
863     return;
864   }
865 }
866
867 void
868 cmGlobalNinjaGenerator
869 ::AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs)
870 {
871   if (target->GetType() == cmTarget::GLOBAL_TARGET) {
872     // Global targets only depend on other utilities, which may not appear in
873     // the TargetDepends set (e.g. "all").
874     std::set<cmStdString> const& utils = target->GetUtilities();
875     std::copy(utils.begin(), utils.end(), std::back_inserter(outputs));
876   } else {
877     cmTargetDependSet const& targetDeps =
878       this->GetTargetDirectDepends(*target);
879     for (cmTargetDependSet::const_iterator i = targetDeps.begin();
880          i != targetDeps.end(); ++i) {
881       this->AppendTargetOutputs(*i, outputs);
882     }
883   }
884 }
885
886 void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
887                                             cmTarget* target) {
888   cmNinjaDeps outputs;
889   this->AppendTargetOutputs(target, outputs);
890   // Mark the target's outputs as ambiguous to ensure that no other target uses
891   // the output as an alias.
892   for (cmNinjaDeps::iterator i = outputs.begin(); i != outputs.end(); ++i)
893     TargetAliases[*i] = 0;
894
895   // Insert the alias into the map.  If the alias was already present in the
896   // map and referred to another target, mark it as ambiguous.
897   std::pair<TargetAliasMap::iterator, bool> newAlias =
898     TargetAliases.insert(std::make_pair(alias, target));
899   if (newAlias.second && newAlias.first->second != target)
900     newAlias.first->second = 0;
901 }
902
903 void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
904 {
905   cmGlobalNinjaGenerator::WriteDivider(os);
906   os << "# Target aliases.\n\n";
907
908   for (TargetAliasMap::const_iterator i = TargetAliases.begin();
909        i != TargetAliases.end(); ++i) {
910     // Don't write ambiguous aliases.
911     if (!i->second)
912       continue;
913
914     cmNinjaDeps deps;
915     this->AppendTargetOutputs(i->second, deps);
916
917     this->WritePhonyBuild(os,
918                           "",
919                           cmNinjaDeps(1, i->first),
920                           deps);
921   }
922 }
923
924 void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
925 {
926   //now write out the unknown explicit dependencies.
927
928   //union the configured files, evaluations files and the CombinedBuildOutputs,
929   //and then difference with CombinedExplicitDependencies to find the explicit
930   //dependencies that we have no rule for
931
932   cmGlobalNinjaGenerator::WriteDivider(os);
933   os << "# Unknown Build Time Dependencies.\n"
934      << "# Tell Ninja that they may appear as side effects of build rules\n"
935      << "# otherwise ordered by order-only dependencies.\n\n";
936
937   //get the list of files that cmake itself has generated as a
938   //product of configuration.
939   cmLocalNinjaGenerator *ng =
940     static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0]);
941
942   std::set<std::string> knownDependencies;
943   for (std::vector<cmLocalGenerator *>::const_iterator i =
944        this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i)
945     {
946     //get the vector of files created by this makefile and convert them
947     //to ninja paths, which are all relative in respect to the build directory
948     const std::vector<std::string>& files =
949                                     (*i)->GetMakefile()->GetOutputFiles();
950     typedef std::vector<std::string>::const_iterator vect_it;
951     for(vect_it j = files.begin(); j != files.end(); ++j)
952       {
953       knownDependencies.insert( ng->ConvertToNinjaPath( j->c_str() ) );
954       }
955     }
956
957   for(std::vector<cmGeneratorExpressionEvaluationFile*>::const_iterator
958       li = this->EvaluationFiles.begin();
959       li != this->EvaluationFiles.end();
960       ++li)
961     {
962     //get all the files created by generator expressions and convert them
963     //to ninja paths
964     std::vector<std::string> files = (*li)->GetFiles();
965     typedef std::vector<std::string>::const_iterator vect_it;
966     for(vect_it j = files.begin(); j != files.end(); ++j)
967       {
968       knownDependencies.insert( ng->ConvertToNinjaPath( j->c_str() ) );
969       }
970     }
971
972   for(TargetAliasMap::const_iterator i= this->TargetAliases.begin();
973       i != this->TargetAliases.end();
974       ++i)
975     {
976     knownDependencies.insert( ng->ConvertToNinjaPath(i->first.c_str()) );
977     }
978
979   //remove all source files we know will exist.
980   typedef std::map<std::string, std::set<std::string> >::const_iterator map_it;
981   for(map_it i = this->AssumedSourceDependencies.begin();
982       i != this->AssumedSourceDependencies.end();
983       ++i)
984     {
985     knownDependencies.insert( ng->ConvertToNinjaPath(i->first.c_str()) );
986     }
987
988   //insert outputs from all WirteBuild commands
989   for(std::set<std::string>::iterator i = this->CombinedBuildOutputs.begin();
990       i != this->CombinedBuildOutputs.end(); ++i)
991     {
992     //these paths have already be encoded when added to CombinedBuildOutputs
993     knownDependencies.insert(*i);
994     }
995
996   //after we have combined the data into knownDependencies we have no need
997   //to keep this data around
998   this->CombinedBuildOutputs.clear();
999
1000   //now we difference with CombinedBuildExplicitDependencies to find
1001   //the list of items we know nothing about.
1002   //We have encoded all the paths in CombinedBuildExplicitDependencies
1003   //and knownDependencies so no matter if unix or windows paths they
1004   //should all match now.
1005
1006   std::vector<std::string> unkownExplicitDepends;
1007   this->CombinedBuildExplicitDependencies.erase("all");
1008
1009   std::set_difference(this->CombinedBuildExplicitDependencies.begin(),
1010                       this->CombinedBuildExplicitDependencies.end(),
1011                       knownDependencies.begin(),
1012                       knownDependencies.end(),
1013                       std::back_inserter(unkownExplicitDepends));
1014
1015
1016   std::string const rootBuildDirectory =
1017       this->GetCMakeInstance()->GetHomeOutputDirectory();
1018   for (std::vector<std::string>::const_iterator
1019        i = unkownExplicitDepends.begin();
1020        i != unkownExplicitDepends.end();
1021        ++i)
1022     {
1023     //verify the file is in the build directory
1024     std::string const absDepPath = cmSystemTools::CollapseFullPath(
1025                                      i->c_str(), rootBuildDirectory.c_str());
1026     bool const inBuildDir = cmSystemTools::IsSubDirectory(absDepPath.c_str(),
1027                                                   rootBuildDirectory.c_str());
1028     if(inBuildDir)
1029       {
1030       cmNinjaDeps deps(1,*i);
1031       this->WritePhonyBuild(os,
1032                             "",
1033                             deps,
1034                             deps);
1035       }
1036    }
1037 }
1038
1039 void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
1040 {
1041   // Write headers.
1042   cmGlobalNinjaGenerator::WriteDivider(os);
1043   os << "# Built-in targets\n\n";
1044
1045   this->WriteTargetAll(os);
1046   this->WriteTargetRebuildManifest(os);
1047   this->WriteTargetClean(os);
1048   this->WriteTargetHelp(os);
1049 }
1050
1051 void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
1052 {
1053   cmNinjaDeps outputs;
1054   outputs.push_back("all");
1055
1056   this->WritePhonyBuild(os,
1057                         "The main all target.",
1058                         outputs,
1059                         this->AllDependencies);
1060
1061   cmGlobalNinjaGenerator::WriteDefault(os,
1062                                        outputs,
1063                                        "Make the all target the default.");
1064 }
1065
1066 void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
1067 {
1068   cmLocalGenerator *lg = this->LocalGenerators[0];
1069   cmMakefile* mfRoot = lg->GetMakefile();
1070
1071   cmOStringStream cmd;
1072   cmd << lg->ConvertToOutputFormat(
1073            mfRoot->GetRequiredDefinition("CMAKE_COMMAND"),
1074            cmLocalGenerator::SHELL)
1075       << " -H"
1076       << lg->ConvertToOutputFormat(mfRoot->GetHomeDirectory(),
1077                                    cmLocalGenerator::SHELL)
1078       << " -B"
1079       << lg->ConvertToOutputFormat(mfRoot->GetHomeOutputDirectory(),
1080                                    cmLocalGenerator::SHELL);
1081   WriteRule(*this->RulesFileStream,
1082             "RERUN_CMAKE",
1083             cmd.str(),
1084             "Re-running CMake...",
1085             "Rule for re-running cmake.",
1086             /*depfile=*/ "",
1087             /*rspfile=*/ "",
1088             /*rspcontent*/ "",
1089             /*restat=*/ false,
1090             /*generator=*/ true);
1091
1092   cmNinjaDeps implicitDeps;
1093   for (std::vector<cmLocalGenerator *>::const_iterator i =
1094        this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i) {
1095     const std::vector<std::string>& lf = (*i)->GetMakefile()->GetListFiles();
1096     implicitDeps.insert(implicitDeps.end(), lf.begin(), lf.end());
1097   }
1098   std::sort(implicitDeps.begin(), implicitDeps.end());
1099   implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
1100                      implicitDeps.end());
1101   implicitDeps.push_back("CMakeCache.txt");
1102
1103   this->WriteBuild(os,
1104                    "Re-run CMake if any of its inputs changed.",
1105                    "RERUN_CMAKE",
1106                    /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE),
1107                    /*explicitDeps=*/ cmNinjaDeps(),
1108                    implicitDeps,
1109                    /*orderOnlyDeps=*/ cmNinjaDeps(),
1110                    /*variables=*/ cmNinjaVars());
1111
1112   this->WritePhonyBuild(os,
1113                         "A missing CMake input file is not an error.",
1114                         implicitDeps,
1115                         cmNinjaDeps());
1116 }
1117
1118 std::string cmGlobalNinjaGenerator::ninjaCmd() const
1119 {
1120   cmLocalGenerator* lgen = this->LocalGenerators[0];
1121   if (lgen) {
1122     return lgen->ConvertToOutputFormat(
1123              lgen->GetMakefile()->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"),
1124                                     cmLocalGenerator::SHELL);
1125   }
1126   return "ninja";
1127 }
1128
1129 void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os)
1130 {
1131   WriteRule(*this->RulesFileStream,
1132             "CLEAN",
1133             (ninjaCmd() + " -t clean").c_str(),
1134             "Cleaning all built files...",
1135             "Rule for cleaning all built files.",
1136             /*depfile=*/ "",
1137             /*rspfile=*/ "",
1138             /*rspcontent*/ "",
1139             /*restat=*/ false,
1140             /*generator=*/ false);
1141   WriteBuild(os,
1142              "Clean all the built files.",
1143              "CLEAN",
1144              /*outputs=*/ cmNinjaDeps(1, "clean"),
1145              /*explicitDeps=*/ cmNinjaDeps(),
1146              /*implicitDeps=*/ cmNinjaDeps(),
1147              /*orderOnlyDeps=*/ cmNinjaDeps(),
1148              /*variables=*/ cmNinjaVars());
1149 }
1150
1151 void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os)
1152 {
1153   WriteRule(*this->RulesFileStream,
1154             "HELP",
1155             (ninjaCmd() + " -t targets").c_str(),
1156             "All primary targets available:",
1157             "Rule for printing all primary targets available.",
1158             /*depfile=*/ "",
1159             /*rspfile=*/ "",
1160             /*rspcontent*/ "",
1161             /*restat=*/ false,
1162             /*generator=*/ false);
1163   WriteBuild(os,
1164              "Print all primary targets available.",
1165              "HELP",
1166              /*outputs=*/ cmNinjaDeps(1, "help"),
1167              /*explicitDeps=*/ cmNinjaDeps(),
1168              /*implicitDeps=*/ cmNinjaDeps(),
1169              /*orderOnlyDeps=*/ cmNinjaDeps(),
1170              /*variables=*/ cmNinjaVars());
1171 }