1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmInstallTargetGenerator.cxx,v $
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"
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"))
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/";
70 fromDir
= this->Target
->GetDirectory(0, this->ImportLibrary
);
74 // Perform the main install script generation.
75 this->cmInstallGenerator::GenerateScript(os
);
78 //----------------------------------------------------------------------------
79 void cmInstallTargetGenerator::GenerateScriptConfigs(std::ostream
& os
,
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
);
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
,
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
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
,
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
;
167 std::string from1
= fromDirConfig
;
170 // Handle OSX Bundles.
171 if(this->Target
->IsAppBundleOnApple())
173 // Compute the source locations of the bundle executable and
176 files
.push_back(from1
);
177 type
= cmTarget::INSTALL_DIRECTORY
;
178 // Need to apply install_name_tool and stripping to binary
180 toInstallPath
+= ".app/Contents/MacOS/";
182 this->GetInstallFilename(this->Target
, config
, nameType
);
183 literal_args
+= " USE_SOURCE_PERMISSIONS";
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
);
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
,
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
;
233 from1
+= ".framework";
234 files
.push_back(from1
);
236 type
= cmTarget::INSTALL_DIRECTORY
;
238 // Need to apply install_name_tool and stripping to binary
240 toInstallPath
+= ".framework/Versions/";
241 toInstallPath
+= this->Target
->GetFrameworkVersion();
242 toInstallPath
+= "/";
243 toInstallPath
+= this->GetInstallFilename(this->Target
, config
,
246 literal_args
+= " USE_SOURCE_PERMISSIONS";
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
)
266 fromSOName
= fromDirConfig
;
267 fromSOName
+= targetNameSO
;
269 if(targetNameReal
!= targetName
&&
270 targetNameReal
!= targetNameSO
)
273 fromRealName
= fromDirConfig
;
274 fromRealName
+= targetNameReal
;
277 // Add the names based on the current namelink mode.
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;
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
);
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.
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.
340 this->AddRPathCheckRule(tw
, indent
.Next(), config
, toDestDirPath
);
341 std::string tws
= tw
.str();
343 // Add the rules, if any.
346 os
<< indent
<< "IF(EXISTS \"" << toDestDirPath
<< "\")\n";
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(),
363 // Add post-installation tweaks.
364 if(tweakInstalledFile
)
366 // Collect tweaking rules.
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.
377 os
<< indent
<< "IF(EXISTS \"" << toDestDirPath
<< "\")\n";
379 os
<< indent
<< "ENDIF(EXISTS \"" << toDestDirPath
<< "\")\n";
384 //----------------------------------------------------------------------------
386 cmInstallTargetGenerator::GetInstallFilename(const char* config
) const
388 NameType nameType
= this->ImportLibrary
? NameImplib
: NameNormal
;
390 cmInstallTargetGenerator::GetInstallFilename(this->Target
, config
,
394 //----------------------------------------------------------------------------
395 std::string
cmInstallTargetGenerator::GetInstallFilename(cmTarget
* target
,
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
,
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
;
422 // Use the canonical name.
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
)
443 fname
= targetNameSO
;
445 else if(nameType
== NameReal
)
447 // Use the real name.
448 fname
= targetNameReal
;
452 // Use the canonical name.
460 //----------------------------------------------------------------------------
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
))
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())
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.
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.
503 this->GetInstallFilename(tgt
, config
, NameSO
);
505 // Map from the build-tree install_name.
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.
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
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
;
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 //----------------------------------------------------------------------------
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())
577 // Get the link information for this target.
578 // It can provide the RPATH.
579 cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
);
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 //----------------------------------------------------------------------------
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())
608 // Get the link information for this target.
609 // It can provide the RPATH.
610 cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
);
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
)
628 // Write a rule to run chrpath to set the install-tree RPATH
631 os
<< indent
<< "FILE(RPATH_REMOVE\n"
632 << indent
<< " FILE \"" << toDestDirPath
<< "\")\n";
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 //----------------------------------------------------------------------------
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
)
658 // Don't handle OSX Bundles.
659 if(this->Target
->GetMakefile()->IsOn("APPLE") &&
660 this->Target
->GetPropertyAsBool("MACOSX_BUNDLE"))
665 if(! this->Target
->GetMakefile()->IsSet("CMAKE_STRIP"))
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 //----------------------------------------------------------------------------
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
)
690 // Perform post-installation processing on the file depending
692 if(!this->Target
->GetMakefile()->IsOn("APPLE"))
698 this->Target
->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
704 os
<< indent
<< "EXECUTE_PROCESS(COMMAND \""
705 << ranlib
<< "\" \"" << toDestDirPath
<< "\")\n";