From f3f57cc4edd528aaf0b8d8633d5f9990f0d804af Mon Sep 17 00:00:00 2001
From: Amine Najahi <anajahi@mathworks.com>
Date: Thu, 22 Apr 2021 20:26:30 +0100
Subject: NMake: Use UTF-8 with BOM if supported by nmake

Fixes: #21792
---
 Help/release/dev/nmake-utf8.rst         | 5 +++++
 Source/cmGeneratedFileStream.cxx        | 5 +++++
 Source/cmGlobalNMakeMakefileGenerator.h | 2 +-
 Source/cmMakefileTargetGenerator.cxx    | 3 ++-
 Source/cm_codecvt.cxx                   | 1 +
 Source/cm_codecvt.hxx                   | 1 +
 6 files changed, 15 insertions(+), 2 deletions(-)
 create mode 100644 Help/release/dev/nmake-utf8.rst

diff --git a/Help/release/dev/nmake-utf8.rst b/Help/release/dev/nmake-utf8.rst
new file mode 100644
index 0000000..ebbb45b
--- /dev/null
+++ b/Help/release/dev/nmake-utf8.rst
@@ -0,0 +1,5 @@
+nmake-utf8
+----------
+
+* The :generator:`NMake Makefiles` generator now encodes the generated
+  makefiles as UTF-8 with a BOM when using ``nmake`` from VS 9 or above.
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
index 43f384a..06778b1 100644
--- a/Source/cmGeneratedFileStream.cxx
+++ b/Source/cmGeneratedFileStream.cxx
@@ -42,6 +42,11 @@ cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name,
 #else
   static_cast<void>(encoding);
 #endif
+  if (encoding == codecvt::UTF8_WITH_BOM) {
+    // Write the BOM encoding header into the file
+    char magic[] = { char(0xEF), char(0xBB), char(0xBF) };
+    this->write(magic, 3);
+  }
 }
 
 cmGeneratedFileStream::~cmGeneratedFileStream()
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index ed52378..402b89f 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -31,7 +31,7 @@ public:
   /** Get encoding used by generator for makefile files */
   codecvt::Encoding GetMakefileEncoding() const override
   {
-    return codecvt::ANSI;
+    return this->NMakeSupportsUTF8 ? codecvt::UTF8_WITH_BOM : codecvt::ANSI;
   }
 
   /** Get the documentation entry for this generator.  */
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index fa469ed..5b6c58d 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -2058,7 +2058,8 @@ std::string cmMakefileTargetGenerator::CreateResponseFile(
   // Create the response file.
   std::string responseFileNameFull =
     cmStrCat(this->TargetBuildDirectoryFull, '/', name);
-  cmGeneratedFileStream responseStream(responseFileNameFull);
+  cmGeneratedFileStream responseStream(
+    responseFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
   responseStream.SetCopyIfDifferent(true);
   responseStream << options << "\n";
 
diff --git a/Source/cm_codecvt.cxx b/Source/cm_codecvt.cxx
index 15f83e0..216d3f0 100644
--- a/Source/cm_codecvt.cxx
+++ b/Source/cm_codecvt.cxx
@@ -31,6 +31,7 @@ codecvt::codecvt(Encoding e)
     // We don't know which ANSI encoding to use for other platforms than
     // Windows so we don't do any conversion there
     case codecvt::UTF8:
+    case codecvt::UTF8_WITH_BOM:
     // Assume internal encoding is UTF-8
     case codecvt::None:
     // No encoding
diff --git a/Source/cm_codecvt.hxx b/Source/cm_codecvt.hxx
index 1860211..b73204f 100644
--- a/Source/cm_codecvt.hxx
+++ b/Source/cm_codecvt.hxx
@@ -14,6 +14,7 @@ public:
   {
     None,
     UTF8,
+    UTF8_WITH_BOM,
     ANSI
   };
 
-- 
cgit v0.12