STYLE: Fix typo in GetFilenameLastExtension docs
[cmake.git] / Source / cmInstallTargetGenerator.cxx
blob310c90f576b9f536f1e984c8df37e8017356c9e7
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmInstallTargetGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2008-10-03 14:11:47 $
7 Version: $Revision: 1.66 $
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 "cmInstallTargetGenerator.h"
19 #include "cmComputeLinkInformation.h"
20 #include "cmGlobalGenerator.h"
21 #include "cmLocalGenerator.h"
22 #include "cmMakefile.h"
23 #include "cmake.h"
25 #include <assert.h>
27 //----------------------------------------------------------------------------
28 cmInstallTargetGenerator
29 ::cmInstallTargetGenerator(cmTarget& t, const char* dest, bool implib,
30 const char* file_permissions,
31 std::vector<std::string> const& configurations,
32 const char* component, bool optional):
33 cmInstallGenerator(dest, configurations, component), Target(&t),
34 ImportLibrary(implib), FilePermissions(file_permissions), Optional(optional)
36 this->NamelinkMode = NamelinkModeNone;
37 this->Target->SetHaveInstallRule(true);
40 //----------------------------------------------------------------------------
41 cmInstallTargetGenerator
42 ::~cmInstallTargetGenerator()
46 //----------------------------------------------------------------------------
47 void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
49 // Warn if installing an exclude-from-all target.
50 if(this->Target->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
52 cmOStringStream msg;
53 msg << "WARNING: Target \"" << this->Target->GetName()
54 << "\" has EXCLUDE_FROM_ALL set and will not be built by default "
55 << "but an install rule has been provided for it. CMake does "
56 << "not define behavior for this case.";
57 cmSystemTools::Message(msg.str().c_str(), "Warning");
60 // Compute the build tree directory from which to copy the target.
61 std::string& fromDir = this->FromDir;
62 if(this->Target->NeedRelinkBeforeInstall())
64 fromDir = this->Target->GetMakefile()->GetStartOutputDirectory();
65 fromDir += cmake::GetCMakeFilesDirectory();
66 fromDir += "/CMakeRelink.dir/";
68 else
70 fromDir = this->Target->GetDirectory(0, this->ImportLibrary);
71 fromDir += "/";
74 // Perform the main install script generation.
75 this->cmInstallGenerator::GenerateScript(os);
78 //----------------------------------------------------------------------------
79 void cmInstallTargetGenerator::GenerateScriptConfigs(std::ostream& os,
80 Indent const& indent)
82 if(this->ConfigurationTypes->empty())
84 // In a single-configuration generator, only the install rule's
85 // configuration test is important. If that passes, the target is
86 // installed regardless of for what configuration it was built.
87 this->cmInstallGenerator::GenerateScriptConfigs(os, indent);
89 else
91 // In a multi-configuration generator, a separate rule is produced
92 // in a block for each configuration that is built. However, the
93 // list of configurations is restricted to those for which this
94 // install rule applies.
95 for(std::vector<std::string>::const_iterator i =
96 this->ConfigurationTypes->begin();
97 i != this->ConfigurationTypes->end(); ++i)
99 const char* config = i->c_str();
100 if(this->InstallsForConfig(config))
102 // Generate a per-configuration block.
103 std::string config_test = this->CreateConfigTest(config);
104 os << indent << "IF(" << config_test << ")\n";
105 this->GenerateScriptForConfig(os, config, indent.Next());
106 os << indent << "ENDIF(" << config_test << ")\n";
112 //----------------------------------------------------------------------------
113 void cmInstallTargetGenerator::GenerateScriptActions(std::ostream& os,
114 Indent const& indent)
116 // This is reached for single-configuration generators only.
117 this->GenerateScriptForConfig(os, this->ConfigurationName, indent);
120 //----------------------------------------------------------------------------
121 void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
122 const char* config,
123 Indent const& indent)
125 // Compute the per-configuration directory containing the files.
126 std::string fromDirConfig = this->FromDir;
127 this->Target->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()
128 ->AppendDirectoryForConfig("", config, "/", fromDirConfig);
130 // Compute the full path to the main installed file for this target.
131 NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
132 std::string toInstallPath = this->GetInstallDestination();
133 toInstallPath += "/";
134 toInstallPath += this->GetInstallFilename(this->Target, config, nameType);
136 // Track whether post-install operations should be added to the
137 // script.
138 bool tweakInstalledFile = true;
140 // Compute the list of files to install for this target.
141 std::vector<std::string> files;
142 std::string literal_args;
143 cmTarget::TargetType type = this->Target->GetType();
144 if(type == cmTarget::EXECUTABLE)
146 // There is a bug in cmInstallCommand if this fails.
147 assert(this->NamelinkMode == NamelinkModeNone);
149 std::string targetName;
150 std::string targetNameReal;
151 std::string targetNameImport;
152 std::string targetNamePDB;
153 this->Target->GetExecutableNames(targetName, targetNameReal,
154 targetNameImport, targetNamePDB,
155 config);
156 if(this->ImportLibrary)
158 std::string from1 = fromDirConfig;
159 from1 += targetNameImport;
160 files.push_back(from1);
162 // An import library looks like a static library.
163 type = cmTarget::STATIC_LIBRARY;
165 else
167 std::string from1 = fromDirConfig;
168 from1 += targetName;
170 // Handle OSX Bundles.
171 if(this->Target->IsAppBundleOnApple())
173 // Compute the source locations of the bundle executable and
174 // Info.plist file.
175 from1 += ".app";
176 files.push_back(from1);
177 type = cmTarget::INSTALL_DIRECTORY;
178 // Need to apply install_name_tool and stripping to binary
179 // inside bundle.
180 toInstallPath += ".app/Contents/MacOS/";
181 toInstallPath +=
182 this->GetInstallFilename(this->Target, config, nameType);
183 literal_args += " USE_SOURCE_PERMISSIONS";
185 else
187 // Operations done at install time on the installed file should
188 // be done on the real file and not any of the symlinks.
189 toInstallPath = this->GetInstallDestination();
190 toInstallPath += "/";
191 toInstallPath += targetNameReal;
193 files.push_back(from1);
194 if(targetNameReal != targetName)
196 std::string from2 = fromDirConfig;
197 from2 += targetNameReal;
198 files.push_back(from2);
203 else
205 std::string targetName;
206 std::string targetNameSO;
207 std::string targetNameReal;
208 std::string targetNameImport;
209 std::string targetNamePDB;
210 this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
211 targetNameImport, targetNamePDB,
212 config);
213 if(this->ImportLibrary)
215 // There is a bug in cmInstallCommand if this fails.
216 assert(this->NamelinkMode == NamelinkModeNone);
218 std::string from1 = fromDirConfig;
219 from1 += targetNameImport;
220 files.push_back(from1);
222 // An import library looks like a static library.
223 type = cmTarget::STATIC_LIBRARY;
225 else if(this->Target->IsFrameworkOnApple())
227 // There is a bug in cmInstallCommand if this fails.
228 assert(this->NamelinkMode == NamelinkModeNone);
230 // Compute the build tree location of the framework directory
231 std::string from1 = fromDirConfig;
232 from1 += targetName;
233 from1 += ".framework";
234 files.push_back(from1);
236 type = cmTarget::INSTALL_DIRECTORY;
238 // Need to apply install_name_tool and stripping to binary
239 // inside framework.
240 toInstallPath += ".framework/Versions/";
241 toInstallPath += this->Target->GetFrameworkVersion();
242 toInstallPath += "/";
243 toInstallPath += this->GetInstallFilename(this->Target, config,
244 NameNormal);
246 literal_args += " USE_SOURCE_PERMISSIONS";
248 else
250 // Operations done at install time on the installed file should
251 // be done on the real file and not any of the symlinks.
252 toInstallPath = this->GetInstallDestination();
253 toInstallPath += "/";
254 toInstallPath += targetNameReal;
256 // Construct the list of file names to install for this library.
257 bool haveNamelink = false;
258 std::string fromName;
259 std::string fromSOName;
260 std::string fromRealName;
261 fromName = fromDirConfig;
262 fromName += targetName;
263 if(targetNameSO != targetName)
265 haveNamelink = true;
266 fromSOName = fromDirConfig;
267 fromSOName += targetNameSO;
269 if(targetNameReal != targetName &&
270 targetNameReal != targetNameSO)
272 haveNamelink = true;
273 fromRealName = fromDirConfig;
274 fromRealName += targetNameReal;
277 // Add the names based on the current namelink mode.
278 if(haveNamelink)
280 // With a namelink we need to check the mode.
281 if(this->NamelinkMode == NamelinkModeOnly)
283 // Install the namelink only.
284 files.push_back(fromName);
285 tweakInstalledFile = false;
287 else
289 // Install the real file if it has its own name.
290 if(!fromRealName.empty())
292 files.push_back(fromRealName);
295 // Install the soname link if it has its own name.
296 if(!fromSOName.empty())
298 files.push_back(fromSOName);
301 // Install the namelink if it is not to be skipped.
302 if(this->NamelinkMode != NamelinkModeSkip)
304 files.push_back(fromName);
308 else
310 // Without a namelink there will be only one file. Install it
311 // if this is not a namelink-only rule.
312 if(this->NamelinkMode != NamelinkModeOnly)
314 files.push_back(fromName);
320 // Skip this rule if no files are to be installed for the target.
321 if(files.empty())
323 return;
326 // Construct the path of the file on disk after installation on
327 // which tweaks may be performed.
328 std::string toDestDirPath = "$ENV{DESTDIR}";
329 if(toInstallPath[0] != '/' && toInstallPath[0] != '$')
331 toDestDirPath += "/";
333 toDestDirPath += toInstallPath;
335 // Add pre-installation tweaks.
336 if(tweakInstalledFile)
338 // Collect tweaking rules.
339 cmOStringStream tw;
340 this->AddRPathCheckRule(tw, indent.Next(), config, toDestDirPath);
341 std::string tws = tw.str();
343 // Add the rules, if any.
344 if(!tws.empty())
346 os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n";
347 os << tws;
348 os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n";
352 // Write code to install the target file.
353 const char* no_dir_permissions = 0;
354 const char* no_rename = 0;
355 const char* no_properties = 0;
356 bool optional = this->Optional || this->ImportLibrary;
357 this->AddInstallRule(os, type, files,
358 optional, no_properties,
359 this->FilePermissions.c_str(), no_dir_permissions,
360 no_rename, literal_args.c_str(),
361 indent);
363 // Add post-installation tweaks.
364 if(tweakInstalledFile)
366 // Collect tweaking rules.
367 cmOStringStream tw;
368 this->AddInstallNamePatchRule(tw, indent.Next(), config, toDestDirPath);
369 this->AddChrpathPatchRule(tw, indent.Next(), config, toDestDirPath);
370 this->AddRanlibRule(tw, indent.Next(), type, toDestDirPath);
371 this->AddStripRule(tw, indent.Next(), type, toDestDirPath);
372 std::string tws = tw.str();
374 // Add the rules, if any.
375 if(!tws.empty())
377 os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n";
378 os << tws;
379 os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n";
384 //----------------------------------------------------------------------------
385 std::string
386 cmInstallTargetGenerator::GetInstallFilename(const char* config) const
388 NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
389 return
390 cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
391 nameType);
394 //----------------------------------------------------------------------------
395 std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
396 const char* config,
397 NameType nameType)
399 std::string fname;
400 // Compute the name of the library.
401 if(target->GetType() == cmTarget::EXECUTABLE)
403 std::string targetName;
404 std::string targetNameReal;
405 std::string targetNameImport;
406 std::string targetNamePDB;
407 target->GetExecutableNames(targetName, targetNameReal,
408 targetNameImport, targetNamePDB,
409 config);
410 if(nameType == NameImplib)
412 // Use the import library name.
413 fname = targetNameImport;
415 else if(nameType == NameReal)
417 // Use the canonical name.
418 fname = targetNameReal;
420 else
422 // Use the canonical name.
423 fname = targetName;
426 else
428 std::string targetName;
429 std::string targetNameSO;
430 std::string targetNameReal;
431 std::string targetNameImport;
432 std::string targetNamePDB;
433 target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
434 targetNameImport, targetNamePDB, config);
435 if(nameType == NameImplib)
437 // Use the import library name.
438 fname = targetNameImport;
440 else if(nameType == NameSO)
442 // Use the soname.
443 fname = targetNameSO;
445 else if(nameType == NameReal)
447 // Use the real name.
448 fname = targetNameReal;
450 else
452 // Use the canonical name.
453 fname = targetName;
457 return fname;
460 //----------------------------------------------------------------------------
461 void
462 cmInstallTargetGenerator
463 ::AddInstallNamePatchRule(std::ostream& os, Indent const& indent,
464 const char* config, std::string const& toDestDirPath)
466 if(this->ImportLibrary ||
467 !(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
468 this->Target->GetType() == cmTarget::MODULE_LIBRARY ||
469 this->Target->GetType() == cmTarget::EXECUTABLE))
471 return;
474 // Fix the install_name settings in installed binaries.
475 std::string installNameTool =
476 this->Target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
478 if(!installNameTool.size())
480 return;
483 // Build a map of build-tree install_name to install-tree install_name for
484 // shared libraries linked to this target.
485 std::map<cmStdString, cmStdString> install_name_remap;
486 if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config))
488 std::set<cmTarget*> const& sharedLibs = cli->GetSharedLibrariesLinked();
489 for(std::set<cmTarget*>::const_iterator j = sharedLibs.begin();
490 j != sharedLibs.end(); ++j)
492 // If the build tree and install tree use different path
493 // components of the install_name field then we need to create a
494 // mapping to be applied after installation.
495 cmTarget* tgt = *j;
496 std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
497 std::string for_install = tgt->GetInstallNameDirForInstallTree(config);
498 if(for_build != for_install)
500 // The directory portions differ. Append the filename to
501 // create the mapping.
502 std::string fname =
503 this->GetInstallFilename(tgt, config, NameSO);
505 // Map from the build-tree install_name.
506 for_build += fname;
508 // Map to the install-tree install_name.
509 for_install += fname;
511 // Store the mapping entry.
512 install_name_remap[for_build] = for_install;
517 // Edit the install_name of the target itself if necessary.
518 std::string new_id;
519 if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
521 std::string for_build =
522 this->Target->GetInstallNameDirForBuildTree(config);
523 std::string for_install =
524 this->Target->GetInstallNameDirForInstallTree(config);
526 if(this->Target->IsFrameworkOnApple() && for_install.empty())
528 // Frameworks seem to have an id corresponding to their own full
529 // path.
530 // ...
531 // for_install = fullDestPath_without_DESTDIR_or_name;
534 // If the install name will change on installation set the new id
535 // on the installed file.
536 if(for_build != for_install)
538 // Prepare to refer to the install-tree install_name.
539 new_id = for_install;
540 new_id += this->GetInstallFilename(this->Target, config, NameSO);
544 // Write a rule to run install_name_tool to set the install-tree
545 // install_name value and references.
546 if(!new_id.empty() || !install_name_remap.empty())
548 os << indent << "EXECUTE_PROCESS(COMMAND \"" << installNameTool;
549 os << "\"";
550 if(!new_id.empty())
552 os << "\n" << indent << " -id \"" << new_id << "\"";
554 for(std::map<cmStdString, cmStdString>::const_iterator
555 i = install_name_remap.begin();
556 i != install_name_remap.end(); ++i)
558 os << "\n" << indent << " -change \""
559 << i->first << "\" \"" << i->second << "\"";
561 os << "\n" << indent << " \"" << toDestDirPath << "\")\n";
565 //----------------------------------------------------------------------------
566 void
567 cmInstallTargetGenerator
568 ::AddRPathCheckRule(std::ostream& os, Indent const& indent,
569 const char* config, std::string const& toDestDirPath)
571 // Skip the chrpath if the target does not need it.
572 if(this->ImportLibrary || !this->Target->IsChrpathUsed())
574 return;
577 // Get the link information for this target.
578 // It can provide the RPATH.
579 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
580 if(!cli)
582 return;
585 // Get the install RPATH from the link information.
586 std::string newRpath = cli->GetChrpathString();
588 // Write a rule to remove the installed file if its rpath is not the
589 // new rpath. This is needed for existing build/install trees when
590 // the installed rpath changes but the file is not rebuilt.
591 os << indent << "FILE(RPATH_CHECK\n"
592 << indent << " FILE \"" << toDestDirPath << "\"\n"
593 << indent << " RPATH \"" << newRpath << "\")\n";
596 //----------------------------------------------------------------------------
597 void
598 cmInstallTargetGenerator
599 ::AddChrpathPatchRule(std::ostream& os, Indent const& indent,
600 const char* config, std::string const& toDestDirPath)
602 // Skip the chrpath if the target does not need it.
603 if(this->ImportLibrary || !this->Target->IsChrpathUsed())
605 return;
608 // Get the link information for this target.
609 // It can provide the RPATH.
610 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
611 if(!cli)
613 return;
616 // Construct the original rpath string to be replaced.
617 std::string oldRpath = cli->GetRPathString(false);
619 // Get the install RPATH from the link information.
620 std::string newRpath = cli->GetChrpathString();
622 // Skip the rule if the paths are identical
623 if(oldRpath == newRpath)
625 return;
628 // Write a rule to run chrpath to set the install-tree RPATH
629 if(newRpath.empty())
631 os << indent << "FILE(RPATH_REMOVE\n"
632 << indent << " FILE \"" << toDestDirPath << "\")\n";
634 else
636 os << indent << "FILE(RPATH_CHANGE\n"
637 << indent << " FILE \"" << toDestDirPath << "\"\n"
638 << indent << " OLD_RPATH \"" << oldRpath << "\"\n"
639 << indent << " NEW_RPATH \"" << newRpath << "\")\n";
643 //----------------------------------------------------------------------------
644 void
645 cmInstallTargetGenerator::AddStripRule(std::ostream& os,
646 Indent const& indent,
647 cmTarget::TargetType type,
648 const std::string& toDestDirPath)
651 // don't strip static libraries, because it removes the only symbol table
652 // they have so you can't link to them anymore
653 if(type == cmTarget::STATIC_LIBRARY)
655 return;
658 // Don't handle OSX Bundles.
659 if(this->Target->GetMakefile()->IsOn("APPLE") &&
660 this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
662 return;
665 if(! this->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
667 return;
670 os << indent << "IF(CMAKE_INSTALL_DO_STRIP)\n";
671 os << indent << " EXECUTE_PROCESS(COMMAND \""
672 << this->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
673 << "\" \"" << toDestDirPath << "\")\n";
674 os << indent << "ENDIF(CMAKE_INSTALL_DO_STRIP)\n";
677 //----------------------------------------------------------------------------
678 void
679 cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
680 Indent const& indent,
681 cmTarget::TargetType type,
682 const std::string& toDestDirPath)
684 // Static libraries need ranlib on this platform.
685 if(type != cmTarget::STATIC_LIBRARY)
687 return;
690 // Perform post-installation processing on the file depending
691 // on its type.
692 if(!this->Target->GetMakefile()->IsOn("APPLE"))
694 return;
697 std::string ranlib =
698 this->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
699 if(ranlib.empty())
701 return;
704 os << indent << "EXECUTE_PROCESS(COMMAND \""
705 << ranlib << "\" \"" << toDestDirPath << "\")\n";