ENH: Return utility target after creation
[cmake.git] / Source / cmMakefileLibraryTargetGenerator.cxx
blob64e13227f5b02f4e698d66ea0669541451e72103
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMakefileLibraryTargetGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2008-09-02 16:06:32 $
7 Version: $Revision: 1.64 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmMakefileLibraryTargetGenerator.h"
19 #include "cmGeneratedFileStream.h"
20 #include "cmGlobalUnixMakefileGenerator3.h"
21 #include "cmLocalUnixMakefileGenerator3.h"
22 #include "cmMakefile.h"
23 #include "cmSourceFile.h"
24 #include "cmTarget.h"
25 #include "cmake.h"
27 #include <memory> // auto_ptr
29 //----------------------------------------------------------------------------
30 cmMakefileLibraryTargetGenerator
31 ::cmMakefileLibraryTargetGenerator(cmTarget* target):
32 cmMakefileTargetGenerator(target)
34 this->CustomCommandDriver = OnDepends;
35 this->Target->GetLibraryNames(
36 this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
37 this->TargetNameImport, this->TargetNamePDB,
38 this->LocalGenerator->ConfigurationName.c_str());
40 if(this->Target->IsFrameworkOnApple())
42 this->FrameworkVersion = this->Target->GetFrameworkVersion();
43 this->MacContentDirectory = this->Target->GetDirectory();
44 this->MacContentDirectory += "/";
45 this->MacContentDirectory += this->TargetNameOut;
46 this->MacContentDirectory += ".framework/Versions/";
47 this->MacContentDirectory += this->FrameworkVersion;
48 this->MacContentDirectory += "/";
52 //----------------------------------------------------------------------------
53 void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
55 // create the build.make file and directory, put in the common blocks
56 this->CreateRuleFile();
58 // write rules used to help build object files
59 this->WriteCommonCodeRules();
61 // write in rules for object files and custom commands
62 this->WriteTargetBuildRules();
64 // write the per-target per-language flags
65 this->WriteTargetLanguageFlags();
67 // write the link rules
68 // Write the rule for this target type.
69 switch(this->Target->GetType())
71 case cmTarget::STATIC_LIBRARY:
72 this->WriteStaticLibraryRules();
73 break;
74 case cmTarget::SHARED_LIBRARY:
75 this->WriteSharedLibraryRules(false);
76 if(this->Target->NeedRelinkBeforeInstall())
78 // Write rules to link an installable version of the target.
79 this->WriteSharedLibraryRules(true);
81 break;
82 case cmTarget::MODULE_LIBRARY:
83 this->WriteModuleLibraryRules(false);
84 if(this->Target->NeedRelinkBeforeInstall())
86 // Write rules to link an installable version of the target.
87 this->WriteModuleLibraryRules(true);
89 break;
90 default:
91 // If language is not known, this is an error.
92 cmSystemTools::Error("Unknown Library Type");
93 break;
96 // Write the requires target.
97 this->WriteTargetRequiresRules();
99 // Write clean target
100 this->WriteTargetCleanRules();
102 // Write the dependency generation rule. This must be done last so
103 // that multiple output pair information is available.
104 this->WriteTargetDependRules();
106 // close the streams
107 this->CloseFileStreams();
110 //----------------------------------------------------------------------------
111 void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
113 const char* linkLanguage =
114 this->Target->GetLinkerLanguage(this->GlobalGenerator);
115 std::string linkRuleVar = "CMAKE_";
116 if (linkLanguage)
118 linkRuleVar += linkLanguage;
120 linkRuleVar += "_CREATE_STATIC_LIBRARY";
122 std::string extraFlags;
123 this->LocalGenerator->AppendFlags
124 (extraFlags,this->Target->GetProperty("STATIC_LIBRARY_FLAGS"));
125 this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), false);
128 //----------------------------------------------------------------------------
129 void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
131 if(this->Target->IsFrameworkOnApple())
133 this->WriteFrameworkRules(relink);
134 return;
136 const char* linkLanguage =
137 this->Target->GetLinkerLanguage(this->GlobalGenerator);
138 std::string linkRuleVar = "CMAKE_";
139 if (linkLanguage)
141 linkRuleVar += linkLanguage;
143 linkRuleVar += "_CREATE_SHARED_LIBRARY";
145 std::string extraFlags;
146 this->LocalGenerator->AppendFlags
147 (extraFlags, this->Target->GetProperty("LINK_FLAGS"));
148 std::string linkFlagsConfig = "LINK_FLAGS_";
149 linkFlagsConfig +=
150 cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
151 this->LocalGenerator->AppendFlags
152 (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
154 this->LocalGenerator->AddConfigVariableFlags
155 (extraFlags, "CMAKE_SHARED_LINKER_FLAGS",
156 this->LocalGenerator->ConfigurationName.c_str());
157 if(this->Makefile->IsOn("WIN32") && !(this->Makefile->IsOn("CYGWIN")
158 || this->Makefile->IsOn("MINGW")))
160 const std::vector<cmSourceFile*>& sources =
161 this->Target->GetSourceFiles();
162 for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
163 i != sources.end(); ++i)
165 cmSourceFile* sf = *i;
166 if(sf->GetExtension() == "def")
168 extraFlags += " ";
169 extraFlags +=
170 this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG");
171 extraFlags +=
172 this->Convert(sf->GetFullPath().c_str(),
173 cmLocalGenerator::START_OUTPUT,
174 cmLocalGenerator::SHELL);
178 this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
181 //----------------------------------------------------------------------------
182 void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
184 const char* linkLanguage =
185 this->Target->GetLinkerLanguage(this->GlobalGenerator);
186 std::string linkRuleVar = "CMAKE_";
187 if (linkLanguage)
189 linkRuleVar += linkLanguage;
191 linkRuleVar += "_CREATE_SHARED_MODULE";
193 std::string extraFlags;
194 this->LocalGenerator->AppendFlags(extraFlags,
195 this->Target->GetProperty("LINK_FLAGS"));
196 std::string linkFlagsConfig = "LINK_FLAGS_";
197 linkFlagsConfig +=
198 cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
199 this->LocalGenerator->AppendFlags
200 (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
201 this->LocalGenerator->AddConfigVariableFlags
202 (extraFlags, "CMAKE_MODULE_LINKER_FLAGS",
203 this->LocalGenerator->ConfigurationName.c_str());
205 // TODO: .def files should be supported here also.
206 this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
209 //----------------------------------------------------------------------------
210 void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
212 const char* linkLanguage =
213 this->Target->GetLinkerLanguage(this->GlobalGenerator);
214 std::string linkRuleVar = "CMAKE_";
215 if (linkLanguage)
217 linkRuleVar += linkLanguage;
219 linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
221 std::string extraFlags;
222 this->LocalGenerator->AppendFlags(extraFlags,
223 this->Target->GetProperty("LINK_FLAGS"));
224 std::string linkFlagsConfig = "LINK_FLAGS_";
225 linkFlagsConfig +=
226 cmSystemTools::UpperCase(this->LocalGenerator->ConfigurationName.c_str());
227 this->LocalGenerator->AppendFlags
228 (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
229 this->LocalGenerator->AddConfigVariableFlags
230 (extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS",
231 this->LocalGenerator->ConfigurationName.c_str());
233 // TODO: .def files should be supported here also.
234 this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
237 //----------------------------------------------------------------------------
238 void
239 cmMakefileLibraryTargetGenerator
240 ::CreateFramework(std::string const& targetName)
242 // Configure the Info.plist file into the Resources directory.
243 this->MacContentFolders.insert("Resources");
244 std::string plist = this->MacContentDirectory + "Resources/Info.plist";
245 this->LocalGenerator->GenerateFrameworkInfoPList(this->Target,
246 targetName.c_str(),
247 plist.c_str());
249 // TODO: Use the cmMakefileTargetGenerator::ExtraFiles vector to
250 // drive rules to create these files at build time.
251 std::string oldName;
252 std::string newName;
254 // Compute the location of the top-level foo.framework directory.
255 std::string top = this->Target->GetDirectory();
256 top += "/";
257 top += this->TargetNameOut;
258 top += ".framework/";
260 // Make foo.framework/Versions
261 std::string versions = top;
262 versions += "Versions";
263 cmSystemTools::MakeDirectory(versions.c_str());
265 // Make foo.framework/Versions/version
266 std::string version = versions;
267 version += "/";
268 version += this->FrameworkVersion;
269 cmSystemTools::MakeDirectory(version.c_str());
271 // Current -> version
272 oldName = this->FrameworkVersion;
273 newName = versions;
274 newName += "/Current";
275 cmSystemTools::RemoveFile(newName.c_str());
276 cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
277 this->Makefile->AddCMakeOutputFile(newName.c_str());
279 // foo -> Versions/Current/foo
280 oldName = "Versions/Current/";
281 oldName += this->TargetNameOut;
282 newName = top;
283 newName += this->TargetNameOut;
284 cmSystemTools::RemoveFile(newName.c_str());
285 cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
286 this->Makefile->AddCMakeOutputFile(newName.c_str());
288 // Resources -> Versions/Current/Resources
289 if(this->MacContentFolders.find("Resources") !=
290 this->MacContentFolders.end())
292 oldName = "Versions/Current/Resources";
293 newName = top;
294 newName += "Resources";
295 cmSystemTools::RemoveFile(newName.c_str());
296 cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
297 this->Makefile->AddCMakeOutputFile(newName.c_str());
300 // Headers -> Versions/Current/Headers
301 if(this->MacContentFolders.find("Headers") !=
302 this->MacContentFolders.end())
304 oldName = "Versions/Current/Headers";
305 newName = top;
306 newName += "Headers";
307 cmSystemTools::RemoveFile(newName.c_str());
308 cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
309 this->Makefile->AddCMakeOutputFile(newName.c_str());
312 // PrivateHeaders -> Versions/Current/PrivateHeaders
313 if(this->MacContentFolders.find("PrivateHeaders") !=
314 this->MacContentFolders.end())
316 oldName = "Versions/Current/PrivateHeaders";
317 newName = top;
318 newName += "PrivateHeaders";
319 cmSystemTools::RemoveFile(newName.c_str());
320 cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
321 this->Makefile->AddCMakeOutputFile(newName.c_str());
325 //----------------------------------------------------------------------------
326 void cmMakefileLibraryTargetGenerator::WriteLibraryRules
327 (const char* linkRuleVar, const char* extraFlags, bool relink)
329 // TODO: Merge the methods that call this method to avoid
330 // code duplication.
331 std::vector<std::string> commands;
333 std::string relPath = this->LocalGenerator->GetHomeRelativeOutputPath();
334 std::string objTarget;
336 // Build list of dependencies.
337 std::vector<std::string> depends;
338 for(std::vector<std::string>::const_iterator obj = this->Objects.begin();
339 obj != this->Objects.end(); ++obj)
341 objTarget = relPath;
342 objTarget += *obj;
343 depends.push_back(objTarget);
346 // Add dependencies on targets that must be built first.
347 this->AppendTargetDepends(depends);
349 // Add a dependency on the rule file itself.
350 this->LocalGenerator->AppendRuleDepend(depends,
351 this->BuildFileNameFull.c_str());
353 for(std::vector<std::string>::const_iterator obj
354 = this->ExternalObjects.begin();
355 obj != this->ExternalObjects.end(); ++obj)
357 depends.push_back(*obj);
360 // Get the language to use for linking this library.
361 const char* linkLanguage =
362 this->Target->GetLinkerLanguage(this->GlobalGenerator);
364 // Make sure we have a link language.
365 if(!linkLanguage)
367 cmSystemTools::Error("Cannot determine link language for target \"",
368 this->Target->GetName(), "\".");
369 return;
372 // Create set of linking flags.
373 std::string linkFlags;
374 this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
376 // Add OSX version flags, if any.
377 if(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
378 this->Target->GetType() == cmTarget::MODULE_LIBRARY)
380 this->AppendOSXVerFlag(linkFlags, linkLanguage, "COMPATIBILITY", true);
381 this->AppendOSXVerFlag(linkFlags, linkLanguage, "CURRENT", false);
384 // Construct the name of the library.
385 std::string targetName;
386 std::string targetNameSO;
387 std::string targetNameReal;
388 std::string targetNameImport;
389 std::string targetNamePDB;
390 this->Target->GetLibraryNames(
391 targetName, targetNameSO, targetNameReal, targetNameImport, targetNamePDB,
392 this->LocalGenerator->ConfigurationName.c_str());
394 // Construct the full path version of the names.
395 std::string outpath;
396 std::string outpathImp;
397 if(this->Target->IsFrameworkOnApple())
399 outpath = this->MacContentDirectory;
400 this->CreateFramework(targetName);
402 else if(relink)
404 outpath = this->Makefile->GetStartOutputDirectory();
405 outpath += cmake::GetCMakeFilesDirectory();
406 outpath += "/CMakeRelink.dir";
407 cmSystemTools::MakeDirectory(outpath.c_str());
408 outpath += "/";
409 if(!targetNameImport.empty())
411 outpathImp = outpath;
414 else
416 outpath = this->Target->GetDirectory();
417 cmSystemTools::MakeDirectory(outpath.c_str());
418 outpath += "/";
419 if(!targetNameImport.empty())
421 outpathImp = this->Target->GetDirectory(0, true);
422 cmSystemTools::MakeDirectory(outpathImp.c_str());
423 outpathImp += "/";
427 std::string targetFullPath = outpath + targetName;
428 std::string targetFullPathPDB = outpath + targetNamePDB;
429 std::string targetFullPathSO = outpath + targetNameSO;
430 std::string targetFullPathReal = outpath + targetNameReal;
431 std::string targetFullPathImport = outpathImp + targetNameImport;
433 // Construct the output path version of the names for use in command
434 // arguments.
435 std::string targetOutPathPDB =
436 this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::FULL,
437 cmLocalGenerator::SHELL);
438 std::string targetOutPath =
439 this->Convert(targetFullPath.c_str(),cmLocalGenerator::START_OUTPUT,
440 cmLocalGenerator::SHELL);
441 std::string targetOutPathSO =
442 this->Convert(targetFullPathSO.c_str(),cmLocalGenerator::START_OUTPUT,
443 cmLocalGenerator::SHELL);
444 std::string targetOutPathReal =
445 this->Convert(targetFullPathReal.c_str(),cmLocalGenerator::START_OUTPUT,
446 cmLocalGenerator::SHELL);
447 std::string targetOutPathImport =
448 this->Convert(targetFullPathImport.c_str(),cmLocalGenerator::START_OUTPUT,
449 cmLocalGenerator::SHELL);
451 // Add the link message.
452 std::string buildEcho = "Linking ";
453 buildEcho += linkLanguage;
454 const char* forbiddenFlagVar = 0;
455 switch(this->Target->GetType())
457 case cmTarget::STATIC_LIBRARY:
458 buildEcho += " static library ";
459 break;
460 case cmTarget::SHARED_LIBRARY:
461 forbiddenFlagVar = "_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS";
462 buildEcho += " shared library ";
463 break;
464 case cmTarget::MODULE_LIBRARY:
465 forbiddenFlagVar = "_CREATE_SHARED_MODULE_FORBIDDEN_FLAGS";
466 buildEcho += " shared module ";
467 break;
468 default:
469 buildEcho += " library ";
470 break;
472 buildEcho += targetOutPath.c_str();
473 this->LocalGenerator->AppendEcho(commands, buildEcho.c_str(),
474 cmLocalUnixMakefileGenerator3::EchoLink);
476 // Construct a list of files associated with this library that may
477 // need to be cleaned.
478 std::vector<std::string> libCleanFiles;
479 if(this->Target->GetPropertyAsBool("CLEAN_DIRECT_OUTPUT"))
481 // The user has requested that only the files directly built
482 // by this target be cleaned instead of all possible names.
483 libCleanFiles.push_back(this->Convert(targetFullPath.c_str(),
484 cmLocalGenerator::START_OUTPUT,
485 cmLocalGenerator::UNCHANGED));
486 if(targetNameReal != targetName)
488 libCleanFiles.push_back(this->Convert(targetFullPathReal.c_str(),
489 cmLocalGenerator::START_OUTPUT,
490 cmLocalGenerator::UNCHANGED));
492 if(targetNameSO != targetName &&
493 targetNameSO != targetNameReal)
495 libCleanFiles.push_back(this->Convert(targetFullPathSO.c_str(),
496 cmLocalGenerator::START_OUTPUT,
497 cmLocalGenerator::UNCHANGED));
499 if(!targetNameImport.empty())
501 libCleanFiles.push_back(this->Convert(targetFullPathImport.c_str(),
502 cmLocalGenerator::START_OUTPUT,
503 cmLocalGenerator::UNCHANGED));
506 else
508 // This target may switch between static and shared based
509 // on a user option or the BUILD_SHARED_LIBS switch. Clean
510 // all possible names.
511 std::string cleanStaticName;
512 std::string cleanSharedName;
513 std::string cleanSharedSOName;
514 std::string cleanSharedRealName;
515 std::string cleanImportName;
516 std::string cleanPDBName;
517 this->Target->GetLibraryCleanNames(
518 cleanStaticName,
519 cleanSharedName,
520 cleanSharedSOName,
521 cleanSharedRealName,
522 cleanImportName,
523 cleanPDBName,
524 this->LocalGenerator->ConfigurationName.c_str());
525 std::string cleanFullStaticName = outpath + cleanStaticName;
526 std::string cleanFullSharedName = outpath + cleanSharedName;
527 std::string cleanFullSharedSOName = outpath + cleanSharedSOName;
528 std::string cleanFullSharedRealName = outpath + cleanSharedRealName;
529 std::string cleanFullImportName = outpathImp + cleanImportName;
530 std::string cleanFullPDBName = outpath + cleanPDBName;
531 libCleanFiles.push_back
532 (this->Convert(cleanFullStaticName.c_str(),
533 cmLocalGenerator::START_OUTPUT,
534 cmLocalGenerator::UNCHANGED));
535 if(cleanSharedRealName != cleanStaticName)
537 libCleanFiles.push_back(this->Convert(cleanFullSharedRealName.c_str(),
538 cmLocalGenerator::START_OUTPUT,
539 cmLocalGenerator::UNCHANGED));
541 if(cleanSharedSOName != cleanStaticName &&
542 cleanSharedSOName != cleanSharedRealName)
544 libCleanFiles.push_back(this->Convert(cleanFullSharedSOName.c_str(),
545 cmLocalGenerator::START_OUTPUT,
546 cmLocalGenerator::UNCHANGED));
548 if(cleanSharedName != cleanStaticName &&
549 cleanSharedName != cleanSharedSOName &&
550 cleanSharedName != cleanSharedRealName)
552 libCleanFiles.push_back(this->Convert(cleanFullSharedName.c_str(),
553 cmLocalGenerator::START_OUTPUT,
554 cmLocalGenerator::UNCHANGED));
556 if(!cleanImportName.empty())
558 libCleanFiles.push_back(this->Convert(cleanFullImportName.c_str(),
559 cmLocalGenerator::START_OUTPUT,
560 cmLocalGenerator::UNCHANGED));
563 // List the PDB for cleaning only when the whole target is
564 // cleaned. We do not want to delete the .pdb file just before
565 // linking the target.
566 this->CleanFiles.push_back
567 (this->Convert(cleanFullPDBName.c_str(),
568 cmLocalGenerator::START_OUTPUT,
569 cmLocalGenerator::UNCHANGED));
572 #ifdef _WIN32
573 // There may be a manifest file for this target. Add it to the
574 // clean set just in case.
575 if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
577 libCleanFiles.push_back(
578 this->Convert((targetFullPath+".manifest").c_str(),
579 cmLocalGenerator::START_OUTPUT,
580 cmLocalGenerator::UNCHANGED));
582 #endif
584 std::vector<std::string> commands1;
585 // Add a command to remove any existing files for this library.
586 // for static libs only
587 if(this->Target->GetType() == cmTarget::STATIC_LIBRARY)
589 this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,
590 *this->Target, "target");
591 this->LocalGenerator->CreateCDCommand
592 (commands1,
593 this->Makefile->GetStartOutputDirectory(),
594 this->Makefile->GetHomeOutputDirectory());
595 commands.insert(commands.end(), commands1.begin(), commands1.end());
596 commands1.clear();
599 // Add the pre-build and pre-link rules building but not when relinking.
600 if(!relink)
602 this->LocalGenerator
603 ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands());
604 this->LocalGenerator
605 ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
608 // Determine whether a link script will be used.
609 bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
611 // Select whether to use a response file for objects.
612 bool useResponseFile = false;
614 std::string responseVar = "CMAKE_";
615 responseVar += linkLanguage;
616 responseVar += "_USE_RESPONSE_FILE_FOR_OBJECTS";
617 if(this->Makefile->IsOn(responseVar.c_str()))
619 useResponseFile = true;
623 // For static libraries there might be archiving rules.
624 bool haveStaticLibraryRule = false;
625 std::vector<std::string> archiveCreateCommands;
626 std::vector<std::string> archiveAppendCommands;
627 std::vector<std::string> archiveFinishCommands;
628 std::string::size_type archiveCommandLimit = std::string::npos;
629 if(this->Target->GetType() == cmTarget::STATIC_LIBRARY)
631 haveStaticLibraryRule =
632 this->Makefile->GetDefinition(linkRuleVar)? true:false;
633 std::string arCreateVar = "CMAKE_";
634 arCreateVar += linkLanguage;
635 arCreateVar += "_ARCHIVE_CREATE";
636 if(const char* rule = this->Makefile->GetDefinition(arCreateVar.c_str()))
638 cmSystemTools::ExpandListArgument(rule, archiveCreateCommands);
640 std::string arAppendVar = "CMAKE_";
641 arAppendVar += linkLanguage;
642 arAppendVar += "_ARCHIVE_APPEND";
643 if(const char* rule = this->Makefile->GetDefinition(arAppendVar.c_str()))
645 cmSystemTools::ExpandListArgument(rule, archiveAppendCommands);
647 std::string arFinishVar = "CMAKE_";
648 arFinishVar += linkLanguage;
649 arFinishVar += "_ARCHIVE_FINISH";
650 if(const char* rule = this->Makefile->GetDefinition(arFinishVar.c_str()))
652 cmSystemTools::ExpandListArgument(rule, archiveFinishCommands);
656 // Decide whether to use archiving rules.
657 bool useArchiveRules =
658 !haveStaticLibraryRule &&
659 !archiveCreateCommands.empty() && !archiveAppendCommands.empty();
660 if(useArchiveRules)
662 // Archiving rules are always run with a link script.
663 useLinkScript = true;
665 // Archiving rules never use a response file.
666 useResponseFile = false;
668 // Limit the length of individual object lists to less than the
669 // 32K command line length limit on Windows. We could make this a
670 // platform file variable but this should work everywhere.
671 archiveCommandLimit = 30000;
674 // Expand the rule variables.
675 std::vector<std::string> real_link_commands;
677 // Set path conversion for link script shells.
678 this->LocalGenerator->SetLinkScriptShell(useLinkScript);
680 // Collect up flags to link in needed libraries.
681 cmOStringStream linklibs;
682 if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
684 this->LocalGenerator
685 ->OutputLinkLibraries(linklibs, *this->Target, relink);
688 // Construct object file lists that may be needed to expand the
689 // rule.
690 std::string variableName;
691 std::string variableNameExternal;
692 this->WriteObjectsVariable(variableName, variableNameExternal);
693 std::string buildObjs;
694 if(useResponseFile)
696 std::string objects;
697 this->WriteObjectsString(objects);
698 std::string objects_rsp =
699 this->CreateResponseFile("objects.rsp", objects, depends);
700 buildObjs = "@";
701 buildObjs += this->Convert(objects_rsp.c_str(),
702 cmLocalGenerator::NONE,
703 cmLocalGenerator::SHELL);
705 else if(useLinkScript)
707 if(!useArchiveRules)
709 this->WriteObjectsString(buildObjs);
712 else
714 buildObjs = "$(";
715 buildObjs += variableName;
716 buildObjs += ") $(";
717 buildObjs += variableNameExternal;
718 buildObjs += ")";
720 std::string cleanObjs = "$(";
721 cleanObjs += variableName;
722 cleanObjs += ")";
723 cmLocalGenerator::RuleVariables vars;
724 vars.TargetPDB = targetOutPathPDB.c_str();
726 // Setup the target version.
727 std::string targetVersionMajor;
728 std::string targetVersionMinor;
730 cmOStringStream majorStream;
731 cmOStringStream minorStream;
732 int major;
733 int minor;
734 this->Target->GetTargetVersion(major, minor);
735 majorStream << major;
736 minorStream << minor;
737 targetVersionMajor = majorStream.str();
738 targetVersionMinor = minorStream.str();
740 vars.TargetVersionMajor = targetVersionMajor.c_str();
741 vars.TargetVersionMinor = targetVersionMinor.c_str();
743 vars.Language = linkLanguage;
744 vars.Objects = buildObjs.c_str();
745 std::string objdir = cmake::GetCMakeFilesDirectoryPostSlash();
746 objdir += this->Target->GetName();
747 objdir += ".dir";
748 objdir = this->Convert(objdir.c_str(),
749 cmLocalGenerator::START_OUTPUT,
750 cmLocalGenerator::SHELL);
751 vars.ObjectDir = objdir.c_str();
752 vars.Target = targetOutPathReal.c_str();
753 std::string linkString = linklibs.str();
754 vars.LinkLibraries = linkString.c_str();
755 vars.ObjectsQuoted = buildObjs.c_str();
756 vars.TargetSOName= targetNameSO.c_str();
757 vars.LinkFlags = linkFlags.c_str();
759 // Compute the directory portion of the install_name setting.
760 std::string install_name_dir;
761 if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
763 // Get the install_name directory for the build tree.
764 const char* config = this->LocalGenerator->ConfigurationName.c_str();
765 install_name_dir = this->Target->GetInstallNameDirForBuildTree(config);
767 // Set the rule variable replacement value.
768 if(install_name_dir.empty())
770 vars.TargetInstallNameDir = "";
772 else
774 // Convert to a path for the native build tool.
775 install_name_dir =
776 this->LocalGenerator->Convert(install_name_dir.c_str(),
777 cmLocalGenerator::NONE,
778 cmLocalGenerator::SHELL, false);
779 vars.TargetInstallNameDir = install_name_dir.c_str();
782 std::string langFlags;
783 this->LocalGenerator
784 ->AddLanguageFlags(langFlags, linkLanguage,
785 this->LocalGenerator->ConfigurationName.c_str());
786 // remove any language flags that might not work with the
787 // particular os
788 if(forbiddenFlagVar)
790 this->RemoveForbiddenFlags(forbiddenFlagVar,
791 linkLanguage, langFlags);
793 vars.LanguageCompileFlags = langFlags.c_str();
795 // Construct the main link rule and expand placeholders.
796 this->LocalGenerator->TargetImplib = targetOutPathImport;
797 if(useArchiveRules)
799 // Construct the individual object list strings.
800 std::vector<std::string> object_strings;
801 this->WriteObjectsStrings(object_strings, archiveCommandLimit);
803 // Create the archive with the first set of objects.
804 std::vector<std::string>::iterator osi = object_strings.begin();
806 vars.Objects = osi->c_str();
807 for(std::vector<std::string>::const_iterator
808 i = archiveCreateCommands.begin();
809 i != archiveCreateCommands.end(); ++i)
811 std::string cmd = *i;
812 this->LocalGenerator->ExpandRuleVariables(cmd, vars);
813 real_link_commands.push_back(cmd);
816 // Append to the archive with the other object sets.
817 for(++osi; osi != object_strings.end(); ++osi)
819 vars.Objects = osi->c_str();
820 for(std::vector<std::string>::const_iterator
821 i = archiveAppendCommands.begin();
822 i != archiveAppendCommands.end(); ++i)
824 std::string cmd = *i;
825 this->LocalGenerator->ExpandRuleVariables(cmd, vars);
826 real_link_commands.push_back(cmd);
829 // Finish the archive.
830 vars.Objects = "";
831 for(std::vector<std::string>::const_iterator
832 i = archiveFinishCommands.begin();
833 i != archiveFinishCommands.end(); ++i)
835 std::string cmd = *i;
836 this->LocalGenerator->ExpandRuleVariables(cmd, vars);
837 real_link_commands.push_back(cmd);
840 else
842 // Get the set of commands.
843 std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
844 cmSystemTools::ExpandListArgument(linkRule, real_link_commands);
846 // Expand placeholders.
847 for(std::vector<std::string>::iterator i = real_link_commands.begin();
848 i != real_link_commands.end(); ++i)
850 this->LocalGenerator->ExpandRuleVariables(*i, vars);
853 this->LocalGenerator->TargetImplib = "";
855 // Restore path conversion to normal shells.
856 this->LocalGenerator->SetLinkScriptShell(false);
859 // Optionally convert the build rule to use a script to avoid long
860 // command lines in the make shell.
861 if(useLinkScript)
863 // Use a link script.
864 const char* name = (relink? "relink.txt" : "link.txt");
865 this->CreateLinkScript(name, real_link_commands, commands1, depends);
867 else
869 // No link script. Just use the link rule directly.
870 commands1 = real_link_commands;
872 this->LocalGenerator->CreateCDCommand
873 (commands1,
874 this->Makefile->GetStartOutputDirectory(),
875 this->Makefile->GetHomeOutputDirectory());
876 commands.insert(commands.end(), commands1.begin(), commands1.end());
877 commands1.clear();
879 // Add a rule to create necessary symlinks for the library.
880 if(targetOutPath != targetOutPathReal)
882 std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_library ";
883 symlink += targetOutPathReal;
884 symlink += " ";
885 symlink += targetOutPathSO;
886 symlink += " ";
887 symlink += targetOutPath;
888 commands1.push_back(symlink);
889 this->LocalGenerator->CreateCDCommand(commands1,
890 this->Makefile->GetStartOutputDirectory(),
891 this->Makefile->GetHomeOutputDirectory());
892 commands.insert(commands.end(), commands1.begin(), commands1.end());
893 commands1.clear();
895 // Add the post-build rules when building but not when relinking.
896 if(!relink)
898 this->LocalGenerator->
899 AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
902 // Write the build rule.
903 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
904 targetFullPathReal.c_str(),
905 depends, commands, false);
907 // Some targets have more than one output file. Create rules to
908 // drive the build if any extra outputs are missing.
909 std::vector<std::string> extraOutputs;
910 if(targetNameSO != targetNameReal)
912 this->GenerateExtraOutput(targetFullPathSO.c_str(),
913 targetFullPathReal.c_str());
915 if(targetName != targetNameSO &&
916 targetName != targetNameReal)
918 this->GenerateExtraOutput(targetFullPath.c_str(),
919 targetFullPathReal.c_str());
922 // Write the main driver rule to build everything in this target.
923 this->WriteTargetDriverRule(targetFullPath.c_str(), relink);
925 // Clean all the possible library names and symlinks.
926 this->CleanFiles.insert(this->CleanFiles.end(),
927 libCleanFiles.begin(),libCleanFiles.end());
930 //----------------------------------------------------------------------------
931 void
932 cmMakefileLibraryTargetGenerator
933 ::AppendOSXVerFlag(std::string& flags, const char* lang,
934 const char* name, bool so)
936 // Lookup the flag to specify the version.
937 std::string fvar = "CMAKE_";
938 fvar += lang;
939 fvar += "_OSX_";
940 fvar += name;
941 fvar += "_VERSION_FLAG";
942 const char* flag = this->Makefile->GetDefinition(fvar.c_str());
944 // Skip if no such flag.
945 if(!flag)
947 return;
950 // Lookup the target version information.
951 int major;
952 int minor;
953 int patch;
954 this->Target->GetTargetVersion(so, major, minor, patch);
955 if(major > 0 || minor > 0 || patch > 0)
957 // Append the flag since a non-zero version is specified.
958 cmOStringStream vflag;
959 vflag << flag << major << "." << minor << "." << patch;
960 this->LocalGenerator->AppendFlags(flags, vflag.str().c_str());