参考资料1
常规MinGw-w64编译步骤(以GCC13.2.0为例)
-
环境:Windows-64bit or Linux + Wine-64bit
-
安装MSYS2:Install MSYS2 from:
http://sourceforge.net/projects/msys2/
(MSYS2 wiki: https://www.msys2.org/wiki/MSYS2-installation/)
-
把来自niXman的编译脚本放到以下目录
Get the scripts into <msys root>/home/<user>/mingw-builds
:
cd && git clone <paste correct url>
git clone https://github.com/niXman/mingw-builds.git
-
在MSYS2环境中删除以下文件夹或重命名
In the MSYS2 file structure delete or rename the /mingw32
and /mingw64
directory.
-
从环境变量中删除指向任何预安装的 MinGW 的路径
Delete the paths pointing to any preinstalled MinGW from the PATH
environment variable.
-
进入以下目录
Go into the MinGW-builds root directory:
cd && cd mingw-builds
-
编译选项Options
-
运行Run: (注意:编译运行前需做本地化修改,详见下文)
1
2
|
cd mingw-builds
./build --mode=gcc-13.2.0 --buildroot=/c/buildroot --jobs=4 --rev=0 --with-default-msvcrt=ucrt --rt-version=v11 --threads=posix --exceptions=seh --arch=x86_64 --bin-compress --enable-languages=c,c++,fortran
|
- 编译得到的编译器为:
c:\buildroot\archives\x86_64-13.2.0-release-posix-seh-ucrt-rt_v11-rev0.7z
其中c:\buildroot
为上一步由--buildroot=/c/buildroot
指定
本地化需要修改内容(以GCC13.2.0为例)-按参考资料2
- 编译前修改编译参数:
脚本文件:scripts/gcc-13.2.0.sh
将--disable-nls
修改为--enable-nls
- (可选)将仓库中所有文件的
--disable-nls
修改为--enable-nls
- 对GCC13.2.0源码打补丁
- 按
参考资料2
制作补丁文件patches\gcc\gcc13.2.0-fix-localedir.patch
(注意在Windows下要dos2unix)
- 在
scripts\gcc-13.2.0.sh
加入上述补丁文件
结果说明-按参考资料2
-
情况1,只改第1条
需依赖C:\msys64\mingw64\share\locale\zh_CN\LC_MESSAGES\gcc.mo
才能输出中文。
其中C:\msys64\mingw64
是编译MinGW64 GCC13.2.0
时用的编译器的路径。视编译情况需调整。gcc.exe、g++.exe、cc1.exe、cc1plus.exe
都依赖这个路径。
-
情况2,全改第1、2条
Windows 7/8.1控制台正常。windows 10/11控制台正常输出错误提示时中文乱码(如果换为GCC11.4.0也正常)。
但在小熊猫C++使用此编译器时,Windows 7/8.1/10/11全部正常。因为其使用管道。
网友猜测可能原因:
GCC为了兼容Windows残废的VT序列用力过猛,结果遇到真支持VT序列的Windows就抓瞎了
-
参考资料2
相比参考资料3
的优点:
- 不用再复制一份语言文件
- 支持中文编译器路径、支持中文源文件路径、支持中文源文件名,均含调试
本地化需要修改内容(以GCC13.2.0为例)-按参考资料3
- 编译前修改编译参数:
脚本文件:scripts/gcc-13.2.0.sh
将--disable-nls
修改为--enable-nls
- (可选)将仓库中所有文件的
--disable-nls
修改为--enable-nls
- 修改gcc源码中gcc\intl.cc文件进行修改,详见下文:参考资料3。
这里要重点说明的是,gcc的源码是编译脚本自动下载的,正常见情况下无法修改。
这里提供几个方法:
- 方法1:参考上文添加补丁文件
- 方法2:编译完成后去
c:\buildroot\src
目录找到gcc-13.2.0\gcc\intl.cc
修改,然后重新编译。
- 方法3:
脚本文件:scripts/gcc-13.2.0.sh
中有gcc的源码的下载地址,下载下来修改代码后再传到网上(我用了我自己的云服务器),并将这个下载地址修改为你的地址。
1
2
3
4
5
6
7
8
|
# 脚本文件:scripts/gcc-13.2.0.sh
PKG_VERSION=13.2.0
PKG_NAME=gcc-${PKG_VERSION}
PKG_DIR_NAME=gcc-${PKG_VERSION}
PKG_TYPE=.tar.xz
PKG_URLS=(
"https://ftpmirror.gnu.org/gnu/gcc/gcc-${PKG_VERSION}/gcc-${PKG_VERSION}${PKG_TYPE}"
)
|
上述网址即https://ftpmirror.gnu.org/gnu/gcc/gcc-13.2.0/gcc-13.2.0.tar.xz
我这里改为了http://www.yuanpeirong.com/gcc-13.2.0.tar.xz
因资金有限,编译后,现在我已经在我的服务器上删除了,你不用找了
- 编译完成后解压编译器:
x86_64-13.2.0-release-posix-seh-ucrt-rt_v11-rev0.7z
在mingw64
目录下,将share\locale\zh_CN\LC_MESSAGES\*.*
拷贝一份至
libexec\gcc\x86_64-w64-mingw32\
下,最后形成的路径为
libexec\gcc\x86_64-w64-mingw32\share\locale\zh_CN\LC_MESSAGES\*.*
结果说明-按参考资料3
-
情况1,只改第1条
需依赖C:\msys64\mingw64\share\locale\zh_CN\LC_MESSAGES\gcc.mo
才能输出中文。
其中C:\msys64\mingw64
是编译MinGW64 GCC13.2.0
时用的编译器的路径。视编译情况需调整。gcc.exe、g++.exe、cc1.exe、cc1plus.exe
都依赖这个路径。
-
情况2,只改第1、2条
只有gcc -v、gcc --version、gcc --help
能输出中文。
-
情况3,全改第1、2、3条
Windows 7/8.1控制台正常。windows 10/11控制台正常输出错误提示时中文乱码。
但在小熊猫C++使用此编译器时,Windows 7/8.1/10/11全部正常。因为其使用管道。
网友猜测可能原因:
GCC为了兼容Windows残废的VT序列用力过猛,结果遇到真支持VT序列的Windows就抓瞎了
用Github Action自动编译
可快速编译各个版本,此处不另外展开
参考资料2:网友cyano.CN
的NLS补丁
- 来源:https://github.com/redpanda-cpp/mingw-lite/blob/nls/patch/gcc-fix-localedir.patch
- 其修改了
gcc-13.2.0/gcc/intl.cc
和gcc-13.2.0/libcpp/init.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
diff --unified --recursive --text gcc-13.2.0.orig/gcc/intl.cc gcc-13.2.0/gcc/intl.cc
--- gcc-13.2.0.orig/gcc/intl.cc 2023-07-27 16:13:04.000000000 +0800
+++ gcc-13.2.0/gcc/intl.cc 2024-02-14 13:43:07.483162078 +0800
@@ -22,6 +22,12 @@
#include "coretypes.h"
#include "intl.h"
+#ifdef _WIN32
+#include <string>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
#ifdef HAVE_LANGINFO_CODESET
#include <langinfo.h>
#endif
@@ -55,7 +61,32 @@
setlocale (LC_ALL, "");
#endif
+#ifdef _WIN32
+ {
+ /* Find the locale directory.
+ TODO: Use config instead of hard-coded dirs. */
+ char buf[MAX_PATH] = {0};
+ GetModuleFileNameA(NULL, buf, MAX_PATH);
+ std::string exe_path = buf;
+
+ /* \libexec\gcc\<triplet>\<version>\cc1.exe */
+ size_t pos = exe_path.rfind(R"(\libexec\gcc\)");
+ if (pos == std::string::npos) {
+ /* \bin\gcc.exe */
+ pos = exe_path.rfind(R"(\bin\)");
+ }
+
+ if (pos == std::string::npos) {
+ (void) bindtextdomain ("gcc", LOCALEDIR);
+ } else {
+ std::string real_prefix = exe_path.substr(0, pos);
+ std::string win32_locale_dir = real_prefix + "/share/locale";
+ (void) bindtextdomain ("gcc", win32_locale_dir.c_str());
+ }
+ }
+#else
(void) bindtextdomain ("gcc", LOCALEDIR);
+#endif
(void) textdomain ("gcc");
/* Opening quotation mark. */
diff --unified --recursive --text gcc-13.2.0.orig/libcpp/init.cc gcc-13.2.0/libcpp/init.cc
--- gcc-13.2.0.orig/libcpp/init.cc 2023-07-27 16:13:07.000000000 +0800
+++ gcc-13.2.0/libcpp/init.cc 2024-02-14 13:42:44.969838638 +0800
@@ -26,6 +26,12 @@
#include "localedir.h"
#include "filenames.h"
+#ifdef _WIN32
+#include <string>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
#ifndef ENABLE_CANONICAL_SYSTEM_HEADERS
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
#define ENABLE_CANONICAL_SYSTEM_HEADERS 1
@@ -181,8 +187,33 @@
init_trigraph_map ();
#ifdef ENABLE_NLS
+#ifdef _WIN32
+ {
+ /* Find the locale directory.
+ TODO: Use config instead of hard-coded dirs. */
+ char buf[MAX_PATH] = {0};
+ GetModuleFileNameA(NULL, buf, MAX_PATH);
+ std::string exe_path = buf;
+
+ /* \libexec\gcc\<triplet>\<version>\cc1.exe */
+ size_t pos = exe_path.rfind(R"(\libexec\gcc\)");
+ if (pos == std::string::npos) {
+ /* \bin\gcc.exe */
+ pos = exe_path.rfind(R"(\bin\)");
+ }
+
+ if (pos == std::string::npos) {
+ (void) bindtextdomain (PACKAGE, LOCALEDIR);
+ } else {
+ std::string real_prefix = exe_path.substr(0, pos);
+ std::string win32_locale_dir = real_prefix + "/share/locale";
+ (void) bindtextdomain (PACKAGE, win32_locale_dir.c_str());
+ }
+ }
+#else
(void) bindtextdomain (PACKAGE, LOCALEDIR);
#endif
+#endif
}
}
|
参考资料3
《MinGW/GCC 编译器修改 gettext 初始化路径使之能在任意位置输出中文消息》
来源:https://blog.csdn.net/hackpascal/article/details/15222083
原文摘抄如下:
GCC 编译器支持 gettext 的本地化,MinGW 也一样,只是可惜他们在内部实现时使用了绝对路径。这个绝对路径的前缀(prefix) 由编译时传递给 configure 的 –prefix 设定,这样就导致了 MinGW 只有在指定的位置上才能实现编译消息本地化。
我所做的就是让 GCC 在初始化 gettext 时使用相对路径,这样就能使 MinGW 在任何地方都能使用本地化的字符串了。包含文件搜索路径也同理。
通过查找 bindtextdomain 函数可以知道 gcc 对 gettext 的初始化在 gcc\intl.cc 中完成。包含文件搜索路径定义在 incpath.c 中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
void
gcc_init_libintl (void)
{
#ifdef HAVE_LC_MESSAGES
setlocale (LC_CTYPE, "");
setlocale (LC_MESSAGES, "");
#else
setlocale (LC_ALL, "");
#endif
(void) bindtextdomain ("gcc", LOCALEDIR);
(void) textdomain ("gcc");
/* Opening quotation mark. */
open_quote = _("`");
/* Closing quotation mark. */
close_quote = _("'");
#if defined HAVE_LANGINFO_CODESET
locale_encoding = nl_langinfo (CODESET);
if (locale_encoding != NULL
&& (!strcasecmp (locale_encoding, "utf-8")
|| !strcasecmp (locale_encoding, "utf8")))
locale_utf8 = true;
#endif
if (!strcmp (open_quote, "`") && !strcmp (close_quote, "'"))
{
/* Untranslated quotes that it may be possible to replace with
U+2018 and U+2019; but otherwise use "'" instead of "`" as
opening quote. */
open_quote = "'";
#if defined HAVE_LANGINFO_CODESET
if (locale_utf8)
{
open_quote = "\xe2\x80\x98";
close_quote = "\xe2\x80\x99";
}
#endif
}
}
|
由于我所做的是针对 Windows 下的修改,因此所有改动都要加上 #ifdef WIN32 … #endif
首先在开头加上:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#ifdef WIN32
#include <windows.h>
BOOL DirectoryExists(LPSTR lpszPath)
{
WIN32_FIND_DATA wfd;
BOOL bResult = FALSE;
HANDLE hFind = FindFirstFile(lpszPath, &wfd);
if ((hFind != INVALID_HANDLE_VALUE) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
bResult = TRUE;
}
FindClose(hFind);
return bResult;
}
#endif
|
其中 DirectoryExists 是用来判断路径是否存在的。
然后修改 (void) bindtextdomain (“gcc”, LOCALEDIR); 为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#ifndef WIN32
(void) bindtextdomain ("gcc", LOCALEDIR);
#else
DWORD dwSize = MAX_PATH + 20;
LPSTR lpszName = (LPSTR) xmalloc(dwSize);
DWORD dwRealSize = GetModuleFileNameA(NULL, lpszName, dwSize) + 1;
if (dwRealSize > dwSize)
{
lpszName = (LPSTR) xrealloc(lpszName, dwSize + 20);
GetModuleFileNameA(NULL, lpszName, dwRealSize + 20);
}
/* 去掉文件名 */
int l = strlen(lpszName);
while (l >= 0)
{
if (lpszName[l] == '\\')
break;
l--;
}
lpszName[l] = 0;
/* 去掉一层文件夹 */
l = strlen(lpszName);
while (l > 0)
{
if (lpszName[l] == '\\')
break;
l--;
}
/* 判断是否到根路径 */
if (lpszName[l] != '\\')
(void) bindtextdomain ("gcc", LOCALEDIR);
else
{
// 连接上 share\locale
lpszName[l + 1] = 0;
strcat(lpszName, "share\\locale");
if (DirectoryExists(lpszName))
(void) bindtextdomain ("gcc", lpszName);
else
(void) bindtextdomain ("gcc", LOCALEDIR);
}
free(lpszName);
#endif
|
这样重新编译后,无论 MinGW 位置在哪,它都能显示翻译后的消息了。