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