packaging: Initial packaging
[platform/upstream/cmake.git] / Source / cmLocalNinjaGenerator.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 "cmLocalNinjaGenerator.h"
14 #include "cmCustomCommandGenerator.h"
15 #include "cmMakefile.h"
16 #include "cmGlobalNinjaGenerator.h"
17 #include "cmNinjaTargetGenerator.h"
18 #include "cmGeneratedFileStream.h"
19 #include "cmSourceFile.h"
20 #include "cmComputeLinkInformation.h"
21 #include "cmake.h"
22
23 #include <assert.h>
24
25 cmLocalNinjaGenerator::cmLocalNinjaGenerator()
26   : cmLocalGenerator()
27   , ConfigName("")
28   , HomeRelativeOutputPath("")
29 {
30 #ifdef _WIN32
31   this->WindowsShell = true;
32 #endif
33   this->TargetImplib = "$TARGET_IMPLIB";
34 }
35
36 //----------------------------------------------------------------------------
37 // Virtual public methods.
38
39 cmLocalNinjaGenerator::~cmLocalNinjaGenerator()
40 {
41 }
42
43 void cmLocalNinjaGenerator::Generate()
44 {
45   this->SetConfigName();
46
47   this->WriteProcessedMakefile(this->GetBuildFileStream());
48 #ifdef NINJA_GEN_VERBOSE_FILES
49   this->WriteProcessedMakefile(this->GetRulesFileStream());
50 #endif
51
52   this->WriteBuildFileTop();
53
54   cmTargets& targets = this->GetMakefile()->GetTargets();
55   for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
56     {
57     cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(&t->second);
58     if(tg)
59       {
60       tg->Generate();
61       // Add the target to "all" if required.
62       if (!this->GetGlobalNinjaGenerator()->IsExcluded(
63             this->GetGlobalNinjaGenerator()->GetLocalGenerators()[0],
64             t->second))
65         this->GetGlobalNinjaGenerator()->AddDependencyToAll(&t->second);
66       delete tg;
67       }
68     }
69
70   this->WriteCustomCommandBuildStatements();
71 }
72
73 // Implemented in:
74 //   cmLocalUnixMakefileGenerator3.
75 // Used in:
76 //   Source/cmMakefile.cxx
77 //   Source/cmGlobalGenerator.cxx
78 void cmLocalNinjaGenerator::Configure()
79 {
80   // Compute the path to use when referencing the current output
81   // directory from the top output directory.
82   this->HomeRelativeOutputPath =
83     this->Convert(this->Makefile->GetStartOutputDirectory(), HOME_OUTPUT);
84   if(this->HomeRelativeOutputPath == ".")
85     {
86     this->HomeRelativeOutputPath = "";
87     }
88   this->cmLocalGenerator::Configure();
89
90 }
91
92 // TODO: Picked up from cmLocalUnixMakefileGenerator3.  Refactor it.
93 std::string cmLocalNinjaGenerator
94 ::GetTargetDirectory(cmTarget const& target) const
95 {
96   std::string dir = cmake::GetCMakeFilesDirectoryPostSlash();
97   dir += target.GetName();
98 #if defined(__VMS)
99   dir += "_dir";
100 #else
101   dir += ".dir";
102 #endif
103   return dir;
104 }
105
106 //----------------------------------------------------------------------------
107 // Non-virtual public methods.
108
109 const cmGlobalNinjaGenerator*
110 cmLocalNinjaGenerator::GetGlobalNinjaGenerator() const
111 {
112   return
113     static_cast<const cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
114 }
115
116 cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
117 {
118   return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator());
119 }
120
121 //----------------------------------------------------------------------------
122 // Virtual protected methods.
123
124 std::string
125 cmLocalNinjaGenerator::ConvertToLinkReference(std::string const& lib)
126 {
127   return this->Convert(lib.c_str(), HOME_OUTPUT, SHELL);
128 }
129
130 std::string
131 cmLocalNinjaGenerator::ConvertToIncludeReference(std::string const& path)
132 {
133   return this->Convert(path.c_str(), HOME_OUTPUT, SHELL);
134 }
135
136 //----------------------------------------------------------------------------
137 // Private methods.
138
139 cmGeneratedFileStream& cmLocalNinjaGenerator::GetBuildFileStream() const
140 {
141   return *this->GetGlobalNinjaGenerator()->GetBuildFileStream();
142 }
143
144 cmGeneratedFileStream& cmLocalNinjaGenerator::GetRulesFileStream() const
145 {
146   return *this->GetGlobalNinjaGenerator()->GetRulesFileStream();
147 }
148
149 const cmake* cmLocalNinjaGenerator::GetCMakeInstance() const
150 {
151   return this->GetGlobalGenerator()->GetCMakeInstance();
152 }
153
154 cmake* cmLocalNinjaGenerator::GetCMakeInstance()
155 {
156   return this->GetGlobalGenerator()->GetCMakeInstance();
157 }
158
159 bool cmLocalNinjaGenerator::isRootMakefile() const
160 {
161   return (strcmp(this->Makefile->GetCurrentDirectory(),
162                  this->GetCMakeInstance()->GetHomeDirectory()) == 0);
163 }
164
165 void cmLocalNinjaGenerator::WriteBuildFileTop()
166 {
167   // We do that only once for the top CMakeLists.txt file.
168   if(!this->isRootMakefile())
169     return;
170
171   // For the build file.
172   this->WriteProjectHeader(this->GetBuildFileStream());
173   this->WriteNinjaFilesInclusion(this->GetBuildFileStream());
174
175   // For the rule file.
176   this->WriteProjectHeader(this->GetRulesFileStream());
177 }
178
179 void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os)
180 {
181   cmGlobalNinjaGenerator::WriteDivider(os);
182   os
183     << "# Project: " << this->GetMakefile()->GetProjectName() << std::endl
184     << "# Configuration: " << this->ConfigName << std::endl
185     ;
186   cmGlobalNinjaGenerator::WriteDivider(os);
187 }
188
189 void cmLocalNinjaGenerator::WriteNinjaFilesInclusion(std::ostream& os)
190 {
191   cmGlobalNinjaGenerator::WriteDivider(os);
192   os
193     << "# Include auxiliary files.\n"
194     << "\n"
195     ;
196   cmGlobalNinjaGenerator::WriteInclude(os,
197                                       cmGlobalNinjaGenerator::NINJA_RULES_FILE,
198                                        "Include rules file.");
199   os << "\n";
200 }
201
202 void cmLocalNinjaGenerator::SetConfigName()
203 {
204   // Store the configuration name that will be generated.
205   if(const char* config =
206        this->GetMakefile()->GetDefinition("CMAKE_BUILD_TYPE"))
207     {
208     // Use the build type given by the user.
209     this->ConfigName = config;
210     }
211   else
212     {
213     // No configuration type given.
214     this->ConfigName = "";
215     }
216 }
217
218 void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os)
219 {
220   cmGlobalNinjaGenerator::WriteDivider(os);
221   os
222     << "# Write statements declared in CMakeLists.txt:" << std::endl
223     << "# " << this->Makefile->GetCurrentListFile() << std::endl
224     ;
225   if(this->isRootMakefile())
226     os << "# Which is the root file." << std::endl;
227   cmGlobalNinjaGenerator::WriteDivider(os);
228   os << std::endl;
229 }
230
231 std::string cmLocalNinjaGenerator::ConvertToNinjaPath(const char *path)
232 {
233   std::string convPath = this->Convert(path, cmLocalGenerator::HOME_OUTPUT);
234 #ifdef _WIN32
235   cmSystemTools::ReplaceString(convPath, "/", "\\");
236 #endif
237   return convPath;
238 }
239
240 void
241 cmLocalNinjaGenerator
242 ::AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs)
243 {
244   this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs);
245 }
246
247 void
248 cmLocalNinjaGenerator
249 ::AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs)
250 {
251   this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs);
252 }
253
254 void cmLocalNinjaGenerator::AppendCustomCommandDeps(const cmCustomCommand *cc,
255                                                     cmNinjaDeps &ninjaDeps)
256 {
257   const std::vector<std::string> &deps = cc->GetDepends();
258   for (std::vector<std::string>::const_iterator i = deps.begin();
259        i != deps.end(); ++i) {
260     std::string dep;
261     if (this->GetRealDependency(i->c_str(), this->GetConfigName(), dep))
262       ninjaDeps.push_back(ConvertToNinjaPath(dep.c_str()));
263   }
264 }
265
266 std::string cmLocalNinjaGenerator::BuildCommandLine(
267                                     const std::vector<std::string> &cmdLines)
268 {
269   // If we have no commands but we need to build a command anyway, use ":".
270   // This happens when building a POST_BUILD value for link targets that
271   // don't use POST_BUILD.
272   if (cmdLines.empty())
273 #ifdef _WIN32
274     return "cd .";
275 #else
276     return ":";
277 #endif
278
279   cmOStringStream cmd;
280   for (std::vector<std::string>::const_iterator li = cmdLines.begin();
281        li != cmdLines.end(); ++li) {
282     if (li != cmdLines.begin()) {
283       cmd << " && ";
284 #ifdef _WIN32
285     } else if (cmdLines.size() > 1) {
286       cmd << "cmd.exe /c ";
287 #endif
288     }
289     cmd << *li;
290   }
291   return cmd.str();
292 }
293
294 void cmLocalNinjaGenerator::AppendCustomCommandLines(const cmCustomCommand *cc,
295                                             std::vector<std::string> &cmdLines)
296 {
297   cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), this->Makefile);
298   if (ccg.GetNumberOfCommands() > 0) {
299     const char* wd = cc->GetWorkingDirectory();
300     if (!wd)
301       wd = this->GetMakefile()->GetStartOutputDirectory();
302
303     cmOStringStream cdCmd;
304 #ifdef _WIN32
305         std::string cdStr = "cd /D ";
306 #else
307         std::string cdStr = "cd ";
308 #endif
309     cdCmd << cdStr << this->ConvertToOutputFormat(wd, SHELL);
310     cmdLines.push_back(cdCmd.str());
311   }
312   for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) {
313     cmdLines.push_back(this->ConvertToOutputFormat(ccg.GetCommand(i).c_str(),
314                                                    SHELL));
315     std::string& cmd = cmdLines.back();
316     ccg.AppendArguments(i, cmd);
317   }
318 }
319
320 void
321 cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
322   cmCustomCommand const *cc, const cmNinjaDeps& orderOnlyDeps)
323 {
324   if (this->GetGlobalNinjaGenerator()->SeenCustomCommand(cc))
325     return;
326
327   const std::vector<std::string> &outputs = cc->GetOutputs();
328   cmNinjaDeps ninjaOutputs(outputs.size()), ninjaDeps;
329
330   std::transform(outputs.begin(), outputs.end(),
331                  ninjaOutputs.begin(), MapToNinjaPath());
332   this->AppendCustomCommandDeps(cc, ninjaDeps);
333
334   for (cmNinjaDeps::iterator i = ninjaOutputs.begin(); i != ninjaOutputs.end();
335        ++i)
336     this->GetGlobalNinjaGenerator()->SeenCustomCommandOutput(*i);
337
338   std::vector<std::string> cmdLines;
339   this->AppendCustomCommandLines(cc, cmdLines);
340
341   if (cmdLines.empty()) {
342     this->GetGlobalNinjaGenerator()->WritePhonyBuild(
343       this->GetBuildFileStream(),
344       "Phony custom command for " +
345       ninjaOutputs[0],
346       ninjaOutputs,
347       ninjaDeps,
348       cmNinjaDeps(),
349       orderOnlyDeps,
350       cmNinjaVars());
351   } else {
352     this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild(
353       this->BuildCommandLine(cmdLines),
354       this->ConstructComment(*cc),
355       "Custom command for " + ninjaOutputs[0],
356       ninjaOutputs,
357       ninjaDeps,
358       orderOnlyDeps);
359   }
360 }
361
362 void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc,
363                                                    cmTarget* target)
364 {
365   this->CustomCommandTargets[cc].insert(target);
366 }
367
368 void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements()
369 {
370   for (CustomCommandTargetMap::iterator i = this->CustomCommandTargets.begin();
371        i != this->CustomCommandTargets.end(); ++i) {
372     // A custom command may appear on multiple targets.  However, some build
373     // systems exist where the target dependencies on some of the targets are
374     // overspecified, leading to a dependency cycle.  If we assume all target
375     // dependencies are a superset of the true target dependencies for this
376     // custom command, we can take the set intersection of all target
377     // dependencies to obtain a correct dependency list.
378     //
379     // FIXME: This won't work in certain obscure scenarios involving indirect
380     // dependencies.
381     std::set<cmTarget*>::iterator j = i->second.begin();
382     assert(j != i->second.end());
383     std::vector<std::string> ccTargetDeps;
384     this->AppendTargetDepends(*j, ccTargetDeps);
385     std::sort(ccTargetDeps.begin(), ccTargetDeps.end());
386     ++j;
387
388     for (; j != i->second.end(); ++j) {
389       std::vector<std::string> jDeps, depsIntersection;
390       this->AppendTargetDepends(*j, jDeps);
391       std::sort(jDeps.begin(), jDeps.end());
392       std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(),
393                             jDeps.begin(), jDeps.end(),
394                             std::back_inserter(depsIntersection));
395       ccTargetDeps = depsIntersection;
396     }
397
398     this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps);
399   }
400 }