diff options
author | Brad King <brad.king@kitware.com> | 2008-02-04 22:03:48 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2008-02-04 22:03:48 (GMT) |
commit | 8401c5ba065f9c66bfd1c495762001c6dacd5d9c (patch) | |
tree | 7cf1e9d906e64771528e5c7bf80389f10682a77b | |
parent | 852f6018bbe2bb52a3b7cbef95dba04c8e8f6a0c (diff) | |
download | CMake-8401c5ba065f9c66bfd1c495762001c6dacd5d9c.zip CMake-8401c5ba065f9c66bfd1c495762001c6dacd5d9c.tar.gz CMake-8401c5ba065f9c66bfd1c495762001c6dacd5d9c.tar.bz2 |
ENH: Allow separate installation of shared libs and their links.
- Add NAMELINK_ONLY and NAMELINK_SKIP to INSTALL command
- Options select a \"namelink\" mode
- cmInstallTargetGenerator selects files/link based on mode
- See bug #4419
-rw-r--r-- | Source/cmInstallCommand.cxx | 65 | ||||
-rw-r--r-- | Source/cmInstallCommand.h | 21 | ||||
-rw-r--r-- | Source/cmInstallCommandArguments.cxx | 28 | ||||
-rw-r--r-- | Source/cmInstallCommandArguments.h | 4 | ||||
-rw-r--r-- | Source/cmInstallTargetGenerator.cxx | 113 | ||||
-rw-r--r-- | Source/cmInstallTargetGenerator.h | 11 |
6 files changed, 222 insertions, 20 deletions
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 056e276..868fb75 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -283,6 +283,57 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) return false; } + // Enforce argument rules too complex to specify for the + // general-purpose parser. + if(archiveArgs.GetNamelinkOnly() || + runtimeArgs.GetNamelinkOnly() || + frameworkArgs.GetNamelinkOnly() || + bundleArgs.GetNamelinkOnly() || + privateHeaderArgs.GetNamelinkOnly() || + publicHeaderArgs.GetNamelinkOnly() || + resourceArgs.GetNamelinkOnly()) + { + this->SetError( + "TARGETS given NAMELINK_ONLY option not in LIBRARY group. " + "The NAMELINK_ONLY option may be specified only following LIBRARY." + ); + return false; + } + if(archiveArgs.GetNamelinkSkip() || + runtimeArgs.GetNamelinkSkip() || + frameworkArgs.GetNamelinkSkip() || + bundleArgs.GetNamelinkSkip() || + privateHeaderArgs.GetNamelinkSkip() || + publicHeaderArgs.GetNamelinkSkip() || + resourceArgs.GetNamelinkSkip()) + { + this->SetError( + "TARGETS given NAMELINK_SKIP option not in LIBRARY group. " + "The NAMELINK_SKIP option may be specified only following LIBRARY." + ); + return false; + } + if(libraryArgs.GetNamelinkOnly() && libraryArgs.GetNamelinkSkip()) + { + this->SetError( + "TARGETS given NAMELINK_ONLY and NAMELINK_SKIP. " + "At most one of these two options may be specified." + ); + return false; + } + + // Select the mode for installing symlinks to versioned shared libraries. + cmInstallTargetGenerator::NamelinkModeType + namelinkMode = cmInstallTargetGenerator::NamelinkModeNone; + if(libraryArgs.GetNamelinkOnly()) + { + namelinkMode = cmInstallTargetGenerator::NamelinkModeOnly; + } + else if(libraryArgs.GetNamelinkSkip()) + { + namelinkMode = cmInstallTargetGenerator::NamelinkModeSkip; + } + // Check if there is something to do. if(targetList.GetVector().empty()) { @@ -352,6 +403,12 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // cygwin. Currently no other platform is a DLL platform. if(dll_platform) { + // When in namelink only mode skip all libraries on Windows. + if(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) + { + continue; + } + // This is a DLL platform. if(!archiveArgs.GetDestination().empty()) { @@ -378,6 +435,12 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // INSTALL properties. Otherwise, use the LIBRARY properties. if(target.IsFrameworkOnApple()) { + // When in namelink only mode skip frameworks. + if(namelinkMode == cmInstallTargetGenerator::NamelinkModeOnly) + { + continue; + } + // Use the FRAMEWORK properties. if (!frameworkArgs.GetDestination().empty()) { @@ -400,6 +463,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) { libraryGenerator = CreateInstallTargetGenerator(target, libraryArgs, false); + libraryGenerator->SetNamelinkMode(namelinkMode); } else { @@ -438,6 +502,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) { libraryGenerator = CreateInstallTargetGenerator(target, libraryArgs, false); + libraryGenerator->SetNamelinkMode(namelinkMode); } else { diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h index e2d451e..4978059 100644 --- a/Source/cmInstallCommand.h +++ b/Source/cmInstallCommand.h @@ -105,7 +105,7 @@ public: " [PERMISSIONS permissions...]\n" " [CONFIGURATIONS [Debug|Release|...]]\n" " [COMPONENT <component>]\n" - " [OPTIONAL]\n" + " [OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP]\n" " ] [...])\n" "The TARGETS form specifies rules for installing targets from a " "project. There are five kinds of target files that may be " @@ -140,6 +140,25 @@ public: "See documentation of the PRIVATE_HEADER, PUBLIC_HEADER, and RESOURCE " "target properties for details." "\n" + "Either NAMELINK_ONLY or NAMELINK_SKIP may be specified as a LIBRARY " + "option. " + "On some platforms a versioned shared library has a symbolic link " + "such as\n" + " lib<name>.so -> lib<name>.so.1\n" + "where \"lib<name>.so.1\" is the soname of the library and " + "\"lib<name>.so\" is a \"namelink\" allowing linkers to find the " + "library when given \"-l<name>\". " + "The NAMELINK_ONLY option causes installation of only the namelink " + "when a library target is installed. " + "The NAMELINK_SKIP option causes installation of library files other " + "than the namelink when a library target is installed. " + "When neither option is given both portions are installed. " + "On platforms where versioned shared libraries do not have namelinks " + "or when a library is not versioned the NAMELINK_SKIP option installs " + "the library and the NAMELINK_ONLY option installs nothing. " + "See the VERSION and SOVERSION target properties for details on " + "creating versioned shared libraries." + "\n" "One or more groups of properties may be specified in a single call " "to the TARGETS form of this command. A target may be installed more " "than once to different locations. Consider hypothetical " diff --git a/Source/cmInstallCommandArguments.cxx b/Source/cmInstallCommandArguments.cxx index 506954c..ddfd9d4 100644 --- a/Source/cmInstallCommandArguments.cxx +++ b/Source/cmInstallCommandArguments.cxx @@ -37,6 +37,8 @@ cmInstallCommandArguments::cmInstallCommandArguments() ,Permissions (&Parser, "PERMISSIONS" , &ArgumentGroup) ,Configurations(&Parser, "CONFIGURATIONS", &ArgumentGroup) ,Optional (&Parser, "OPTIONAL" , &ArgumentGroup) +,NamelinkOnly (&Parser, "NAMELINK_ONLY" , &ArgumentGroup) +,NamelinkSkip (&Parser, "NAMELINK_SKIP" , &ArgumentGroup) ,GenericArguments(0) { this->Component.SetDefaultString("Unspecified"); @@ -107,6 +109,32 @@ bool cmInstallCommandArguments::GetOptional() const return false; } +bool cmInstallCommandArguments::GetNamelinkOnly() const +{ + if (this->NamelinkOnly.IsEnabled()) + { + return true; + } + if (this->GenericArguments!=0) + { + return this->GenericArguments->GetNamelinkOnly(); + } + return false; +} + +bool cmInstallCommandArguments::GetNamelinkSkip() const +{ + if (this->NamelinkSkip.IsEnabled()) + { + return true; + } + if (this->GenericArguments!=0) + { + return this->GenericArguments->GetNamelinkSkip(); + } + return false; +} + const std::vector<std::string>& cmInstallCommandArguments::GetConfigurations() const { diff --git a/Source/cmInstallCommandArguments.h b/Source/cmInstallCommandArguments.h index 7fc35a0..eac9dae 100644 --- a/Source/cmInstallCommandArguments.h +++ b/Source/cmInstallCommandArguments.h @@ -39,6 +39,8 @@ class cmInstallCommandArguments const std::string& GetPermissions() const; const std::vector<std::string>& GetConfigurations() const; bool GetOptional() const; + bool GetNamelinkOnly() const; + bool GetNamelinkSkip() const; // once HandleDirectoryMode() is also switched to using // cmInstallCommandArguments then these two functions can become non-static @@ -54,6 +56,8 @@ class cmInstallCommandArguments cmCAStringVector Permissions; cmCAStringVector Configurations; cmCAEnabler Optional; + cmCAEnabler NamelinkOnly; + cmCAEnabler NamelinkSkip; std::string DestinationString; std::string PermissionsString; diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index fb27a6d..c1fcfb6 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -22,9 +22,6 @@ #include "cmMakefile.h" #include "cmake.h" -// TODO: -// - Skip IF(EXISTS) checks if nothing is done with the installed file - //---------------------------------------------------------------------------- cmInstallTargetGenerator ::cmInstallTargetGenerator(cmTarget& t, const char* dest, bool implib, @@ -34,6 +31,7 @@ cmInstallTargetGenerator cmInstallGenerator(dest, configurations, component), Target(&t), ImportLibrary(implib), FilePermissions(file_permissions), Optional(optional) { + this->NamelinkMode = NamelinkModeNone; this->Target->SetHaveInstallRule(true); } @@ -149,12 +147,19 @@ cmInstallTargetGenerator toInstallPath += this->GetInstallFilename(this->Target, config, this->ImportLibrary, false); + // Track whether post-install operations should be added to the + // script. + bool tweakInstalledFile = true; + // Compute the list of files to install for this target. std::vector<std::string> files; std::string literal_args; cmTarget::TargetType type = this->Target->GetType(); if(type == cmTarget::EXECUTABLE) { + // There is a bug in cmInstallCommand if this fails. + assert(this->NamelinkMode == NamelinkModeNone); + std::string targetName; std::string targetNameReal; std::string targetNameImport; @@ -215,6 +220,9 @@ cmInstallTargetGenerator config); if(this->ImportLibrary) { + // There is a bug in cmInstallCommand if this fails. + assert(this->NamelinkMode == NamelinkModeNone); + std::string from1 = fromDirConfig; from1 += targetNameImport; files.push_back(from1); @@ -224,6 +232,9 @@ cmInstallTargetGenerator } else if(this->Target->IsFrameworkOnApple()) { + // There is a bug in cmInstallCommand if this fails. + assert(this->NamelinkMode == NamelinkModeNone); + // Compute the build tree location of the framework directory std::string from1 = fromDirConfig; // Remove trailing slashes... so that from1 ends with ".framework": @@ -243,25 +254,82 @@ cmInstallTargetGenerator } else { - std::string from1 = fromDirConfig; - from1 += targetName; - files.push_back(from1); + // Operations done at install time on the installed file should + // be done on the real file and not any of the symlinks. + toInstallPath = this->GetInstallDestination(); + toInstallPath += "/"; + toInstallPath += targetNameReal; + + // Construct the list of file names to install for this library. + bool haveNamelink = false; + std::string fromName; + std::string fromSOName; + std::string fromRealName; + fromName = fromDirConfig; + fromName += targetName; if(targetNameSO != targetName) { - std::string from2 = fromDirConfig; - from2 += targetNameSO; - files.push_back(from2); + haveNamelink = true; + fromSOName = fromDirConfig; + fromSOName += targetNameSO; } if(targetNameReal != targetName && targetNameReal != targetNameSO) { - std::string from3 = fromDirConfig; - from3 += targetNameReal; - files.push_back(from3); + haveNamelink = true; + fromRealName = fromDirConfig; + fromRealName += targetNameReal; + } + + // Add the names based on the current namelink mode. + if(haveNamelink) + { + // With a namelink we need to check the mode. + if(this->NamelinkMode == NamelinkModeOnly) + { + // Install the namelink only. + files.push_back(fromName); + tweakInstalledFile = false; + } + else + { + // Install the real file if it has its own name. + if(!fromRealName.empty()) + { + files.push_back(fromRealName); + } + + // Install the soname link if it has its own name. + if(!fromSOName.empty()) + { + files.push_back(fromSOName); + } + + // Install the namelink if it is not to be skipped. + if(this->NamelinkMode != NamelinkModeSkip) + { + files.push_back(fromName); + } + } + } + else + { + // Without a namelink there will be only one file. Install it + // if this is not a namelink-only rule. + if(this->NamelinkMode != NamelinkModeOnly) + { + files.push_back(fromName); + } } } } + // Skip this rule if no files are to be installed for the target. + if(files.empty()) + { + return; + } + // Write code to install the target file. const char* no_dir_permissions = 0; const char* no_rename = 0; @@ -273,19 +341,26 @@ cmInstallTargetGenerator no_rename, literal_args.c_str(), indent); + // Construct the path of the file on disk after installation on + // which tweaks may be performed. std::string toDestDirPath = "$ENV{DESTDIR}"; - if(toInstallPath[0] != '/') + if(toInstallPath[0] != '/' && toInstallPath[0] != '$') { toDestDirPath += "/"; } toDestDirPath += toInstallPath; - os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n"; - this->AddInstallNamePatchRule(os, indent.Next(), config, toDestDirPath); - this->AddChrpathPatchRule(os, indent.Next(), config, toDestDirPath); - this->AddRanlibRule(os, indent.Next(), type, toDestDirPath); - this->AddStripRule(os, indent.Next(), type, toDestDirPath); - os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n"; + // TODO: + // - Skip IF(EXISTS) checks if nothing is done with the installed file + if(tweakInstalledFile) + { + os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n"; + this->AddInstallNamePatchRule(os, indent.Next(), config, toDestDirPath); + this->AddChrpathPatchRule(os, indent.Next(), config, toDestDirPath); + this->AddRanlibRule(os, indent.Next(), type, toDestDirPath); + this->AddStripRule(os, indent.Next(), type, toDestDirPath); + os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n"; + } } //---------------------------------------------------------------------------- diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index 64ad784..3b5dbb8 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -36,6 +36,16 @@ public: ); virtual ~cmInstallTargetGenerator(); + /** Select the policy for installing shared library linkable name + symlinks. */ + enum NamelinkModeType + { + NamelinkModeNone, + NamelinkModeOnly, + NamelinkModeSkip + }; + void SetNamelinkMode(NamelinkModeType mode) { this->NamelinkMode = mode; } + std::string GetInstallFilename(const char* config) const; static std::string GetInstallFilename(cmTarget*target, const char* config, bool implib, bool useSOName); @@ -72,6 +82,7 @@ protected: bool ImportLibrary; std::string FilePermissions; bool Optional; + NamelinkModeType NamelinkMode; }; #endif |