Forráskód Böngészése

Merge topic 'makefile-target-special'

a4173ef165 Tests: Enable coverage of special chars in include dirs for Makefiles
d74e651b78 Makefiles: Re-implement makefile target path escaping and quoting
031bfaa865 Makefiles: Factor out makefile target path escaping and quoting
ca343dad07 Makefiles: Convert paths with '#' on command-lines to short path on Windows
af7de05853 Makefiles: Do not use '\#' escape sequence with Windows-style make tools
1639ee70ef cmDepends: Update types to always use a Makefile generator
413d26030f cmGlobalNinjaGenerator: Remove outdated comment

Acked-by: Kitware Robot <[email protected]>
Merge-request: !4605
Brad King 5 éve
szülő
commit
854cc83a76

+ 2 - 2
Source/cmDepends.cxx

@@ -9,12 +9,12 @@
 #include "cmFileTime.h"
 #include "cmFileTime.h"
 #include "cmFileTimeCache.h"
 #include "cmFileTimeCache.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
-#include "cmLocalGenerator.h"
+#include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
 
 
-cmDepends::cmDepends(cmLocalGenerator* lg, std::string targetDir)
+cmDepends::cmDepends(cmLocalUnixMakefileGenerator3* lg, std::string targetDir)
   : LocalGenerator(lg)
   : LocalGenerator(lg)
   , TargetDirectory(std::move(targetDir))
   , TargetDirectory(std::move(targetDir))
 {
 {

+ 8 - 4
Source/cmDepends.h

@@ -12,7 +12,7 @@
 #include <vector>
 #include <vector>
 
 
 class cmFileTimeCache;
 class cmFileTimeCache;
-class cmLocalGenerator;
+class cmLocalUnixMakefileGenerator3;
 
 
 /** \class cmDepends
 /** \class cmDepends
  * \brief Dependency scanner superclass.
  * \brief Dependency scanner superclass.
@@ -29,7 +29,8 @@ public:
 public:
 public:
   /** Instances need to know the build directory name and the relative
   /** Instances need to know the build directory name and the relative
       path from the build directory to the target file.  */
       path from the build directory to the target file.  */
-  cmDepends(cmLocalGenerator* lg = nullptr, std::string targetDir = "");
+  cmDepends(cmLocalUnixMakefileGenerator3* lg = nullptr,
+            std::string targetDir = "");
 
 
   cmDepends(cmDepends const&) = delete;
   cmDepends(cmDepends const&) = delete;
   cmDepends& operator=(cmDepends const&) = delete;
   cmDepends& operator=(cmDepends const&) = delete;
@@ -38,7 +39,10 @@ public:
       scanning dependencies.  This is not a full local generator; it
       scanning dependencies.  This is not a full local generator; it
       has been setup to do relative path conversions for the current
       has been setup to do relative path conversions for the current
       directory.  */
       directory.  */
-  void SetLocalGenerator(cmLocalGenerator* lg) { this->LocalGenerator = lg; }
+  void SetLocalGenerator(cmLocalUnixMakefileGenerator3* lg)
+  {
+    this->LocalGenerator = lg;
+  }
 
 
   /** Set the specific language to be scanned.  */
   /** Set the specific language to be scanned.  */
   void SetLanguage(const std::string& lang) { this->Language = lang; }
   void SetLanguage(const std::string& lang) { this->Language = lang; }
@@ -92,7 +96,7 @@ protected:
                         std::ostream& internalDepends);
                         std::ostream& internalDepends);
 
 
   // The local generator.
   // The local generator.
-  cmLocalGenerator* LocalGenerator;
+  cmLocalUnixMakefileGenerator3* LocalGenerator;
 
 
   // Flag for verbose output.
   // Flag for verbose output.
   bool Verbose = false;
   bool Verbose = false;

+ 6 - 5
Source/cmDependsC.cxx

@@ -7,7 +7,7 @@
 #include "cmsys/FStream.hxx"
 #include "cmsys/FStream.hxx"
 
 
 #include "cmFileTime.h"
 #include "cmFileTime.h"
-#include "cmLocalGenerator.h"
+#include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmStringAlgorithms.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmSystemTools.h"
@@ -22,8 +22,9 @@
 
 
 cmDependsC::cmDependsC() = default;
 cmDependsC::cmDependsC() = default;
 
 
-cmDependsC::cmDependsC(cmLocalGenerator* lg, const std::string& targetDir,
-                       const std::string& lang, const DependencyMap* validDeps)
+cmDependsC::cmDependsC(cmLocalUnixMakefileGenerator3* lg,
+                       const std::string& targetDir, const std::string& lang,
+                       const DependencyMap* validDeps)
   : cmDepends(lg, targetDir)
   : cmDepends(lg, targetDir)
   , ValidDeps(validDeps)
   , ValidDeps(validDeps)
 {
 {
@@ -211,12 +212,12 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
   // written by the original local generator for this directory
   // written by the original local generator for this directory
   // convert the dependencies to paths relative to the home output
   // convert the dependencies to paths relative to the home output
   // directory.  We must do the same here.
   // directory.  We must do the same here.
-  std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i);
+  std::string obj_m = this->LocalGenerator->ConvertToMakefilePath(obj_i);
   internalDepends << obj_i << '\n';
   internalDepends << obj_i << '\n';
 
 
   for (std::string const& dep : dependencies) {
   for (std::string const& dep : dependencies) {
     makeDepends << obj_m << ": "
     makeDepends << obj_m << ": "
-                << cmSystemTools::ConvertToOutputPath(
+                << this->LocalGenerator->ConvertToMakefilePath(
                      this->LocalGenerator->MaybeConvertToRelativePath(binDir,
                      this->LocalGenerator->MaybeConvertToRelativePath(binDir,
                                                                       dep))
                                                                       dep))
                 << '\n';
                 << '\n';

+ 2 - 2
Source/cmDependsC.h

@@ -16,7 +16,7 @@
 
 
 #include "cmDepends.h"
 #include "cmDepends.h"
 
 
-class cmLocalGenerator;
+class cmLocalUnixMakefileGenerator3;
 
 
 /** \class cmDependsC
 /** \class cmDependsC
  * \brief Dependency scanner for C and C++ object files.
  * \brief Dependency scanner for C and C++ object files.
@@ -27,7 +27,7 @@ public:
   /** Checking instances need to know the build directory name and the
   /** Checking instances need to know the build directory name and the
       relative path from the build directory to the target file.  */
       relative path from the build directory to the target file.  */
   cmDependsC();
   cmDependsC();
-  cmDependsC(cmLocalGenerator* lg, const std::string& targetDir,
+  cmDependsC(cmLocalUnixMakefileGenerator3* lg, const std::string& targetDir,
              const std::string& lang, const DependencyMap* validDeps);
              const std::string& lang, const DependencyMap* validDeps);
 
 
   /** Virtual destructor to cleanup subclasses properly.  */
   /** Virtual destructor to cleanup subclasses properly.  */

+ 2 - 2
Source/cmDependsFortran.cxx

@@ -12,7 +12,7 @@
 
 
 #include "cmFortranParser.h" /* Interface to parser object.  */
 #include "cmFortranParser.h" /* Interface to parser object.  */
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratedFileStream.h"
-#include "cmLocalGenerator.h"
+#include "cmLocalUnixMakefileGenerator3.h"
 #include "cmMakefile.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
 #include "cmOutputConverter.h"
 #include "cmStateDirectory.h"
 #include "cmStateDirectory.h"
@@ -70,7 +70,7 @@ public:
 
 
 cmDependsFortran::cmDependsFortran() = default;
 cmDependsFortran::cmDependsFortran() = default;
 
 
-cmDependsFortran::cmDependsFortran(cmLocalGenerator* lg)
+cmDependsFortran::cmDependsFortran(cmLocalUnixMakefileGenerator3* lg)
   : cmDepends(lg)
   : cmDepends(lg)
   , Internal(new cmDependsFortranInternals)
   , Internal(new cmDependsFortranInternals)
 {
 {

+ 2 - 2
Source/cmDependsFortran.h

@@ -15,7 +15,7 @@
 
 
 class cmDependsFortranInternals;
 class cmDependsFortranInternals;
 class cmFortranSourceInfo;
 class cmFortranSourceInfo;
-class cmLocalGenerator;
+class cmLocalUnixMakefileGenerator3;
 
 
 /** \class cmDependsFortran
 /** \class cmDependsFortran
  * \brief Dependency scanner for Fortran object files.
  * \brief Dependency scanner for Fortran object files.
@@ -31,7 +31,7 @@ public:
       path from the build directory to the target file, the source
       path from the build directory to the target file, the source
       file from which to start scanning, the include file search
       file from which to start scanning, the include file search
       path, and the target directory.  */
       path, and the target directory.  */
-  cmDependsFortran(cmLocalGenerator* lg);
+  cmDependsFortran(cmLocalUnixMakefileGenerator3* lg);
 
 
   /** Virtual destructor to cleanup subclasses properly.  */
   /** Virtual destructor to cleanup subclasses properly.  */
   ~cmDependsFortran() override;
   ~cmDependsFortran() override;

+ 1 - 0
Source/cmGlobalBorlandMakefileGenerator.h

@@ -46,6 +46,7 @@ public:
 
 
   bool AllowNotParallel() const override { return false; }
   bool AllowNotParallel() const override { return false; }
   bool AllowDeleteOnError() const override { return false; }
   bool AllowDeleteOnError() const override { return false; }
+  bool CanEscapeOctothorpe() const override { return true; }
 
 
 protected:
 protected:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(

+ 0 - 2
Source/cmGlobalNinjaGenerator.cxx

@@ -436,8 +436,6 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm)
 #ifdef _WIN32
 #ifdef _WIN32
   cm->GetState()->SetWindowsShell(true);
   cm->GetState()->SetWindowsShell(true);
 #endif
 #endif
-  // // Ninja is not ported to non-Unix OS yet.
-  // this->ForceUnixPaths = true;
   this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake";
   this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake";
 }
 }
 
 

+ 78 - 0
Source/cmGlobalUnixMakefileGenerator3.cxx

@@ -117,6 +117,12 @@ void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
   gt->ObjectDirectory = dir;
   gt->ObjectDirectory = dir;
 }
 }
 
 
+bool cmGlobalUnixMakefileGenerator3::CanEscapeOctothorpe() const
+{
+  // Make tools that use UNIX-style '/' paths also support '\' escaping.
+  return this->ForceUnixPaths;
+}
+
 void cmGlobalUnixMakefileGenerator3::Configure()
 void cmGlobalUnixMakefileGenerator3::Configure()
 {
 {
   // Initialize CMAKE_EDIT_COMMAND cache entry.
   // Initialize CMAKE_EDIT_COMMAND cache entry.
@@ -480,6 +486,78 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2(
   }
   }
 }
 }
 
 
+namespace {
+std::string ConvertToMakefilePathForUnix(std::string const& path)
+{
+  std::string result;
+  result.reserve(path.size());
+  for (char c : path) {
+    switch (c) {
+      case '=':
+        // We provide 'EQUALS = =' to encode '=' in a non-assignment case.
+        result.append("$(EQUALS)");
+        break;
+      case '$':
+        result.append("$$");
+        break;
+      case '\\':
+      case ' ':
+      case '#':
+        result.push_back('\\');
+        CM_FALLTHROUGH;
+      default:
+        result.push_back(c);
+        break;
+    }
+  }
+  return result;
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+std::string ConvertToMakefilePathForWindows(std::string const& path)
+{
+  bool const quote = path.find_first_of(" #") != std::string::npos;
+  std::string result;
+  result.reserve(path.size() + (quote ? 2 : 0));
+  if (quote) {
+    result.push_back('"');
+  }
+  for (char c : path) {
+    switch (c) {
+      case '=':
+        // We provide 'EQUALS = =' to encode '=' in a non-assignment case.
+        result.append("$(EQUALS)");
+        break;
+      case '$':
+        result.append("$$");
+        break;
+      case '/':
+        result.push_back('\\');
+        break;
+      default:
+        result.push_back(c);
+        break;
+    }
+  }
+  if (quote) {
+    result.push_back('"');
+  }
+  return result;
+}
+#endif
+}
+
+std::string cmGlobalUnixMakefileGenerator3::ConvertToMakefilePath(
+  std::string const& path) const
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  if (!this->ForceUnixPaths) {
+    return ConvertToMakefilePathForWindows(path);
+  }
+#endif
+  return ConvertToMakefilePathForUnix(path);
+}
+
 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
 cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& /*projectName*/,
   const std::string& makeProgram, const std::string& /*projectName*/,

+ 9 - 0
Source/cmGlobalUnixMakefileGenerator3.h

@@ -136,6 +136,12 @@ public:
       or dependencies.  */
       or dependencies.  */
   std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
   std::string GetEmptyRuleHackDepends() { return this->EmptyRuleHackDepends; }
 
 
+  /**
+   * Convert a file path to a Makefile target or dependency with
+   * escaping and quoting suitable for the generator's make tool.
+   */
+  std::string ConvertToMakefilePath(std::string const& path) const;
+
   // change the build command for speed
   // change the build command for speed
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     const std::string& makeProgram, const std::string& projectName,
     const std::string& makeProgram, const std::string& projectName,
@@ -157,6 +163,9 @@ public:
   /** Does the make tool tolerate .DELETE_ON_ERROR? */
   /** Does the make tool tolerate .DELETE_ON_ERROR? */
   virtual bool AllowDeleteOnError() const { return true; }
   virtual bool AllowDeleteOnError() const { return true; }
 
 
+  /** Does the make tool interpret '\#' as '#'?  */
+  virtual bool CanEscapeOctothorpe() const;
+
   bool IsIPOSupported() const override { return true; }
   bool IsIPOSupported() const override { return true; }
 
 
   void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
   void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;

+ 16 - 39
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -48,37 +48,6 @@
 #  include "cmDependsJava.h"
 #  include "cmDependsJava.h"
 #endif
 #endif
 
 
-// Escape special characters in Makefile dependency lines
-class cmMakeSafe
-{
-public:
-  cmMakeSafe(const char* s)
-    : Data(s)
-  {
-  }
-  cmMakeSafe(std::string const& s)
-    : Data(s.c_str())
-  {
-  }
-
-private:
-  const char* Data;
-  friend std::ostream& operator<<(std::ostream& os, cmMakeSafe const& self)
-  {
-    for (const char* c = self.Data; *c; ++c) {
-      switch (*c) {
-        case '=':
-          os << "$(EQUALS)";
-          break;
-        default:
-          os << *c;
-          break;
-      }
-    }
-    return os;
-  }
-};
-
 // Helper function used below.
 // Helper function used below.
 static std::string cmSplitExtension(std::string const& in, std::string& base)
 static std::string cmSplitExtension(std::string const& in, std::string& base)
 {
 {
@@ -498,6 +467,14 @@ const std::string& cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath()
   return this->HomeRelativeOutputPath;
   return this->HomeRelativeOutputPath;
 }
 }
 
 
+std::string cmLocalUnixMakefileGenerator3::ConvertToMakefilePath(
+  std::string const& path) const
+{
+  cmGlobalUnixMakefileGenerator3* gg =
+    static_cast<cmGlobalUnixMakefileGenerator3*>(this->GlobalGenerator);
+  return gg->ConvertToMakefilePath(path);
+}
+
 void cmLocalUnixMakefileGenerator3::WriteMakeRule(
 void cmLocalUnixMakefileGenerator3::WriteMakeRule(
   std::ostream& os, const char* comment, const std::string& target,
   std::ostream& os, const char* comment, const std::string& target,
   const std::vector<std::string>& depends,
   const std::vector<std::string>& depends,
@@ -528,7 +505,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule(
   }
   }
 
 
   // Construct the left hand side of the rule.
   // Construct the left hand side of the rule.
-  std::string tgt = cmSystemTools::ConvertToOutputPath(
+  std::string tgt = this->ConvertToMakefilePath(
     this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target));
     this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target));
 
 
   const char* space = "";
   const char* space = "";
@@ -542,30 +519,30 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule(
   if (symbolic) {
   if (symbolic) {
     if (const char* sym =
     if (const char* sym =
           this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) {
           this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) {
-      os << cmMakeSafe(tgt) << space << ": " << sym << "\n";
+      os << tgt << space << ": " << sym << "\n";
     }
     }
   }
   }
 
 
   // Write the rule.
   // Write the rule.
   if (depends.empty()) {
   if (depends.empty()) {
     // No dependencies.  The commands will always run.
     // No dependencies.  The commands will always run.
-    os << cmMakeSafe(tgt) << space << ":\n";
+    os << tgt << space << ":\n";
   } else {
   } else {
     // Split dependencies into multiple rule lines.  This allows for
     // Split dependencies into multiple rule lines.  This allows for
     // very long dependency lists even on older make implementations.
     // very long dependency lists even on older make implementations.
     std::string binDir = this->GetBinaryDirectory();
     std::string binDir = this->GetBinaryDirectory();
     for (std::string const& depend : depends) {
     for (std::string const& depend : depends) {
-      replace = depend;
-      replace = cmSystemTools::ConvertToOutputPath(
-        this->MaybeConvertToRelativePath(binDir, replace));
-      os << cmMakeSafe(tgt) << space << ": " << cmMakeSafe(replace) << "\n";
+      os << tgt << space << ": "
+         << this->ConvertToMakefilePath(
+              this->MaybeConvertToRelativePath(binDir, depend))
+         << '\n';
     }
     }
   }
   }
 
 
   // Write the list of commands.
   // Write the list of commands.
   os << cmWrap("\t", commands, "", "\n") << "\n";
   os << cmWrap("\t", commands, "", "\n") << "\n";
   if (symbolic && !this->IsWatcomWMake()) {
   if (symbolic && !this->IsWatcomWMake()) {
-    os << ".PHONY : " << cmMakeSafe(tgt) << "\n";
+    os << ".PHONY : " << tgt << "\n";
   }
   }
   os << "\n";
   os << "\n";
   // Add the output to the local help if requested.
   // Add the output to the local help if requested.

+ 6 - 0
Source/cmLocalUnixMakefileGenerator3.h

@@ -46,6 +46,12 @@ public:
   // local generators StartOutputDirectory
   // local generators StartOutputDirectory
   const std::string& GetHomeRelativeOutputPath();
   const std::string& GetHomeRelativeOutputPath();
 
 
+  /**
+   * Convert a file path to a Makefile target or dependency with
+   * escaping and quoting suitable for the generator's make tool.
+   */
+  std::string ConvertToMakefilePath(std::string const& path) const;
+
   // Write out a make rule
   // Write out a make rule
   void WriteMakeRule(std::ostream& os, const char* comment,
   void WriteMakeRule(std::ostream& os, const char* comment,
                      const std::string& target,
                      const std::string& target,

+ 10 - 4
Source/cmMakefileTargetGenerator.cxx

@@ -341,12 +341,16 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
                           << "\n";
                           << "\n";
   }
   }
 
 
+  bool const escapeOctothorpe = this->GlobalGenerator->CanEscapeOctothorpe();
+
   for (std::string const& language : languages) {
   for (std::string const& language : languages) {
     std::string defines = this->GetDefines(language, this->GetConfigName());
     std::string defines = this->GetDefines(language, this->GetConfigName());
     std::string includes = this->GetIncludes(language, this->GetConfigName());
     std::string includes = this->GetIncludes(language, this->GetConfigName());
-    // Escape comment characters so they do not terminate assignment.
-    cmSystemTools::ReplaceString(defines, "#", "\\#");
-    cmSystemTools::ReplaceString(includes, "#", "\\#");
+    if (escapeOctothorpe) {
+      // Escape comment characters so they do not terminate assignment.
+      cmSystemTools::ReplaceString(defines, "#", "\\#");
+      cmSystemTools::ReplaceString(includes, "#", "\\#");
+    }
     *this->FlagFileStream << language << "_DEFINES = " << defines << "\n\n";
     *this->FlagFileStream << language << "_DEFINES = " << defines << "\n\n";
     *this->FlagFileStream << language << "_INCLUDES = " << includes << "\n\n";
     *this->FlagFileStream << language << "_INCLUDES = " << includes << "\n\n";
 
 
@@ -357,7 +361,9 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
     for (const std::string& arch : architectures) {
     for (const std::string& arch : architectures) {
       std::string flags =
       std::string flags =
         this->GetFlags(language, this->GetConfigName(), arch);
         this->GetFlags(language, this->GetConfigName(), arch);
-      cmSystemTools::ReplaceString(flags, "#", "\\#");
+      if (escapeOctothorpe) {
+        cmSystemTools::ReplaceString(flags, "#", "\\#");
+      }
       *this->FlagFileStream << language << "_FLAGS" << arch << " = " << flags
       *this->FlagFileStream << language << "_FLAGS" << arch << " = " << flags
                             << "\n\n";
                             << "\n\n";
     }
     }

+ 1 - 1
Source/cmOutputConverter.cxx

@@ -26,7 +26,7 @@ std::string cmOutputConverter::ConvertToOutputForExisting(
   // already exists, we can use a short-path to reference it without a
   // already exists, we can use a short-path to reference it without a
   // space.
   // space.
   if (this->GetState()->UseWindowsShell() &&
   if (this->GetState()->UseWindowsShell() &&
-      remote.find(' ') != std::string::npos &&
+      remote.find_first_of(" #") != std::string::npos &&
       cmSystemTools::FileExists(remote)) {
       cmSystemTools::FileExists(remote)) {
     std::string tmp;
     std::string tmp;
     if (cmSystemTools::GetShortPath(remote, tmp)) {
     if (cmSystemTools::GetShortPath(remote, tmp)) {

+ 2 - 0
Tests/CMakeLists.txt

@@ -3477,6 +3477,8 @@ ${CMake_SOURCE_DIR}/Utilities/Release/push.bash --dir dev -- '${CMake_BUILD_NIGH
     --build-two-config
     --build-two-config
     ${build_generator_args}
     ${build_generator_args}
     --build-project IncludeDirectories
     --build-project IncludeDirectories
+    --build-options
+      -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES}
     --test-command IncludeDirectories)
     --test-command IncludeDirectories)
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/IncludeDirectories")
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/IncludeDirectories")
 
 

+ 28 - 13
Tests/IncludeDirectories/CMakeLists.txt

@@ -66,21 +66,36 @@ else()
 endif()
 endif()
 
 
 # Test escaping of special characters in include directory paths.
 # Test escaping of special characters in include directory paths.
-# FIXME: Implement full support in Makefile generators
-if(NOT CMAKE_GENERATOR MATCHES "Make")
-  set(special_chars "~@#$%^&=[]{}()!'")
-  if(NOT CMAKE_GENERATOR STREQUAL "Visual Studio 9 2008")
-    string(APPEND special_chars ",")
-  endif()
-  if(NOT WIN32 AND NOT CYGWIN)
-    string(APPEND special_chars "*?<>")
-  endif()
-  set(special_dir "${CMAKE_CURRENT_BINARY_DIR}/special-${special_chars}-include")
-  file(WRITE "${special_dir}/SpecialDir.h" "#define SPECIAL_DIR_H\n")
+set(special_chars "~@%&{}()!'")
+if(NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
+  # Watcom seems to have no way to encode these characters.
+  string(APPEND special_chars "#=[]")
+endif()
+if(NOT (MINGW AND CMAKE_GENERATOR MATCHES "(Unix|MSYS) Makefiles"))
+  # FIXME: Dependencies work but command-line generation does not handle '$'.
+  string(APPEND special_chars "$")
+endif()
+if(NOT CMAKE_GENERATOR MATCHES "(Borland|NMake) Makefiles")
+  # NMake and Borland seem to have no way to encode a single '^'.
+  string(APPEND special_chars "^")
+endif()
+if(NOT CMAKE_GENERATOR MATCHES "Visual Studio 9 2008|Watcom WMake")
+  # The vcproj format separates values with ','.
+  string(APPEND special_chars ",")
+endif()
+if(NOT WIN32 AND NOT CYGWIN)
+  string(APPEND special_chars "*?<>")
+endif()
+set(special_dir "${CMAKE_CURRENT_BINARY_DIR}/special-${special_chars}-include")
+file(WRITE "${special_dir}/SpecialDir.h" "#define SPECIAL_DIR_H\n")
+target_include_directories(IncludeDirectories PRIVATE "${special_dir}")
+target_compile_definitions(IncludeDirectories PRIVATE INCLUDE_SPECIAL_DIR)
+
+if(MAKE_SUPPORTS_SPACES)
   set(special_space_dir "${CMAKE_CURRENT_BINARY_DIR}/special-space ${special_chars}-include")
   set(special_space_dir "${CMAKE_CURRENT_BINARY_DIR}/special-space ${special_chars}-include")
   file(WRITE "${special_space_dir}/SpecialSpaceDir.h" "#define SPECIAL_SPACE_DIR_H\n")
   file(WRITE "${special_space_dir}/SpecialSpaceDir.h" "#define SPECIAL_SPACE_DIR_H\n")
-  target_include_directories(IncludeDirectories PRIVATE "${special_dir}" "${special_space_dir}")
-  target_compile_definitions(IncludeDirectories PRIVATE INCLUDE_SPECIAL_DIR)
+  target_include_directories(IncludeDirectories PRIVATE "${special_space_dir}")
+  target_compile_definitions(IncludeDirectories PRIVATE INCLUDE_SPECIAL_SPACE_DIR)
 endif()
 endif()
 
 
 add_library(ordertest ordertest.cpp)
 add_library(ordertest ordertest.cpp)

+ 3 - 0
Tests/IncludeDirectories/main.cpp

@@ -8,6 +8,9 @@
 #  ifndef SPECIAL_DIR_H
 #  ifndef SPECIAL_DIR_H
 #    error "SPECIAL_DIR_H not defined"
 #    error "SPECIAL_DIR_H not defined"
 #  endif
 #  endif
+#endif
+
+#ifdef INCLUDE_SPECIAL_SPACE_DIR
 #  include "SpecialSpaceDir.h"
 #  include "SpecialSpaceDir.h"
 #  ifndef SPECIAL_SPACE_DIR_H
 #  ifndef SPECIAL_SPACE_DIR_H
 #    error "SPECIAL_SPACE_DIR_H not defined"
 #    error "SPECIAL_SPACE_DIR_H not defined"

+ 1 - 1
Tests/TryCompile/CMakeLists.txt

@@ -187,7 +187,7 @@ try_compile(SHOULD_FAIL_DUE_TO_BAD_SOURCE
 if(SHOULD_FAIL_DUE_TO_BAD_SOURCE AND NOT CMAKE_GENERATOR MATCHES "Watcom WMake|NMake Makefiles")
 if(SHOULD_FAIL_DUE_TO_BAD_SOURCE AND NOT CMAKE_GENERATOR MATCHES "Watcom WMake|NMake Makefiles")
   string(REPLACE "\n" "\n  " output "  ${output}")
   string(REPLACE "\n" "\n  " output "  ${output}")
   message(SEND_ERROR "try_compile with bad#source.c did not fail:\n${output}")
   message(SEND_ERROR "try_compile with bad#source.c did not fail:\n${output}")
-elseif(NOT output MATCHES [[(bad#source\.c|bad\\)]])
+elseif(NOT output MATCHES [[(bad#source\.c|bad\.c|bad')]])
   string(REPLACE "\n" "\n  " output "  ${output}")
   string(REPLACE "\n" "\n  " output "  ${output}")
   message(SEND_ERROR "try_compile with bad#source.c failed without mentioning bad source:\n${output}")
   message(SEND_ERROR "try_compile with bad#source.c failed without mentioning bad source:\n${output}")
 else()
 else()