From 413d26030f559c9871d94b7c99cda305d53525c8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 10 Apr 2020 12:53:01 -0400 Subject: cmGlobalNinjaGenerator: Remove outdated comment --- Source/cmGlobalNinjaGenerator.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 5a31ab2..b33afff 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -436,8 +436,6 @@ cmGlobalNinjaGenerator::cmGlobalNinjaGenerator(cmake* cm) #ifdef _WIN32 cm->GetState()->SetWindowsShell(true); #endif - // // Ninja is not ported to non-Unix OS yet. - // this->ForceUnixPaths = true; this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake"; } -- cgit v0.12 From 1639ee70ef7986c4c6ad72db1b2552bcaa5b88fa Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 10 Apr 2020 11:30:24 -0400 Subject: cmDepends: Update types to always use a Makefile generator We only use these classes with a `cmLocalUnixMakefileGenerator3`. Construct using that type instead of just `cmLocalGenerator` so that the Makefile-specific methods are available. --- Source/cmDepends.cxx | 4 ++-- Source/cmDepends.h | 12 ++++++++---- Source/cmDependsC.cxx | 7 ++++--- Source/cmDependsC.h | 4 ++-- Source/cmDependsFortran.cxx | 4 ++-- Source/cmDependsFortran.h | 4 ++-- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index d4e8da6..d8aa730 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -9,12 +9,12 @@ #include "cmFileTime.h" #include "cmFileTimeCache.h" #include "cmGeneratedFileStream.h" -#include "cmLocalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -cmDepends::cmDepends(cmLocalGenerator* lg, std::string targetDir) +cmDepends::cmDepends(cmLocalUnixMakefileGenerator3* lg, std::string targetDir) : LocalGenerator(lg) , TargetDirectory(std::move(targetDir)) { diff --git a/Source/cmDepends.h b/Source/cmDepends.h index d938775..8cf528f 100644 --- a/Source/cmDepends.h +++ b/Source/cmDepends.h @@ -12,7 +12,7 @@ #include class cmFileTimeCache; -class cmLocalGenerator; +class cmLocalUnixMakefileGenerator3; /** \class cmDepends * \brief Dependency scanner superclass. @@ -29,7 +29,8 @@ public: public: /** Instances need to know the build directory name and the relative 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& operator=(cmDepends const&) = delete; @@ -38,7 +39,10 @@ public: scanning dependencies. This is not a full local generator; it has been setup to do relative path conversions for the current directory. */ - void SetLocalGenerator(cmLocalGenerator* lg) { this->LocalGenerator = lg; } + void SetLocalGenerator(cmLocalUnixMakefileGenerator3* lg) + { + this->LocalGenerator = lg; + } /** Set the specific language to be scanned. */ void SetLanguage(const std::string& lang) { this->Language = lang; } @@ -92,7 +96,7 @@ protected: std::ostream& internalDepends); // The local generator. - cmLocalGenerator* LocalGenerator; + cmLocalUnixMakefileGenerator3* LocalGenerator; // Flag for verbose output. bool Verbose = false; diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 01bb6ed..0748c65 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -7,7 +7,7 @@ #include "cmsys/FStream.hxx" #include "cmFileTime.h" -#include "cmLocalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -22,8 +22,9 @@ 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) , ValidDeps(validDeps) { diff --git a/Source/cmDependsC.h b/Source/cmDependsC.h index 868c94a..e01faa4 100644 --- a/Source/cmDependsC.h +++ b/Source/cmDependsC.h @@ -16,7 +16,7 @@ #include "cmDepends.h" -class cmLocalGenerator; +class cmLocalUnixMakefileGenerator3; /** \class cmDependsC * \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 relative path from the build directory to the target file. */ cmDependsC(); - cmDependsC(cmLocalGenerator* lg, const std::string& targetDir, + cmDependsC(cmLocalUnixMakefileGenerator3* lg, const std::string& targetDir, const std::string& lang, const DependencyMap* validDeps); /** Virtual destructor to cleanup subclasses properly. */ diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 666306c..fe3411d 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -12,7 +12,7 @@ #include "cmFortranParser.h" /* Interface to parser object. */ #include "cmGeneratedFileStream.h" -#include "cmLocalGenerator.h" +#include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmStateDirectory.h" @@ -72,7 +72,7 @@ public: cmDependsFortran::cmDependsFortran() = default; -cmDependsFortran::cmDependsFortran(cmLocalGenerator* lg) +cmDependsFortran::cmDependsFortran(cmLocalUnixMakefileGenerator3* lg) : cmDepends(lg) , Internal(new cmDependsFortranInternals) { diff --git a/Source/cmDependsFortran.h b/Source/cmDependsFortran.h index e3e0d05..3e306dd 100644 --- a/Source/cmDependsFortran.h +++ b/Source/cmDependsFortran.h @@ -15,7 +15,7 @@ class cmDependsFortranInternals; class cmFortranSourceInfo; -class cmLocalGenerator; +class cmLocalUnixMakefileGenerator3; /** \class cmDependsFortran * \brief Dependency scanner for Fortran object files. @@ -31,7 +31,7 @@ public: path from the build directory to the target file, the source file from which to start scanning, the include file search path, and the target directory. */ - cmDependsFortran(cmLocalGenerator* lg); + cmDependsFortran(cmLocalUnixMakefileGenerator3* lg); /** Virtual destructor to cleanup subclasses properly. */ ~cmDependsFortran() override; -- cgit v0.12 From af7de05853f9ced4703b7dc470f7eb475f1ede9c Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 14 Apr 2020 08:15:30 -0400 Subject: Makefiles: Do not use '\#' escape sequence with Windows-style make tools Since commit fbf7a92975 (Makefile: Handle '#' in COMPILE_OPTIONS, 2014-08-12, v3.1.0-rc1~174^2) we escape `#` as `\#` in `flags.make` variable assignments so that they are not treated as a comment. Windows-style make tools like NMake do not interpret backslashes in that way. Other means will be needed to handle `#` in contexts where it is even possible. The test suite is not covering this for NMake anyway, and actually has a workaround in `Tests/TryCompile` for the old behavior, which we can now update. --- Source/cmGlobalBorlandMakefileGenerator.h | 1 + Source/cmGlobalUnixMakefileGenerator3.cxx | 6 ++++++ Source/cmGlobalUnixMakefileGenerator3.h | 3 +++ Source/cmMakefileTargetGenerator.cxx | 14 ++++++++++---- Tests/TryCompile/CMakeLists.txt | 2 +- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h index 9af0eac..3c97955 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.h +++ b/Source/cmGlobalBorlandMakefileGenerator.h @@ -46,6 +46,7 @@ public: bool AllowNotParallel() const override { return false; } bool AllowDeleteOnError() const override { return false; } + bool CanEscapeOctothorpe() const override { return true; } protected: std::vector GenerateBuildCommand( diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 582877f..3ace290 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -117,6 +117,12 @@ void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory( gt->ObjectDirectory = dir; } +bool cmGlobalUnixMakefileGenerator3::CanEscapeOctothorpe() const +{ + // Make tools that use UNIX-style '/' paths also support '\' escaping. + return this->ForceUnixPaths; +} + void cmGlobalUnixMakefileGenerator3::Configure() { // Initialize CMAKE_EDIT_COMMAND cache entry. diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 19b2b85..44a0fd6 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -157,6 +157,9 @@ public: /** Does the make tool tolerate .DELETE_ON_ERROR? */ virtual bool AllowDeleteOnError() const { return true; } + /** Does the make tool interpret '\#' as '#'? */ + virtual bool CanEscapeOctothorpe() const; + bool IsIPOSupported() const override { return true; } void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 5bb4c57..dc3a2a1 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -341,12 +341,16 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() << "\n"; } + bool const escapeOctothorpe = this->GlobalGenerator->CanEscapeOctothorpe(); + for (std::string const& language : languages) { std::string defines = this->GetDefines(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 << "_INCLUDES = " << includes << "\n\n"; @@ -357,7 +361,9 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() for (const std::string& arch : architectures) { std::string flags = this->GetFlags(language, this->GetConfigName(), arch); - cmSystemTools::ReplaceString(flags, "#", "\\#"); + if (escapeOctothorpe) { + cmSystemTools::ReplaceString(flags, "#", "\\#"); + } *this->FlagFileStream << language << "_FLAGS" << arch << " = " << flags << "\n\n"; } diff --git a/Tests/TryCompile/CMakeLists.txt b/Tests/TryCompile/CMakeLists.txt index 9ec9b70..df921d8 100644 --- a/Tests/TryCompile/CMakeLists.txt +++ b/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") string(REPLACE "\n" "\n " output " ${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}") message(SEND_ERROR "try_compile with bad#source.c failed without mentioning bad source:\n${output}") else() -- cgit v0.12 From ca343dad0782733e5e39e7f1427d613e1cad5cf9 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 14 Apr 2020 08:24:24 -0400 Subject: Makefiles: Convert paths with '#' on command-lines to short path on Windows In `ConvertToOutputForExisting` we convert paths with spaces to short paths on Windows for use on command lines, e.g. for include directories. Do the same for paths with `#` since tools like NMake do not have a way to reliably put `#` in variable assignments. --- Source/cmOutputConverter.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index 1c6fad1..68bf3af 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -26,7 +26,7 @@ std::string cmOutputConverter::ConvertToOutputForExisting( // already exists, we can use a short-path to reference it without a // space. if (this->GetState()->UseWindowsShell() && - remote.find(' ') != std::string::npos && + remote.find_first_of(" #") != std::string::npos && cmSystemTools::FileExists(remote)) { std::string tmp; if (cmSystemTools::GetShortPath(remote, tmp)) { -- cgit v0.12 From 031bfaa865956c101aff74d35573381ebe71f0a1 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 10 Apr 2020 12:08:20 -0400 Subject: Makefiles: Factor out makefile target path escaping and quoting Code paths that write makefile target paths use a combination of `cmSystemTools::ConvertToOutputPath` and `cmMakeSafe`. Some were missing the latter. Wrap these two steps up into a dedicated `ConvertToMakefilePath` method provided on both the local and global generators. --- Source/cmDependsC.cxx | 4 +-- Source/cmGlobalUnixMakefileGenerator3.cxx | 19 +++++++++++ Source/cmGlobalUnixMakefileGenerator3.h | 6 ++++ Source/cmLocalUnixMakefileGenerator3.cxx | 55 +++++++++---------------------- Source/cmLocalUnixMakefileGenerator3.h | 6 ++++ 5 files changed, 49 insertions(+), 41 deletions(-) diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 0748c65..4499a66 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -212,12 +212,12 @@ bool cmDependsC::WriteDependencies(const std::set& sources, // written by the original local generator for this directory // convert the dependencies to paths relative to the home output // 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'; for (std::string const& dep : dependencies) { makeDepends << obj_m << ": " - << cmSystemTools::ConvertToOutputPath( + << this->LocalGenerator->ConvertToMakefilePath( this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep)) << '\n'; diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 3ace290..8a41d49 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -486,6 +486,25 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2( } } +std::string cmGlobalUnixMakefileGenerator3::ConvertToMakefilePath( + std::string const& path) const +{ + std::string const& out = cmSystemTools::ConvertToOutputPath(path); + std::string result; + result.reserve(out.size()); + for (char c : out) { + switch (c) { + case '=': + result.append("$(EQUALS)"); + break; + default: + result.push_back(c); + break; + } + } + return result; +} + std::vector cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( const std::string& makeProgram, const std::string& /*projectName*/, diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index 44a0fd6..1caa4b7 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -136,6 +136,12 @@ public: or dependencies. */ 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 std::vector GenerateBuildCommand( const std::string& makeProgram, const std::string& projectName, diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 99428bc..aa8912e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -48,37 +48,6 @@ # include "cmDependsJava.h" #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. static std::string cmSplitExtension(std::string const& in, std::string& base) { @@ -498,6 +467,14 @@ const std::string& cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath() return this->HomeRelativeOutputPath; } +std::string cmLocalUnixMakefileGenerator3::ConvertToMakefilePath( + std::string const& path) const +{ + cmGlobalUnixMakefileGenerator3* gg = + static_cast(this->GlobalGenerator); + return gg->ConvertToMakefilePath(path); +} + void cmLocalUnixMakefileGenerator3::WriteMakeRule( std::ostream& os, const char* comment, const std::string& target, const std::vector& depends, @@ -528,7 +505,7 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } // Construct the left hand side of the rule. - std::string tgt = cmSystemTools::ConvertToOutputPath( + std::string tgt = this->ConvertToMakefilePath( this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), target)); const char* space = ""; @@ -542,30 +519,30 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( if (symbolic) { if (const char* sym = this->Makefile->GetDefinition("CMAKE_MAKE_SYMBOLIC_RULE")) { - os << cmMakeSafe(tgt) << space << ": " << sym << "\n"; + os << tgt << space << ": " << sym << "\n"; } } // Write the rule. if (depends.empty()) { // No dependencies. The commands will always run. - os << cmMakeSafe(tgt) << space << ":\n"; + os << tgt << space << ":\n"; } else { // Split dependencies into multiple rule lines. This allows for // very long dependency lists even on older make implementations. std::string binDir = this->GetBinaryDirectory(); 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. os << cmWrap("\t", commands, "", "\n") << "\n"; if (symbolic && !this->IsWatcomWMake()) { - os << ".PHONY : " << cmMakeSafe(tgt) << "\n"; + os << ".PHONY : " << tgt << "\n"; } os << "\n"; // Add the output to the local help if requested. diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 68eeb29..2b07952 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -46,6 +46,12 @@ public: // local generators StartOutputDirectory 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 void WriteMakeRule(std::ostream& os, const char* comment, const std::string& target, -- cgit v0.12 From d74e651b7834937a6761b880d4e713683f5a44e3 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 10 Apr 2020 15:15:21 -0400 Subject: Makefiles: Re-implement makefile target path escaping and quoting Previously we used `cmSystemTools::ConvertToOutputPath` which internally used KWSys methods * SystemTools::ConvertToUnixOutputPath * SystemTools::ConvertToWindowsOutputPath These were written in very early days of CMake and have some limitations: * They do not encode all characters. E.g. '#' is left out. * They attempt to do some path cleanup and handle existing quotes. These days CMake has clean unquoted paths already. * They attempted to encode paths both for makefile targets and for shell command lines. The latter use has mostly been replaced. * Choosing between the two methods depends on a global variable! Several code paths in CMake have to copy the global generator's member ForceUnixPaths variable over to the cmSystemTools global. Re-implement the `ConvertToMakefilePath` method to drop use of those methods. Compute suitable makefile target path escaping and quoting via local logic. Add support for more characters like '#'. Fixes: #20555 --- Source/cmGlobalUnixMakefileGenerator3.cxx | 63 ++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 8a41d49..5363ea5 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -486,24 +486,77 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2( } } -std::string cmGlobalUnixMakefileGenerator3::ConvertToMakefilePath( - std::string const& path) const +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) { - std::string const& out = cmSystemTools::ConvertToOutputPath(path); + bool const quote = path.find_first_of(" #") != std::string::npos; std::string result; - result.reserve(out.size()); - for (char c : out) { + 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 cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( -- cgit v0.12 From a4173ef1658078d4dde186489e136c805b370410 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 10 Apr 2020 15:15:27 -0400 Subject: Tests: Enable coverage of special chars in include dirs for Makefiles Issue: #20555 --- Tests/CMakeLists.txt | 2 ++ Tests/IncludeDirectories/CMakeLists.txt | 41 ++++++++++++++++++++++----------- Tests/IncludeDirectories/main.cpp | 3 +++ 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 6428235..cc2931b 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -3477,6 +3477,8 @@ ${CMake_SOURCE_DIR}/Utilities/Release/push.bash --dir dev -- '${CMake_BUILD_NIGH --build-two-config ${build_generator_args} --build-project IncludeDirectories + --build-options + -DMAKE_SUPPORTS_SPACES=${MAKE_SUPPORTS_SPACES} --test-command IncludeDirectories) list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/IncludeDirectories") diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt index 838a236..eb08676 100644 --- a/Tests/IncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/CMakeLists.txt @@ -66,21 +66,36 @@ else() endif() # 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") 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() add_library(ordertest ordertest.cpp) diff --git a/Tests/IncludeDirectories/main.cpp b/Tests/IncludeDirectories/main.cpp index 7368ee9..6dc88e2 100644 --- a/Tests/IncludeDirectories/main.cpp +++ b/Tests/IncludeDirectories/main.cpp @@ -8,6 +8,9 @@ # ifndef SPECIAL_DIR_H # error "SPECIAL_DIR_H not defined" # endif +#endif + +#ifdef INCLUDE_SPECIAL_SPACE_DIR # include "SpecialSpaceDir.h" # ifndef SPECIAL_SPACE_DIR_H # error "SPECIAL_SPACE_DIR_H not defined" -- cgit v0.12