summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Source/cmInstallCommand.cxx65
-rw-r--r--Source/cmInstallCommand.h21
-rw-r--r--Source/cmInstallCommandArguments.cxx28
-rw-r--r--Source/cmInstallCommandArguments.h4
-rw-r--r--Source/cmInstallTargetGenerator.cxx113
-rw-r--r--Source/cmInstallTargetGenerator.h11
6 files changed, 222 insertions, 20 deletions
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 056e2763e9..868fb7554e 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 e2d451ee08..4978059b15 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 506954c8b0..ddfd9d4c36 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 7fc35a0c18..eac9dae915 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 fb27a6dd27..c1fcfb62d4 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 64ad784172..3b5dbb897b 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