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