1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmInstallTargetGenerator.cxx,v $
6 Date: $Date: 2008-03-02 21:48:50 $
7 Version: $Revision: 1.62 $
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");
63 // Begin this block of installation.
64 std::string component_test
=
65 this->CreateComponentTest(this->Component
.c_str());
66 os
<< indent
<< "IF(" << component_test
<< ")\n";
68 // Compute the build tree directory from which to copy the target.
70 if(this->Target
->NeedRelinkBeforeInstall())
72 fromDir
= this->Target
->GetMakefile()->GetStartOutputDirectory();
73 fromDir
+= cmake::GetCMakeFilesDirectory();
74 fromDir
+= "/CMakeRelink.dir/";
78 fromDir
= this->Target
->GetDirectory(0, this->ImportLibrary
);
82 // Generate a portion of the script for each configuration.
83 if(this->ConfigurationTypes
->empty())
85 this->GenerateScriptForConfig(os
, fromDir
.c_str(),
86 this->ConfigurationName
,
91 for(std::vector
<std::string
>::const_iterator i
=
92 this->ConfigurationTypes
->begin();
93 i
!= this->ConfigurationTypes
->end(); ++i
)
95 this->GenerateScriptForConfig(os
, fromDir
.c_str(), i
->c_str(),
100 // End this block of installation.
101 os
<< indent
<< "ENDIF(" << component_test
<< ")\n\n";
104 //----------------------------------------------------------------------------
105 void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream
& os
,
108 Indent
const& indent
)
110 // Compute the per-configuration directory containing the files.
111 std::string fromDirConfig
= fromDir
;
112 this->Target
->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()
113 ->AppendDirectoryForConfig("", config
, "/", fromDirConfig
);
115 if(config
&& *config
)
117 // Skip this configuration for config-specific installation that
118 // does not match it.
119 if(!this->InstallsForConfig(config
))
124 // Generate a per-configuration block.
125 std::string config_test
= this->CreateConfigTest(config
);
126 os
<< indent
<< "IF(" << config_test
<< ")\n";
127 this->GenerateScriptForConfigDir(os
, fromDirConfig
.c_str(), config
,
129 os
<< indent
<< "ENDIF(" << config_test
<< ")\n";
133 this->GenerateScriptForConfigDir(os
, fromDirConfig
.c_str(), config
,
138 //----------------------------------------------------------------------------
140 cmInstallTargetGenerator
141 ::GenerateScriptForConfigDir(std::ostream
& os
,
142 const char* fromDirConfig
,
144 Indent
const& indent
)
146 // Compute the full path to the main installed file for this target.
147 NameType nameType
= this->ImportLibrary
? NameImplib
: NameNormal
;
148 std::string toInstallPath
= this->GetInstallDestination();
149 toInstallPath
+= "/";
150 toInstallPath
+= this->GetInstallFilename(this->Target
, config
, nameType
);
152 // Track whether post-install operations should be added to the
154 bool tweakInstalledFile
= true;
156 // Compute the list of files to install for this target.
157 std::vector
<std::string
> files
;
158 std::string literal_args
;
159 cmTarget::TargetType type
= this->Target
->GetType();
160 if(type
== cmTarget::EXECUTABLE
)
162 // There is a bug in cmInstallCommand if this fails.
163 assert(this->NamelinkMode
== NamelinkModeNone
);
165 std::string targetName
;
166 std::string targetNameReal
;
167 std::string targetNameImport
;
168 std::string targetNamePDB
;
169 this->Target
->GetExecutableNames(targetName
, targetNameReal
,
170 targetNameImport
, targetNamePDB
,
172 if(this->ImportLibrary
)
174 std::string from1
= fromDirConfig
;
175 from1
+= targetNameImport
;
176 files
.push_back(from1
);
178 // An import library looks like a static library.
179 type
= cmTarget::STATIC_LIBRARY
;
183 std::string from1
= fromDirConfig
;
186 // Handle OSX Bundles.
187 if(this->Target
->IsAppBundleOnApple())
189 // Compute the source locations of the bundle executable and
192 files
.push_back(from1
);
193 type
= cmTarget::INSTALL_DIRECTORY
;
194 // Need to apply install_name_tool and stripping to binary
196 toInstallPath
+= ".app/Contents/MacOS/";
198 this->GetInstallFilename(this->Target
, config
, nameType
);
199 literal_args
+= " USE_SOURCE_PERMISSIONS";
203 files
.push_back(from1
);
204 if(targetNameReal
!= targetName
)
206 std::string from2
= fromDirConfig
;
207 from2
+= targetNameReal
;
208 files
.push_back(from2
);
215 std::string targetName
;
216 std::string targetNameSO
;
217 std::string targetNameReal
;
218 std::string targetNameImport
;
219 std::string targetNamePDB
;
220 this->Target
->GetLibraryNames(targetName
, targetNameSO
, targetNameReal
,
221 targetNameImport
, targetNamePDB
,
223 if(this->ImportLibrary
)
225 // There is a bug in cmInstallCommand if this fails.
226 assert(this->NamelinkMode
== NamelinkModeNone
);
228 std::string from1
= fromDirConfig
;
229 from1
+= targetNameImport
;
230 files
.push_back(from1
);
232 // An import library looks like a static library.
233 type
= cmTarget::STATIC_LIBRARY
;
235 else if(this->Target
->IsFrameworkOnApple())
237 // There is a bug in cmInstallCommand if this fails.
238 assert(this->NamelinkMode
== NamelinkModeNone
);
240 // Compute the build tree location of the framework directory
241 std::string from1
= fromDirConfig
;
242 // Remove trailing slashes... so that from1 ends with ".framework":
244 cmSystemTools::ConvertToUnixSlashes(from1
);
245 files
.push_back(from1
);
247 type
= cmTarget::INSTALL_DIRECTORY
;
249 // Need to apply install_name_tool and stripping to binary
251 toInstallPath
+= ".framework/";
252 toInstallPath
+= this->GetInstallFilename(this->Target
, config
,
255 literal_args
+= " USE_SOURCE_PERMISSIONS";
259 // Operations done at install time on the installed file should
260 // be done on the real file and not any of the symlinks.
261 toInstallPath
= this->GetInstallDestination();
262 toInstallPath
+= "/";
263 toInstallPath
+= targetNameReal
;
265 // Construct the list of file names to install for this library.
266 bool haveNamelink
= false;
267 std::string fromName
;
268 std::string fromSOName
;
269 std::string fromRealName
;
270 fromName
= fromDirConfig
;
271 fromName
+= targetName
;
272 if(targetNameSO
!= targetName
)
275 fromSOName
= fromDirConfig
;
276 fromSOName
+= targetNameSO
;
278 if(targetNameReal
!= targetName
&&
279 targetNameReal
!= targetNameSO
)
282 fromRealName
= fromDirConfig
;
283 fromRealName
+= targetNameReal
;
286 // Add the names based on the current namelink mode.
289 // With a namelink we need to check the mode.
290 if(this->NamelinkMode
== NamelinkModeOnly
)
292 // Install the namelink only.
293 files
.push_back(fromName
);
294 tweakInstalledFile
= false;
298 // Install the real file if it has its own name.
299 if(!fromRealName
.empty())
301 files
.push_back(fromRealName
);
304 // Install the soname link if it has its own name.
305 if(!fromSOName
.empty())
307 files
.push_back(fromSOName
);
310 // Install the namelink if it is not to be skipped.
311 if(this->NamelinkMode
!= NamelinkModeSkip
)
313 files
.push_back(fromName
);
319 // Without a namelink there will be only one file. Install it
320 // if this is not a namelink-only rule.
321 if(this->NamelinkMode
!= NamelinkModeOnly
)
323 files
.push_back(fromName
);
329 // Skip this rule if no files are to be installed for the target.
335 // Write code to install the target file.
336 const char* no_dir_permissions
= 0;
337 const char* no_rename
= 0;
338 const char* no_properties
= 0;
339 bool optional
= this->Optional
|| this->ImportLibrary
;
340 this->AddInstallRule(os
, type
, files
,
341 optional
, no_properties
,
342 this->FilePermissions
.c_str(), no_dir_permissions
,
343 no_rename
, literal_args
.c_str(),
346 // Construct the path of the file on disk after installation on
347 // which tweaks may be performed.
348 std::string toDestDirPath
= "$ENV{DESTDIR}";
349 if(toInstallPath
[0] != '/' && toInstallPath
[0] != '$')
351 toDestDirPath
+= "/";
353 toDestDirPath
+= toInstallPath
;
356 // - Skip IF(EXISTS) checks if nothing is done with the installed file
357 if(tweakInstalledFile
)
359 os
<< indent
<< "IF(EXISTS \"" << toDestDirPath
<< "\")\n";
360 this->AddInstallNamePatchRule(os
, indent
.Next(), config
, toDestDirPath
);
361 this->AddChrpathPatchRule(os
, indent
.Next(), config
, toDestDirPath
);
362 this->AddRanlibRule(os
, indent
.Next(), type
, toDestDirPath
);
363 this->AddStripRule(os
, indent
.Next(), type
, toDestDirPath
);
364 os
<< indent
<< "ENDIF(EXISTS \"" << toDestDirPath
<< "\")\n";
368 //----------------------------------------------------------------------------
370 cmInstallTargetGenerator::GetInstallFilename(const char* config
) const
372 NameType nameType
= this->ImportLibrary
? NameImplib
: NameNormal
;
374 cmInstallTargetGenerator::GetInstallFilename(this->Target
, config
,
378 //----------------------------------------------------------------------------
379 std::string
cmInstallTargetGenerator::GetInstallFilename(cmTarget
* target
,
384 // Compute the name of the library.
385 if(target
->GetType() == cmTarget::EXECUTABLE
)
387 std::string targetName
;
388 std::string targetNameReal
;
389 std::string targetNameImport
;
390 std::string targetNamePDB
;
391 target
->GetExecutableNames(targetName
, targetNameReal
,
392 targetNameImport
, targetNamePDB
,
394 if(nameType
== NameImplib
)
396 // Use the import library name.
397 fname
= targetNameImport
;
399 else if(nameType
== NameReal
)
401 // Use the canonical name.
402 fname
= targetNameReal
;
406 // Use the canonical name.
412 std::string targetName
;
413 std::string targetNameSO
;
414 std::string targetNameReal
;
415 std::string targetNameImport
;
416 std::string targetNamePDB
;
417 target
->GetLibraryNames(targetName
, targetNameSO
, targetNameReal
,
418 targetNameImport
, targetNamePDB
, config
);
419 if(nameType
== NameImplib
)
421 // Use the import library name.
422 fname
= targetNameImport
;
424 else if(nameType
== NameSO
)
427 fname
= targetNameSO
;
429 else if(nameType
== NameReal
)
431 // Use the real name.
432 fname
= targetNameReal
;
436 // Use the canonical name.
444 //----------------------------------------------------------------------------
446 cmInstallTargetGenerator
447 ::AddInstallNamePatchRule(std::ostream
& os
, Indent
const& indent
,
448 const char* config
, std::string
const& toDestDirPath
)
450 if(this->ImportLibrary
||
451 !(this->Target
->GetType() == cmTarget::SHARED_LIBRARY
||
452 this->Target
->GetType() == cmTarget::MODULE_LIBRARY
||
453 this->Target
->GetType() == cmTarget::EXECUTABLE
))
458 // Fix the install_name settings in installed binaries.
459 std::string installNameTool
=
460 this->Target
->GetMakefile()->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL");
462 if(!installNameTool
.size())
467 // Build a map of build-tree install_name to install-tree install_name for
468 // shared libraries linked to this target.
469 std::map
<cmStdString
, cmStdString
> install_name_remap
;
470 if(cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
))
472 std::set
<cmTarget
*> const& sharedLibs
= cli
->GetSharedLibrariesLinked();
473 for(std::set
<cmTarget
*>::const_iterator j
= sharedLibs
.begin();
474 j
!= sharedLibs
.end(); ++j
)
476 // If the build tree and install tree use different path
477 // components of the install_name field then we need to create a
478 // mapping to be applied after installation.
480 std::string for_build
= tgt
->GetInstallNameDirForBuildTree(config
);
481 std::string for_install
= tgt
->GetInstallNameDirForInstallTree(config
);
482 if(for_build
!= for_install
)
484 // The directory portions differ. Append the filename to
485 // create the mapping.
487 this->GetInstallFilename(tgt
, config
, NameSO
);
489 // Map from the build-tree install_name.
492 // Map to the install-tree install_name.
493 for_install
+= fname
;
495 // Store the mapping entry.
496 install_name_remap
[for_build
] = for_install
;
501 // Edit the install_name of the target itself if necessary.
503 if(this->Target
->GetType() == cmTarget::SHARED_LIBRARY
)
505 std::string for_build
=
506 this->Target
->GetInstallNameDirForBuildTree(config
);
507 std::string for_install
=
508 this->Target
->GetInstallNameDirForInstallTree(config
);
510 if(this->Target
->IsFrameworkOnApple() && for_install
.empty())
512 // Frameworks seem to have an id corresponding to their own full
515 // for_install = fullDestPath_without_DESTDIR_or_name;
518 // If the install name will change on installation set the new id
519 // on the installed file.
520 if(for_build
!= for_install
)
522 // Prepare to refer to the install-tree install_name.
523 new_id
= for_install
;
524 new_id
+= this->GetInstallFilename(this->Target
, config
, NameSO
);
528 // Write a rule to run install_name_tool to set the install-tree
529 // install_name value and references.
530 if(!new_id
.empty() || !install_name_remap
.empty())
532 os
<< indent
<< "EXECUTE_PROCESS(COMMAND \"" << installNameTool
;
536 os
<< "\n" << indent
<< " -id \"" << new_id
<< "\"";
538 for(std::map
<cmStdString
, cmStdString
>::const_iterator
539 i
= install_name_remap
.begin();
540 i
!= install_name_remap
.end(); ++i
)
542 os
<< "\n" << indent
<< " -change \""
543 << i
->first
<< "\" \"" << i
->second
<< "\"";
545 os
<< "\n" << indent
<< " \"" << toDestDirPath
<< "\")\n";
549 //----------------------------------------------------------------------------
551 cmInstallTargetGenerator
552 ::AddChrpathPatchRule(std::ostream
& os
, Indent
const& indent
,
553 const char* config
, std::string
const& toDestDirPath
)
555 // Skip the chrpath if the target does not need it.
556 if(this->ImportLibrary
|| !this->Target
->IsChrpathUsed())
561 // Get the link information for this target.
562 // It can provide the RPATH.
563 cmComputeLinkInformation
* cli
= this->Target
->GetLinkInformation(config
);
569 // Construct the original rpath string to be replaced.
570 std::string oldRpath
= cli
->GetRPathString(false);
572 // Get the install RPATH from the link information.
573 std::string newRpath
= cli
->GetChrpathString();
575 // Skip the rule if the paths are identical
576 if(oldRpath
== newRpath
)
581 // Write a rule to run chrpath to set the install-tree RPATH
582 os
<< indent
<< "FILE(CHRPATH FILE \"" << toDestDirPath
<< "\"\n"
583 << indent
<< " OLD_RPATH \"" << oldRpath
<< "\"\n"
584 << indent
<< " NEW_RPATH \"" << newRpath
<< "\")\n";
587 //----------------------------------------------------------------------------
589 cmInstallTargetGenerator::AddStripRule(std::ostream
& os
,
590 Indent
const& indent
,
591 cmTarget::TargetType type
,
592 const std::string
& toDestDirPath
)
595 // don't strip static libraries, because it removes the only symbol table
596 // they have so you can't link to them anymore
597 if(type
== cmTarget::STATIC_LIBRARY
)
602 // Don't handle OSX Bundles.
603 if(this->Target
->GetMakefile()->IsOn("APPLE") &&
604 this->Target
->GetPropertyAsBool("MACOSX_BUNDLE"))
609 if(! this->Target
->GetMakefile()->IsSet("CMAKE_STRIP"))
614 os
<< indent
<< "IF(CMAKE_INSTALL_DO_STRIP)\n";
615 os
<< indent
<< " EXECUTE_PROCESS(COMMAND \""
616 << this->Target
->GetMakefile()->GetDefinition("CMAKE_STRIP")
617 << "\" \"" << toDestDirPath
<< "\")\n";
618 os
<< indent
<< "ENDIF(CMAKE_INSTALL_DO_STRIP)\n";
621 //----------------------------------------------------------------------------
623 cmInstallTargetGenerator::AddRanlibRule(std::ostream
& os
,
624 Indent
const& indent
,
625 cmTarget::TargetType type
,
626 const std::string
& toDestDirPath
)
628 // Static libraries need ranlib on this platform.
629 if(type
!= cmTarget::STATIC_LIBRARY
)
634 // Perform post-installation processing on the file depending
636 if(!this->Target
->GetMakefile()->IsOn("APPLE"))
642 this->Target
->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
648 os
<< indent
<< "EXECUTE_PROCESS(COMMAND \""
649 << ranlib
<< "\" \"" << toDestDirPath
<< "\")\n";