1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmInstallTargetGenerator.cxx,v $
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"
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"))
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/";
71 fromDir
= this->Target
->GetDirectory(0, this->ImportLibrary
);
75 // Perform the main install script generation.
76 this->cmInstallGenerator::GenerateScript(os
);
79 //----------------------------------------------------------------------------
80 void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream
& os
,
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();
93 toInstallPath
+= this->GetInstallFilename(this->Target
, config
, nameType
);
95 // Track whether post-install operations should be added to the
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
,
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
;
126 std::string from1
= fromDirConfig
;
129 // Handle OSX Bundles.
130 if(this->Target
->IsAppBundleOnApple())
132 // Compute the source locations of the bundle executable and
135 files
.push_back(from1
);
136 type
= cmTarget::INSTALL_DIRECTORY
;
137 // Need to apply install_name_tool and stripping to binary
139 toInstallPath
+= ".app/Contents/MacOS/";
141 this->GetInstallFilename(this->Target
, config
, nameType
);
142 literal_args
+= " USE_SOURCE_PERMISSIONS";
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
);
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
,
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
;
192 from1
+= ".framework";
193 files
.push_back(from1
);
195 type
= cmTarget::INSTALL_DIRECTORY
;
197 // Need to apply install_name_tool and stripping to binary
199 toInstallPath
+= ".framework/Versions/";
200 toInstallPath
+= this->Target
->GetFrameworkVersion();
201 toInstallPath
+= "/";
202 toInstallPath
+= this->GetInstallFilename(this->Target
, config
,
205 literal_args
+= " USE_SOURCE_PERMISSIONS";
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
)
225 fromSOName
= fromDirConfig
;
226 fromSOName
+= targetNameSO
;
228 if(targetNameReal
!= targetName
&&
229 targetNameReal
!= targetNameSO
)
232 fromRealName
= fromDirConfig
;
233 fromRealName
+= targetNameReal
;
236 // Add the names based on the current namelink mode.
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;
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
);
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.
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.
299 this->AddRPathCheckRule(tw
, indent
.Next(), config
, toDestDirPath
);
300 std::string tws
= tw
.str();
302 // Add the rules, if any.
305 os
<< indent
<< "IF(EXISTS \"" << toDestDirPath
<< "\")\n";
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
,
317 this->FilePermissions
.c_str(), no_dir_permissions
,
318 no_rename
, literal_args
.c_str(),
321 // Add post-installation tweaks.
322 if(tweakInstalledFile
)
324 // Collect tweaking rules.
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.
335 os
<< indent
<< "IF(EXISTS \"" << toDestDirPath
<< "\")\n";
337 os
<< indent
<< "ENDIF(EXISTS \"" << toDestDirPath
<< "\")\n";
342 //----------------------------------------------------------------------------
344 cmInstallTargetGenerator::GetInstallFilename(const char* config
) const
346 NameType nameType
= this->ImportLibrary
? NameImplib
: NameNormal
;
348 cmInstallTargetGenerator::GetInstallFilename(this->Target
, config
,
352 //----------------------------------------------------------------------------
353 std::string
cmInstallTargetGenerator::GetInstallFilename(cmTarget
* target
,
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
,
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
;
380 // Use the canonical name.
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
)
401 fname
= targetNameSO
;
403 else if(nameType
== NameReal
)
405 // Use the real name.
406 fname
= targetNameReal
;
410 // Use the canonical name.
418 //----------------------------------------------------------------------------
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
))
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())
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
)
452 // The install_name of an imported target does not change.
453 if(tgt
->IsImported())
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.
468 this->GetInstallFilename(tgt
, config
, NameSO
);
470 // Map from the build-tree install_name.
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.
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
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
;
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 //----------------------------------------------------------------------------
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())
542 // Get the link information for this target.
543 // It can provide the RPATH.
544 cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
);
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 //----------------------------------------------------------------------------
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())
573 // Get the link information for this target.
574 // It can provide the RPATH.
575 cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
);
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
)
593 // Write a rule to run chrpath to set the install-tree RPATH
596 os
<< indent
<< "FILE(RPATH_REMOVE\n"
597 << indent
<< " FILE \"" << toDestDirPath
<< "\")\n";
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 //----------------------------------------------------------------------------
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
)
623 // Don't handle OSX Bundles.
624 if(this->Target
->GetMakefile()->IsOn("APPLE") &&
625 this->Target
->GetPropertyAsBool("MACOSX_BUNDLE"))
630 if(! this->Target
->GetMakefile()->IsSet("CMAKE_STRIP"))
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 //----------------------------------------------------------------------------
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
)
655 // Perform post-installation processing on the file depending
657 if(!this->Target
->GetMakefile()->IsOn("APPLE"))
663 this->Target
->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
669 os
<< indent
<< "EXECUTE_PROCESS(COMMAND \""
670 << ranlib
<< "\" \"" << toDestDirPath
<< "\")\n";