1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmInstallTargetGenerator.cxx,v $
6 Date: $Date: 2009-03-16 14:39:49 $
7 Version: $Revision: 1.68 $
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 const char* no_properties
= 0;
315 bool optional
= this->Optional
|| this->ImportLibrary
;
316 this->AddInstallRule(os
, type
, files
,
317 optional
, no_properties
,
318 this->FilePermissions
.c_str(), no_dir_permissions
,
319 no_rename
, literal_args
.c_str(),
322 // Add post-installation tweaks.
323 if(tweakInstalledFile
)
325 // Collect tweaking rules.
327 this->AddInstallNamePatchRule(tw
, indent
.Next(), config
, toDestDirPath
);
328 this->AddChrpathPatchRule(tw
, indent
.Next(), config
, toDestDirPath
);
329 this->AddRanlibRule(tw
, indent
.Next(), type
, toDestDirPath
);
330 this->AddStripRule(tw
, indent
.Next(), type
, toDestDirPath
);
331 std::string tws
= tw
.str();
333 // Add the rules, if any.
336 os
<< indent
<< "IF(EXISTS \"" << toDestDirPath
<< "\")\n";
338 os
<< indent
<< "ENDIF(EXISTS \"" << toDestDirPath
<< "\")\n";
343 //----------------------------------------------------------------------------
345 cmInstallTargetGenerator::GetInstallFilename(const char* config
) const
347 NameType nameType
= this->ImportLibrary
? NameImplib
: NameNormal
;
349 cmInstallTargetGenerator::GetInstallFilename(this->Target
, config
,
353 //----------------------------------------------------------------------------
354 std::string
cmInstallTargetGenerator::GetInstallFilename(cmTarget
* target
,
359 // Compute the name of the library.
360 if(target
->GetType() == cmTarget::EXECUTABLE
)
362 std::string targetName
;
363 std::string targetNameReal
;
364 std::string targetNameImport
;
365 std::string targetNamePDB
;
366 target
->GetExecutableNames(targetName
, targetNameReal
,
367 targetNameImport
, targetNamePDB
,
369 if(nameType
== NameImplib
)
371 // Use the import library name.
372 fname
= targetNameImport
;
374 else if(nameType
== NameReal
)
376 // Use the canonical name.
377 fname
= targetNameReal
;
381 // Use the canonical name.
387 std::string targetName
;
388 std::string targetNameSO
;
389 std::string targetNameReal
;
390 std::string targetNameImport
;
391 std::string targetNamePDB
;
392 target
->GetLibraryNames(targetName
, targetNameSO
, targetNameReal
,
393 targetNameImport
, targetNamePDB
, config
);
394 if(nameType
== NameImplib
)
396 // Use the import library name.
397 fname
= targetNameImport
;
399 else if(nameType
== NameSO
)
402 fname
= targetNameSO
;
404 else if(nameType
== NameReal
)
406 // Use the real name.
407 fname
= targetNameReal
;
411 // Use the canonical name.
419 //----------------------------------------------------------------------------
421 cmInstallTargetGenerator
422 ::AddInstallNamePatchRule(std::ostream
& os
, Indent
const& indent
,
423 const char* config
, std::string
const& toDestDirPath
)
425 if(this->ImportLibrary
||
426 !(this->Target
->GetType() == cmTarget::SHARED_LIBRARY
||
427 this->Target
->GetType() == cmTarget::MODULE_LIBRARY
||
428 this->Target
->GetType() == cmTarget::EXECUTABLE
))
433 // Fix the install_name settings in installed binaries.
434 std::string installNameTool
=
435 this->Target
->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
437 if(!installNameTool
.size())
442 // Build a map of build-tree install_name to install-tree install_name for
443 // shared libraries linked to this target.
444 std::map
<cmStdString
, cmStdString
> install_name_remap
;
445 if(cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
))
447 std::set
<cmTarget
*> const& sharedLibs
= cli
->GetSharedLibrariesLinked();
448 for(std::set
<cmTarget
*>::const_iterator j
= sharedLibs
.begin();
449 j
!= sharedLibs
.end(); ++j
)
453 // The install_name of an imported target does not change.
454 if(tgt
->IsImported())
459 // If the build tree and install tree use different path
460 // components of the install_name field then we need to create a
461 // mapping to be applied after installation.
462 std::string for_build
= tgt
->GetInstallNameDirForBuildTree(config
);
463 std::string for_install
= tgt
->GetInstallNameDirForInstallTree(config
);
464 if(for_build
!= for_install
)
466 // The directory portions differ. Append the filename to
467 // create the mapping.
469 this->GetInstallFilename(tgt
, config
, NameSO
);
471 // Map from the build-tree install_name.
474 // Map to the install-tree install_name.
475 for_install
+= fname
;
477 // Store the mapping entry.
478 install_name_remap
[for_build
] = for_install
;
483 // Edit the install_name of the target itself if necessary.
485 if(this->Target
->GetType() == cmTarget::SHARED_LIBRARY
)
487 std::string for_build
=
488 this->Target
->GetInstallNameDirForBuildTree(config
);
489 std::string for_install
=
490 this->Target
->GetInstallNameDirForInstallTree(config
);
492 if(this->Target
->IsFrameworkOnApple() && for_install
.empty())
494 // Frameworks seem to have an id corresponding to their own full
497 // for_install = fullDestPath_without_DESTDIR_or_name;
500 // If the install name will change on installation set the new id
501 // on the installed file.
502 if(for_build
!= for_install
)
504 // Prepare to refer to the install-tree install_name.
505 new_id
= for_install
;
506 new_id
+= this->GetInstallFilename(this->Target
, config
, NameSO
);
510 // Write a rule to run install_name_tool to set the install-tree
511 // install_name value and references.
512 if(!new_id
.empty() || !install_name_remap
.empty())
514 os
<< indent
<< "EXECUTE_PROCESS(COMMAND \"" << installNameTool
;
518 os
<< "\n" << indent
<< " -id \"" << new_id
<< "\"";
520 for(std::map
<cmStdString
, cmStdString
>::const_iterator
521 i
= install_name_remap
.begin();
522 i
!= install_name_remap
.end(); ++i
)
524 os
<< "\n" << indent
<< " -change \""
525 << i
->first
<< "\" \"" << i
->second
<< "\"";
527 os
<< "\n" << indent
<< " \"" << toDestDirPath
<< "\")\n";
531 //----------------------------------------------------------------------------
533 cmInstallTargetGenerator
534 ::AddRPathCheckRule(std::ostream
& os
, Indent
const& indent
,
535 const char* config
, std::string
const& toDestDirPath
)
537 // Skip the chrpath if the target does not need it.
538 if(this->ImportLibrary
|| !this->Target
->IsChrpathUsed())
543 // Get the link information for this target.
544 // It can provide the RPATH.
545 cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
);
551 // Get the install RPATH from the link information.
552 std::string newRpath
= cli
->GetChrpathString();
554 // Write a rule to remove the installed file if its rpath is not the
555 // new rpath. This is needed for existing build/install trees when
556 // the installed rpath changes but the file is not rebuilt.
557 os
<< indent
<< "FILE(RPATH_CHECK\n"
558 << indent
<< " FILE \"" << toDestDirPath
<< "\"\n"
559 << indent
<< " RPATH \"" << newRpath
<< "\")\n";
562 //----------------------------------------------------------------------------
564 cmInstallTargetGenerator
565 ::AddChrpathPatchRule(std::ostream
& os
, Indent
const& indent
,
566 const char* config
, std::string
const& toDestDirPath
)
568 // Skip the chrpath if the target does not need it.
569 if(this->ImportLibrary
|| !this->Target
->IsChrpathUsed())
574 // Get the link information for this target.
575 // It can provide the RPATH.
576 cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
);
582 // Construct the original rpath string to be replaced.
583 std::string oldRpath
= cli
->GetRPathString(false);
585 // Get the install RPATH from the link information.
586 std::string newRpath
= cli
->GetChrpathString();
588 // Skip the rule if the paths are identical
589 if(oldRpath
== newRpath
)
594 // Write a rule to run chrpath to set the install-tree RPATH
597 os
<< indent
<< "FILE(RPATH_REMOVE\n"
598 << indent
<< " FILE \"" << toDestDirPath
<< "\")\n";
602 os
<< indent
<< "FILE(RPATH_CHANGE\n"
603 << indent
<< " FILE \"" << toDestDirPath
<< "\"\n"
604 << indent
<< " OLD_RPATH \"" << oldRpath
<< "\"\n"
605 << indent
<< " NEW_RPATH \"" << newRpath
<< "\")\n";
609 //----------------------------------------------------------------------------
611 cmInstallTargetGenerator::AddStripRule(std::ostream
& os
,
612 Indent
const& indent
,
613 cmTarget::TargetType type
,
614 const std::string
& toDestDirPath
)
617 // don't strip static libraries, because it removes the only symbol table
618 // they have so you can't link to them anymore
619 if(type
== cmTarget::STATIC_LIBRARY
)
624 // Don't handle OSX Bundles.
625 if(this->Target
->GetMakefile()->IsOn("APPLE") &&
626 this->Target
->GetPropertyAsBool("MACOSX_BUNDLE"))
631 if(! this->Target
->GetMakefile()->IsSet("CMAKE_STRIP"))
636 os
<< indent
<< "IF(CMAKE_INSTALL_DO_STRIP)\n";
637 os
<< indent
<< " EXECUTE_PROCESS(COMMAND \""
638 << this->Target
->GetMakefile()->GetDefinition("CMAKE_STRIP")
639 << "\" \"" << toDestDirPath
<< "\")\n";
640 os
<< indent
<< "ENDIF(CMAKE_INSTALL_DO_STRIP)\n";
643 //----------------------------------------------------------------------------
645 cmInstallTargetGenerator::AddRanlibRule(std::ostream
& os
,
646 Indent
const& indent
,
647 cmTarget::TargetType type
,
648 const std::string
& toDestDirPath
)
650 // Static libraries need ranlib on this platform.
651 if(type
!= cmTarget::STATIC_LIBRARY
)
656 // Perform post-installation processing on the file depending
658 if(!this->Target
->GetMakefile()->IsOn("APPLE"))
664 this->Target
->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
670 os
<< indent
<< "EXECUTE_PROCESS(COMMAND \""
671 << ranlib
<< "\" \"" << toDestDirPath
<< "\")\n";