Imported Upstream version 2.8.9
[platform/upstream/cmake.git] / Source / cmNinjaNormalTargetGenerator.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 "cmNinjaNormalTargetGenerator.h"
14 #include "cmLocalNinjaGenerator.h"
15 #include "cmGlobalNinjaGenerator.h"
16 #include "cmSourceFile.h"
17 #include "cmGeneratedFileStream.h"
18 #include "cmMakefile.h"
19 #include "cmOSXBundleGenerator.h"
20
21 #include <assert.h>
22 #include <algorithm>
23
24 #ifndef _WIN32
25 #include <unistd.h>
26 #endif
27
28
29 cmNinjaNormalTargetGenerator::
30 cmNinjaNormalTargetGenerator(cmTarget* target)
31   : cmNinjaTargetGenerator(target)
32   , TargetNameOut()
33   , TargetNameSO()
34   , TargetNameReal()
35   , TargetNameImport()
36   , TargetNamePDB()
37   , TargetLinkLanguage(0)
38 {
39   cmOSXBundleGenerator::PrepareTargetProperties(target);
40
41   this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
42   if (target->GetType() == cmTarget::EXECUTABLE)
43     target->GetExecutableNames(this->TargetNameOut,
44                                this->TargetNameReal,
45                                this->TargetNameImport,
46                                this->TargetNamePDB,
47                                GetLocalGenerator()->GetConfigName());
48   else
49     target->GetLibraryNames(this->TargetNameOut,
50                             this->TargetNameSO,
51                             this->TargetNameReal,
52                             this->TargetNameImport,
53                             this->TargetNamePDB,
54                             GetLocalGenerator()->GetConfigName());
55
56   if(target->GetType() != cmTarget::OBJECT_LIBRARY)
57     {
58     // on Windows the output dir is already needed at compile time
59     // ensure the directory exists (OutDir test)
60     EnsureDirectoryExists(target->GetDirectory(this->GetConfigName()));
61     }
62
63   this->OSXBundleGenerator = new cmOSXBundleGenerator(target,
64                                                       this->TargetNameOut,
65                                                       this->GetConfigName());
66   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
67 }
68
69 cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
70 {
71   delete this->OSXBundleGenerator;
72 }
73
74 void cmNinjaNormalTargetGenerator::Generate()
75 {
76   if (!this->TargetLinkLanguage) {
77     cmSystemTools::Error("CMake can not determine linker language for target:",
78                          this->GetTarget()->GetName());
79     return;
80   }
81
82   // Write the rules for each language.
83   this->WriteLanguagesRules();
84
85   // Write the build statements
86   this->WriteObjectBuildStatements();
87
88   if(this->GetTarget()->GetType() == cmTarget::OBJECT_LIBRARY)
89     {
90     this->WriteObjectLibStatement();
91     }
92   else
93     {
94     this->WriteLinkRule(false); // write rule without rspfile support
95     this->WriteLinkRule(true);  // write rule with rspfile support
96     this->WriteLinkStatement();
97     }
98 }
99
100 void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
101 {
102 #ifdef NINJA_GEN_VERBOSE_FILES
103   cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
104   this->GetRulesFileStream()
105     << "# Rules for each languages for "
106     << cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
107     << " target "
108     << this->GetTargetName()
109     << "\n\n";
110 #endif
111
112   std::set<cmStdString> languages;
113   this->GetTarget()->GetLanguages(languages);
114   for(std::set<cmStdString>::const_iterator l = languages.begin();
115       l != languages.end();
116       ++l)
117     this->WriteLanguageRules(*l);
118 }
119
120 const char *cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
121 {
122   switch (this->GetTarget()->GetType()) {
123     case cmTarget::STATIC_LIBRARY:
124       return "static library";
125     case cmTarget::SHARED_LIBRARY:
126       return "shared library";
127     case cmTarget::MODULE_LIBRARY:
128       if (this->GetTarget()->IsCFBundleOnApple())
129         return "CFBundle shared module";
130       else
131         return "shared module";
132     case cmTarget::EXECUTABLE:
133       return "executable";
134     default:
135       return 0;
136   }
137 }
138
139 std::string
140 cmNinjaNormalTargetGenerator
141 ::LanguageLinkerRule() const
142 {
143   return std::string(this->TargetLinkLanguage)
144     + "_"
145     + cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
146     + "_LINKER";
147 }
148
149 void
150 cmNinjaNormalTargetGenerator
151 ::WriteLinkRule(bool useResponseFile)
152 {
153   cmTarget::TargetType targetType = this->GetTarget()->GetType();
154   std::string ruleName = this->LanguageLinkerRule();
155   if (useResponseFile)
156     ruleName += "_RSPFILE";
157
158   // Select whether to use a response file for objects.
159   std::string rspfile;
160   std::string rspcontent;
161
162   if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
163     cmLocalGenerator::RuleVariables vars;
164     vars.RuleLauncher = "RULE_LAUNCH_LINK";
165     vars.CMTarget = this->GetTarget();
166     vars.Language = this->TargetLinkLanguage;
167
168     std::string responseFlag;
169     if (!useResponseFile) {
170       vars.Objects = "$in";
171       vars.LinkLibraries = "$LINK_LIBRARIES";
172     } else {
173         // handle response file
174         std::string cmakeLinkVar = std::string("CMAKE_") +
175                         this->TargetLinkLanguage + "_RESPONSE_FILE_LINK_FLAG";
176         const char * flag = GetMakefile()->GetDefinition(cmakeLinkVar.c_str());
177         if(flag) {
178           responseFlag = flag;
179         } else {
180           responseFlag = "@";
181         }
182         rspfile = "$out.rsp";
183         responseFlag += rspfile;
184         rspcontent = "$in $LINK_LIBRARIES";
185         vars.Objects = responseFlag.c_str();
186         vars.LinkLibraries = "";
187     }
188
189     vars.ObjectDir = "$OBJECT_DIR";
190
191     // TODO:
192     // Makefile generator expands <TARGET> to the plain target name
193     // with suffix. $out expands to a relative path. This difference
194     // could make trouble when switching to Ninja generator. Maybe
195     // using TARGET_NAME and RuleVariables::TargetName is a fix.
196     vars.Target = "$out";
197
198     vars.SONameFlag = "$SONAME_FLAG";
199     vars.TargetSOName = "$SONAME";
200     vars.TargetInstallNameDir = "$INSTALLNAME_DIR";
201     vars.TargetPDB = "$TARGET_PDB";
202
203     // Setup the target version.
204     std::string targetVersionMajor;
205     std::string targetVersionMinor;
206     {
207     cmOStringStream majorStream;
208     cmOStringStream minorStream;
209     int major;
210     int minor;
211     this->GetTarget()->GetTargetVersion(major, minor);
212     majorStream << major;
213     minorStream << minor;
214     targetVersionMajor = majorStream.str();
215     targetVersionMinor = minorStream.str();
216     }
217     vars.TargetVersionMajor = targetVersionMajor.c_str();
218     vars.TargetVersionMinor = targetVersionMinor.c_str();
219
220     vars.Flags = "$FLAGS";
221     vars.LinkFlags = "$LINK_FLAGS";
222
223     std::string langFlags;
224     if (targetType != cmTarget::EXECUTABLE) {
225       this->GetLocalGenerator()->AddLanguageFlags(langFlags,
226                                                   this->TargetLinkLanguage,
227                                                   this->GetConfigName());
228       langFlags += " $ARCH_FLAGS";
229       vars.LanguageCompileFlags = langFlags.c_str();
230     }
231
232     // Rule for linking library/executable.
233     std::vector<std::string> linkCmds = this->ComputeLinkCmd();
234     for(std::vector<std::string>::iterator i = linkCmds.begin();
235         i != linkCmds.end();
236         ++i)
237       {
238       this->GetLocalGenerator()->ExpandRuleVariables(*i, vars);
239       }
240     linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
241     linkCmds.push_back("$POST_BUILD");
242     std::string linkCmd =
243       this->GetLocalGenerator()->BuildCommandLine(linkCmds);
244
245     // Write the linker rule with response file if needed.
246     cmOStringStream comment;
247     comment << "Rule for linking " << this->TargetLinkLanguage << " "
248             << this->GetVisibleTypeName() << ".";
249     cmOStringStream description;
250     description << "Linking " << this->TargetLinkLanguage << " "
251                 << this->GetVisibleTypeName() << " $out";
252     this->GetGlobalGenerator()->AddRule(ruleName,
253                                         linkCmd,
254                                         description.str(),
255                                         comment.str(),
256                                         /*depfile*/ "",
257                                         rspfile,
258                                         rspcontent);
259   }
260
261   if (this->TargetNameOut != this->TargetNameReal) {
262     std::string cmakeCommand =
263       this->GetLocalGenerator()->ConvertToOutputFormat(
264         this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"),
265         cmLocalGenerator::SHELL);
266     if (targetType == cmTarget::EXECUTABLE)
267       this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_EXECUTABLE",
268                                           cmakeCommand +
269                                           " -E cmake_symlink_executable"
270                                           " $in $out && $POST_BUILD",
271                                           "Creating executable symlink $out",
272                                       "Rule for creating executable symlink.");
273     else
274       this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_LIBRARY",
275                                           cmakeCommand +
276                                           " -E cmake_symlink_library"
277                                           " $in $SONAME $out && $POST_BUILD",
278                                           "Creating library symlink $out",
279                                          "Rule for creating library symlink.");
280   }
281 }
282
283 std::vector<std::string>
284 cmNinjaNormalTargetGenerator
285 ::ComputeLinkCmd()
286 {
287   std::vector<std::string> linkCmds;
288   cmTarget::TargetType targetType = this->GetTarget()->GetType();
289   switch (targetType) {
290     case cmTarget::STATIC_LIBRARY: {
291       // Check if you have a non archive way to create the static library.
292       {
293       std::string linkCmdVar = "CMAKE_";
294       linkCmdVar += this->TargetLinkLanguage;
295       linkCmdVar += "_CREATE_STATIC_LIBRARY";
296       if (const char *linkCmd =
297             this->GetMakefile()->GetDefinition(linkCmdVar.c_str()))
298         {
299         cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
300         return linkCmds;
301         }
302       }
303
304       // We have archive link commands set. First, delete the existing archive.
305       std::string cmakeCommand =
306         this->GetLocalGenerator()->ConvertToOutputFormat(
307           this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"),
308           cmLocalGenerator::SHELL);
309       linkCmds.push_back(cmakeCommand + " -E remove $out");
310
311       // TODO: Use ARCHIVE_APPEND for archives over a certain size.
312       {
313       std::string linkCmdVar = "CMAKE_";
314       linkCmdVar += this->TargetLinkLanguage;
315       linkCmdVar += "_ARCHIVE_CREATE";
316       const char *linkCmd =
317         this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
318       cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
319       }
320       {
321       std::string linkCmdVar = "CMAKE_";
322       linkCmdVar += this->TargetLinkLanguage;
323       linkCmdVar += "_ARCHIVE_FINISH";
324       const char *linkCmd =
325         this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
326       cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
327       }
328       return linkCmds;
329     }
330     case cmTarget::SHARED_LIBRARY:
331     case cmTarget::MODULE_LIBRARY:
332     case cmTarget::EXECUTABLE: {
333       std::string linkCmdVar = "CMAKE_";
334       linkCmdVar += this->TargetLinkLanguage;
335       switch (targetType) {
336       case cmTarget::SHARED_LIBRARY:
337         linkCmdVar += "_CREATE_SHARED_LIBRARY";
338         break;
339       case cmTarget::MODULE_LIBRARY:
340         linkCmdVar += "_CREATE_SHARED_MODULE";
341         break;
342       case cmTarget::EXECUTABLE:
343         linkCmdVar += "_LINK_EXECUTABLE";
344         break;
345       default:
346         assert(0 && "Unexpected target type");
347       }
348
349       const char *linkCmd =
350         this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
351       cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
352       return linkCmds;
353     }
354     default:
355       assert(0 && "Unexpected target type");
356   }
357   return std::vector<std::string>();
358 }
359
360 void cmNinjaNormalTargetGenerator::WriteLinkStatement()
361 {
362   cmTarget::TargetType targetType = this->GetTarget()->GetType();
363
364   std::string targetOutput = ConvertToNinjaPath(
365     this->GetTarget()->GetFullPath(this->GetConfigName()).c_str());
366   std::string targetOutputReal = ConvertToNinjaPath(
367     this->GetTarget()->GetFullPath(this->GetConfigName(),
368                                    /*implib=*/false,
369                                    /*realpath=*/true).c_str());
370   std::string targetOutputImplib = ConvertToNinjaPath(
371     this->GetTarget()->GetFullPath(this->GetConfigName(),
372                                    /*implib=*/true).c_str());
373
374   if (this->GetTarget()->IsAppBundleOnApple())
375     {
376     // Create the app bundle
377     std::string outpath;
378     this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath);
379
380     // Calculate the output path
381     targetOutput = outpath + this->TargetNameOut;
382     targetOutput = this->ConvertToNinjaPath(targetOutput.c_str());
383     targetOutputReal = outpath + this->TargetNameReal;
384     targetOutputReal = this->ConvertToNinjaPath(targetOutputReal.c_str());
385     }
386   else if (this->GetTarget()->IsFrameworkOnApple())
387     {
388     // Create the library framework.
389     this->OSXBundleGenerator->CreateFramework(this->TargetNameOut);
390     }
391   else if(this->GetTarget()->IsCFBundleOnApple())
392     {
393     // Create the core foundation bundle.
394     std::string outpath;
395     this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut, outpath);
396     }
397
398   // Write comments.
399   cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
400   this->GetBuildFileStream()
401     << "# Link build statements for "
402     << cmTarget::GetTargetTypeName(targetType)
403     << " target "
404     << this->GetTargetName()
405     << "\n\n";
406
407   cmNinjaDeps emptyDeps;
408   cmNinjaVars vars;
409
410   // Compute the comment.
411   cmOStringStream comment;
412   comment << "Link the " << this->GetVisibleTypeName() << " "
413           << targetOutputReal;
414
415   // Compute outputs.
416   cmNinjaDeps outputs;
417   outputs.push_back(targetOutputReal);
418
419   // Compute specific libraries to link with.
420   cmNinjaDeps explicitDeps = this->GetObjects();
421   cmNinjaDeps implicitDeps = this->ComputeLinkDeps();
422
423   this->GetLocalGenerator()->GetTargetFlags(vars["LINK_LIBRARIES"],
424                                             vars["FLAGS"],
425                                             vars["LINK_FLAGS"],
426                                             *this->GetTarget());
427
428   this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]);
429
430   // Compute architecture specific link flags.  Yes, these go into a different
431   // variable for executables, probably due to a mistake made when duplicating
432   // code between the Makefile executable and library generators.
433   std::string flags = (targetType == cmTarget::EXECUTABLE
434                                ? vars["FLAGS"]
435                                : vars["ARCH_FLAGS"]);
436   this->GetLocalGenerator()->AddArchitectureFlags(flags,
437                              this->GetTarget(),
438                              this->TargetLinkLanguage,
439                              this->GetConfigName());
440   if (targetType == cmTarget::EXECUTABLE) {
441     vars["FLAGS"] = flags;
442   } else {
443     vars["ARCH_FLAGS"] = flags;
444   }
445   if (this->GetTarget()->HasSOName(this->GetConfigName())) {
446     vars["SONAME_FLAG"] =
447       this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage);
448     vars["SONAME"] = this->TargetNameSO;
449     if (targetType == cmTarget::SHARED_LIBRARY) {
450       std::string install_name_dir = this->GetTarget()
451         ->GetInstallNameDirForBuildTree(this->GetConfigName());
452
453       if (!install_name_dir.empty()) {
454         vars["INSTALLNAME_DIR"] =
455           this->GetLocalGenerator()->Convert(install_name_dir.c_str(),
456               cmLocalGenerator::NONE,
457               cmLocalGenerator::SHELL, false);
458       }
459     }
460   }
461
462   std::string path;
463   if (!this->TargetNameImport.empty()) {
464     path = this->GetLocalGenerator()->ConvertToOutputFormat(
465                     targetOutputImplib.c_str(), cmLocalGenerator::SHELL);
466     vars["TARGET_IMPLIB"] = path;
467     EnsureParentDirectoryExists(path);
468   }
469
470   cmMakefile* mf = this->GetMakefile();
471   if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") ||
472       mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID"))
473     {
474     path = this->GetTargetPDB();
475     vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat(
476                           ConvertToNinjaPath(path.c_str()).c_str(),
477                           cmLocalGenerator::SHELL);
478     EnsureParentDirectoryExists(path);
479     }
480   else
481     {
482     // It is common to place debug symbols at a specific place,
483     // so we need a plain target name in the rule available.
484     std::string prefix;
485     std::string base;
486     std::string suffix;
487     this->GetTarget()->GetFullNameComponents(prefix, base, suffix);
488     std::string dbg_suffix = ".dbg";
489     // TODO: Where to document?
490     if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX"))
491       dbg_suffix = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX");
492     vars["TARGET_PDB"] = base + suffix + dbg_suffix;
493     }
494
495   if (mf->IsOn("CMAKE_COMPILER_IS_MINGW"))
496     {
497     path = GetTarget()->GetSupportDirectory();
498     vars["OBJECT_DIR"] = ConvertToNinjaPath(path.c_str());
499     EnsureDirectoryExists(path);
500     // ar.exe can't handle backslashes in rsp files (implictly used by gcc)
501     std::string& linkLibraries = vars["LINK_LIBRARIES"];
502     std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
503     }
504
505   std::vector<cmCustomCommand> *cmdLists[3] = {
506     &this->GetTarget()->GetPreBuildCommands(),
507     &this->GetTarget()->GetPreLinkCommands(),
508     &this->GetTarget()->GetPostBuildCommands()
509   };
510
511   std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
512   std::vector<std::string> *cmdLineLists[3] = {
513     &preLinkCmdLines,
514     &preLinkCmdLines,
515     &postBuildCmdLines
516   };
517
518   for (unsigned i = 0; i != 3; ++i) {
519     for (std::vector<cmCustomCommand>::const_iterator
520          ci = cmdLists[i]->begin();
521          ci != cmdLists[i]->end(); ++ci) {
522       this->GetLocalGenerator()->AppendCustomCommandLines(&*ci,
523                                                           *cmdLineLists[i]);
524     }
525   }
526
527   // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for
528   // the link commands.
529   if (!preLinkCmdLines.empty()) {
530     path = this->GetLocalGenerator()->ConvertToOutputFormat(
531       this->GetMakefile()->GetHomeOutputDirectory(),
532       cmLocalGenerator::SHELL);
533     preLinkCmdLines.push_back("cd " + path);
534   }
535
536   vars["PRE_LINK"] =
537     this->GetLocalGenerator()->BuildCommandLine(preLinkCmdLines);
538   std::string postBuildCmdLine =
539     this->GetLocalGenerator()->BuildCommandLine(postBuildCmdLines);
540
541   cmNinjaVars symlinkVars;
542   if (targetOutput == targetOutputReal) {
543     vars["POST_BUILD"] = postBuildCmdLine;
544   } else {
545     vars["POST_BUILD"] = ":";
546     symlinkVars["POST_BUILD"] = postBuildCmdLine;
547   }
548
549   int linkRuleLength = this->GetGlobalGenerator()->
550                                  GetRuleCmdLength(this->LanguageLinkerRule());
551 #ifdef _WIN32
552   int commandLineLengthLimit = 8000 - linkRuleLength;
553 #elif defined(__linux) || defined(__APPLE__)
554   // for instance ARG_MAX is 2096152 on Ubuntu or 262144 on Mac
555   int commandLineLengthLimit = ((int)sysconf(_SC_ARG_MAX))
556                                     - linkRuleLength - 1000;
557 #else
558   int commandLineLengthLimit = -1;
559 #endif
560
561   // Write the build statement for this target.
562   cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
563                                      comment.str(),
564                                      this->LanguageLinkerRule(),
565                                      outputs,
566                                      explicitDeps,
567                                      implicitDeps,
568                                      emptyDeps,
569                                      vars,
570                                      commandLineLengthLimit);
571
572   if (targetOutput != targetOutputReal) {
573     if (targetType == cmTarget::EXECUTABLE) {
574       cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
575                                   "Create executable symlink " + targetOutput,
576                                          "CMAKE_SYMLINK_EXECUTABLE",
577                                          cmNinjaDeps(1, targetOutput),
578                                          cmNinjaDeps(1, targetOutputReal),
579                                          emptyDeps,
580                                          emptyDeps,
581                                          symlinkVars);
582     } else {
583       cmNinjaDeps symlinks;
584       const std::string soName = this->GetTargetFilePath(this->TargetNameSO);
585       // If one link has to be created.
586       if (targetOutputReal == soName || targetOutput == soName) {
587         symlinkVars["SONAME"] = soName;
588       } else {
589         symlinkVars["SONAME"] = "";
590         symlinks.push_back(soName);
591       }
592       symlinks.push_back(targetOutput);
593       cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
594                                       "Create library symlink " + targetOutput,
595                                          "CMAKE_SYMLINK_LIBRARY",
596                                          symlinks,
597                                          cmNinjaDeps(1, targetOutputReal),
598                                          emptyDeps,
599                                          emptyDeps,
600                                          symlinkVars);
601     }
602   }
603
604   if (!this->TargetNameImport.empty()) {
605     // Since using multiple outputs would mess up the $out variable, use an
606     // alias for the import library.
607     cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
608                                             "Alias for import library.",
609                                             cmNinjaDeps(1, targetOutputImplib),
610                                             cmNinjaDeps(1, targetOutputReal));
611   }
612
613   // Add aliases for the file name and the target name.
614   this->GetGlobalGenerator()->AddTargetAlias(this->TargetNameOut,
615                                              this->GetTarget());
616   this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
617                                              this->GetTarget());
618 }
619
620 //----------------------------------------------------------------------------
621 void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
622 {
623   // Write a phony output that depends on all object files.
624   cmNinjaDeps outputs;
625   this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs);
626   cmNinjaDeps depends = this->GetObjects();
627   cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
628                                           "Object library "
629                                           + this->GetTargetName(),
630                                           outputs,
631                                           depends);
632
633   // Add aliases for the target name.
634   this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
635                                              this->GetTarget());
636 }