summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2005-08-17 16:11:18 -0400
committerBrad King <brad.king@kitware.com>2005-08-17 16:11:18 -0400
commitd392acb4e65e2ce133acf4a07dba983060f58725 (patch)
tree94e70b90a43f93849beccb3fb45131d5927a971b
parent78112eef25772968412c32026b6a98f3817afe8d (diff)
downloadcmake-d392acb4e65e2ce133acf4a07dba983060f58725.tar.gz
ENH: Added versioned executable support. This partially addresses bug#2143. Also made OUTPUT_NAME work when installing executables.
-rw-r--r--Source/cmFileCommand.cxx47
-rw-r--r--Source/cmLocalGenerator.cxx19
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx74
-rw-r--r--Source/cmSetTargetPropertiesCommand.h3
-rw-r--r--Source/cmTarget.cxx71
-rw-r--r--Source/cmTarget.h17
6 files changed, 198 insertions, 33 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 7fd5910b09..64d3bd9db4 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -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;
}
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 2433414b67..f0e531db40 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -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:
{
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 2ca5731331..f397106a4f 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -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));
}
//----------------------------------------------------------------------------
diff --git a/Source/cmSetTargetPropertiesCommand.h b/Source/cmSetTargetPropertiesCommand.h
index 8786637ffd..64e78d69b8 100644
--- a/Source/cmSetTargetPropertiesCommand.h
+++ b/Source/cmSetTargetPropertiesCommand.h
@@ -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 "
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 77491ff4d9..b16f80cc45 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -929,17 +929,17 @@ const char* cmTarget::GetPrefixVariableInternal(TargetType type)
return "";
}
-std::string cmTarget::GetFullName(cmMakefile* mf)
+std::string cmTarget::GetFullName(cmMakefile* mf)
{
return this->GetFullNameInternal(mf, this->GetType());
}
std::string cmTarget::GetFullNameInternal(cmMakefile* mf,
- TargetType type)
+ TargetType type)
{
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;
+ }
+}
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 17961fe963..c1c68e9832 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -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();