summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2021-02-26 16:49:50 (GMT)
committerKyle Edwards <kyle.edwards@kitware.com>2021-03-09 16:09:24 (GMT)
commit9af6e2e7b2940d5ba4d138f0df5950a675ec41c0 (patch)
treeed6741d332a8c57fe1d1dab37292a842b516cedd
parent4250c5f91b67a84318c31485a2ab36ab64967f21 (diff)
downloadCMake-9af6e2e7b2940d5ba4d138f0df5950a675ec41c0.zip
CMake-9af6e2e7b2940d5ba4d138f0df5950a675ec41c0.tar.gz
CMake-9af6e2e7b2940d5ba4d138f0df5950a675ec41c0.tar.bz2
Ninja: Use new wincodepage tool to determine encoding
Ninja 1.11 and later uses UTF-8 on Windows when possible, and includes a tool that reports the code page in use. Use this tool to determine what encoding to write the Ninja files in. Fixes: #21866
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx65
-rw-r--r--Source/cmGlobalNinjaGenerator.h5
-rw-r--r--Source/cmLocalNinjaGenerator.cxx5
3 files changed, 66 insertions, 9 deletions
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 7eac169..36be45c 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -9,6 +9,7 @@
#include <cm/iterator>
#include <cm/memory>
+#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/memory>
@@ -503,14 +504,7 @@ std::unique_ptr<cmLocalGenerator> cmGlobalNinjaGenerator::CreateLocalGenerator(
codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const
{
-#ifdef _WIN32
- // Ninja on Windows does not support non-ANSI characters.
- // https://github.com/ninja-build/ninja/issues/1195
- return codecvt::ANSI;
-#else
- // No encoding conversion needed on other platforms.
- return codecvt::None;
-#endif
+ return this->NinjaExpectedEncoding;
}
void cmGlobalNinjaGenerator::GetDocumentation(cmDocumentationEntry& entry)
@@ -731,6 +725,61 @@ void cmGlobalNinjaGenerator::CheckNinjaFeatures()
this->NinjaSupportsMetadataOnRegeneration = !cmSystemTools::VersionCompare(
cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
RequiredNinjaVersionForMetadataOnRegeneration().c_str());
+#ifdef _WIN32
+ this->NinjaSupportsCodePage = !cmSystemTools::VersionCompare(
+ cmSystemTools::OP_LESS, this->NinjaVersion.c_str(),
+ RequiredNinjaVersionForCodePage().c_str());
+ if (this->NinjaSupportsCodePage) {
+ this->CheckNinjaCodePage();
+ } else {
+ this->NinjaExpectedEncoding = codecvt::ANSI;
+ }
+#endif
+}
+
+void cmGlobalNinjaGenerator::CheckNinjaCodePage()
+{
+ std::vector<std::string> command{ this->NinjaCommand, "-t", "wincodepage" };
+ std::string output;
+ std::string error;
+ int result;
+ if (!cmSystemTools::RunSingleCommand(command, &output, &error, &result,
+ nullptr, cmSystemTools::OUTPUT_NONE)) {
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
+ cmStrCat("Running\n '",
+ cmJoin(command, "' '"),
+ "'\n"
+ "failed with:\n ",
+ error));
+ cmSystemTools::SetFatalErrorOccured();
+ } else if (result == 0) {
+ std::istringstream outputStream(output);
+ std::string line;
+ bool found = false;
+ while (cmSystemTools::GetLineFromStream(outputStream, line)) {
+ if (cmHasLiteralPrefix(line, "Build file encoding: ")) {
+ cm::string_view lineView(line);
+ cm::string_view encoding =
+ lineView.substr(cmStrLen("Build file encoding: "));
+ if (encoding == "UTF-8") {
+ // Ninja expects UTF-8. We use that internally. No conversion needed.
+ this->NinjaExpectedEncoding = codecvt::None;
+ } else {
+ this->NinjaExpectedEncoding = codecvt::ANSI;
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::WARNING,
+ "Could not determine Ninja's code page, defaulting to UTF-8");
+ this->NinjaExpectedEncoding = codecvt::None;
+ }
+ } else {
+ this->NinjaExpectedEncoding = codecvt::ANSI;
+ }
}
bool cmGlobalNinjaGenerator::CheckLanguages(
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 0c919ef..9f31708 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -388,6 +388,7 @@ public:
{
return "1.10.2";
}
+ static std::string RequiredNinjaVersionForCodePage() { return "1.11"; }
bool SupportsConsolePool() const;
bool SupportsImplicitOuts() const;
bool SupportsManifestRestat() const;
@@ -474,6 +475,7 @@ private:
std::string GetEditCacheCommand() const override;
bool FindMakeProgram(cmMakefile* mf) override;
void CheckNinjaFeatures();
+ void CheckNinjaCodePage();
bool CheckLanguages(std::vector<std::string> const& languages,
cmMakefile* mf) const override;
bool CheckFortran(cmMakefile* mf) const;
@@ -568,6 +570,9 @@ private:
bool NinjaSupportsUnconditionalRecompactTool = false;
bool NinjaSupportsMultipleOutputs = false;
bool NinjaSupportsMetadataOnRegeneration = false;
+ bool NinjaSupportsCodePage = false;
+
+ codecvt::Encoding NinjaExpectedEncoding = codecvt::None;
bool DiagnosedCxxModuleSupport = false;
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 8ed411a..050c907 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -97,9 +97,12 @@ void cmLocalNinjaGenerator::Generate()
// contains any non-ASCII characters and dependency checking will fail.
// As a workaround, leave the msvc_deps_prefix UTF-8 encoded even though
// the rest of the file is ANSI encoded.
- if (GetConsoleOutputCP() == CP_UTF8 && GetACP() != CP_UTF8) {
+ if (GetConsoleOutputCP() == CP_UTF8 && GetACP() != CP_UTF8 &&
+ this->GetGlobalGenerator()->GetMakefileEncoding() != codecvt::None) {
this->GetRulesFileStream().WriteRaw(showIncludesPrefix);
} else {
+ // Ninja 1.11 and above uses the UTF-8 code page if it's supported, so
+ // in that case we can write it normally without using raw bytes.
this->GetRulesFileStream() << showIncludesPrefix;
}
#else