ENH: Added versioned executable support. This partially addresses bug#2143. Also made OUTPUT_NAME work when installing executables.

This commit is contained in:
Brad King 2005-08-17 16:11:18 -04:00
parent 78112eef25
commit d392acb4e6
6 changed files with 198 additions and 33 deletions

View File

@ -570,6 +570,9 @@ bool cmFileCommand::HandleInstallCommand(
smanifest_files += soname.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 )
@ -581,14 +584,48 @@ bool cmFileCommand::HandleInstallCommand(
}
break;
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 )
{
cmOStringStream str;
str << cmSystemTools::GetFilenamePath(ctarget)
<< "/" << extra_dir << "/"
<< fname;
ctarget = str.str();
str << extra_dir << "/";
}
str << fname;
ctarget = str.str();
}
break;
}

View File

@ -369,6 +369,18 @@ void cmLocalGenerator::GenerateInstallRules()
}
break;
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"))
{
fname = exeOutPath;
@ -385,7 +397,8 @@ void cmLocalGenerator::GenerateInstallRules()
pdest += ".app/Contents";
bdest += ".app/Contents/MacOS";
// 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();
// now install the Info.plist file
this->AddInstallRule(fout, pdest.c_str(),
@ -396,8 +409,10 @@ void cmLocalGenerator::GenerateInstallRules()
fname = exeOutPath;
fname += l->second.GetFullName(m_Makefile);
files = fname.c_str();
this->AddInstallRule(fout, dest, type, files);
this->AddInstallRule(fout, dest, type, files, false,
properties.c_str());
}
}
break;
case cmTarget::INSTALL_FILES:
{

View File

@ -1279,35 +1279,34 @@ cmLocalUnixMakefileGenerator3
// Add a dependency on the rule file itself.
this->AppendRuleDepend(depends, ruleFileName);
// Construct the full path to the executable that will be generated.
std::string targetFullPath = m_ExecutableOutputPath;
if(targetFullPath.length() == 0)
// Get the name of the executable to generate.
std::string targetName;
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();
targetFullPath += "/";
outpath = m_Makefile->GetStartOutputDirectory();
outpath += "/";
}
#ifdef __APPLE__
if(target.GetPropertyAsBool("MACOSX_BUNDLE"))
{
// Make bundle directories
targetFullPath += target.GetName();
targetFullPath += ".app/Contents/MacOS/";
outpath += target.GetName();
outpath += ".app/Contents/MacOS/";
}
#endif
// do we have a different executable name?
if (target.GetProperty("OUTPUT_NAME"))
{
targetFullPath += target.GetProperty("OUTPUT_NAME");
}
else
{
targetFullPath += target.GetName();
}
targetFullPath += cmSystemTools::GetExecutableExtension();
std::string targetFullPath = outpath + targetName;
std::string targetFullPathReal = outpath + targetNameReal;
// 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.
const char* linkLanguage =
@ -1387,6 +1386,27 @@ cmLocalUnixMakefileGenerator3
// Add target-specific linker 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.
this->AppendCustomCommands(commands, target.GetPreBuildCommands());
this->AppendCustomCommands(commands, target.GetPreLinkCommands());
@ -1398,6 +1418,16 @@ cmLocalUnixMakefileGenerator3
std::string linkRule = m_Makefile->GetRequiredDefinition(linkRuleVar.c_str());
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.
this->AppendCustomCommands(commands, target.GetPostBuildCommands());
@ -1427,7 +1457,7 @@ cmLocalUnixMakefileGenerator3
this->ExpandRuleVariables(*i,
linkLanguage,
buildObjs.c_str(),
targetOutPath.c_str(),
targetOutPathReal.c_str(),
linklibs.str().c_str(),
0,
0,
@ -1453,9 +1483,9 @@ cmLocalUnixMakefileGenerator3
this->WriteConvenienceRule(ruleFileStream, targetFullPath.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
(this->Convert(targetFullPath.c_str(),HOME_OUTPUT,MAKEFILE));
}
//----------------------------------------------------------------------------

View File

@ -71,6 +71,9 @@ public:
"supports symlinks and the linker supports so-names. "
"If only one of both is specified the missing is assumed to have "
"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 "
"used in place of the target name when creating executables."
"If not set here then it is set to target_EXPORTS by default "

View File

@ -939,7 +939,7 @@ std::string cmTarget::GetFullNameInternal(cmMakefile* mf,
{
const char* targetPrefix = this->GetProperty("PREFIX");
const char* targetSuffix = this->GetProperty("SUFFIX");
if(!targetSuffix && this->GetType() == cmTarget::EXECUTABLE)
if(!targetSuffix && type == cmTarget::EXECUTABLE)
{
targetSuffix = cmSystemTools::GetExecutableExtension();
}
@ -973,9 +973,26 @@ std::string cmTarget::GetFullNameInternal(cmMakefile* mf,
{
targetSuffix = mf->GetSafeDefinition(suffixVar);
}
// Begin the final name with the prefix.
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:"";
// Return the final name.
return name;
}
@ -1125,3 +1142,49 @@ void cmTarget::GetLibraryNamesInternal(cmMakefile* mf,
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;
}
}

View File

@ -186,6 +186,19 @@ public:
std::string& sharedName,
std::string& sharedSOName,
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:
/**
* A list of direct dependencies. Use in conjunction with DependencyMap.
@ -249,6 +262,10 @@ private:
std::string& soName,
std::string& realName,
TargetType type);
void GetExecutableNamesInternal(cmMakefile* mf,
std::string& name,
std::string& realName,
TargetType type);
// update the value of the LOCATION var
void UpdateLocation();