Kaynağa Gözat

Merge topic 'extract-cmLinkLineComputer'

41340304 cmLinkLineComputer: Extract link libraries computation from cmLocalGenerator
f03d446e cmLinkLineComputer: Move FrameworkPath computation from cmLocalGenerator
3444105f cmLocalGenerator: Inline last use of local variable
77c4202e cmLinkLineComputer: Move RPath computation from cmLocalGenerator
09b6cc66 cmLinkLineComputer: Move LinkPath computation from cmLocalGenerator
0c978063 cmLinkLineComputer: Move ComputeLinkLibs from cmLocalGenerator
0152a01f cmLocalGenerator: Move variable to where it is used
011e6870 cmLocalGenerator: Use a std::string instead of char*
cbca80f3 cmLocalGenerator: Move stringstream to where it is used
d48f69d0 cmLocalGenerator: Move flag determination up in the function
ff8e321c cmLocalGenerator: Separate stdlib content from library stream
80f57e67 cmLocalGenerator: Separate rpath content from library stream
7ef83468 cmLocalGenerator: Pass link library info to OutputLinkLibraries
69295812 Makefiles: Port CreateLinkLibs to cmLinkLineComputer
5b361fdd cmLinkLineComputer: Extract from cmLocalGenerator
2e5d1990 Ninja: Constify
...
Brad King 9 yıl önce
ebeveyn
işleme
656ebaca3b

+ 6 - 0
Source/CMakeLists.txt

@@ -300,6 +300,8 @@ set(SRCS
   cmInstallDirectoryGenerator.cxx
   cmInstallDirectoryGenerator.cxx
   cmLinkedTree.h
   cmLinkedTree.h
   cmLinkItem.h
   cmLinkItem.h
+  cmLinkLineComputer.cxx
+  cmLinkLineComputer.h
   cmListFileCache.cxx
   cmListFileCache.cxx
   cmListFileCache.h
   cmListFileCache.h
   cmListFileLexer.c
   cmListFileLexer.c
@@ -318,6 +320,8 @@ set(SRCS
   cmMakefileUtilityTargetGenerator.cxx
   cmMakefileUtilityTargetGenerator.cxx
   cmMessenger.cxx
   cmMessenger.cxx
   cmMessenger.h
   cmMessenger.h
+  cmMSVC60LinkLineComputer.cxx
+  cmMSVC60LinkLineComputer.h
   cmOSXBundleGenerator.cxx
   cmOSXBundleGenerator.cxx
   cmOSXBundleGenerator.h
   cmOSXBundleGenerator.h
   cmOutputConverter.cxx
   cmOutputConverter.cxx
@@ -545,6 +549,8 @@ set(SRCS ${SRCS}
   cmNinjaNormalTargetGenerator.h
   cmNinjaNormalTargetGenerator.h
   cmNinjaUtilityTargetGenerator.cxx
   cmNinjaUtilityTargetGenerator.cxx
   cmNinjaUtilityTargetGenerator.h
   cmNinjaUtilityTargetGenerator.h
+  cmNinjaLinkLineComputer.cxx
+  cmNinjaLinkLineComputer.h
   )
   )
 
 
 # Temporary variable for tools targets
 # Temporary variable for tools targets

+ 4 - 2
Source/cmCommonTargetGenerator.cxx

@@ -12,6 +12,7 @@
 #include "cmComputeLinkInformation.h"
 #include "cmComputeLinkInformation.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalCommonGenerator.h"
 #include "cmGlobalCommonGenerator.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalCommonGenerator.h"
 #include "cmLocalCommonGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
@@ -59,7 +60,8 @@ void cmCommonTargetGenerator::AddFeatureFlags(std::string& flags,
   }
   }
 }
 }
 
 
-void cmCommonTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
+void cmCommonTargetGenerator::AddModuleDefinitionFlag(
+  cmLinkLineComputer* linkLineComputer, std::string& flags)
 {
 {
   if (!this->ModuleDefinitionFile) {
   if (!this->ModuleDefinitionFile) {
     return;
     return;
@@ -76,7 +78,7 @@ void cmCommonTargetGenerator::AddModuleDefinitionFlag(std::string& flags)
   // vs6's "cl -link" pass it to the linker.
   // vs6's "cl -link" pass it to the linker.
   std::string flag = defFileFlag;
   std::string flag = defFileFlag;
   flag += this->LocalGenerator->ConvertToOutputFormat(
   flag += this->LocalGenerator->ConvertToOutputFormat(
-    this->LocalGenerator->ConvertToLinkReference(
+    linkLineComputer->ConvertToLinkReference(
       this->ModuleDefinitionFile->GetFullPath()),
       this->ModuleDefinitionFile->GetFullPath()),
     cmOutputConverter::SHELL);
     cmOutputConverter::SHELL);
   this->LocalGenerator->AppendFlags(flags, flag);
   this->LocalGenerator->AppendFlags(flags, flag);

+ 3 - 1
Source/cmCommonTargetGenerator.h

@@ -16,6 +16,7 @@ class cmGlobalCommonGenerator;
 class cmLocalCommonGenerator;
 class cmLocalCommonGenerator;
 class cmMakefile;
 class cmMakefile;
 class cmSourceFile;
 class cmSourceFile;
+class cmLinkLineComputer;
 
 
 /** \class cmCommonTargetGenerator
 /** \class cmCommonTargetGenerator
  * \brief Common infrastructure for Makefile and Ninja per-target generators
  * \brief Common infrastructure for Makefile and Ninja per-target generators
@@ -37,7 +38,8 @@ protected:
   bool GetFeatureAsBool(const std::string& feature);
   bool GetFeatureAsBool(const std::string& feature);
 
 
   // Helper to add flag for windows .def file.
   // Helper to add flag for windows .def file.
-  void AddModuleDefinitionFlag(std::string& flags);
+  void AddModuleDefinitionFlag(cmLinkLineComputer* linkLineComputer,
+                               std::string& flags);
 
 
   cmGeneratorTarget* GeneratorTarget;
   cmGeneratorTarget* GeneratorTarget;
   cmMakefile* Makefile;
   cmMakefile* Makefile;

+ 9 - 2
Source/cmGhsMultiTargetGenerator.cxx

@@ -5,6 +5,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGhsMultiGenerator.h"
 #include "cmGlobalGhsMultiGenerator.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
 #include "cmSourceFile.h"
@@ -362,9 +363,15 @@ void cmGhsMultiTargetGenerator::WriteTargetLinkLibraries(
       this->GeneratorTarget->GetCreateRuleVariable(language, config);
       this->GeneratorTarget->GetCreateRuleVariable(language, config);
     bool useWatcomQuote =
     bool useWatcomQuote =
       this->Makefile->IsOn(createRule + "_USE_WATCOM_QUOTE");
       this->Makefile->IsOn(createRule + "_USE_WATCOM_QUOTE");
+    CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer(
+      this->GetGlobalGenerator()->CreateLinkLineComputer(
+        this->LocalGenerator,
+        this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+    linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+
     this->LocalGenerator->GetTargetFlags(
     this->LocalGenerator->GetTargetFlags(
-      config, linkLibraries, flags, linkFlags, frameworkPath, linkPath,
-      this->GeneratorTarget, useWatcomQuote);
+      linkLineComputer.get(), config, linkLibraries, flags, linkFlags,
+      frameworkPath, linkPath, this->GeneratorTarget);
     linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
     linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
 
 
     if (!linkPath.empty()) {
     if (!linkPath.empty()) {

+ 14 - 0
Source/cmGlobalGenerator.cxx

@@ -20,7 +20,9 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmInstallGenerator.h"
 #include "cmInstallGenerator.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
+#include "cmMSVC60LinkLineComputer.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
 #include "cmPolicies.h"
@@ -1412,6 +1414,18 @@ cmGlobalGenerator::CreateQtAutoGeneratorsTargets()
   return autogenTargets;
   return autogenTargets;
 }
 }
 
 
+cmLinkLineComputer* cmGlobalGenerator::CreateLinkLineComputer(
+  cmOutputConverter* outputConverter, cmState::Directory stateDir) const
+{
+  return new cmLinkLineComputer(outputConverter, stateDir);
+}
+
+cmLinkLineComputer* cmGlobalGenerator::CreateMSVC60LinkLineComputer(
+  cmOutputConverter* outputConverter, cmState::Directory stateDir) const
+{
+  return new cmMSVC60LinkLineComputer(outputConverter, stateDir);
+}
+
 void cmGlobalGenerator::FinalizeTargetCompileInfo()
 void cmGlobalGenerator::FinalizeTargetCompileInfo()
 {
 {
   std::vector<std::string> const langs =
   std::vector<std::string> const langs =

+ 8 - 0
Source/cmGlobalGenerator.h

@@ -34,7 +34,9 @@ class cmExportBuildFileGenerator;
 class cmExternalMakefileProjectGenerator;
 class cmExternalMakefileProjectGenerator;
 class cmGeneratorTarget;
 class cmGeneratorTarget;
 class cmLocalGenerator;
 class cmLocalGenerator;
+class cmLinkLineComputer;
 class cmMakefile;
 class cmMakefile;
+class cmOutputConverter;
 class cmake;
 class cmake;
 
 
 /** \class cmGlobalGenerator
 /** \class cmGlobalGenerator
@@ -105,6 +107,12 @@ public:
    */
    */
   virtual void Generate();
   virtual void Generate();
 
 
+  virtual cmLinkLineComputer* CreateLinkLineComputer(
+    cmOutputConverter* outputConverter, cmState::Directory stateDir) const;
+
+  cmLinkLineComputer* CreateMSVC60LinkLineComputer(
+    cmOutputConverter* outputConverter, cmState::Directory stateDir) const;
+
   /**
   /**
    * Set/Get and Clear the enabled languages.
    * Set/Get and Clear the enabled languages.
    */
    */

+ 13 - 2
Source/cmGlobalNinjaGenerator.cxx

@@ -11,6 +11,7 @@
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalNinjaGenerator.h"
 #include "cmLocalNinjaGenerator.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
+#include "cmNinjaLinkLineComputer.h"
 #include "cmOutputConverter.h"
 #include "cmOutputConverter.h"
 #include "cmState.h"
 #include "cmState.h"
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
@@ -64,6 +65,14 @@ void cmGlobalNinjaGenerator::WriteComment(std::ostream& os,
   os << "# " << comment.substr(lpos) << "\n\n";
   os << "# " << comment.substr(lpos) << "\n\n";
 }
 }
 
 
+cmLinkLineComputer* cmGlobalNinjaGenerator::CreateLinkLineComputer(
+  cmOutputConverter* outputConverter, cmState::Directory /* stateDir */) const
+{
+  return new cmNinjaLinkLineComputer(
+    outputConverter,
+    this->LocalGenerators[0]->GetStateSnapshot().GetDirectory(), this);
+}
+
 std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name)
 std::string cmGlobalNinjaGenerator::EncodeRuleName(std::string const& name)
 {
 {
   // Ninja rule names must match "[a-zA-Z0-9_.-]+".  Use ".xx" to encode
   // Ninja rule names must match "[a-zA-Z0-9_.-]+".  Use ".xx" to encode
@@ -830,7 +839,8 @@ static void EnsureTrailingSlash(std::string& path)
 #endif
 #endif
 }
 }
 
 
-std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path)
+std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(
+  const std::string& path) const
 {
 {
   cmLocalNinjaGenerator* ng =
   cmLocalNinjaGenerator* ng =
     static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]);
     static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]);
@@ -1421,7 +1431,8 @@ void cmGlobalNinjaGenerator::InitOutputPathPrefix()
   EnsureTrailingSlash(this->OutputPathPrefix);
   EnsureTrailingSlash(this->OutputPathPrefix);
 }
 }
 
 
-std::string cmGlobalNinjaGenerator::NinjaOutputPath(std::string const& path)
+std::string cmGlobalNinjaGenerator::NinjaOutputPath(
+  std::string const& path) const
 {
 {
   if (!this->HasOutputPathPrefix() || cmSystemTools::FileIsFullPath(path)) {
   if (!this->HasOutputPathPrefix() || cmSystemTools::FileIsFullPath(path)) {
     return path;
     return path;

+ 6 - 2
Source/cmGlobalNinjaGenerator.h

@@ -70,6 +70,10 @@ public:
   std::string EncodePath(const std::string& path);
   std::string EncodePath(const std::string& path);
   static std::string EncodeDepfileSpace(const std::string& path);
   static std::string EncodeDepfileSpace(const std::string& path);
 
 
+  cmLinkLineComputer* CreateLinkLineComputer(
+    cmOutputConverter* outputConverter,
+    cmState::Directory stateDir) const CM_OVERRIDE;
+
   /**
   /**
    * Write the given @a comment to the output stream @a os. It
    * Write the given @a comment to the output stream @a os. It
    * handles new line character properly.
    * handles new line character properly.
@@ -233,7 +237,7 @@ public:
     return this->RulesFileStream;
     return this->RulesFileStream;
   }
   }
 
 
-  std::string ConvertToNinjaPath(const std::string& path);
+  std::string ConvertToNinjaPath(const std::string& path) const;
   std::string ConvertToNinjaFolderRule(const std::string& path);
   std::string ConvertToNinjaFolderRule(const std::string& path);
 
 
   struct MapToNinjaPathImpl
   struct MapToNinjaPathImpl
@@ -333,7 +337,7 @@ public:
   bool SupportsConsolePool() const;
   bool SupportsConsolePool() const;
   bool SupportsImplicitOuts() const;
   bool SupportsImplicitOuts() const;
 
 
-  std::string NinjaOutputPath(std::string const& path);
+  std::string NinjaOutputPath(std::string const& path) const;
   bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
   bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); }
   void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
   void StripNinjaOutputPathPrefixAsSuffix(std::string& path);
 
 

+ 179 - 0
Source/cmLinkLineComputer.cxx

@@ -0,0 +1,179 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmLinkLineComputer.h"
+#include "cmComputeLinkInformation.h"
+#include "cmGeneratorTarget.h"
+#include "cmOutputConverter.h"
+
+cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter* outputConverter,
+                                       cmState::Directory stateDir)
+  : StateDir(stateDir)
+  , OutputConverter(outputConverter)
+  , ForResponse(false)
+  , UseWatcomQuote(false)
+  , Relink(false)
+{
+}
+
+cmLinkLineComputer::~cmLinkLineComputer()
+{
+}
+
+void cmLinkLineComputer::SetUseWatcomQuote(bool useWatcomQuote)
+{
+  this->UseWatcomQuote = useWatcomQuote;
+}
+
+void cmLinkLineComputer::SetForResponse(bool forResponse)
+{
+  this->ForResponse = forResponse;
+}
+
+void cmLinkLineComputer::SetRelink(bool relink)
+{
+  this->Relink = relink;
+}
+
+std::string cmLinkLineComputer::ConvertToLinkReference(
+  std::string const& lib) const
+{
+  std::string relLib = lib;
+
+  if (cmOutputConverter::ContainedInDirectory(
+        this->StateDir.GetCurrentBinary(), lib, this->StateDir)) {
+    relLib = cmOutputConverter::ForceToRelativePath(
+      this->StateDir.GetCurrentBinary(), lib);
+  }
+  return relLib;
+}
+
+std::string cmLinkLineComputer::ComputeLinkLibs(cmComputeLinkInformation& cli)
+{
+  std::string linkLibs;
+  typedef cmComputeLinkInformation::ItemVector ItemVector;
+  ItemVector const& items = cli.GetItems();
+  for (ItemVector::const_iterator li = items.begin(); li != items.end();
+       ++li) {
+    if (li->Target && li->Target->GetType() == cmState::INTERFACE_LIBRARY) {
+      continue;
+    }
+    if (li->IsPath) {
+      linkLibs +=
+        this->ConvertToOutputFormat(this->ConvertToLinkReference(li->Value));
+    } else {
+      linkLibs += li->Value;
+    }
+    linkLibs += " ";
+  }
+  return linkLibs;
+}
+
+std::string cmLinkLineComputer::ConvertToOutputFormat(std::string const& input)
+{
+  cmOutputConverter::OutputFormat shellFormat = (this->ForResponse)
+    ? cmOutputConverter::RESPONSE
+    : ((this->UseWatcomQuote) ? cmOutputConverter::WATCOMQUOTE
+                              : cmOutputConverter::SHELL);
+
+  return this->OutputConverter->ConvertToOutputFormat(input, shellFormat);
+}
+
+std::string cmLinkLineComputer::ConvertToOutputForExisting(
+  std::string const& input)
+{
+  cmOutputConverter::OutputFormat shellFormat = (this->ForResponse)
+    ? cmOutputConverter::RESPONSE
+    : ((this->UseWatcomQuote) ? cmOutputConverter::WATCOMQUOTE
+                              : cmOutputConverter::SHELL);
+
+  return this->OutputConverter->ConvertToOutputForExisting(input, shellFormat);
+}
+
+std::string cmLinkLineComputer::ComputeLinkPath(
+  cmComputeLinkInformation& cli, std::string const& libPathFlag,
+  std::string const& libPathTerminator)
+{
+  std::string linkPath;
+  std::vector<std::string> const& libDirs = cli.GetDirectories();
+  for (std::vector<std::string>::const_iterator libDir = libDirs.begin();
+       libDir != libDirs.end(); ++libDir) {
+    std::string libpath = this->ConvertToOutputForExisting(*libDir);
+    linkPath += " " + libPathFlag;
+    linkPath += libpath;
+    linkPath += libPathTerminator;
+    linkPath += " ";
+  }
+  return linkPath;
+}
+
+std::string cmLinkLineComputer::ComputeRPath(cmComputeLinkInformation& cli)
+{
+  std::string rpath;
+  // Check what kind of rpath flags to use.
+  if (cli.GetRuntimeSep().empty()) {
+    // Each rpath entry gets its own option ("-R a -R b -R c")
+    std::vector<std::string> runtimeDirs;
+    cli.GetRPath(runtimeDirs, this->Relink);
+
+    for (std::vector<std::string>::iterator ri = runtimeDirs.begin();
+         ri != runtimeDirs.end(); ++ri) {
+      rpath += cli.GetRuntimeFlag();
+      rpath += this->ConvertToOutputFormat(*ri);
+      rpath += " ";
+    }
+  } else {
+    // All rpath entries are combined ("-Wl,-rpath,a:b:c").
+    std::string rpathString = cli.GetRPathString(this->Relink);
+
+    // Store the rpath option in the stream.
+    if (!rpathString.empty()) {
+      rpath += cli.GetRuntimeFlag();
+      rpath +=
+        this->OutputConverter->EscapeForShell(rpathString, !this->ForResponse);
+      rpath += " ";
+    }
+  }
+  return rpath;
+}
+
+std::string cmLinkLineComputer::ComputeFrameworkPath(
+  cmComputeLinkInformation& cli, std::string const& fwSearchFlag)
+{
+  std::string frameworkPath;
+  if (!fwSearchFlag.empty()) {
+    std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
+    for (std::vector<std::string>::const_iterator fdi = fwDirs.begin();
+         fdi != fwDirs.end(); ++fdi) {
+      frameworkPath += fwSearchFlag;
+      frameworkPath += this->ConvertToOutputFormat(*fdi);
+      frameworkPath += " ";
+    }
+  }
+  return frameworkPath;
+}
+
+std::string cmLinkLineComputer::ComputeLinkLibraries(
+  cmComputeLinkInformation& cli, std::string const& stdLibString)
+{
+  std::ostringstream fout;
+  fout << this->ComputeRPath(cli);
+
+  // Write the library flags to the build rule.
+  fout << this->ComputeLinkLibs(cli);
+
+  // Add the linker runtime search path if any.
+  std::string rpath_link = cli.GetRPathLinkString();
+  if (!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) {
+    fout << cli.GetRPathLinkFlag();
+    fout << this->OutputConverter->EscapeForShell(rpath_link,
+                                                  !this->ForResponse);
+    fout << " ";
+  }
+
+  if (!stdLibString.empty()) {
+    fout << stdLibString << " ";
+  }
+
+  return fout.str();
+}

+ 50 - 0
Source/cmLinkLineComputer.h

@@ -0,0 +1,50 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#ifndef cmLinkLineComputer_h
+#define cmLinkLineComputer_h
+
+#include "cmState.h"
+
+class cmComputeLinkInformation;
+class cmOutputConverter;
+
+class cmLinkLineComputer
+{
+public:
+  cmLinkLineComputer(cmOutputConverter* outputConverter,
+                     cmState::Directory stateDir);
+  virtual ~cmLinkLineComputer();
+
+  void SetUseWatcomQuote(bool useWatcomQuote);
+  void SetForResponse(bool forResponse);
+  void SetRelink(bool relink);
+
+  virtual std::string ConvertToLinkReference(std::string const& input) const;
+
+  std::string ComputeLinkPath(cmComputeLinkInformation& cli,
+                              std::string const& libPathFlag,
+                              std::string const& libPathTerminator);
+
+  std::string ComputeFrameworkPath(cmComputeLinkInformation& cli,
+                                   std::string const& fwSearchFlag);
+
+  std::string ComputeLinkLibraries(cmComputeLinkInformation& cli,
+                                   std::string const& stdLibString);
+
+private:
+  std::string ComputeLinkLibs(cmComputeLinkInformation& cli);
+  std::string ComputeRPath(cmComputeLinkInformation& cli);
+
+  std::string ConvertToOutputFormat(std::string const& input);
+  std::string ConvertToOutputForExisting(std::string const& input);
+
+  cmState::Directory StateDir;
+  cmOutputConverter* OutputConverter;
+
+  bool ForResponse;
+  bool UseWatcomQuote;
+  bool Relink;
+};
+
+#endif

+ 32 - 135
Source/cmLocalGenerator.cxx

@@ -12,6 +12,7 @@
 #include "cmInstallGenerator.h"
 #include "cmInstallGenerator.h"
 #include "cmInstallScriptGenerator.h"
 #include "cmInstallScriptGenerator.h"
 #include "cmInstallTargetGenerator.h"
 #include "cmInstallTargetGenerator.h"
+#include "cmLinkLineComputer.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
 #include "cmSourceFile.h"
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
@@ -1148,11 +1149,12 @@ void cmLocalGenerator::GetStaticLibraryFlags(std::string& flags,
 }
 }
 
 
 void cmLocalGenerator::GetTargetFlags(
 void cmLocalGenerator::GetTargetFlags(
-  const std::string& config, std::string& linkLibs, std::string& flags,
-  std::string& linkFlags, std::string& frameworkPath, std::string& linkPath,
-  cmGeneratorTarget* target, bool useWatcomQuote)
+  cmLinkLineComputer* linkLineComputer, const std::string& config,
+  std::string& linkLibs, std::string& flags, std::string& linkFlags,
+  std::string& frameworkPath, std::string& linkPath, cmGeneratorTarget* target)
 {
 {
   const std::string buildType = cmSystemTools::UpperCase(config);
   const std::string buildType = cmSystemTools::UpperCase(config);
+  cmComputeLinkInformation* pcli = target->GetLinkInformation(config);
   const char* libraryLinkVariable =
   const char* libraryLinkVariable =
     "CMAKE_SHARED_LINKER_FLAGS"; // default to shared library
     "CMAKE_SHARED_LINKER_FLAGS"; // default to shared library
 
 
@@ -1203,8 +1205,10 @@ void cmLocalGenerator::GetTargetFlags(
           linkFlags += " ";
           linkFlags += " ";
         }
         }
       }
       }
-      this->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, *target,
-                                false, false, useWatcomQuote);
+      if (pcli) {
+        this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
+                                  frameworkPath, linkPath);
+      }
     } break;
     } break;
     case cmState::EXECUTABLE: {
     case cmState::EXECUTABLE: {
       linkFlags += this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
       linkFlags += this->Makefile->GetSafeDefinition("CMAKE_EXE_LINKER_FLAGS");
@@ -1223,8 +1227,10 @@ void cmLocalGenerator::GetTargetFlags(
         return;
         return;
       }
       }
       this->AddLanguageFlags(flags, linkLanguage, buildType);
       this->AddLanguageFlags(flags, linkLanguage, buildType);
-      this->OutputLinkLibraries(linkLibs, frameworkPath, linkPath, *target,
-                                false, false, useWatcomQuote);
+      if (pcli) {
+        this->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
+                                  frameworkPath, linkPath);
+      }
       if (cmSystemTools::IsOn(
       if (cmSystemTools::IsOn(
             this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) {
             this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) {
         std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") +
         std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") +
@@ -1383,155 +1389,46 @@ std::string cmLocalGenerator::GetTargetFortranFlags(
   return std::string();
   return std::string();
 }
 }
 
 
-std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-  // Work-ardound command line parsing limitations in MSVC 6.0
-  if (this->Makefile->IsOn("MSVC60")) {
-    // Search for the last space.
-    std::string::size_type pos = lib.rfind(' ');
-    if (pos != lib.npos) {
-      // Find the slash after the last space, if any.
-      pos = lib.find('/', pos);
-
-      // Convert the portion of the path with a space to a short path.
-      std::string sp;
-      if (cmSystemTools::GetShortPath(lib.substr(0, pos).c_str(), sp)) {
-        // Append the rest of the path with no space.
-        sp += lib.substr(pos);
-
-        return sp;
-      }
-    }
-  }
-#endif
-
-  // Normal behavior.
-  return this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), lib);
-}
-
 /**
 /**
  * Output the linking rules on a command line.  For executables,
  * Output the linking rules on a command line.  For executables,
  * targetLibrary should be a NULL pointer.  For libraries, it should point
  * targetLibrary should be a NULL pointer.  For libraries, it should point
  * to the name of the library.  This will not link a library against itself.
  * to the name of the library.  This will not link a library against itself.
  */
  */
-void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries,
-                                           std::string& frameworkPath,
-                                           std::string& linkPath,
-                                           cmGeneratorTarget& tgt, bool relink,
-                                           bool forResponseFile,
-                                           bool useWatcomQuote)
-{
-  OutputFormat shellFormat =
-    (forResponseFile) ? RESPONSE : ((useWatcomQuote) ? WATCOMQUOTE : SHELL);
-  bool escapeAllowMakeVars = !forResponseFile;
-  std::ostringstream fout;
-  std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
-  cmComputeLinkInformation* pcli = tgt.GetLinkInformation(config);
-  if (!pcli) {
-    return;
-  }
+void cmLocalGenerator::OutputLinkLibraries(
+  cmComputeLinkInformation* pcli, cmLinkLineComputer* linkLineComputer,
+  std::string& linkLibraries, std::string& frameworkPath,
+  std::string& linkPath)
+{
   cmComputeLinkInformation& cli = *pcli;
   cmComputeLinkInformation& cli = *pcli;
 
 
   std::string linkLanguage = cli.GetLinkLanguage();
   std::string linkLanguage = cli.GetLinkLanguage();
 
 
-  std::string linkLibs;
-
   std::string libPathFlag =
   std::string libPathFlag =
     this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
     this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG");
   std::string libPathTerminator =
   std::string libPathTerminator =
     this->Makefile->GetSafeDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
     this->Makefile->GetSafeDefinition("CMAKE_LIBRARY_PATH_TERMINATOR");
 
 
-  // Append the framework search path flags.
-  std::string fwSearchFlagVar = "CMAKE_";
-  fwSearchFlagVar += linkLanguage;
-  fwSearchFlagVar += "_FRAMEWORK_SEARCH_FLAG";
-  const char* fwSearchFlag = this->Makefile->GetDefinition(fwSearchFlagVar);
-  if (fwSearchFlag && *fwSearchFlag) {
-    std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths();
-    for (std::vector<std::string>::const_iterator fdi = fwDirs.begin();
-         fdi != fwDirs.end(); ++fdi) {
-      frameworkPath += fwSearchFlag;
-      frameworkPath += this->ConvertToOutputFormat(*fdi, shellFormat);
-      frameworkPath += " ";
-    }
-  }
-
-  // Append the library search path flags.
-  std::vector<std::string> const& libDirs = cli.GetDirectories();
-  for (std::vector<std::string>::const_iterator libDir = libDirs.begin();
-       libDir != libDirs.end(); ++libDir) {
-    std::string libpath =
-      this->ConvertToOutputForExisting(*libDir, shellFormat);
-    linkPath += " " + libPathFlag;
-    linkPath += libpath;
-    linkPath += libPathTerminator;
-    linkPath += " ";
-  }
-
-  // Append the link items.
-  typedef cmComputeLinkInformation::ItemVector ItemVector;
-  ItemVector const& items = cli.GetItems();
-  for (ItemVector::const_iterator li = items.begin(); li != items.end();
-       ++li) {
-    if (li->Target && li->Target->GetType() == cmState::INTERFACE_LIBRARY) {
-      continue;
-    }
-    if (li->IsPath) {
-      linkLibs += this->ConvertToOutputFormat(
-        this->ConvertToLinkReference(li->Value), shellFormat);
-    } else {
-      linkLibs += li->Value;
-    }
-    linkLibs += " ";
-  }
-
-  // Check what kind of rpath flags to use.
-  if (cli.GetRuntimeSep().empty()) {
-    // Each rpath entry gets its own option ("-R a -R b -R c")
-    std::vector<std::string> runtimeDirs;
-    cli.GetRPath(runtimeDirs, relink);
-
-    std::string rpath;
-    for (std::vector<std::string>::iterator ri = runtimeDirs.begin();
-         ri != runtimeDirs.end(); ++ri) {
-      rpath += cli.GetRuntimeFlag();
-      rpath += this->ConvertToOutputFormat(*ri, shellFormat);
-      rpath += " ";
-    }
-    fout << rpath;
-  } else {
-    // All rpath entries are combined ("-Wl,-rpath,a:b:c").
-    std::string rpath = cli.GetRPathString(relink);
-
-    // Store the rpath option in the stream.
-    if (!rpath.empty()) {
-      fout << cli.GetRuntimeFlag();
-      fout << this->EscapeForShell(rpath, escapeAllowMakeVars);
-      fout << " ";
-    }
-  }
-
-  // Write the library flags to the build rule.
-  fout << linkLibs;
-
-  // Add the linker runtime search path if any.
-  std::string rpath_link = cli.GetRPathLinkString();
-  if (!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) {
-    fout << cli.GetRPathLinkFlag();
-    fout << this->EscapeForShell(rpath_link, escapeAllowMakeVars);
-    fout << " ";
-  }
-
   // Add standard libraries for this language.
   // Add standard libraries for this language.
   std::string standardLibsVar = "CMAKE_";
   std::string standardLibsVar = "CMAKE_";
   standardLibsVar += cli.GetLinkLanguage();
   standardLibsVar += cli.GetLinkLanguage();
   standardLibsVar += "_STANDARD_LIBRARIES";
   standardLibsVar += "_STANDARD_LIBRARIES";
+  std::string stdLibString;
   if (const char* stdLibs = this->Makefile->GetDefinition(standardLibsVar)) {
   if (const char* stdLibs = this->Makefile->GetDefinition(standardLibsVar)) {
-    fout << stdLibs << " ";
+    stdLibString = stdLibs;
   }
   }
 
 
-  linkLibraries = fout.str();
+  // Append the framework search path flags.
+  std::string fwSearchFlagVar = "CMAKE_";
+  fwSearchFlagVar += linkLanguage;
+  fwSearchFlagVar += "_FRAMEWORK_SEARCH_FLAG";
+  std::string fwSearchFlag =
+    this->Makefile->GetSafeDefinition(fwSearchFlagVar);
+
+  frameworkPath = linkLineComputer->ComputeFrameworkPath(cli, fwSearchFlag);
+  linkPath =
+    linkLineComputer->ComputeLinkPath(cli, libPathFlag, libPathTerminator);
+
+  linkLibraries = linkLineComputer->ComputeLinkLibraries(cli, stdLibString);
 }
 }
 
 
 std::string cmLocalGenerator::GetLinkLibsCMP0065(
 std::string cmLocalGenerator::GetLinkLibsCMP0065(

+ 9 - 8
Source/cmLocalGenerator.h

@@ -19,11 +19,13 @@
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
 
 
+class cmComputeLinkInformation;
 class cmCustomCommandGenerator;
 class cmCustomCommandGenerator;
 class cmGeneratorTarget;
 class cmGeneratorTarget;
 class cmGlobalGenerator;
 class cmGlobalGenerator;
 class cmMakefile;
 class cmMakefile;
 class cmSourceFile;
 class cmSourceFile;
+class cmLinkLineComputer;
 
 
 /** \class cmLocalGenerator
 /** \class cmLocalGenerator
  * \brief Create required build files for a directory.
  * \brief Create required build files for a directory.
@@ -312,10 +314,11 @@ public:
 
 
   /** Fill out these strings for the given target.  Libraries to link,
   /** Fill out these strings for the given target.  Libraries to link,
    *  flags, and linkflags. */
    *  flags, and linkflags. */
-  void GetTargetFlags(const std::string& config, std::string& linkLibs,
+  void GetTargetFlags(cmLinkLineComputer* linkLineComputer,
+                      const std::string& config, std::string& linkLibs,
                       std::string& flags, std::string& linkFlags,
                       std::string& flags, std::string& linkFlags,
                       std::string& frameworkPath, std::string& linkPath,
                       std::string& frameworkPath, std::string& linkPath,
-                      cmGeneratorTarget* target, bool useWatcomQuote);
+                      cmGeneratorTarget* target);
   void GetTargetDefines(cmGeneratorTarget const* target,
   void GetTargetDefines(cmGeneratorTarget const* target,
                         std::string const& config, std::string const& lang,
                         std::string const& config, std::string const& lang,
                         std::set<std::string>& defines) const;
                         std::set<std::string>& defines) const;
@@ -345,10 +348,10 @@ public:
 
 
 protected:
 protected:
   ///! put all the libraries for a target on into the given stream
   ///! put all the libraries for a target on into the given stream
-  void OutputLinkLibraries(std::string& linkLibraries,
-                           std::string& frameworkPath, std::string& linkPath,
-                           cmGeneratorTarget&, bool relink,
-                           bool forResponseFile, bool useWatcomQuote);
+  void OutputLinkLibraries(cmComputeLinkInformation* pcli,
+                           cmLinkLineComputer* linkLineComputer,
+                           std::string& linkLibraries,
+                           std::string& frameworkPath, std::string& linkPath);
 
 
   // Expand rule variables in CMake of the type found in language rules
   // Expand rule variables in CMake of the type found in language rules
   void ExpandRuleVariables(std::string& string,
   void ExpandRuleVariables(std::string& string,
@@ -370,8 +373,6 @@ protected:
   std::string& CreateSafeUniqueObjectFileName(const std::string& sin,
   std::string& CreateSafeUniqueObjectFileName(const std::string& sin,
                                               std::string const& dir_max);
                                               std::string const& dir_max);
 
 
-  virtual std::string ConvertToLinkReference(std::string const& lib);
-
   /** Check whether the native build system supports the given
   /** Check whether the native build system supports the given
       definition.  Issues a warning.  */
       definition.  Issues a warning.  */
   virtual bool CheckDefinition(std::string const& define) const;
   virtual bool CheckDefinition(std::string const& define) const;

+ 0 - 6
Source/cmLocalNinjaGenerator.cxx

@@ -120,12 +120,6 @@ cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
 
 
 // Virtual protected methods.
 // Virtual protected methods.
 
 
-std::string cmLocalNinjaGenerator::ConvertToLinkReference(
-  std::string const& lib)
-{
-  return this->GetGlobalNinjaGenerator()->ConvertToNinjaPath(lib);
-}
-
 std::string cmLocalNinjaGenerator::ConvertToIncludeReference(
 std::string cmLocalNinjaGenerator::ConvertToIncludeReference(
   std::string const& path, cmOutputConverter::OutputFormat format,
   std::string const& path, cmOutputConverter::OutputFormat format,
   bool forceFullPaths)
   bool forceFullPaths)

+ 0 - 2
Source/cmLocalNinjaGenerator.h

@@ -76,8 +76,6 @@ public:
   void AppendCustomCommandDeps(cmCustomCommandGenerator const& ccg,
   void AppendCustomCommandDeps(cmCustomCommandGenerator const& ccg,
                                cmNinjaDeps& ninjaDeps);
                                cmNinjaDeps& ninjaDeps);
 
 
-  std::string ConvertToLinkReference(std::string const& lib) CM_OVERRIDE;
-
   void ComputeObjectFilenames(
   void ComputeObjectFilenames(
     std::map<cmSourceFile const*, std::string>& mapping,
     std::map<cmSourceFile const*, std::string>& mapping,
     cmGeneratorTarget const* gt = CM_NULLPTR) CM_OVERRIDE;
     cmGeneratorTarget const* gt = CM_NULLPTR) CM_OVERRIDE;

+ 36 - 0
Source/cmMSVC60LinkLineComputer.cxx

@@ -0,0 +1,36 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmMSVC60LinkLineComputer.h"
+
+#include "cmSystemTools.h"
+
+cmMSVC60LinkLineComputer::cmMSVC60LinkLineComputer(
+  cmOutputConverter* outputConverter, cmState::Directory stateDir)
+  : cmLinkLineComputer(outputConverter, stateDir)
+{
+}
+
+std::string cmMSVC60LinkLineComputer::ConvertToLinkReference(
+  std::string const& lib) const
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  // Work-ardound command line parsing limitations in MSVC 6.0
+  // Search for the last space.
+  std::string::size_type pos = lib.rfind(' ');
+  if (pos != lib.npos) {
+    // Find the slash after the last space, if any.
+    pos = lib.find('/', pos);
+
+    // Convert the portion of the path with a space to a short path.
+    std::string sp;
+    if (cmSystemTools::GetShortPath(lib.substr(0, pos).c_str(), sp)) {
+      // Append the rest of the path with no space.
+      sp += lib.substr(pos);
+      return sp;
+    }
+  }
+#endif
+
+  return cmLinkLineComputer::ConvertToLinkReference(lib);
+}

+ 19 - 0
Source/cmMSVC60LinkLineComputer.h

@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#ifndef cmMSVC60LinkLineComputer_h
+#define cmMSVC60LinkLineComputer_h
+
+#include "cmLinkLineComputer.h"
+
+class cmMSVC60LinkLineComputer : public cmLinkLineComputer
+{
+public:
+  cmMSVC60LinkLineComputer(cmOutputConverter* outputConverter,
+                           cmState::Directory stateDir);
+
+  std::string ConvertToLinkReference(std::string const& input) const
+    CM_OVERRIDE;
+};
+
+#endif

+ 19 - 3
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -5,6 +5,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
@@ -215,7 +216,14 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   this->LocalGenerator->AppendFlags(
   this->LocalGenerator->AppendFlags(
     linkFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
     linkFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
 
 
-  this->AddModuleDefinitionFlag(linkFlags);
+  {
+    CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer(
+      this->CreateLinkLineComputer(
+        this->LocalGenerator,
+        this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+
+    this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags);
+  }
 
 
   // Construct a list of files associated with this executable that
   // Construct a list of files associated with this executable that
   // may need to be cleaned.
   // may need to be cleaned.
@@ -296,10 +304,18 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
     // Set path conversion for link script shells.
     // Set path conversion for link script shells.
     this->LocalGenerator->SetLinkScriptShell(useLinkScript);
     this->LocalGenerator->SetLinkScriptShell(useLinkScript);
 
 
+    CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer(
+      this->CreateLinkLineComputer(
+        this->LocalGenerator,
+        this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+    linkLineComputer->SetForResponse(useResponseFileForLibs);
+    linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+    linkLineComputer->SetRelink(relink);
+
     // Collect up flags to link in needed libraries.
     // Collect up flags to link in needed libraries.
     std::string linkLibs;
     std::string linkLibs;
-    this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends,
-                         useWatcomQuote);
+    this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
+                         useResponseFileForLibs, depends);
 
 
     // Construct object file lists that may be needed to expand the
     // Construct object file lists that may be needed to expand the
     // rule.
     // rule.

+ 26 - 4
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -5,6 +5,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
@@ -159,7 +160,13 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
 
 
   this->LocalGenerator->AddConfigVariableFlags(
   this->LocalGenerator->AddConfigVariableFlags(
     extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
     extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
-  this->AddModuleDefinitionFlag(extraFlags);
+
+  CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer(
+    this->CreateLinkLineComputer(
+      this->LocalGenerator,
+      this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+
+  this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags);
 
 
   if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) {
   if (this->GeneratorTarget->GetProperty("LINK_WHAT_YOU_USE")) {
     this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed");
     this->LocalGenerator->AppendFlags(extraFlags, " -Wl,--no-as-needed");
@@ -184,7 +191,13 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
     extraFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
     extraFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig));
   this->LocalGenerator->AddConfigVariableFlags(
   this->LocalGenerator->AddConfigVariableFlags(
     extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
     extraFlags, "CMAKE_MODULE_LINKER_FLAGS", this->ConfigName);
-  this->AddModuleDefinitionFlag(extraFlags);
+
+  CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer(
+    this->CreateLinkLineComputer(
+      this->LocalGenerator,
+      this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+
+  this->AddModuleDefinitionFlag(linkLineComputer.get(), extraFlags);
 
 
   this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
   this->WriteLibraryRules(linkRuleVar, extraFlags, relink);
 }
 }
@@ -491,8 +504,17 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
     // Collect up flags to link in needed libraries.
     // Collect up flags to link in needed libraries.
     std::string linkLibs;
     std::string linkLibs;
     if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) {
     if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) {
-      this->CreateLinkLibs(linkLibs, relink, useResponseFileForLibs, depends,
-                           useWatcomQuote);
+
+      CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer(
+        this->CreateLinkLineComputer(
+          this->LocalGenerator,
+          this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+      linkLineComputer->SetForResponse(useResponseFileForLibs);
+      linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+      linkLineComputer->SetRelink(relink);
+
+      this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
+                           useResponseFileForLibs, depends);
     }
     }
 
 
     // Construct object file lists that may be needed to expand the
     // Construct object file lists that may be needed to expand the

+ 19 - 5
Source/cmMakefileTargetGenerator.cxx

@@ -10,6 +10,7 @@
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
 #include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
@@ -1588,15 +1589,28 @@ std::string cmMakefileTargetGenerator::CreateResponseFile(
   return responseFileName;
   return responseFileName;
 }
 }
 
 
+cmLinkLineComputer* cmMakefileTargetGenerator::CreateLinkLineComputer(
+  cmOutputConverter* outputConverter, cmState::Directory stateDir)
+{
+  if (this->Makefile->IsOn("MSVC60")) {
+    return this->GlobalGenerator->CreateMSVC60LinkLineComputer(outputConverter,
+                                                               stateDir);
+  }
+  return this->GlobalGenerator->CreateLinkLineComputer(outputConverter,
+                                                       stateDir);
+}
+
 void cmMakefileTargetGenerator::CreateLinkLibs(
 void cmMakefileTargetGenerator::CreateLinkLibs(
-  std::string& linkLibs, bool relink, bool useResponseFile,
-  std::vector<std::string>& makefile_depends, bool useWatcomQuote)
+  cmLinkLineComputer* linkLineComputer, std::string& linkLibs,
+  bool useResponseFile, std::vector<std::string>& makefile_depends)
 {
 {
   std::string frameworkPath;
   std::string frameworkPath;
   std::string linkPath;
   std::string linkPath;
-  this->LocalGenerator->OutputLinkLibraries(linkLibs, frameworkPath, linkPath,
-                                            *this->GeneratorTarget, relink,
-                                            useResponseFile, useWatcomQuote);
+  std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+  cmComputeLinkInformation* pcli =
+    this->GeneratorTarget->GetLinkInformation(config);
+  this->LocalGenerator->OutputLinkLibraries(pcli, linkLineComputer, linkLibs,
+                                            frameworkPath, linkPath);
   linkLibs = frameworkPath + linkPath + linkLibs;
   linkLibs = frameworkPath + linkPath + linkLibs;
 
 
   if (useResponseFile && linkLibs.find_first_not_of(' ') != linkLibs.npos) {
   if (useResponseFile && linkLibs.find_first_not_of(' ') != linkLibs.npos) {

+ 7 - 3
Source/cmMakefileTargetGenerator.h

@@ -20,6 +20,7 @@ class cmGeneratedFileStream;
 class cmGeneratorTarget;
 class cmGeneratorTarget;
 class cmGlobalUnixMakefileGenerator3;
 class cmGlobalUnixMakefileGenerator3;
 class cmSourceFile;
 class cmSourceFile;
+class cmLinkLineComputer;
 
 
 /** \class cmMakefileTargetGenerator
 /** \class cmMakefileTargetGenerator
  * \brief Support Routines for writing makefiles
  * \brief Support Routines for writing makefiles
@@ -139,6 +140,9 @@ protected:
                         std::vector<std::string>& makefile_commands,
                         std::vector<std::string>& makefile_commands,
                         std::vector<std::string>& makefile_depends);
                         std::vector<std::string>& makefile_depends);
 
 
+  cmLinkLineComputer* CreateLinkLineComputer(
+    cmOutputConverter* outputConverter, cmState::Directory stateDir);
+
   /** Create a response file with the given set of options.  Returns
   /** Create a response file with the given set of options.  Returns
       the relative path from the target build working directory to the
       the relative path from the target build working directory to the
       response file name.  */
       response file name.  */
@@ -149,9 +153,9 @@ protected:
   bool CheckUseResponseFileForLibraries(std::string const& l) const;
   bool CheckUseResponseFileForLibraries(std::string const& l) const;
 
 
   /** Create list of flags for link libraries. */
   /** Create list of flags for link libraries. */
-  void CreateLinkLibs(std::string& linkLibs, bool relink, bool useResponseFile,
-                      std::vector<std::string>& makefile_depends,
-                      bool useWatcomQuote);
+  void CreateLinkLibs(cmLinkLineComputer* linkLineComputer,
+                      std::string& linkLibs, bool useResponseFile,
+                      std::vector<std::string>& makefile_depends);
 
 
   /** Create lists of object files for linking and cleaning.  */
   /** Create lists of object files for linking and cleaning.  */
   void CreateObjectLists(bool useLinkScript, bool useArchiveRules,
   void CreateObjectLists(bool useLinkScript, bool useArchiveRules,

+ 19 - 0
Source/cmNinjaLinkLineComputer.cxx

@@ -0,0 +1,19 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include "cmNinjaLinkLineComputer.h"
+#include "cmGlobalNinjaGenerator.h"
+
+cmNinjaLinkLineComputer::cmNinjaLinkLineComputer(
+  cmOutputConverter* outputConverter, cmState::Directory stateDir,
+  cmGlobalNinjaGenerator const* gg)
+  : cmLinkLineComputer(outputConverter, stateDir)
+  , GG(gg)
+{
+}
+
+std::string cmNinjaLinkLineComputer::ConvertToLinkReference(
+  std::string const& lib) const
+{
+  return GG->ConvertToNinjaPath(lib);
+}

+ 26 - 0
Source/cmNinjaLinkLineComputer.h

@@ -0,0 +1,26 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#ifndef cmNinjaLinkLineComputer_h
+#define cmNinjaLinkLineComputer_h
+
+#include "cmLinkLineComputer.h"
+#include "cmState.h"
+
+class cmGlobalNinjaGenerator;
+
+class cmNinjaLinkLineComputer : public cmLinkLineComputer
+{
+public:
+  cmNinjaLinkLineComputer(cmOutputConverter* outputConverter,
+                          cmState::Directory stateDir,
+                          cmGlobalNinjaGenerator const* gg);
+
+  std::string ConvertToLinkReference(std::string const& input) const
+    CM_OVERRIDE;
+
+private:
+  cmGlobalNinjaGenerator const* GG;
+};
+
+#endif

+ 11 - 4
Source/cmNinjaNormalTargetGenerator.cxx

@@ -8,6 +8,7 @@
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalNinjaGenerator.h"
 #include "cmGlobalNinjaGenerator.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalNinjaGenerator.h"
 #include "cmLocalNinjaGenerator.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
@@ -470,9 +471,15 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
   vars["TARGET_FILE"] =
   vars["TARGET_FILE"] =
     localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
     localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
 
 
-  localGen.GetTargetFlags(this->GetConfigName(), vars["LINK_LIBRARIES"],
-                          vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath,
-                          linkPath, &genTarget, useWatcomQuote);
+  CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer(
+    this->GetGlobalGenerator()->CreateLinkLineComputer(
+      this->GetLocalGenerator(),
+      this->GetLocalGenerator()->GetStateSnapshot().GetDirectory()));
+  linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
+
+  localGen.GetTargetFlags(
+    linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"],
+    vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget);
   if (this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
   if (this->GetMakefile()->IsOn("CMAKE_SUPPORT_WINDOWS_EXPORT_ALL_SYMBOLS") &&
       (gt.GetType() == cmState::SHARED_LIBRARY ||
       (gt.GetType() == cmState::SHARED_LIBRARY ||
        gt.IsExecutableWithExports())) {
        gt.IsExecutableWithExports())) {
@@ -497,7 +504,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
 
 
   this->addPoolNinjaVariable("JOB_POOL_LINK", &gt, vars);
   this->addPoolNinjaVariable("JOB_POOL_LINK", &gt, vars);
 
 
-  this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]);
+  this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]);
   vars["LINK_FLAGS"] =
   vars["LINK_FLAGS"] =
     cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
     cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
 
 

+ 5 - 2
Source/cmServerProtocol.cxx

@@ -7,6 +7,7 @@
 #include "cmFileMonitor.h"
 #include "cmFileMonitor.h"
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGenerator.h"
+#include "cmLinkLineComputer.h"
 #include "cmListFileCache.h"
 #include "cmListFileCache.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
@@ -728,8 +729,10 @@ static Json::Value DumpTarget(cmGeneratorTarget* target,
     std::string linkLanguageFlags;
     std::string linkLanguageFlags;
     std::string frameworkPath;
     std::string frameworkPath;
     std::string linkPath;
     std::string linkPath;
-    lg->GetTargetFlags(config, linkLibs, linkLanguageFlags, linkFlags,
-                       frameworkPath, linkPath, target, false);
+    cmLinkLineComputer linkLineComputer(lg,
+                                        lg->GetStateSnapshot().GetDirectory());
+    lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags,
+                       linkFlags, frameworkPath, linkPath, target);
 
 
     linkLibs = cmSystemTools::TrimWhitespace(linkLibs);
     linkLibs = cmSystemTools::TrimWhitespace(linkLibs);
     linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
     linkFlags = cmSystemTools::TrimWhitespace(linkFlags);

+ 5 - 2
Source/cmake.cxx

@@ -12,6 +12,7 @@
 #include "cmGeneratorTarget.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGenerator.h"
 #include "cmGlobalGeneratorFactory.h"
 #include "cmGlobalGeneratorFactory.h"
+#include "cmLinkLineComputer.h"
 #include "cmLocalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmMessenger.h"
 #include "cmMessenger.h"
@@ -582,8 +583,10 @@ bool cmake::FindPackage(const std::vector<std::string>& args)
     gg->CreateGenerationObjects();
     gg->CreateGenerationObjects();
     cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName());
     cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName());
     cmLocalGenerator* lg = gtgt->GetLocalGenerator();
     cmLocalGenerator* lg = gtgt->GetLocalGenerator();
-    lg->GetTargetFlags(buildType, linkLibs, flags, linkFlags, frameworkPath,
-                       linkPath, gtgt, false);
+    cmLinkLineComputer linkLineComputer(lg,
+                                        lg->GetStateSnapshot().GetDirectory());
+    lg->GetTargetFlags(&linkLineComputer, buildType, linkLibs, flags,
+                       linkFlags, frameworkPath, linkPath, gtgt);
     linkLibs = frameworkPath + linkPath + linkLibs;
     linkLibs = frameworkPath + linkPath + linkLibs;
 
 
     printf("%s\n", linkLibs.c_str());
     printf("%s\n", linkLibs.c_str());

+ 2 - 0
bootstrap

@@ -297,6 +297,8 @@ CMAKE_CXX_SOURCES="\
   cmFileTimeComparison \
   cmFileTimeComparison \
   cmGlobalUnixMakefileGenerator3 \
   cmGlobalUnixMakefileGenerator3 \
   cmLocalUnixMakefileGenerator3 \
   cmLocalUnixMakefileGenerator3 \
+  cmLinkLineComputer \
+  cmMSVC60LinkLineComputer \
   cmMakefileExecutableTargetGenerator \
   cmMakefileExecutableTargetGenerator \
   cmMakefileLibraryTargetGenerator \
   cmMakefileLibraryTargetGenerator \
   cmMakefileTargetGenerator \
   cmMakefileTargetGenerator \