1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
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 "cmInstallTargetGenerator.h"
14 #include "cmComputeLinkInformation.h"
15 #include "cmGlobalGenerator.h"
16 #include "cmLocalGenerator.h"
17 #include "cmMakefile.h"
22 //----------------------------------------------------------------------------
23 cmInstallTargetGenerator
24 ::cmInstallTargetGenerator(cmTarget& t, const char* dest, bool implib,
25 const char* file_permissions,
26 std::vector<std::string> const& configurations,
27 const char* component, bool optional):
28 cmInstallGenerator(dest, configurations, component), Target(&t),
29 ImportLibrary(implib), FilePermissions(file_permissions), Optional(optional)
31 this->ActionsPerConfig = true;
32 this->NamelinkMode = NamelinkModeNone;
33 this->Target->SetHaveInstallRule(true);
36 //----------------------------------------------------------------------------
37 cmInstallTargetGenerator
38 ::~cmInstallTargetGenerator()
42 //----------------------------------------------------------------------------
43 void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
45 // Warn if installing an exclude-from-all target.
46 if(this->Target->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
49 msg << "WARNING: Target \"" << this->Target->GetName()
50 << "\" has EXCLUDE_FROM_ALL set and will not be built by default "
51 << "but an install rule has been provided for it. CMake does "
52 << "not define behavior for this case.";
53 cmSystemTools::Message(msg.str().c_str(), "Warning");
56 // Perform the main install script generation.
57 this->cmInstallGenerator::GenerateScript(os);
60 //----------------------------------------------------------------------------
61 void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
65 // Compute the build tree directory from which to copy the target.
66 std::string fromDirConfig;
67 if(this->Target->NeedRelinkBeforeInstall(config))
69 fromDirConfig = this->Target->GetMakefile()->GetStartOutputDirectory();
70 fromDirConfig += cmake::GetCMakeFilesDirectory();
71 fromDirConfig += "/CMakeRelink.dir/";
75 fromDirConfig = this->Target->GetDirectory(config, this->ImportLibrary);
78 std::string toDir = this->GetInstallDestination();
81 // Compute the list of files to install for this target.
82 std::vector<std::string> filesFrom;
83 std::vector<std::string> filesTo;
84 std::string literal_args;
85 cmTarget::TargetType targetType = this->Target->GetType();
86 cmInstallType type = cmInstallType();
89 case cmTarget::EXECUTABLE: type = cmInstallType_EXECUTABLE; break;
90 case cmTarget::STATIC_LIBRARY: type = cmInstallType_STATIC_LIBRARY; break;
91 case cmTarget::SHARED_LIBRARY: type = cmInstallType_SHARED_LIBRARY; break;
92 case cmTarget::MODULE_LIBRARY: type = cmInstallType_MODULE_LIBRARY; break;
93 case cmTarget::OBJECT_LIBRARY:
94 case cmTarget::UTILITY:
95 case cmTarget::GLOBAL_TARGET:
96 case cmTarget::UNKNOWN_LIBRARY:
97 this->Target->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR,
98 "cmInstallTargetGenerator created with non-installable target.");
101 if(targetType == cmTarget::EXECUTABLE)
103 // There is a bug in cmInstallCommand if this fails.
104 assert(this->NamelinkMode == NamelinkModeNone);
106 std::string targetName;
107 std::string targetNameReal;
108 std::string targetNameImport;
109 std::string targetNamePDB;
110 this->Target->GetExecutableNames(targetName, targetNameReal,
111 targetNameImport, targetNamePDB,
113 if(this->ImportLibrary)
115 std::string from1 = fromDirConfig + targetNameImport;
116 std::string to1 = toDir + targetNameImport;
117 filesFrom.push_back(from1);
118 filesTo.push_back(to1);
119 std::string targetNameImportLib;
120 if(this->Target->GetImplibGNUtoMS(targetNameImport,
121 targetNameImportLib))
123 filesFrom.push_back(fromDirConfig + targetNameImportLib);
124 filesTo.push_back(toDir + targetNameImportLib);
127 // An import library looks like a static library.
128 type = cmInstallType_STATIC_LIBRARY;
132 std::string from1 = fromDirConfig + targetName;
133 std::string to1 = toDir + targetName;
135 // Handle OSX Bundles.
136 if(this->Target->IsAppBundleOnApple())
138 // Install the whole app bundle directory.
139 type = cmInstallType_DIRECTORY;
140 literal_args += " USE_SOURCE_PERMISSIONS";
143 // Tweaks apply to the binary inside the bundle.
144 to1 += ".app/Contents/MacOS/";
149 // Tweaks apply to the real file, so list it first.
150 if(targetNameReal != targetName)
152 std::string from2 = fromDirConfig + targetNameReal;
153 std::string to2 = toDir += targetNameReal;
154 filesFrom.push_back(from2);
155 filesTo.push_back(to2);
159 filesFrom.push_back(from1);
160 filesTo.push_back(to1);
165 std::string targetName;
166 std::string targetNameSO;
167 std::string targetNameReal;
168 std::string targetNameImport;
169 std::string targetNamePDB;
170 this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
171 targetNameImport, targetNamePDB,
173 if(this->ImportLibrary)
175 // There is a bug in cmInstallCommand if this fails.
176 assert(this->NamelinkMode == NamelinkModeNone);
178 std::string from1 = fromDirConfig + targetNameImport;
179 std::string to1 = toDir + targetNameImport;
180 filesFrom.push_back(from1);
181 filesTo.push_back(to1);
182 std::string targetNameImportLib;
183 if(this->Target->GetImplibGNUtoMS(targetNameImport,
184 targetNameImportLib))
186 filesFrom.push_back(fromDirConfig + targetNameImportLib);
187 filesTo.push_back(toDir + targetNameImportLib);
190 // An import library looks like a static library.
191 type = cmInstallType_STATIC_LIBRARY;
193 else if(this->Target->IsFrameworkOnApple())
195 // There is a bug in cmInstallCommand if this fails.
196 assert(this->NamelinkMode == NamelinkModeNone);
198 // Install the whole framework directory.
199 type = cmInstallType_DIRECTORY;
200 literal_args += " USE_SOURCE_PERMISSIONS";
202 std::string from1 = fromDirConfig + targetName;
203 from1 = cmSystemTools::GetFilenamePath(from1);
205 // Tweaks apply to the binary inside the bundle.
206 std::string to1 = toDir + targetNameReal;
208 filesFrom.push_back(from1);
209 filesTo.push_back(to1);
213 bool haveNamelink = false;
215 // Library link name.
216 std::string fromName = fromDirConfig + targetName;
217 std::string toName = toDir + targetName;
219 // Library interface name.
220 std::string fromSOName;
221 std::string toSOName;
222 if(targetNameSO != targetName)
225 fromSOName = fromDirConfig + targetNameSO;
226 toSOName = toDir + targetNameSO;
229 // Library implementation name.
230 std::string fromRealName;
231 std::string toRealName;
232 if(targetNameReal != targetName &&
233 targetNameReal != targetNameSO)
236 fromRealName = fromDirConfig + targetNameReal;
237 toRealName = toDir + targetNameReal;
240 // Add the names based on the current namelink mode.
243 // With a namelink we need to check the mode.
244 if(this->NamelinkMode == NamelinkModeOnly)
246 // Install the namelink only.
247 filesFrom.push_back(fromName);
248 filesTo.push_back(toName);
252 // Install the real file if it has its own name.
253 if(!fromRealName.empty())
255 filesFrom.push_back(fromRealName);
256 filesTo.push_back(toRealName);
259 // Install the soname link if it has its own name.
260 if(!fromSOName.empty())
262 filesFrom.push_back(fromSOName);
263 filesTo.push_back(toSOName);
266 // Install the namelink if it is not to be skipped.
267 if(this->NamelinkMode != NamelinkModeSkip)
269 filesFrom.push_back(fromName);
270 filesTo.push_back(toName);
276 // Without a namelink there will be only one file. Install it
277 // if this is not a namelink-only rule.
278 if(this->NamelinkMode != NamelinkModeOnly)
280 filesFrom.push_back(fromName);
281 filesTo.push_back(toName);
287 // If this fails the above code is buggy.
288 assert(filesFrom.size() == filesTo.size());
290 // Skip this rule if no files are to be installed for the target.
291 if(filesFrom.empty())
296 // Add pre-installation tweaks.
297 this->AddTweak(os, indent, config, filesTo,
298 &cmInstallTargetGenerator::PreReplacementTweaks);
300 // Write code to install the target file.
301 const char* no_dir_permissions = 0;
302 const char* no_rename = 0;
303 bool optional = this->Optional || this->ImportLibrary;
304 this->AddInstallRule(os, type, filesFrom,
306 this->FilePermissions.c_str(), no_dir_permissions,
307 no_rename, literal_args.c_str(),
310 // Add post-installation tweaks.
311 this->AddTweak(os, indent, config, filesTo,
312 &cmInstallTargetGenerator::PostReplacementTweaks);
315 //----------------------------------------------------------------------------
317 cmInstallTargetGenerator::GetInstallFilename(const char* config) const
319 NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
321 cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
325 //----------------------------------------------------------------------------
326 std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
331 // Compute the name of the library.
332 if(target->GetType() == cmTarget::EXECUTABLE)
334 std::string targetName;
335 std::string targetNameReal;
336 std::string targetNameImport;
337 std::string targetNamePDB;
338 target->GetExecutableNames(targetName, targetNameReal,
339 targetNameImport, targetNamePDB,
341 if(nameType == NameImplib)
343 // Use the import library name.
344 if(!target->GetImplibGNUtoMS(targetNameImport, fname,
345 "${CMAKE_IMPORT_LIBRARY_SUFFIX}"))
347 fname = targetNameImport;
350 else if(nameType == NameReal)
352 // Use the canonical name.
353 fname = targetNameReal;
357 // Use the canonical name.
363 std::string targetName;
364 std::string targetNameSO;
365 std::string targetNameReal;
366 std::string targetNameImport;
367 std::string targetNamePDB;
368 target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
369 targetNameImport, targetNamePDB, config);
370 if(nameType == NameImplib)
372 // Use the import library name.
373 if(!target->GetImplibGNUtoMS(targetNameImport, fname,
374 "${CMAKE_IMPORT_LIBRARY_SUFFIX}"))
376 fname = targetNameImport;
379 else if(nameType == NameSO)
382 fname = targetNameSO;
384 else if(nameType == NameReal)
386 // Use the real name.
387 fname = targetNameReal;
391 // Use the canonical name.
399 //----------------------------------------------------------------------------
401 cmInstallTargetGenerator
402 ::AddTweak(std::ostream& os, Indent const& indent, const char* config,
403 std::string const& file, TweakMethod tweak)
406 (this->*tweak)(tw, indent.Next(), config, file);
407 std::string tws = tw.str();
410 os << indent << "IF(EXISTS \"" << file << "\" AND\n"
411 << indent << " NOT IS_SYMLINK \"" << file << "\")\n";
413 os << indent << "ENDIF()\n";
417 //----------------------------------------------------------------------------
419 cmInstallTargetGenerator
420 ::AddTweak(std::ostream& os, Indent const& indent, const char* config,
421 std::vector<std::string> const& files, TweakMethod tweak)
423 if(files.size() == 1)
425 // Tweak a single file.
426 this->AddTweak(os, indent, config, this->GetDestDirPath(files[0]), tweak);
430 // Generate a foreach loop to tweak multiple files.
432 this->AddTweak(tw, indent.Next(), config, "${file}", tweak);
433 std::string tws = tw.str();
436 Indent indent2 = indent.Next().Next();
437 os << indent << "FOREACH(file\n";
438 for(std::vector<std::string>::const_iterator i = files.begin();
439 i != files.end(); ++i)
441 os << indent2 << "\"" << this->GetDestDirPath(*i) << "\"\n";
443 os << indent2 << ")\n";
445 os << indent << "ENDFOREACH()\n";
450 //----------------------------------------------------------------------------
451 std::string cmInstallTargetGenerator::GetDestDirPath(std::string const& file)
453 // Construct the path of the file on disk after installation on
454 // which tweaks may be performed.
455 std::string toDestDirPath = "$ENV{DESTDIR}";
456 if(file[0] != '/' && file[0] != '$')
458 toDestDirPath += "/";
460 toDestDirPath += file;
461 return toDestDirPath;
464 //----------------------------------------------------------------------------
465 void cmInstallTargetGenerator::PreReplacementTweaks(std::ostream& os,
466 Indent const& indent,
468 std::string const& file)
470 this->AddRPathCheckRule(os, indent, config, file);
473 //----------------------------------------------------------------------------
474 void cmInstallTargetGenerator::PostReplacementTweaks(std::ostream& os,
475 Indent const& indent,
477 std::string const& file)
479 this->AddInstallNamePatchRule(os, indent, config, file);
480 this->AddChrpathPatchRule(os, indent, config, file);
481 this->AddRanlibRule(os, indent, file);
482 this->AddStripRule(os, indent, file);
485 //----------------------------------------------------------------------------
487 cmInstallTargetGenerator
488 ::AddInstallNamePatchRule(std::ostream& os, Indent const& indent,
489 const char* config, std::string const& toDestDirPath)
491 if(this->ImportLibrary ||
492 !(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
493 this->Target->GetType() == cmTarget::MODULE_LIBRARY ||
494 this->Target->GetType() == cmTarget::EXECUTABLE))
499 // Fix the install_name settings in installed binaries.
500 std::string installNameTool =
501 this->Target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
503 if(!installNameTool.size())
508 // Build a map of build-tree install_name to install-tree install_name for
509 // shared libraries linked to this target.
510 std::map<cmStdString, cmStdString> install_name_remap;
511 if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config))
513 std::set<cmTarget*> const& sharedLibs = cli->GetSharedLibrariesLinked();
514 for(std::set<cmTarget*>::const_iterator j = sharedLibs.begin();
515 j != sharedLibs.end(); ++j)
519 // The install_name of an imported target does not change.
520 if(tgt->IsImported())
525 // If the build tree and install tree use different path
526 // components of the install_name field then we need to create a
527 // mapping to be applied after installation.
528 std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
529 std::string for_install = tgt->GetInstallNameDirForInstallTree();
530 if(for_build != for_install)
532 // The directory portions differ. Append the filename to
533 // create the mapping.
535 this->GetInstallFilename(tgt, config, NameSO);
537 // Map from the build-tree install_name.
540 // Map to the install-tree install_name.
541 for_install += fname;
543 // Store the mapping entry.
544 install_name_remap[for_build] = for_install;
549 // Edit the install_name of the target itself if necessary.
551 if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
553 std::string for_build =
554 this->Target->GetInstallNameDirForBuildTree(config);
555 std::string for_install =
556 this->Target->GetInstallNameDirForInstallTree();
558 if(this->Target->IsFrameworkOnApple() && for_install.empty())
560 // Frameworks seem to have an id corresponding to their own full
563 // for_install = fullDestPath_without_DESTDIR_or_name;
566 // If the install name will change on installation set the new id
567 // on the installed file.
568 if(for_build != for_install)
570 // Prepare to refer to the install-tree install_name.
571 new_id = for_install;
572 new_id += this->GetInstallFilename(this->Target, config, NameSO);
576 // Write a rule to run install_name_tool to set the install-tree
577 // install_name value and references.
578 if(!new_id.empty() || !install_name_remap.empty())
580 os << indent << "EXECUTE_PROCESS(COMMAND \"" << installNameTool;
584 os << "\n" << indent << " -id \"" << new_id << "\"";
586 for(std::map<cmStdString, cmStdString>::const_iterator
587 i = install_name_remap.begin();
588 i != install_name_remap.end(); ++i)
590 os << "\n" << indent << " -change \""
591 << i->first << "\" \"" << i->second << "\"";
593 os << "\n" << indent << " \"" << toDestDirPath << "\")\n";
597 //----------------------------------------------------------------------------
599 cmInstallTargetGenerator
600 ::AddRPathCheckRule(std::ostream& os, Indent const& indent,
601 const char* config, std::string const& toDestDirPath)
603 // Skip the chrpath if the target does not need it.
604 if(this->ImportLibrary || !this->Target->IsChrpathUsed(config))
610 if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
615 // Get the link information for this target.
616 // It can provide the RPATH.
617 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
623 // Get the install RPATH from the link information.
624 std::string newRpath = cli->GetChrpathString();
626 // Write a rule to remove the installed file if its rpath is not the
627 // new rpath. This is needed for existing build/install trees when
628 // the installed rpath changes but the file is not rebuilt.
629 os << indent << "FILE(RPATH_CHECK\n"
630 << indent << " FILE \"" << toDestDirPath << "\"\n"
631 << indent << " RPATH \"" << newRpath << "\")\n";
634 //----------------------------------------------------------------------------
636 cmInstallTargetGenerator
637 ::AddChrpathPatchRule(std::ostream& os, Indent const& indent,
638 const char* config, std::string const& toDestDirPath)
640 // Skip the chrpath if the target does not need it.
641 if(this->ImportLibrary || !this->Target->IsChrpathUsed(config))
646 // Get the link information for this target.
647 // It can provide the RPATH.
648 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
654 if(this->Target->GetMakefile()->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME"))
656 // If using install_name_tool, set up the rules to modify the rpaths.
657 std::string installNameTool =
658 this->Target->GetMakefile()->
659 GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
661 std::vector<std::string> oldRuntimeDirs, newRuntimeDirs;
662 cli->GetRPath(oldRuntimeDirs, false);
663 cli->GetRPath(newRuntimeDirs, true);
665 // Note: These are separate commands to avoid install_name_tool
666 // corruption on 10.6.
667 for(std::vector<std::string>::const_iterator i = oldRuntimeDirs.begin();
668 i != oldRuntimeDirs.end(); ++i)
670 os << indent << "execute_process(COMMAND " << installNameTool << "\n";
671 os << indent << " -delete_rpath \"" << *i << "\"\n";
672 os << indent << " \"" << toDestDirPath << "\")\n";
675 for(std::vector<std::string>::const_iterator i = newRuntimeDirs.begin();
676 i != newRuntimeDirs.end(); ++i)
678 os << indent << "execute_process(COMMAND " << installNameTool << "\n";
679 os << indent << " -add_rpath \"" << *i << "\"\n";
680 os << indent << " \"" << toDestDirPath << "\")\n";
685 // Construct the original rpath string to be replaced.
686 std::string oldRpath = cli->GetRPathString(false);
688 // Get the install RPATH from the link information.
689 std::string newRpath = cli->GetChrpathString();
691 // Skip the rule if the paths are identical
692 if(oldRpath == newRpath)
697 // Write a rule to run chrpath to set the install-tree RPATH
700 os << indent << "FILE(RPATH_REMOVE\n"
701 << indent << " FILE \"" << toDestDirPath << "\")\n";
705 os << indent << "FILE(RPATH_CHANGE\n"
706 << indent << " FILE \"" << toDestDirPath << "\"\n"
707 << indent << " OLD_RPATH \"" << oldRpath << "\"\n"
708 << indent << " NEW_RPATH \"" << newRpath << "\")\n";
713 //----------------------------------------------------------------------------
715 cmInstallTargetGenerator::AddStripRule(std::ostream& os,
716 Indent const& indent,
717 const std::string& toDestDirPath)
720 // don't strip static and import libraries, because it removes the only
721 // symbol table they have so you can't link to them anymore
722 if(this->Target->GetType()==cmTarget::STATIC_LIBRARY || this->ImportLibrary)
727 // Don't handle OSX Bundles.
728 if(this->Target->GetMakefile()->IsOn("APPLE") &&
729 this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
734 if(! this->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
739 os << indent << "IF(CMAKE_INSTALL_DO_STRIP)\n";
740 os << indent << " EXECUTE_PROCESS(COMMAND \""
741 << this->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
742 << "\" \"" << toDestDirPath << "\")\n";
743 os << indent << "ENDIF(CMAKE_INSTALL_DO_STRIP)\n";
746 //----------------------------------------------------------------------------
748 cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
749 Indent const& indent,
750 const std::string& toDestDirPath)
752 // Static libraries need ranlib on this platform.
753 if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
758 // Perform post-installation processing on the file depending
760 if(!this->Target->GetMakefile()->IsOn("APPLE"))
766 this->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
772 os << indent << "EXECUTE_PROCESS(COMMAND \""
773 << ranlib << "\" \"" << toDestDirPath << "\")\n";