ENH: put the 64 bit paths first
[cmake.git] / Source / cmInstallTargetGenerator.cxx
blob1775942ddc57f28f45df09c77d2b00b2571909b1
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmInstallTargetGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2009-04-27 17:20:57 $
7 Version: $Revision: 1.69 $
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->ActionsPerConfig = true;
37 this->NamelinkMode = NamelinkModeNone;
38 this->Target->SetHaveInstallRule(true);
41 //----------------------------------------------------------------------------
42 cmInstallTargetGenerator
43 ::~cmInstallTargetGenerator()
47 //----------------------------------------------------------------------------
48 void cmInstallTargetGenerator::GenerateScript(std::ostream& os)
50 // Warn if installing an exclude-from-all target.
51 if(this->Target->GetPropertyAsBool("EXCLUDE_FROM_ALL"))
53 cmOStringStream msg;
54 msg << "WARNING: Target \"" << this->Target->GetName()
55 << "\" has EXCLUDE_FROM_ALL set and will not be built by default "
56 << "but an install rule has been provided for it. CMake does "
57 << "not define behavior for this case.";
58 cmSystemTools::Message(msg.str().c_str(), "Warning");
61 // Compute the build tree directory from which to copy the target.
62 std::string& fromDir = this->FromDir;
63 if(this->Target->NeedRelinkBeforeInstall())
65 fromDir = this->Target->GetMakefile()->GetStartOutputDirectory();
66 fromDir += cmake::GetCMakeFilesDirectory();
67 fromDir += "/CMakeRelink.dir/";
69 else
71 fromDir = this->Target->GetDirectory(0, this->ImportLibrary);
72 fromDir += "/";
75 // Perform the main install script generation.
76 this->cmInstallGenerator::GenerateScript(os);
79 //----------------------------------------------------------------------------
80 void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
81 const char* config,
82 Indent const& indent)
84 // Compute the per-configuration directory containing the files.
85 std::string fromDirConfig = this->FromDir;
86 this->Target->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()
87 ->AppendDirectoryForConfig("", config, "/", fromDirConfig);
89 // Compute the full path to the main installed file for this target.
90 NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
91 std::string toInstallPath = this->GetInstallDestination();
92 toInstallPath += "/";
93 toInstallPath += this->GetInstallFilename(this->Target, config, nameType);
95 // Track whether post-install operations should be added to the
96 // script.
97 bool tweakInstalledFile = true;
99 // Compute the list of files to install for this target.
100 std::vector<std::string> files;
101 std::string literal_args;
102 cmTarget::TargetType type = this->Target->GetType();
103 if(type == cmTarget::EXECUTABLE)
105 // There is a bug in cmInstallCommand if this fails.
106 assert(this->NamelinkMode == NamelinkModeNone);
108 std::string targetName;
109 std::string targetNameReal;
110 std::string targetNameImport;
111 std::string targetNamePDB;
112 this->Target->GetExecutableNames(targetName, targetNameReal,
113 targetNameImport, targetNamePDB,
114 config);
115 if(this->ImportLibrary)
117 std::string from1 = fromDirConfig;
118 from1 += targetNameImport;
119 files.push_back(from1);
121 // An import library looks like a static library.
122 type = cmTarget::STATIC_LIBRARY;
124 else
126 std::string from1 = fromDirConfig;
127 from1 += targetName;
129 // Handle OSX Bundles.
130 if(this->Target->IsAppBundleOnApple())
132 // Compute the source locations of the bundle executable and
133 // Info.plist file.
134 from1 += ".app";
135 files.push_back(from1);
136 type = cmTarget::INSTALL_DIRECTORY;
137 // Need to apply install_name_tool and stripping to binary
138 // inside bundle.
139 toInstallPath += ".app/Contents/MacOS/";
140 toInstallPath +=
141 this->GetInstallFilename(this->Target, config, nameType);
142 literal_args += " USE_SOURCE_PERMISSIONS";
144 else
146 // Operations done at install time on the installed file should
147 // be done on the real file and not any of the symlinks.
148 toInstallPath = this->GetInstallDestination();
149 toInstallPath += "/";
150 toInstallPath += targetNameReal;
152 files.push_back(from1);
153 if(targetNameReal != targetName)
155 std::string from2 = fromDirConfig;
156 from2 += targetNameReal;
157 files.push_back(from2);
162 else
164 std::string targetName;
165 std::string targetNameSO;
166 std::string targetNameReal;
167 std::string targetNameImport;
168 std::string targetNamePDB;
169 this->Target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
170 targetNameImport, targetNamePDB,
171 config);
172 if(this->ImportLibrary)
174 // There is a bug in cmInstallCommand if this fails.
175 assert(this->NamelinkMode == NamelinkModeNone);
177 std::string from1 = fromDirConfig;
178 from1 += targetNameImport;
179 files.push_back(from1);
181 // An import library looks like a static library.
182 type = cmTarget::STATIC_LIBRARY;
184 else if(this->Target->IsFrameworkOnApple())
186 // There is a bug in cmInstallCommand if this fails.
187 assert(this->NamelinkMode == NamelinkModeNone);
189 // Compute the build tree location of the framework directory
190 std::string from1 = fromDirConfig;
191 from1 += targetName;
192 from1 += ".framework";
193 files.push_back(from1);
195 type = cmTarget::INSTALL_DIRECTORY;
197 // Need to apply install_name_tool and stripping to binary
198 // inside framework.
199 toInstallPath += ".framework/Versions/";
200 toInstallPath += this->Target->GetFrameworkVersion();
201 toInstallPath += "/";
202 toInstallPath += this->GetInstallFilename(this->Target, config,
203 NameNormal);
205 literal_args += " USE_SOURCE_PERMISSIONS";
207 else
209 // Operations done at install time on the installed file should
210 // be done on the real file and not any of the symlinks.
211 toInstallPath = this->GetInstallDestination();
212 toInstallPath += "/";
213 toInstallPath += targetNameReal;
215 // Construct the list of file names to install for this library.
216 bool haveNamelink = false;
217 std::string fromName;
218 std::string fromSOName;
219 std::string fromRealName;
220 fromName = fromDirConfig;
221 fromName += targetName;
222 if(targetNameSO != targetName)
224 haveNamelink = true;
225 fromSOName = fromDirConfig;
226 fromSOName += targetNameSO;
228 if(targetNameReal != targetName &&
229 targetNameReal != targetNameSO)
231 haveNamelink = true;
232 fromRealName = fromDirConfig;
233 fromRealName += targetNameReal;
236 // Add the names based on the current namelink mode.
237 if(haveNamelink)
239 // With a namelink we need to check the mode.
240 if(this->NamelinkMode == NamelinkModeOnly)
242 // Install the namelink only.
243 files.push_back(fromName);
244 tweakInstalledFile = false;
246 else
248 // Install the real file if it has its own name.
249 if(!fromRealName.empty())
251 files.push_back(fromRealName);
254 // Install the soname link if it has its own name.
255 if(!fromSOName.empty())
257 files.push_back(fromSOName);
260 // Install the namelink if it is not to be skipped.
261 if(this->NamelinkMode != NamelinkModeSkip)
263 files.push_back(fromName);
267 else
269 // Without a namelink there will be only one file. Install it
270 // if this is not a namelink-only rule.
271 if(this->NamelinkMode != NamelinkModeOnly)
273 files.push_back(fromName);
279 // Skip this rule if no files are to be installed for the target.
280 if(files.empty())
282 return;
285 // Construct the path of the file on disk after installation on
286 // which tweaks may be performed.
287 std::string toDestDirPath = "$ENV{DESTDIR}";
288 if(toInstallPath[0] != '/' && toInstallPath[0] != '$')
290 toDestDirPath += "/";
292 toDestDirPath += toInstallPath;
294 // Add pre-installation tweaks.
295 if(tweakInstalledFile)
297 // Collect tweaking rules.
298 cmOStringStream tw;
299 this->AddRPathCheckRule(tw, indent.Next(), config, toDestDirPath);
300 std::string tws = tw.str();
302 // Add the rules, if any.
303 if(!tws.empty())
305 os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n";
306 os << tws;
307 os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n";
311 // Write code to install the target file.
312 const char* no_dir_permissions = 0;
313 const char* no_rename = 0;
314 bool optional = this->Optional || this->ImportLibrary;
315 this->AddInstallRule(os, type, files,
316 optional,
317 this->FilePermissions.c_str(), no_dir_permissions,
318 no_rename, literal_args.c_str(),
319 indent);
321 // Add post-installation tweaks.
322 if(tweakInstalledFile)
324 // Collect tweaking rules.
325 cmOStringStream tw;
326 this->AddInstallNamePatchRule(tw, indent.Next(), config, toDestDirPath);
327 this->AddChrpathPatchRule(tw, indent.Next(), config, toDestDirPath);
328 this->AddRanlibRule(tw, indent.Next(), type, toDestDirPath);
329 this->AddStripRule(tw, indent.Next(), type, toDestDirPath);
330 std::string tws = tw.str();
332 // Add the rules, if any.
333 if(!tws.empty())
335 os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n";
336 os << tws;
337 os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n";
342 //----------------------------------------------------------------------------
343 std::string
344 cmInstallTargetGenerator::GetInstallFilename(const char* config) const
346 NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
347 return
348 cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
349 nameType);
352 //----------------------------------------------------------------------------
353 std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
354 const char* config,
355 NameType nameType)
357 std::string fname;
358 // Compute the name of the library.
359 if(target->GetType() == cmTarget::EXECUTABLE)
361 std::string targetName;
362 std::string targetNameReal;
363 std::string targetNameImport;
364 std::string targetNamePDB;
365 target->GetExecutableNames(targetName, targetNameReal,
366 targetNameImport, targetNamePDB,
367 config);
368 if(nameType == NameImplib)
370 // Use the import library name.
371 fname = targetNameImport;
373 else if(nameType == NameReal)
375 // Use the canonical name.
376 fname = targetNameReal;
378 else
380 // Use the canonical name.
381 fname = targetName;
384 else
386 std::string targetName;
387 std::string targetNameSO;
388 std::string targetNameReal;
389 std::string targetNameImport;
390 std::string targetNamePDB;
391 target->GetLibraryNames(targetName, targetNameSO, targetNameReal,
392 targetNameImport, targetNamePDB, config);
393 if(nameType == NameImplib)
395 // Use the import library name.
396 fname = targetNameImport;
398 else if(nameType == NameSO)
400 // Use the soname.
401 fname = targetNameSO;
403 else if(nameType == NameReal)
405 // Use the real name.
406 fname = targetNameReal;
408 else
410 // Use the canonical name.
411 fname = targetName;
415 return fname;
418 //----------------------------------------------------------------------------
419 void
420 cmInstallTargetGenerator
421 ::AddInstallNamePatchRule(std::ostream& os, Indent const& indent,
422 const char* config, std::string const& toDestDirPath)
424 if(this->ImportLibrary ||
425 !(this->Target->GetType() == cmTarget::SHARED_LIBRARY ||
426 this->Target->GetType() == cmTarget::MODULE_LIBRARY ||
427 this->Target->GetType() == cmTarget::EXECUTABLE))
429 return;
432 // Fix the install_name settings in installed binaries.
433 std::string installNameTool =
434 this->Target->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
436 if(!installNameTool.size())
438 return;
441 // Build a map of build-tree install_name to install-tree install_name for
442 // shared libraries linked to this target.
443 std::map<cmStdString, cmStdString> install_name_remap;
444 if(cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config))
446 std::set<cmTarget*> const& sharedLibs = cli->GetSharedLibrariesLinked();
447 for(std::set<cmTarget*>::const_iterator j = sharedLibs.begin();
448 j != sharedLibs.end(); ++j)
450 cmTarget* tgt = *j;
452 // The install_name of an imported target does not change.
453 if(tgt->IsImported())
455 continue;
458 // If the build tree and install tree use different path
459 // components of the install_name field then we need to create a
460 // mapping to be applied after installation.
461 std::string for_build = tgt->GetInstallNameDirForBuildTree(config);
462 std::string for_install = tgt->GetInstallNameDirForInstallTree(config);
463 if(for_build != for_install)
465 // The directory portions differ. Append the filename to
466 // create the mapping.
467 std::string fname =
468 this->GetInstallFilename(tgt, config, NameSO);
470 // Map from the build-tree install_name.
471 for_build += fname;
473 // Map to the install-tree install_name.
474 for_install += fname;
476 // Store the mapping entry.
477 install_name_remap[for_build] = for_install;
482 // Edit the install_name of the target itself if necessary.
483 std::string new_id;
484 if(this->Target->GetType() == cmTarget::SHARED_LIBRARY)
486 std::string for_build =
487 this->Target->GetInstallNameDirForBuildTree(config);
488 std::string for_install =
489 this->Target->GetInstallNameDirForInstallTree(config);
491 if(this->Target->IsFrameworkOnApple() && for_install.empty())
493 // Frameworks seem to have an id corresponding to their own full
494 // path.
495 // ...
496 // for_install = fullDestPath_without_DESTDIR_or_name;
499 // If the install name will change on installation set the new id
500 // on the installed file.
501 if(for_build != for_install)
503 // Prepare to refer to the install-tree install_name.
504 new_id = for_install;
505 new_id += this->GetInstallFilename(this->Target, config, NameSO);
509 // Write a rule to run install_name_tool to set the install-tree
510 // install_name value and references.
511 if(!new_id.empty() || !install_name_remap.empty())
513 os << indent << "EXECUTE_PROCESS(COMMAND \"" << installNameTool;
514 os << "\"";
515 if(!new_id.empty())
517 os << "\n" << indent << " -id \"" << new_id << "\"";
519 for(std::map<cmStdString, cmStdString>::const_iterator
520 i = install_name_remap.begin();
521 i != install_name_remap.end(); ++i)
523 os << "\n" << indent << " -change \""
524 << i->first << "\" \"" << i->second << "\"";
526 os << "\n" << indent << " \"" << toDestDirPath << "\")\n";
530 //----------------------------------------------------------------------------
531 void
532 cmInstallTargetGenerator
533 ::AddRPathCheckRule(std::ostream& os, Indent const& indent,
534 const char* config, std::string const& toDestDirPath)
536 // Skip the chrpath if the target does not need it.
537 if(this->ImportLibrary || !this->Target->IsChrpathUsed())
539 return;
542 // Get the link information for this target.
543 // It can provide the RPATH.
544 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
545 if(!cli)
547 return;
550 // Get the install RPATH from the link information.
551 std::string newRpath = cli->GetChrpathString();
553 // Write a rule to remove the installed file if its rpath is not the
554 // new rpath. This is needed for existing build/install trees when
555 // the installed rpath changes but the file is not rebuilt.
556 os << indent << "FILE(RPATH_CHECK\n"
557 << indent << " FILE \"" << toDestDirPath << "\"\n"
558 << indent << " RPATH \"" << newRpath << "\")\n";
561 //----------------------------------------------------------------------------
562 void
563 cmInstallTargetGenerator
564 ::AddChrpathPatchRule(std::ostream& os, Indent const& indent,
565 const char* config, std::string const& toDestDirPath)
567 // Skip the chrpath if the target does not need it.
568 if(this->ImportLibrary || !this->Target->IsChrpathUsed())
570 return;
573 // Get the link information for this target.
574 // It can provide the RPATH.
575 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
576 if(!cli)
578 return;
581 // Construct the original rpath string to be replaced.
582 std::string oldRpath = cli->GetRPathString(false);
584 // Get the install RPATH from the link information.
585 std::string newRpath = cli->GetChrpathString();
587 // Skip the rule if the paths are identical
588 if(oldRpath == newRpath)
590 return;
593 // Write a rule to run chrpath to set the install-tree RPATH
594 if(newRpath.empty())
596 os << indent << "FILE(RPATH_REMOVE\n"
597 << indent << " FILE \"" << toDestDirPath << "\")\n";
599 else
601 os << indent << "FILE(RPATH_CHANGE\n"
602 << indent << " FILE \"" << toDestDirPath << "\"\n"
603 << indent << " OLD_RPATH \"" << oldRpath << "\"\n"
604 << indent << " NEW_RPATH \"" << newRpath << "\")\n";
608 //----------------------------------------------------------------------------
609 void
610 cmInstallTargetGenerator::AddStripRule(std::ostream& os,
611 Indent const& indent,
612 cmTarget::TargetType type,
613 const std::string& toDestDirPath)
616 // don't strip static libraries, because it removes the only symbol table
617 // they have so you can't link to them anymore
618 if(type == cmTarget::STATIC_LIBRARY)
620 return;
623 // Don't handle OSX Bundles.
624 if(this->Target->GetMakefile()->IsOn("APPLE") &&
625 this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
627 return;
630 if(! this->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
632 return;
635 os << indent << "IF(CMAKE_INSTALL_DO_STRIP)\n";
636 os << indent << " EXECUTE_PROCESS(COMMAND \""
637 << this->Target->GetMakefile()->GetDefinition("CMAKE_STRIP")
638 << "\" \"" << toDestDirPath << "\")\n";
639 os << indent << "ENDIF(CMAKE_INSTALL_DO_STRIP)\n";
642 //----------------------------------------------------------------------------
643 void
644 cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
645 Indent const& indent,
646 cmTarget::TargetType type,
647 const std::string& toDestDirPath)
649 // Static libraries need ranlib on this platform.
650 if(type != cmTarget::STATIC_LIBRARY)
652 return;
655 // Perform post-installation processing on the file depending
656 // on its type.
657 if(!this->Target->GetMakefile()->IsOn("APPLE"))
659 return;
662 std::string ranlib =
663 this->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
664 if(ranlib.empty())
666 return;
669 os << indent << "EXECUTE_PROCESS(COMMAND \""
670 << ranlib << "\" \"" << toDestDirPath << "\")\n";