Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmMakefileLibraryTargetGenerator.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmMakefileLibraryTargetGenerator.h"
13
14 #include "cmGeneratedFileStream.h"
15 #include "cmGlobalUnixMakefileGenerator3.h"
16 #include "cmLocalUnixMakefileGenerator3.h"
17 #include "cmMakefile.h"
18 #include "cmSourceFile.h"
19 #include "cmTarget.h"
20 #include "cmake.h"
21
22 //----------------------------------------------------------------------------
23 cmMakefileLibraryTargetGenerator
24 ::cmMakefileLibraryTargetGenerator(cmTarget* target):
25   cmMakefileTargetGenerator(target)
26 {
27   this->CustomCommandDriver = OnDepends;
28   this->Target->GetLibraryNames(
29     this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
30     this->TargetNameImport, this->TargetNamePDB, this->ConfigName);
31
32   this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target,
33                                                       this->ConfigName);
34   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
35 }
36
37 //----------------------------------------------------------------------------
38 cmMakefileLibraryTargetGenerator
39 ::~cmMakefileLibraryTargetGenerator()
40 {
41   delete this->OSXBundleGenerator;
42 }
43
44 //----------------------------------------------------------------------------
45 void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
46 {
47   // create the build.make file and directory, put in the common blocks
48   this->CreateRuleFile();
49
50   // write rules used to help build object files
51   this->WriteCommonCodeRules();
52
53   // write the per-target per-language flags
54   this->WriteTargetLanguageFlags();
55
56   // write in rules for object files and custom commands
57   this->WriteTargetBuildRules();
58
59   // write the link rules
60   // Write the rule for this target type.
61   switch(this->Target->GetType())
62     {
63     case cmTarget::STATIC_LIBRARY:
64       this->WriteStaticLibraryRules();
65       break;
66     case cmTarget::SHARED_LIBRARY:
67       this->WriteSharedLibraryRules(false);
68       if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
69         {
70         // Write rules to link an installable version of the target.
71         this->WriteSharedLibraryRules(true);
72         }
73       break;
74     case cmTarget::MODULE_LIBRARY:
75       this->WriteModuleLibraryRules(false);
76       if(this->Target->NeedRelinkBeforeInstall(this->ConfigName))
77         {
78         // Write rules to link an installable version of the target.
79         this->WriteModuleLibraryRules(true);
80         }
81       break;
82     case cmTarget::OBJECT_LIBRARY:
83       this->WriteObjectLibraryRules();
84       break;
85     default:
86       // If language is not known, this is an error.
87       cmSystemTools::Error("Unknown Library Type");
88       break;
89     }
90
91   // Write the requires target.
92   this->WriteTargetRequiresRules();
93
94   // Write clean target
95   this->WriteTargetCleanRules();
96
97   // Write the dependency generation rule.  This must be done last so
98   // that multiple output pair information is available.
99   this->WriteTargetDependRules();
100
101   // close the streams
102   this->CloseFileStreams();
103 }
104
105 //----------------------------------------------------------------------------
106 void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
107 {
108   std::vector<std::string> commands;
109   std::vector<std::string> depends;
110
111   // Add post-build rules.
112   this->LocalGenerator->
113     AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),
114                          this->Target);
115
116   // Depend on the object files.
117   this->AppendObjectDepends(depends);
118
119   // Write the rule.
120   this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
121                                       this->Target->GetName(),
122                                       depends, commands, true);
123
124   // Write the main driver rule to build everything in this target.
125   this->WriteTargetDriverRule(this->Target->GetName(), false);
126 }
127
128 //----------------------------------------------------------------------------
129 void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
130 {
131   const char* linkLanguage =
132     this->Target->GetLinkerLanguage(this->ConfigName);
133   std::string linkRuleVar = "CMAKE_";
134   if (linkLanguage)
135     {
136     linkRuleVar += linkLanguage;
137     }
138   linkRuleVar += "_CREATE_STATIC_LIBRARY";
139
140   if(this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION") &&
141      this->Makefile->GetDefinition((linkRuleVar+"_IPO").c_str()))
142     {
143     linkRuleVar += "_IPO";
144     }
145
146   std::string extraFlags;
147   this->LocalGenerator->GetStaticLibraryFlags(extraFlags,
148     cmSystemTools::UpperCase(this->ConfigName), this->Target);
149   this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), false);
150 }
151
152 //----------------------------------------------------------------------------
153 void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
154 {
155   if(this->Target->IsFrameworkOnApple())
156     {
157     this->WriteFrameworkRules(relink);
158     return;
159     }
160   const char* linkLanguage =
161     this->Target->GetLinkerLanguage(this->ConfigName);
162   std::string linkRuleVar = "CMAKE_";
163   if (linkLanguage)
164     {
165     linkRuleVar += linkLanguage;
166     }
167   linkRuleVar += "_CREATE_SHARED_LIBRARY";
168
169   std::string extraFlags;
170   this->LocalGenerator->AppendFlags
171     (extraFlags, this->Target->GetProperty("LINK_FLAGS"));
172   std::string linkFlagsConfig = "LINK_FLAGS_";
173   linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
174   this->LocalGenerator->AppendFlags
175     (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
176
177   this->LocalGenerator->AddConfigVariableFlags
178     (extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
179   this->AddModuleDefinitionFlag(extraFlags);
180
181   this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
182 }
183
184 //----------------------------------------------------------------------------
185 void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
186 {
187   const char* linkLanguage =
188     this->Target->GetLinkerLanguage(this->ConfigName);
189   std::string linkRuleVar = "CMAKE_";
190   if (linkLanguage)
191     {
192     linkRuleVar += linkLanguage;
193     }
194   linkRuleVar += "_CREATE_SHARED_MODULE";
195
196   std::string extraFlags;
197   this->LocalGenerator->AppendFlags(extraFlags,
198                                     this->Target->GetProperty("LINK_FLAGS"));
199   std::string linkFlagsConfig = "LINK_FLAGS_";
200   linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
201   this->LocalGenerator->AppendFlags
202     (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
203   this->LocalGenerator->AddConfigVariableFlags
204     (extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
205   this->AddModuleDefinitionFlag(extraFlags);
206
207   this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
208 }
209
210 //----------------------------------------------------------------------------
211 void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
212 {
213   const char* linkLanguage =
214     this->Target->GetLinkerLanguage(this->ConfigName);
215   std::string linkRuleVar = "CMAKE_";
216   if (linkLanguage)
217     {
218     linkRuleVar += linkLanguage;
219     }
220   linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
221
222   std::string extraFlags;
223   this->LocalGenerator->AppendFlags(extraFlags,
224                                     this->Target->GetProperty("LINK_FLAGS"));
225   std::string linkFlagsConfig = "LINK_FLAGS_";
226   linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
227   this->LocalGenerator->AppendFlags
228     (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
229   this->LocalGenerator->AddConfigVariableFlags
230     (extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->ConfigName);
231
232   this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
233 }
234
235 //----------------------------------------------------------------------------
236 void cmMakefileLibraryTargetGenerator::WriteLibraryRules
237 (const char* linkRuleVar, const char* extraFlags, bool relink)
238 {
239   // TODO: Merge the methods that call this method to avoid
240   // code duplication.
241   std::vector<std::string> commands;
242
243   // Build list of dependencies.
244   std::vector<std::string> depends;
245   this->AppendLinkDepends(depends);
246
247   // Get the language to use for linking this library.
248   const char* linkLanguage =
249     this->Target->GetLinkerLanguage(this->ConfigName);
250
251   // Make sure we have a link language.
252   if(!linkLanguage)
253     {
254     cmSystemTools::Error("Cannot determine link language for target \"",
255                          this->Target->GetName(), "\".");
256     return;
257     }
258
259   // Create set of linking flags.
260   std::string linkFlags;
261   this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
262
263   // Add OSX version flags, if any.
264   if(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
265      this->Target->GetType() == cmTarget::MODULE_LIBRARY)
266     {
267     this->AppendOSXVerFlag(linkFlags, linkLanguage, "COMPATIBILITY", true);
268     this->AppendOSXVerFlag(linkFlags, linkLanguage, "CURRENT", false);
269     }
270
271   // Construct the name of the library.
272   std::string targetName;
273   std::string targetNameSO;
274   std::string targetNameReal;
275   std::string targetNameImport;
276   std::string targetNamePDB;
277   this->Target->GetLibraryNames(
278     targetName, targetNameSO, targetNameReal, targetNameImport, targetNamePDB,
279     this->ConfigName);
280
281   // Construct the full path version of the names.
282   std::string outpath;
283   std::string outpathImp;
284   if(this->Target->IsFrameworkOnApple())
285     {
286     outpath = this->Target->GetDirectory(this->ConfigName);
287     this->OSXBundleGenerator->CreateFramework(targetName, outpath);
288     outpath += "/";
289     }
290   else if(this->Target->IsCFBundleOnApple())
291     {
292     outpath = this->Target->GetDirectory(this->ConfigName);
293     this->OSXBundleGenerator->CreateCFBundle(targetName, outpath);
294     outpath += "/";
295     }
296   else if(relink)
297     {
298     outpath = this->Makefile->GetStartOutputDirectory();
299     outpath += cmake::GetCMakeFilesDirectory();
300     outpath += "/CMakeRelink.dir";
301     cmSystemTools::MakeDirectory(outpath.c_str());
302     outpath += "/";
303     if(!targetNameImport.empty())
304       {
305       outpathImp = outpath;
306       }
307     }
308   else
309     {
310     outpath = this->Target->GetDirectory(this->ConfigName);
311     cmSystemTools::MakeDirectory(outpath.c_str());
312     outpath += "/";
313     if(!targetNameImport.empty())
314       {
315       outpathImp = this->Target->GetDirectory(this->ConfigName, true);
316       cmSystemTools::MakeDirectory(outpathImp.c_str());
317       outpathImp += "/";
318       }
319     }
320
321   std::string pdbOutputPath = this->Target->GetPDBDirectory();
322   cmSystemTools::MakeDirectory(pdbOutputPath.c_str());
323   pdbOutputPath += "/";
324
325   std::string targetFullPath = outpath + targetName;
326   std::string targetFullPathPDB = pdbOutputPath + targetNamePDB;
327   std::string targetFullPathSO = outpath + targetNameSO;
328   std::string targetFullPathReal = outpath + targetNameReal;
329   std::string targetFullPathImport = outpathImp + targetNameImport;
330
331   // Construct the output path version of the names for use in command
332   // arguments.
333   std::string targetOutPathPDB =
334     this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::NONE,
335                   cmLocalGenerator::SHELL);
336   std::string targetOutPath =
337     this->Convert(targetFullPath.c_str(),cmLocalGenerator::START_OUTPUT,
338                   cmLocalGenerator::SHELL);
339   std::string targetOutPathSO =
340     this->Convert(targetFullPathSO.c_str(),cmLocalGenerator::START_OUTPUT,
341                   cmLocalGenerator::SHELL);
342   std::string targetOutPathReal =
343     this->Convert(targetFullPathReal.c_str(),cmLocalGenerator::START_OUTPUT,
344                   cmLocalGenerator::SHELL);
345   std::string targetOutPathImport =
346     this->Convert(targetFullPathImport.c_str(),cmLocalGenerator::START_OUTPUT,
347                   cmLocalGenerator::SHELL);
348
349   if(!this->NoRuleMessages)
350     {
351     // Add the link message.
352     std::string buildEcho = "Linking ";
353     buildEcho += linkLanguage;
354     switch(this->Target->GetType())
355       {
356       case cmTarget::STATIC_LIBRARY:
357         buildEcho += " static library ";
358         break;
359       case cmTarget::SHARED_LIBRARY:
360         buildEcho += " shared library ";
361         break;
362       case cmTarget::MODULE_LIBRARY:
363         if (this->Target->IsCFBundleOnApple())
364             buildEcho += " CFBundle";
365         buildEcho += " shared module ";
366         break;
367       default:
368         buildEcho += " library ";
369         break;
370       }
371     buildEcho += targetOutPath.c_str();
372     this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
373                                      cmLocalUnixMakefileGenerator3::EchoLink);
374     }
375
376   const char* forbiddenFlagVar = 0;
377   switch(this->Target->GetType())
378     {
379     case cmTarget::SHARED_LIBRARY:
380       forbiddenFlagVar = "_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS";
381       break;
382     case cmTarget::MODULE_LIBRARY:
383       forbiddenFlagVar = "_CREATE_SHARED_MODULE_FORBIDDEN_FLAGS";
384       break;
385     default: break;
386     }
387
388   // Clean files associated with this library.
389   std::vector<std::string> libCleanFiles;
390   libCleanFiles.push_back(this->Convert(targetFullPath.c_str(),
391         cmLocalGenerator::START_OUTPUT,
392         cmLocalGenerator::UNCHANGED));
393   if(targetNameReal != targetName)
394     {
395     libCleanFiles.push_back(this->Convert(targetFullPathReal.c_str(),
396         cmLocalGenerator::START_OUTPUT,
397         cmLocalGenerator::UNCHANGED));
398     }
399   if(targetNameSO != targetName &&
400      targetNameSO != targetNameReal)
401     {
402     libCleanFiles.push_back(this->Convert(targetFullPathSO.c_str(),
403         cmLocalGenerator::START_OUTPUT,
404         cmLocalGenerator::UNCHANGED));
405     }
406   if(!targetNameImport.empty())
407     {
408     libCleanFiles.push_back(this->Convert(targetFullPathImport.c_str(),
409         cmLocalGenerator::START_OUTPUT,
410         cmLocalGenerator::UNCHANGED));
411     std::string implib;
412     if(this->Target->GetImplibGNUtoMS(targetFullPathImport, implib))
413       {
414       libCleanFiles.push_back(this->Convert(implib.c_str(),
415                                             cmLocalGenerator::START_OUTPUT,
416                                             cmLocalGenerator::UNCHANGED));
417       }
418     }
419
420   // List the PDB for cleaning only when the whole target is
421   // cleaned.  We do not want to delete the .pdb file just before
422   // linking the target.
423   this->CleanFiles.push_back
424     (this->Convert(targetFullPathPDB.c_str(),
425                    cmLocalGenerator::START_OUTPUT,
426                    cmLocalGenerator::UNCHANGED));
427
428 #ifdef _WIN32
429   // There may be a manifest file for this target.  Add it to the
430   // clean set just in case.
431   if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
432     {
433     libCleanFiles.push_back(
434       this->Convert((targetFullPath+".manifest").c_str(),
435                     cmLocalGenerator::START_OUTPUT,
436                     cmLocalGenerator::UNCHANGED));
437     }
438 #endif
439
440   std::vector<std::string> commands1;
441   // Add a command to remove any existing files for this library.
442   // for static libs only
443   if(this->Target->GetType() == cmTarget::STATIC_LIBRARY)
444     {
445     this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
446                                              *this->Target, "target");
447     this->LocalGenerator->CreateCDCommand
448       (commands1,
449        this->Makefile->GetStartOutputDirectory(),
450        cmLocalGenerator::HOME_OUTPUT);
451     commands.insert(commands.end(), commands1.begin(), commands1.end());
452     commands1.clear();
453     }
454
455   // Add the pre-build and pre-link rules building but not when relinking.
456   if(!relink)
457     {
458     this->LocalGenerator
459       ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands(),
460                              this->Target);
461     this->LocalGenerator
462       ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands(),
463                              this->Target);
464     }
465
466   // Determine whether a link script will be used.
467   bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
468
469   // Select whether to use a response file for objects.
470   bool useResponseFile = false;
471   {
472   std::string responseVar = "CMAKE_";
473   responseVar += linkLanguage;
474   responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
475   if(this->Makefile->IsOn(responseVar.c_str()))
476     {
477     useResponseFile = true;
478     }
479   }
480
481   // For static libraries there might be archiving rules.
482   bool haveStaticLibraryRule = false;
483   std::vector<std::string> archiveCreateCommands;
484   std::vector<std::string> archiveAppendCommands;
485   std::vector<std::string> archiveFinishCommands;
486   std::string::size_type archiveCommandLimit = std::string::npos;
487   if(this->Target->GetType() == cmTarget::STATIC_LIBRARY)
488     {
489     haveStaticLibraryRule =
490       this->Makefile->GetDefinition(linkRuleVar)? true:false;
491     std::string arCreateVar = "CMAKE_";
492     arCreateVar += linkLanguage;
493     arCreateVar += "_ARCHIVE_CREATE";
494     if(const char* rule = this->Makefile->GetDefinition(arCreateVar.c_str()))
495       {
496       cmSystemTools::ExpandListArgument(rule, archiveCreateCommands);
497       }
498     std::string arAppendVar = "CMAKE_";
499     arAppendVar += linkLanguage;
500     arAppendVar += "_ARCHIVE_APPEND";
501     if(const char* rule = this->Makefile->GetDefinition(arAppendVar.c_str()))
502       {
503       cmSystemTools::ExpandListArgument(rule, archiveAppendCommands);
504       }
505     std::string arFinishVar = "CMAKE_";
506     arFinishVar += linkLanguage;
507     arFinishVar += "_ARCHIVE_FINISH";
508     if(const char* rule = this->Makefile->GetDefinition(arFinishVar.c_str()))
509       {
510       cmSystemTools::ExpandListArgument(rule, archiveFinishCommands);
511       }
512     }
513
514   // Decide whether to use archiving rules.
515   bool useArchiveRules =
516     !haveStaticLibraryRule &&
517     !archiveCreateCommands.empty() && !archiveAppendCommands.empty();
518   if(useArchiveRules)
519     {
520     // Archiving rules are always run with a link script.
521     useLinkScript = true;
522
523     // Archiving rules never use a response file.
524     useResponseFile = false;
525
526     // Limit the length of individual object lists to less than the
527     // 32K command line length limit on Windows.  We could make this a
528     // platform file variable but this should work everywhere.
529     archiveCommandLimit = 30000;
530     }
531
532   // Expand the rule variables.
533   std::vector<std::string> real_link_commands;
534   {
535   // Set path conversion for link script shells.
536   this->LocalGenerator->SetLinkScriptShell(useLinkScript);
537
538   // Collect up flags to link in needed libraries.
539   std::string linkLibs;
540   if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
541     {
542     std::string frameworkPath;
543     std::string linkPath;
544     this->LocalGenerator
545       ->OutputLinkLibraries(linkLibs, frameworkPath, linkPath,
546                             *this->GeneratorTarget, relink);
547     linkLibs = frameworkPath + linkPath + linkLibs;
548     }
549
550   // Construct object file lists that may be needed to expand the
551   // rule.
552   std::string buildObjs;
553   this->CreateObjectLists(useLinkScript, useArchiveRules, useResponseFile,
554                           buildObjs, depends);
555
556   cmLocalGenerator::RuleVariables vars;
557   vars.TargetPDB = targetOutPathPDB.c_str();
558
559   // Setup the target version.
560   std::string targetVersionMajor;
561   std::string targetVersionMinor;
562   {
563   cmOStringStream majorStream;
564   cmOStringStream minorStream;
565   int major;
566   int minor;
567   this->Target->GetTargetVersion(major, minor);
568   majorStream << major;
569   minorStream << minor;
570   targetVersionMajor = majorStream.str();
571   targetVersionMinor = minorStream.str();
572   }
573   vars.TargetVersionMajor = targetVersionMajor.c_str();
574   vars.TargetVersionMinor = targetVersionMinor.c_str();
575
576   vars.RuleLauncher = "RULE_LAUNCH_LINK";
577   vars.CMTarget = this->Target;
578   vars.Language = linkLanguage;
579   vars.Objects = buildObjs.c_str();
580   std::string objectDir = this->Target->GetSupportDirectory();
581   objectDir = this->Convert(objectDir.c_str(),
582                             cmLocalGenerator::START_OUTPUT,
583                             cmLocalGenerator::SHELL);
584   vars.ObjectDir = objectDir.c_str();
585   vars.Target = targetOutPathReal.c_str();
586   vars.LinkLibraries = linkLibs.c_str();
587   vars.ObjectsQuoted = buildObjs.c_str();
588   if (this->Target->HasSOName(this->ConfigName))
589     {
590     vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage);
591     vars.TargetSOName= targetNameSO.c_str();
592     }
593   vars.LinkFlags = linkFlags.c_str();
594
595   // Compute the directory portion of the install_name setting.
596   std::string install_name_dir;
597   if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
598     {
599     // Get the install_name directory for the build tree.
600     install_name_dir =
601       this->Target->GetInstallNameDirForBuildTree(this->ConfigName);
602
603     // Set the rule variable replacement value.
604     if(install_name_dir.empty())
605       {
606       vars.TargetInstallNameDir = "";
607       }
608     else
609       {
610       // Convert to a path for the native build tool.
611       install_name_dir =
612         this->LocalGenerator->Convert(install_name_dir.c_str(),
613                                       cmLocalGenerator::NONE,
614                                       cmLocalGenerator::SHELL, false);
615       vars.TargetInstallNameDir = install_name_dir.c_str();
616       }
617     }
618
619   // Add language feature flags.
620   std::string langFlags;
621   this->AddFeatureFlags(langFlags, linkLanguage);
622
623   this->LocalGenerator->AddArchitectureFlags(langFlags, this->GeneratorTarget,
624                                              linkLanguage, this->ConfigName);
625
626   // remove any language flags that might not work with the
627   // particular os
628   if(forbiddenFlagVar)
629     {
630     this->RemoveForbiddenFlags(forbiddenFlagVar,
631                                linkLanguage, langFlags);
632     }
633   vars.LanguageCompileFlags = langFlags.c_str();
634
635   // Construct the main link rule and expand placeholders.
636   this->LocalGenerator->TargetImplib = targetOutPathImport;
637   if(useArchiveRules)
638     {
639     // Construct the individual object list strings.
640     std::vector<std::string> object_strings;
641     this->WriteObjectsStrings(object_strings, archiveCommandLimit);
642
643     // Create the archive with the first set of objects.
644     std::vector<std::string>::iterator osi = object_strings.begin();
645     {
646     vars.Objects = osi->c_str();
647     for(std::vector<std::string>::const_iterator
648           i = archiveCreateCommands.begin();
649         i != archiveCreateCommands.end(); ++i)
650       {
651       std::string cmd = *i;
652       this->LocalGenerator->ExpandRuleVariables(cmd, vars);
653       real_link_commands.push_back(cmd);
654       }
655     }
656     // Append to the archive with the other object sets.
657     for(++osi; osi != object_strings.end(); ++osi)
658       {
659       vars.Objects = osi->c_str();
660       for(std::vector<std::string>::const_iterator
661             i = archiveAppendCommands.begin();
662           i != archiveAppendCommands.end(); ++i)
663         {
664         std::string cmd = *i;
665         this->LocalGenerator->ExpandRuleVariables(cmd, vars);
666         real_link_commands.push_back(cmd);
667         }
668       }
669     // Finish the archive.
670     vars.Objects = "";
671     for(std::vector<std::string>::const_iterator
672           i = archiveFinishCommands.begin();
673         i != archiveFinishCommands.end(); ++i)
674       {
675       std::string cmd = *i;
676       this->LocalGenerator->ExpandRuleVariables(cmd, vars);
677       real_link_commands.push_back(cmd);
678       }
679     }
680   else
681     {
682     // Get the set of commands.
683     std::string linkRule = this->GetLinkRule(linkRuleVar);
684     cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
685
686     // Expand placeholders.
687     for(std::vector<std::string>::iterator i = real_link_commands.begin();
688         i != real_link_commands.end(); ++i)
689       {
690       this->LocalGenerator->ExpandRuleVariables(*i, vars);
691       }
692     }
693   this->LocalGenerator->TargetImplib = "";
694
695   // Restore path conversion to normal shells.
696   this->LocalGenerator->SetLinkScriptShell(false);
697   }
698
699   // Optionally convert the build rule to use a script to avoid long
700   // command lines in the make shell.
701   if(useLinkScript)
702     {
703     // Use a link script.
704     const char* name = (relink? "relink.txt" : "link.txt");
705     this->CreateLinkScript(name, real_link_commands, commands1, depends);
706     }
707   else
708     {
709     // No link script.  Just use the link rule directly.
710     commands1 = real_link_commands;
711     }
712   this->LocalGenerator->CreateCDCommand
713     (commands1,
714      this->Makefile->GetStartOutputDirectory(),
715      cmLocalGenerator::HOME_OUTPUT);
716   commands.insert(commands.end(), commands1.begin(), commands1.end());
717   commands1.clear();
718
719   // Add a rule to create necessary symlinks for the library.
720   // Frameworks are handled by cmOSXBundleGenerator.
721   if(targetOutPath != targetOutPathReal && !this->Target->IsFrameworkOnApple())
722     {
723     std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library ";
724     symlink += targetOutPathReal;
725     symlink += " ";
726     symlink += targetOutPathSO;
727     symlink += " ";
728     symlink += targetOutPath;
729     commands1.push_back(symlink);
730     this->LocalGenerator->CreateCDCommand(commands1,
731                                   this->Makefile->GetStartOutputDirectory(),
732                                   cmLocalGenerator::HOME_OUTPUT);
733     commands.insert(commands.end(), commands1.begin(), commands1.end());
734     commands1.clear();
735     }
736   // Add the post-build rules when building but not when relinking.
737   if(!relink)
738     {
739     this->LocalGenerator->
740       AppendCustomCommands(commands, this->Target->GetPostBuildCommands(),
741                            this->Target);
742     }
743
744   // Write the build rule.
745   this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
746                                       targetFullPathReal.c_str(),
747                                       depends, commands, false);
748
749   // Some targets have more than one output file.  Create rules to
750   // drive the build if any extra outputs are missing.
751   std::vector<std::string> extraOutputs;
752   if(targetNameSO != targetNameReal)
753     {
754     this->GenerateExtraOutput(targetFullPathSO.c_str(),
755                               targetFullPathReal.c_str());
756     }
757   if(targetName != targetNameSO &&
758      targetName != targetNameReal)
759     {
760     this->GenerateExtraOutput(targetFullPath.c_str(),
761                               targetFullPathReal.c_str());
762     }
763
764   // Write the main driver rule to build everything in this target.
765   this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
766
767   // Clean all the possible library names and symlinks.
768   this->CleanFiles.insert(this->CleanFiles.end(),
769                           libCleanFiles.begin(),libCleanFiles.end());
770 }
771
772 //----------------------------------------------------------------------------
773 void
774 cmMakefileLibraryTargetGenerator
775 ::AppendOSXVerFlag(std::string& flags, const char* lang,
776                    const char* name, bool so)
777 {
778   // Lookup the flag to specify the version.
779   std::string fvar = "CMAKE_";
780   fvar += lang;
781   fvar += "_OSX_";
782   fvar += name;
783   fvar += "_VERSION_FLAG";
784   const char* flag = this->Makefile->GetDefinition(fvar.c_str());
785
786   // Skip if no such flag.
787   if(!flag)
788     {
789     return;
790     }
791
792   // Lookup the target version information.
793   int major;
794   int minor;
795   int patch;
796   this->Target->GetTargetVersion(so, major, minor, patch);
797   if(major > 0 || minor > 0 || patch > 0)
798     {
799     // Append the flag since a non-zero version is specified.
800     cmOStringStream vflag;
801     vflag << flag << major << "." << minor << "." << patch;
802     this->LocalGenerator->AppendFlags(flags, vflag.str().c_str());
803     }
804 }