BUG: fix some bad changes in progress calc
[cmake.git] / Source / cmInstallTargetGenerator.cxx
blob340bd57cda08621b935fcb4c273c768846e1f430
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmInstallTargetGenerator.cxx,v $
5 Language: C++
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"
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->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"))
52 cmOStringStream msg;
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 // Track indentation.
61 Indent indent;
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.
69 std::string fromDir;
70 if(this->Target->NeedRelinkBeforeInstall())
72 fromDir = this->Target->GetMakefile()->GetStartOutputDirectory();
73 fromDir += cmake::GetCMakeFilesDirectory();
74 fromDir += "/CMakeRelink.dir/";
76 else
78 fromDir = this->Target->GetDirectory(0, this->ImportLibrary);
79 fromDir += "/";
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,
87 indent.Next());
89 else
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(),
96 indent.Next());
100 // End this block of installation.
101 os << indent << "ENDIF(" << component_test << ")\n\n";
104 //----------------------------------------------------------------------------
105 void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
106 const char* fromDir,
107 const char* config,
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))
121 return;
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,
128 indent.Next());
129 os << indent << "ENDIF(" << config_test << ")\n";
131 else
133 this->GenerateScriptForConfigDir(os, fromDirConfig.c_str(), config,
134 indent);
138 //----------------------------------------------------------------------------
139 void
140 cmInstallTargetGenerator
141 ::GenerateScriptForConfigDir(std::ostream& os,
142 const char* fromDirConfig,
143 const char* config,
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
153 // script.
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,
171 config);
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;
181 else
183 std::string from1 = fromDirConfig;
184 from1 += targetName;
186 // Handle OSX Bundles.
187 if(this->Target->IsAppBundleOnApple())
189 // Compute the source locations of the bundle executable and
190 // Info.plist file.
191 from1 += ".app";
192 files.push_back(from1);
193 type = cmTarget::INSTALL_DIRECTORY;
194 // Need to apply install_name_tool and stripping to binary
195 // inside bundle.
196 toInstallPath += ".app/Contents/MacOS/";
197 toInstallPath +=
198 this->GetInstallFilename(this->Target, config, nameType);
199 literal_args += " USE_SOURCE_PERMISSIONS";
201 else
203 files.push_back(from1);
204 if(targetNameReal != targetName)
206 std::string from2 = fromDirConfig;
207 from2 += targetNameReal;
208 files.push_back(from2);
213 else
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,
222 config);
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
250 // inside framework.
251 toInstallPath += ".framework/";
252 toInstallPath += this->GetInstallFilename(this->Target, config,
253 NameNormal);
255 literal_args += " USE_SOURCE_PERMISSIONS";
257 else
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)
274 haveNamelink = true;
275 fromSOName = fromDirConfig;
276 fromSOName += targetNameSO;
278 if(targetNameReal != targetName &&
279 targetNameReal != targetNameSO)
281 haveNamelink = true;
282 fromRealName = fromDirConfig;
283 fromRealName += targetNameReal;
286 // Add the names based on the current namelink mode.
287 if(haveNamelink)
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;
296 else
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);
317 else
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.
330 if(files.empty())
332 return;
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(),
344 indent);
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;
355 // TODO:
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 //----------------------------------------------------------------------------
369 std::string
370 cmInstallTargetGenerator::GetInstallFilename(const char* config) const
372 NameType nameType = this->ImportLibrary? NameImplib : NameNormal;
373 return
374 cmInstallTargetGenerator::GetInstallFilename(this->Target, config,
375 nameType);
378 //----------------------------------------------------------------------------
379 std::string cmInstallTargetGenerator::GetInstallFilename(cmTarget* target,
380 const char* config,
381 NameType nameType)
383 std::string fname;
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,
393 config);
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;
404 else
406 // Use the canonical name.
407 fname = targetName;
410 else
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)
426 // Use the soname.
427 fname = targetNameSO;
429 else if(nameType == NameReal)
431 // Use the real name.
432 fname = targetNameReal;
434 else
436 // Use the canonical name.
437 fname = targetName;
441 return fname;
444 //----------------------------------------------------------------------------
445 void
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))
455 return;
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())
464 return;
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.
479 cmTarget* tgt = *j;
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.
486 std::string fname =
487 this->GetInstallFilename(tgt, config, NameSO);
489 // Map from the build-tree install_name.
490 for_build += fname;
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.
502 std::string new_id;
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
513 // path.
514 // ...
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;
533 os << "\"";
534 if(!new_id.empty())
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 //----------------------------------------------------------------------------
550 void
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())
558 return;
561 // Get the link information for this target.
562 // It can provide the RPATH.
563 cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
564 if(!cli)
566 return;
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)
578 return;
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 //----------------------------------------------------------------------------
588 void
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)
599 return;
602 // Don't handle OSX Bundles.
603 if(this->Target->GetMakefile()->IsOn("APPLE") &&
604 this->Target->GetPropertyAsBool("MACOSX_BUNDLE"))
606 return;
609 if(! this->Target->GetMakefile()->IsSet("CMAKE_STRIP"))
611 return;
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 //----------------------------------------------------------------------------
622 void
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)
631 return;
634 // Perform post-installation processing on the file depending
635 // on its type.
636 if(!this->Target->GetMakefile()->IsOn("APPLE"))
638 return;
641 std::string ranlib =
642 this->Target->GetMakefile()->GetRequiredDefinition("CMAKE_RANLIB");
643 if(ranlib.empty())
645 return;
648 os << indent << "EXECUTE_PROCESS(COMMAND \""
649 << ranlib << "\" \"" << toDestDirPath << "\")\n";