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";
201 std::string from1 = fromDirConfig + targetName + ".framework";
203 // Tweaks apply to the binary inside the bundle.
204 std::string to1 = toDir + targetName;
205 to1 += ".framework/Versions/";
206 to1 += this->Target->GetFrameworkVersion();
210 filesFrom.push_back(from1);
211 filesTo.push_back(to1);
215 bool haveNamelink = false;
217 // Library link name.
218 std::string fromName = fromDirConfig + targetName;
219 std::string toName = toDir + targetName;
221 // Library interface name.
222 std::string fromSOName;
223 std::string toSOName;
224 if(targetNameSO != targetName)
227 fromSOName = fromDirConfig + targetNameSO;
228 toSOName = toDir + targetNameSO;
231 // Library implementation name.
232 std::string fromRealName;
233 std::string toRealName;
234 if(targetNameReal != targetName &&
235 targetNameReal != targetNameSO)
238 fromRealName = fromDirConfig + targetNameReal;
239 toRealName = toDir + targetNameReal;
242 // Add the names based on the current namelink mode.
245 // With a namelink we need to check the mode.
246 if(this->NamelinkMode == NamelinkModeOnly)
248 // Install the namelink only.
249 filesFrom.push_back(fromName);
250 filesTo.push_back(toName);
254 // Install the real file if it has its own name.
255 if(!fromRealName.empty())
257 filesFrom.push_back(fromRealName);
258 filesTo.push_back(toRealName);
261 // Install the soname link if it has its own name.
262 if(!fromSOName.empty())
264 filesFrom.push_back(fromSOName);
265 filesTo.push_back(toSOName);
268 // Install the namelink if it is not to be skipped.
269 if(this->NamelinkMode != NamelinkModeSkip)
271 filesFrom.push_back(fromName);
272 filesTo.push_back(toName);
278 // Without a namelink there will be only one file. Install it
279 // if this is not a namelink-only rule.
280 if(this->NamelinkMode != NamelinkModeOnly)
282 filesFrom.push_back(fromName);
283 filesTo.push_back(toName);
289 // If this fails the above code is buggy.
290 assert(filesFrom.size() == filesTo.size());
292 // Skip this rule if no files are to be installed for the target.
293 if(filesFrom.empty())
298 // Add pre-installation tweaks.
299 this->AddTweak(os, indent, config, filesTo,
300 &cmInstallTargetGenerator::PreReplacementTweaks);
302 // Write code to install the target file.
303 const char* no_dir_permissions = 0;
304 const char* no_rename = 0;
305 bool optional = this->Optional || this->ImportLibrary;
306 this->AddInstallRule(os, type, filesFrom,
308 this->FilePermissions.c_str(), no_dir_permissions,
309 no_rename, literal_args.c_str(),
312 // Add post-installation tweaks.
313 this->AddTweak(os, indent, config, filesTo,
314 &cmInstallTargetGenerator::PostReplacementTweaks);
317 //----------------------------------------------------------------------------
319 cmInstallTargetGenerator::GetInstallFilename(const char* config) const
321 NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
323 cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
327 //----------------------------------------------------------------------------
328 std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
333 // Compute the name of the library.
334 if(target->GetType() == cmTarget::EXECUTABLE)
336 std::string targetName;
337 std::string targetNameReal;
338 std::string targetNameImport;
339 std::string targetNamePDB;
340 target->GetExecutableNames(targetName, targetNameReal,
341 targetNameImport, targetNamePDB,
343 if(nameType == NameImplib)
345 // Use the import library name.
346 if(!target->GetImplibGNUtoMS(targetNameImport, fname,
347 "${CMAKE_IMPORT_LIBRARY_SUFFIX}"))
349 fname = targetNameImport;
352 else if(nameType == NameReal)
354 // Use the canonical name.
355 fname = targetNameReal;
359 // Use the canonical name.
365 std::string targetName;
366 std::string targetNameSO;
367 std::string targetNameReal;
368 std::string targetNameImport;
369 std::string targetNamePDB;
370 target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
371 targetNameImport, targetNamePDB, config);
372 if(nameType == NameImplib)
374 // Use the import library name.
375 if(!target->GetImplibGNUtoMS(targetNameImport, fname,
376 "${CMAKE_IMPORT_LIBRARY_SUFFIX}"))
378 fname = targetNameImport;
381 else if(nameType == NameSO)
384 fname = targetNameSO;
386 else if(nameType == NameReal)
388 // Use the real name.
389 fname = targetNameReal;
393 // Use the canonical name.
401 //----------------------------------------------------------------------------
403 cmInstallTargetGenerator
404 ::AddTweak(std::ostream& os, Indent const& indent, const char* config,
405 std::string const& file, TweakMethod tweak)
408 (this->*tweak)(tw, indent.Next(), config, file);
409 std::string tws = tw.str();
412 os << indent << "IF(EXISTS \"" << file << "\" AND\n"
413 << indent << " NOT IS_SYMLINK \"" << file << "\")\n";
415 os << indent << "ENDIF()\n";
419 //----------------------------------------------------------------------------
421 cmInstallTargetGenerator
422 ::AddTweak(std::ostream& os, Indent const& indent, const char* config,
423 std::vector<std::string> const& files, TweakMethod tweak)
425 if(files.size() == 1)
427 // Tweak a single file.
428 this->AddTweak(os, indent, config, this->GetDestDirPath(files[0]), tweak);
432 // Generate a foreach loop to tweak multiple files.
434 this->AddTweak(tw, indent.Next(), config, "${file}", tweak);
435 std::string tws = tw.str();
438 Indent indent2 = indent.Next().Next();
439 os << indent << "FOREACH(file\n";
440 for(std::vector<std::string>::const_iterator i = files.begin();
441 i != files.end(); ++i)
443 os << indent2 << "\"" << this->GetDestDirPath(*i) << "\"\n";
445 os << indent2 << ")\n";
447 os << indent << "ENDFOREACH()\n";
452 //----------------------------------------------------------------------------
453 std::string cmInstallTargetGenerator::GetDestDirPath(std::string const& file)
455 // Construct the path of the file on disk after installation on
456 // which tweaks may be performed.
457 std::string toDestDirPath = "$ENV{DESTDIR}";
458 if(file[0] != '/' && file[0] != '$')
460 toDestDirPath += "/";
462 toDestDirPath += file;
463 return toDestDirPath;
466 //----------------------------------------------------------------------------
467 void cmInstallTargetGenerator::PreReplacementTweaks(std::ostream& os,
468 Indent const& indent,
470 std::string const& file)
472 this->AddRPathCheckRule(os, indent, config, file);
475 //----------------------------------------------------------------------------
476 void cmInstallTargetGenerator::PostReplacementTweaks(std::ostream& os,
477 Indent const& indent,
479 std::string const& file)
481 this->AddInstallNamePatchRule(os, indent, config, file);
482 this->AddChrpathPatchRule(os, indent, config, file);
483 this->AddRanlibRule(os, indent, file);
484 this->AddStripRule(os, indent, file);
487 //----------------------------------------------------------------------------
489 cmInstallTargetGenerator
490 ::AddInstallNamePatchRule(std::ostream& os, Indent const& indent,
491 const char* config, std::string const& toDestDirPath)
493 if(this->ImportLibrary ||
494 !(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
495 this->Target->GetType() == cmTarget::MODULE_LIBRARY ||
496 this->Target->GetType() == cmTarget::EXECUTABLE))
501 // Fix the install_name settings in installed binaries.
502 std::string installNameTool =
503 this->Target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
505 if(!installNameTool.size())
510 // Build a map of build-tree install_name to install-tree install_name for
511 // shared libraries linked to this target.
512 std::map<cmStdString, cmStdString> install_name_remap;
513 if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config))
515 std::set<cmTarget*> const& sharedLibs = cli->GetSharedLibrariesLinked();
516 for(std::set<cmTarget*>::const_iterator j = sharedLibs.begin();
517 j != sharedLibs.end(); ++j)
521 // The install_name of an imported target does not change.
522 if(tgt->IsImported())
527 // If the build tree and install tree use different path
528 // components of the install_name field then we need to create a
529 // mapping to be applied after installation.
530 std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
531 std::string for_install = tgt->GetInstallNameDirForInstallTree(config);
532 if(for_build != for_install)
534 // The directory portions differ. Append the filename to
535 // create the mapping.
537 this->GetInstallFilename(tgt, config, NameSO);
539 // Map from the build-tree install_name.
542 // Map to the install-tree install_name.
543 for_install += fname;
545 // Store the mapping entry.
546 install_name_remap[for_build] = for_install;
551 // Edit the install_name of the target itself if necessary.
553 if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
555 std::string for_build =
556 this->Target->GetInstallNameDirForBuildTree(config);
557 std::string for_install =
558 this->Target->GetInstallNameDirForInstallTree(config);
560 if(this->Target->IsFrameworkOnApple() && for_install.empty())
562 // Frameworks seem to have an id corresponding to their own full
565 // for_install = fullDestPath_without_DESTDIR_or_name;
568 // If the install name will change on installation set the new id
569 // on the installed file.
570 if(for_build != for_install)
572 // Prepare to refer to the install-tree install_name.
573 new_id = for_install;
574 new_id += this->GetInstallFilename(this->Target, config, NameSO);
578 // Write a rule to run install_name_tool to set the install-tree
579 // install_name value and references.
580 if(!new_id.empty() || !install_name_remap.empty())
582 os << indent << "EXECUTE_PROCESS(COMMAND \"" << installNameTool;
586 os << "\n" << indent << " -id \"" << new_id << "\"";
588 for(std::map<cmStdString, cmStdString>::const_iterator
589 i = install_name_remap.begin();
590 i != install_name_remap.end(); ++i)
592 os << "\n" << indent << " -change \""
593 << i->first << "\" \"" << i->second << "\"";
595 os << "\n" << indent << " \"" << toDestDirPath << "\")\n";
599 //----------------------------------------------------------------------------
601 cmInstallTargetGenerator
602 ::AddRPathCheckRule(std::ostream& os, Indent const& indent,
603 const char* config, std::string const& toDestDirPath)
605 // Skip the chrpath if the target does not need it.
606 if(this->ImportLibrary || !this->Target->IsChrpathUsed(config))
611 // Get the link information for this target.
612 // It can provide the RPATH.
613 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
619 // Get the install RPATH from the link information.
620 std::string newRpath = cli->GetChrpathString();
622 // Write a rule to remove the installed file if its rpath is not the
623 // new rpath. This is needed for existing build/install trees when
624 // the installed rpath changes but the file is not rebuilt.
625 os << indent << "FILE(RPATH_CHECK\n"
626 << indent << " FILE \"" << toDestDirPath << "\"\n"
627 << indent << " RPATH \"" << newRpath << "\")\n";
630 //----------------------------------------------------------------------------
632 cmInstallTargetGenerator
633 ::AddChrpathPatchRule(std::ostream& os, Indent const& indent,
634 const char* config, std::string const& toDestDirPath)
636 // Skip the chrpath if the target does not need it.
637 if(this->ImportLibrary || !this->Target->IsChrpathUsed(config))
642 // Get the link information for this target.
643 // It can provide the RPATH.
644 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
650 // Construct the original rpath string to be replaced.
651 std::string oldRpath = cli->GetRPathString(false);
653 // Get the install RPATH from the link information.
654 std::string newRpath = cli->GetChrpathString();
656 // Skip the rule if the paths are identical
657 if(oldRpath == newRpath)
662 // Write a rule to run chrpath to set the install-tree RPATH
665 os << indent << "FILE(RPATH_REMOVE\n"
666 << indent << " FILE \"" << toDestDirPath << "\")\n";
670 os << indent << "FILE(RPATH_CHANGE\n"
671 << indent << " FILE \"" << toDestDirPath << "\"\n"
672 << indent << " OLD_RPATH \"" << oldRpath << "\"\n"
673 << indent << " NEW_RPATH \"" << newRpath << "\")\n";
677 //----------------------------------------------------------------------------
679 cmInstallTargetGenerator::AddStripRule(std::ostream& os,
680 Indent const& indent,
681 const std::string& toDestDirPath)
684 // don't strip static libraries, because it removes the only symbol table
685 // they have so you can't link to them anymore
686 if(this->Target->GetType() == cmTarget::STATIC_LIBRARY)
691 // Don't handle OSX Bundles.
692 if(this->Target->GetMakefile()->IsOn("APPLE") &&
693 this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
698 if(! this->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
703 os << indent << "IF(CMAKE_INSTALL_DO_STRIP)\n";
704 os << indent << " EXECUTE_PROCESS(COMMAND \""
705 << this->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
706 << "\" \"" << toDestDirPath << "\")\n";
707 os << indent << "ENDIF(CMAKE_INSTALL_DO_STRIP)\n";
710 //----------------------------------------------------------------------------
712 cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
713 Indent const& indent,
714 const std::string& toDestDirPath)
716 // Static libraries need ranlib on this platform.
717 if(this->Target->GetType() != cmTarget::STATIC_LIBRARY)
722 // Perform post-installation processing on the file depending
724 if(!this->Target->GetMakefile()->IsOn("APPLE"))
730 this->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
736 os << indent << "EXECUTE_PROCESS(COMMAND \""
737 << ranlib << "\" \"" << toDestDirPath << "\")\n";