1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-18 08:51:52 +08:00

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
This commit is contained in:
Kyle Edwards
2021-02-26 11:49:50 -05:00
parent 4250c5f91b
commit 9af6e2e7b2
3 changed files with 66 additions and 9 deletions

View File

@@ -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(

View File

@@ -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;

View File

@@ -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