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
This commit is contained in:
parent
852f6018bb
commit
8401c5ba06
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue