فهرست منبع

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

Brad King 20 سال پیش
والد
کامیت
d392acb4e6
6فایلهای تغییر یافته به همراه198 افزوده شده و 33 حذف شده
  1. 42 5
      Source/cmFileCommand.cxx
  2. 17 2
      Source/cmLocalGenerator.cxx
  3. 52 22
      Source/cmLocalUnixMakefileGenerator3.cxx
  4. 3 0
      Source/cmSetTargetPropertiesCommand.h
  5. 67 4
      Source/cmTarget.cxx
  6. 17 0
      Source/cmTarget.h

+ 42 - 5
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;
       }
 

+ 17 - 2
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:
           {

+ 52 - 22
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));
 }
 
 //----------------------------------------------------------------------------

+ 3 - 0
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 "

+ 67 - 4
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;
+    }
+}

+ 17 - 0
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();