ENH: Added versioned executable support. This partially addresses bug#2143. Also made OUTPUT_NAME work when installing executables.
This commit is contained in:
parent
78112eef25
commit
d392acb4e6
@ -570,6 +570,9 @@ bool cmFileCommand::HandleInstallCommand(
|
|||||||
smanifest_files += soname.substr(destDirLength);
|
smanifest_files += soname.substr(destDirLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reconstruct the source file path taking into account the
|
||||||
|
// extra directory and possible new file name.
|
||||||
cmOStringStream str;
|
cmOStringStream str;
|
||||||
str << cmSystemTools::GetFilenamePath(ctarget) << "/";
|
str << cmSystemTools::GetFilenamePath(ctarget) << "/";
|
||||||
if ( extra_dir.size() > 0 )
|
if ( extra_dir.size() > 0 )
|
||||||
@ -581,14 +584,48 @@ bool cmFileCommand::HandleInstallCommand(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case cmTarget::EXECUTABLE:
|
case cmTarget::EXECUTABLE:
|
||||||
|
{
|
||||||
|
// Handle executable versioning
|
||||||
|
const char* exe_version = 0;
|
||||||
|
if ( properties.find("VERSION") != properties.end() )
|
||||||
|
{
|
||||||
|
exe_version = properties["VERSION"];
|
||||||
|
}
|
||||||
|
if ( exe_version )
|
||||||
|
{
|
||||||
|
std::string exename = destfile;
|
||||||
|
std::string exename_nopath = fname;
|
||||||
|
exename_nopath += "-";
|
||||||
|
exename_nopath += exe_version;
|
||||||
|
|
||||||
|
fname += "-";
|
||||||
|
fname += exe_version;
|
||||||
|
destfile += "-";
|
||||||
|
destfile += exe_version;
|
||||||
|
|
||||||
|
cmSystemTools::RemoveFile(exename.c_str());
|
||||||
|
|
||||||
|
if (!cmSystemTools::CreateSymlink(exename_nopath.c_str(), exename.c_str()) )
|
||||||
|
{
|
||||||
|
std::string errstring = "error when creating symlink from: " + exename + " to " + exename_nopath;
|
||||||
|
this->SetError(errstring.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
smanifest_files += ";";
|
||||||
|
smanifest_files += exename.substr(destDirLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconstruct the source file path taking into account the
|
||||||
|
// extra directory and possible new file name.
|
||||||
|
cmOStringStream str;
|
||||||
|
str << cmSystemTools::GetFilenamePath(ctarget) << "/";
|
||||||
if ( extra_dir.size() > 0 )
|
if ( extra_dir.size() > 0 )
|
||||||
{
|
{
|
||||||
cmOStringStream str;
|
str << extra_dir << "/";
|
||||||
str << cmSystemTools::GetFilenamePath(ctarget)
|
|
||||||
<< "/" << extra_dir << "/"
|
|
||||||
<< fname;
|
|
||||||
ctarget = str.str();
|
|
||||||
}
|
}
|
||||||
|
str << fname;
|
||||||
|
ctarget = str.str();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,6 +369,18 @@ void cmLocalGenerator::GenerateInstallRules()
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case cmTarget::EXECUTABLE:
|
case cmTarget::EXECUTABLE:
|
||||||
|
{
|
||||||
|
std::string properties;
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
const char* exe_version = 0;
|
||||||
|
#else
|
||||||
|
const char* exe_version = l->second.GetProperty("VERSION");
|
||||||
|
#endif
|
||||||
|
if(exe_version)
|
||||||
|
{
|
||||||
|
properties += " VERSION ";
|
||||||
|
properties += exe_version;
|
||||||
|
}
|
||||||
if(l->second.GetPropertyAsBool("MACOSX_BUNDLE"))
|
if(l->second.GetPropertyAsBool("MACOSX_BUNDLE"))
|
||||||
{
|
{
|
||||||
fname = exeOutPath;
|
fname = exeOutPath;
|
||||||
@ -385,7 +397,8 @@ void cmLocalGenerator::GenerateInstallRules()
|
|||||||
pdest += ".app/Contents";
|
pdest += ".app/Contents";
|
||||||
bdest += ".app/Contents/MacOS";
|
bdest += ".app/Contents/MacOS";
|
||||||
// first install the actual executable
|
// first install the actual executable
|
||||||
this->AddInstallRule(fout, bdest.c_str(), type, files);
|
this->AddInstallRule(fout, bdest.c_str(), type, files,
|
||||||
|
false, properties.c_str());
|
||||||
files = plist.c_str();
|
files = plist.c_str();
|
||||||
// now install the Info.plist file
|
// now install the Info.plist file
|
||||||
this->AddInstallRule(fout, pdest.c_str(),
|
this->AddInstallRule(fout, pdest.c_str(),
|
||||||
@ -396,8 +409,10 @@ void cmLocalGenerator::GenerateInstallRules()
|
|||||||
fname = exeOutPath;
|
fname = exeOutPath;
|
||||||
fname += l->second.GetFullName(m_Makefile);
|
fname += l->second.GetFullName(m_Makefile);
|
||||||
files = fname.c_str();
|
files = fname.c_str();
|
||||||
this->AddInstallRule(fout, dest, type, files);
|
this->AddInstallRule(fout, dest, type, files, false,
|
||||||
|
properties.c_str());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case cmTarget::INSTALL_FILES:
|
case cmTarget::INSTALL_FILES:
|
||||||
{
|
{
|
||||||
|
@ -1279,35 +1279,34 @@ cmLocalUnixMakefileGenerator3
|
|||||||
// Add a dependency on the rule file itself.
|
// Add a dependency on the rule file itself.
|
||||||
this->AppendRuleDepend(depends, ruleFileName);
|
this->AppendRuleDepend(depends, ruleFileName);
|
||||||
|
|
||||||
// Construct the full path to the executable that will be generated.
|
// Get the name of the executable to generate.
|
||||||
std::string targetFullPath = m_ExecutableOutputPath;
|
std::string targetName;
|
||||||
if(targetFullPath.length() == 0)
|
std::string targetNameReal;
|
||||||
|
target.GetExecutableNames(m_Makefile, targetName, targetNameReal);
|
||||||
|
|
||||||
|
// Construct the full path version of the names.
|
||||||
|
std::string outpath = m_ExecutableOutputPath;
|
||||||
|
if(outpath.length() == 0)
|
||||||
{
|
{
|
||||||
targetFullPath = m_Makefile->GetStartOutputDirectory();
|
outpath = m_Makefile->GetStartOutputDirectory();
|
||||||
targetFullPath += "/";
|
outpath += "/";
|
||||||
}
|
}
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
|
if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
|
||||||
{
|
{
|
||||||
// Make bundle directories
|
// Make bundle directories
|
||||||
targetFullPath += target.GetName();
|
outpath += target.GetName();
|
||||||
targetFullPath += ".app/Contents/MacOS/";
|
outpath += ".app/Contents/MacOS/";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
std::string targetFullPath = outpath + targetName;
|
||||||
// do we have a different executable name?
|
std::string targetFullPathReal = outpath + targetNameReal;
|
||||||
if (target.GetProperty("OUTPUT_NAME"))
|
|
||||||
{
|
|
||||||
targetFullPath += target.GetProperty("OUTPUT_NAME");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
targetFullPath += target.GetName();
|
|
||||||
}
|
|
||||||
targetFullPath += cmSystemTools::GetExecutableExtension();
|
|
||||||
|
|
||||||
// Convert to the output path to use in constructing commands.
|
// Convert to the output path to use in constructing commands.
|
||||||
std::string targetOutPath = this->Convert(targetFullPath.c_str(),HOME_OUTPUT,MAKEFILE);
|
std::string targetOutPath =
|
||||||
|
this->Convert(targetFullPath.c_str(),HOME_OUTPUT,MAKEFILE);
|
||||||
|
std::string targetOutPathReal =
|
||||||
|
this->Convert(targetFullPathReal.c_str(),HOME_OUTPUT,MAKEFILE);
|
||||||
|
|
||||||
// Get the language to use for linking this executable.
|
// Get the language to use for linking this executable.
|
||||||
const char* linkLanguage =
|
const char* linkLanguage =
|
||||||
@ -1387,6 +1386,27 @@ cmLocalUnixMakefileGenerator3
|
|||||||
// Add target-specific linker flags.
|
// Add target-specific linker flags.
|
||||||
this->AppendFlags(linkFlags, target.GetProperty("LINK_FLAGS"));
|
this->AppendFlags(linkFlags, target.GetProperty("LINK_FLAGS"));
|
||||||
|
|
||||||
|
// Construct a list of files associated with this executable that
|
||||||
|
// may need to be cleaned.
|
||||||
|
std::vector<std::string> exeCleanFiles;
|
||||||
|
{
|
||||||
|
std::string cleanName;
|
||||||
|
std::string cleanRealName;
|
||||||
|
target.GetExecutableCleanNames(m_Makefile, cleanName,
|
||||||
|
cleanRealName);
|
||||||
|
std::string cleanFullName = outpath + cleanName;
|
||||||
|
std::string cleanFullRealName = outpath + cleanRealName;
|
||||||
|
exeCleanFiles.push_back
|
||||||
|
(this->Convert(cleanFullName.c_str(),HOME_OUTPUT,MAKEFILE));
|
||||||
|
if(cleanRealName != cleanName)
|
||||||
|
{
|
||||||
|
exeCleanFiles.push_back
|
||||||
|
(this->Convert(cleanFullRealName.c_str(),HOME_OUTPUT,MAKEFILE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add a command to remove any existing files for this executable.
|
||||||
|
this->AppendCleanCommand(commands, exeCleanFiles);
|
||||||
|
|
||||||
// Add the pre-build and pre-link rules.
|
// Add the pre-build and pre-link rules.
|
||||||
this->AppendCustomCommands(commands, target.GetPreBuildCommands());
|
this->AppendCustomCommands(commands, target.GetPreBuildCommands());
|
||||||
this->AppendCustomCommands(commands, target.GetPreLinkCommands());
|
this->AppendCustomCommands(commands, target.GetPreLinkCommands());
|
||||||
@ -1398,6 +1418,16 @@ cmLocalUnixMakefileGenerator3
|
|||||||
std::string linkRule = m_Makefile->GetRequiredDefinition(linkRuleVar.c_str());
|
std::string linkRule = m_Makefile->GetRequiredDefinition(linkRuleVar.c_str());
|
||||||
cmSystemTools::ExpandListArgument(linkRule, commands);
|
cmSystemTools::ExpandListArgument(linkRule, commands);
|
||||||
|
|
||||||
|
// Add a rule to create necessary symlinks for the library.
|
||||||
|
if(targetOutPath != targetOutPathReal)
|
||||||
|
{
|
||||||
|
std::string symlink = "$(CMAKE_COMMAND) -E cmake_symlink_executable ";
|
||||||
|
symlink += targetOutPathReal;
|
||||||
|
symlink += " ";
|
||||||
|
symlink += targetOutPath;
|
||||||
|
commands.push_back(symlink);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the post-build rules.
|
// Add the post-build rules.
|
||||||
this->AppendCustomCommands(commands, target.GetPostBuildCommands());
|
this->AppendCustomCommands(commands, target.GetPostBuildCommands());
|
||||||
|
|
||||||
@ -1427,7 +1457,7 @@ cmLocalUnixMakefileGenerator3
|
|||||||
this->ExpandRuleVariables(*i,
|
this->ExpandRuleVariables(*i,
|
||||||
linkLanguage,
|
linkLanguage,
|
||||||
buildObjs.c_str(),
|
buildObjs.c_str(),
|
||||||
targetOutPath.c_str(),
|
targetOutPathReal.c_str(),
|
||||||
linklibs.str().c_str(),
|
linklibs.str().c_str(),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -1453,9 +1483,9 @@ cmLocalUnixMakefileGenerator3
|
|||||||
this->WriteConvenienceRule(ruleFileStream, targetFullPath.c_str(),
|
this->WriteConvenienceRule(ruleFileStream, targetFullPath.c_str(),
|
||||||
buildTargetRuleName.c_str());
|
buildTargetRuleName.c_str());
|
||||||
|
|
||||||
|
// Clean all the possible executable names and symlinks and object files.
|
||||||
|
cleanFiles.insert(cleanFiles.end(),exeCleanFiles.begin(),exeCleanFiles.end());
|
||||||
cleanFiles.push_back(cleanObjs);
|
cleanFiles.push_back(cleanObjs);
|
||||||
cleanFiles.push_back
|
|
||||||
(this->Convert(targetFullPath.c_str(),HOME_OUTPUT,MAKEFILE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -71,6 +71,9 @@ public:
|
|||||||
"supports symlinks and the linker supports so-names. "
|
"supports symlinks and the linker supports so-names. "
|
||||||
"If only one of both is specified the missing is assumed to have "
|
"If only one of both is specified the missing is assumed to have "
|
||||||
"the same version number. "
|
"the same version number. "
|
||||||
|
"For executables VERSION can be used to specify the build version. "
|
||||||
|
"When building or installing appropriate symlinks are created if "
|
||||||
|
"the platform supports symlinks. "
|
||||||
"The OUTPUT_NAME can be used to set an output name that is "
|
"The OUTPUT_NAME can be used to set an output name that is "
|
||||||
"used in place of the target name when creating executables."
|
"used in place of the target name when creating executables."
|
||||||
"If not set here then it is set to target_EXPORTS by default "
|
"If not set here then it is set to target_EXPORTS by default "
|
||||||
|
@ -929,17 +929,17 @@ const char* cmTarget::GetPrefixVariableInternal(TargetType type)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cmTarget::GetFullName(cmMakefile* mf)
|
std::string cmTarget::GetFullName(cmMakefile* mf)
|
||||||
{
|
{
|
||||||
return this->GetFullNameInternal(mf, this->GetType());
|
return this->GetFullNameInternal(mf, this->GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cmTarget::GetFullNameInternal(cmMakefile* mf,
|
std::string cmTarget::GetFullNameInternal(cmMakefile* mf,
|
||||||
TargetType type)
|
TargetType type)
|
||||||
{
|
{
|
||||||
const char* targetPrefix = this->GetProperty("PREFIX");
|
const char* targetPrefix = this->GetProperty("PREFIX");
|
||||||
const char* targetSuffix = this->GetProperty("SUFFIX");
|
const char* targetSuffix = this->GetProperty("SUFFIX");
|
||||||
if(!targetSuffix && this->GetType() == cmTarget::EXECUTABLE)
|
if(!targetSuffix && type == cmTarget::EXECUTABLE)
|
||||||
{
|
{
|
||||||
targetSuffix = cmSystemTools::GetExecutableExtension();
|
targetSuffix = cmSystemTools::GetExecutableExtension();
|
||||||
}
|
}
|
||||||
@ -973,9 +973,26 @@ std::string cmTarget::GetFullNameInternal(cmMakefile* mf,
|
|||||||
{
|
{
|
||||||
targetSuffix = mf->GetSafeDefinition(suffixVar);
|
targetSuffix = mf->GetSafeDefinition(suffixVar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Begin the final name with the prefix.
|
||||||
std::string name = targetPrefix?targetPrefix:"";
|
std::string name = targetPrefix?targetPrefix:"";
|
||||||
name += this->GetName();
|
|
||||||
|
// Append the target name or property-specified name. Support this
|
||||||
|
// only for executable targets.
|
||||||
|
const char* outname = this->GetProperty("OUTPUT_NAME");
|
||||||
|
if(outname && type == cmTarget::EXECUTABLE)
|
||||||
|
{
|
||||||
|
name += outname;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name += this->GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the suffix.
|
||||||
name += targetSuffix?targetSuffix:"";
|
name += targetSuffix?targetSuffix:"";
|
||||||
|
|
||||||
|
// Return the final name.
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1125,3 +1142,49 @@ void cmTarget::GetLibraryNamesInternal(cmMakefile* mf,
|
|||||||
realName += soversion;
|
realName += soversion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmTarget::GetExecutableNames(cmMakefile* mf,
|
||||||
|
std::string& name,
|
||||||
|
std::string& realName)
|
||||||
|
{
|
||||||
|
// Get the names based on the real type of the executable.
|
||||||
|
this->GetExecutableNamesInternal(mf, name, realName, this->GetType());
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmTarget::GetExecutableCleanNames(cmMakefile* mf,
|
||||||
|
std::string& name,
|
||||||
|
std::string& realName)
|
||||||
|
{
|
||||||
|
// Get the name and versioned name of this executable.
|
||||||
|
this->GetExecutableNamesInternal(mf, name, realName, cmTarget::EXECUTABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmTarget::GetExecutableNamesInternal(cmMakefile* mf,
|
||||||
|
std::string& name,
|
||||||
|
std::string& realName,
|
||||||
|
TargetType type)
|
||||||
|
{
|
||||||
|
// This versioning is supported only for executables and then only
|
||||||
|
// when the platform supports symbolic links.
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
const char* version = 0;
|
||||||
|
#else
|
||||||
|
// Check for executable version properties.
|
||||||
|
const char* version = this->GetProperty("VERSION");
|
||||||
|
if(type != cmTarget::EXECUTABLE)
|
||||||
|
{
|
||||||
|
version = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The executable name.
|
||||||
|
name = this->GetFullNameInternal(mf, type);
|
||||||
|
|
||||||
|
// The executable's real name on disk.
|
||||||
|
realName = name;
|
||||||
|
if(version)
|
||||||
|
{
|
||||||
|
realName += "-";
|
||||||
|
realName += version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -186,6 +186,19 @@ public:
|
|||||||
std::string& sharedName,
|
std::string& sharedName,
|
||||||
std::string& sharedSOName,
|
std::string& sharedSOName,
|
||||||
std::string& sharedRealName);
|
std::string& sharedRealName);
|
||||||
|
|
||||||
|
/** Get the names of the executable needed to generate a build rule
|
||||||
|
that takes into account executable version numbers. This should
|
||||||
|
be called only on an executable target. */
|
||||||
|
void GetExecutableNames(cmMakefile* mf, std::string& name,
|
||||||
|
std::string& realName);
|
||||||
|
|
||||||
|
/** Get the names of the executable used to remove existing copies
|
||||||
|
of the executable from the build tree either before linking or
|
||||||
|
during a clean step. This should be called only on an
|
||||||
|
executable target. */
|
||||||
|
void GetExecutableCleanNames(cmMakefile* mf, std::string& name,
|
||||||
|
std::string& realName);
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* A list of direct dependencies. Use in conjunction with DependencyMap.
|
* A list of direct dependencies. Use in conjunction with DependencyMap.
|
||||||
@ -249,6 +262,10 @@ private:
|
|||||||
std::string& soName,
|
std::string& soName,
|
||||||
std::string& realName,
|
std::string& realName,
|
||||||
TargetType type);
|
TargetType type);
|
||||||
|
void GetExecutableNamesInternal(cmMakefile* mf,
|
||||||
|
std::string& name,
|
||||||
|
std::string& realName,
|
||||||
|
TargetType type);
|
||||||
|
|
||||||
// update the value of the LOCATION var
|
// update the value of the LOCATION var
|
||||||
void UpdateLocation();
|
void UpdateLocation();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user