使用 MinGW 中的 GCC 4.8.1 编译 GLib 2.38.1,执行 valac 编译会报如下错误:
ERROR:gspawn-win32-helper.c:226:WinMain: assertion failed: (__argc >=
ARG_COUNT)
阅读代码 glib/gspawn-win32-helper.c 发现此程序依赖于 __argc 和 __argv 全局变量进行参数访问,但有相关说明这两个全局变量是由 Microsoft 编译和 msvcrt.dll 提供,调试发现使用 MinGW 编译的 gspawn-win32-helper.exe 无论是否在命令行下进行都会导致上述错误,而且打印发现 __argc 永远是 0。
查看 /mingw/include/stdlib.h 会发现还有一组访问参数相关的全局变量 _argc 和 _argv,验证后是可行的。解决问题,下面是补丁文件:
From ebe6e6989b49bd119acc2d29b2f8ad0b6bb03313 Mon Sep 17 00:00:00 2001
From: Heiher
Date: Wed, 30 Oct 2013 22:17:29 +0800
Subject: [PATCH] glib/gspawn-win32-helper.c: Fix get arguments for GCC
compiler.
---
glib/gspawn-win32-helper.c | 61 ++++++++++++++++++++++++++--------------------
1 file changed, 34 insertions(+), 27 deletions(-)
diff --git a/glib/gspawn-win32-helper.c b/glib/gspawn-win32-helper.c
index 7896941..8d2bcbd 100644
--- a/glib/gspawn-win32-helper.c
+++ b/glib/gspawn-win32-helper.c
@@ -222,28 +222,35 @@ main (int ignored_argc, char **ignored_argv)
_CrtSetReportMode(_CRT_ASSERT, 0);
#endif
+#ifdef _MSC_VER // for Microsoft compiler
+#define __ARGC __argc
+#define __ARGV __argv
+#else // for GCC compiler (MinGW)
+#define __ARGC _argc
+#define __ARGV _argv
+#endif
- g_assert (__argc >= ARG_COUNT);
+ g_assert (__ARGC >= ARG_COUNT);
/* Fetch the wide-char argument vector */
__wgetmainargs (&argc, &wargv, &wenvp, 0, &si);
- /* We still have the system codepage args in __argv. We can look
+ /* We still have the system codepage args in __ARGV. We can look
* at the first args in which gspawn-win32.c passes us flags and
- * fd numbers in __argv, as we know those are just ASCII anyway.
+ * fd numbers in __ARGV, as we know those are just ASCII anyway.
*/
- g_assert (argc == __argc);
+ g_assert (argc == __ARGC);
/* argv[ARG_CHILD_ERR_REPORT] is the file descriptor number onto
* which write error messages.
*/
- child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]);
+ child_err_report_fd = atoi (__ARGV[ARG_CHILD_ERR_REPORT]);
/* Hack to implement G_SPAWN_FILE_AND_ARGV_ZERO. If
* argv[ARG_CHILD_ERR_REPORT] is suffixed with a '#' it means we get
* the program to run and its argv[0] separately.
*/
- if (__argv[ARG_CHILD_ERR_REPORT][strlen (__argv[ARG_CHILD_ERR_REPORT]) - 1] == '#')
+ if (__ARGV[ARG_CHILD_ERR_REPORT][strlen (__ARGV[ARG_CHILD_ERR_REPORT]) - 1] == '#')
argv_zero_offset++;
/* argv[ARG_HELPER_SYNC] is the file descriptor number we read a
@@ -252,16 +259,16 @@ main (int ignored_argc, char **ignored_argv)
* duplicate the process handle we sent it. Duplicating a handle
* from another process works only if that other process exists.
*/
- helper_sync_fd = atoi (__argv[ARG_HELPER_SYNC]);
+ helper_sync_fd = atoi (__ARGV[ARG_HELPER_SYNC]);
/* argv[ARG_STDIN..ARG_STDERR] are the file descriptor numbers that
* should be dup2'd to 0, 1 and 2. '-' if the corresponding fd
* should be left alone, and 'z' if it should be connected to the
* bit bucket NUL:.
*/
- if (__argv[ARG_STDIN][0] == '-')
+ if (__ARGV[ARG_STDIN][0] == '-')
; /* Nothing */
- else if (__argv[ARG_STDIN][0] == 'z')
+ else if (__ARGV[ARG_STDIN][0] == 'z')
{
fd = open ("NUL:", O_RDONLY);
if (fd != 0)
@@ -272,7 +279,7 @@ main (int ignored_argc, char **ignored_argv)
}
else
{
- fd = atoi (__argv[ARG_STDIN]);
+ fd = atoi (__ARGV[ARG_STDIN]);
if (fd != 0)
{
dup2 (fd, 0);
@@ -280,9 +287,9 @@ main (int ignored_argc, char **ignored_argv)
}
}
- if (__argv[ARG_STDOUT][0] == '-')
+ if (__ARGV[ARG_STDOUT][0] == '-')
; /* Nothing */
- else if (__argv[ARG_STDOUT][0] == 'z')
+ else if (__ARGV[ARG_STDOUT][0] == 'z')
{
fd = open ("NUL:", O_WRONLY);
if (fd != 1)
@@ -293,7 +300,7 @@ main (int ignored_argc, char **ignored_argv)
}
else
{
- fd = atoi (__argv[ARG_STDOUT]);
+ fd = atoi (__ARGV[ARG_STDOUT]);
if (fd != 1)
{
dup2 (fd, 1);
@@ -301,9 +308,9 @@ main (int ignored_argc, char **ignored_argv)
}
}
- if (__argv[ARG_STDERR][0] == '-')
+ if (__ARGV[ARG_STDERR][0] == '-')
; /* Nothing */
- else if (__argv[ARG_STDERR][0] == 'z')
+ else if (__ARGV[ARG_STDERR][0] == 'z')
{
fd = open ("NUL:", O_WRONLY);
if (fd != 2)
@@ -314,7 +321,7 @@ main (int ignored_argc, char **ignored_argv)
}
else
{
- fd = atoi (__argv[ARG_STDERR]);
+ fd = atoi (__ARGV[ARG_STDERR]);
if (fd != 2)
{
dup2 (fd, 2);
@@ -322,19 +329,19 @@ main (int ignored_argc, char **ignored_argv)
}
}
- /* __argv[ARG_WORKING_DIRECTORY] is the directory in which to run the
+ /* __ARGV[ARG_WORKING_DIRECTORY] is the directory in which to run the
* process. If "-", don't change directory.
*/
- if (__argv[ARG_WORKING_DIRECTORY][0] == '-' &&
- __argv[ARG_WORKING_DIRECTORY][1] == 0)
+ if (__ARGV[ARG_WORKING_DIRECTORY][0] == '-' &&
+ __ARGV[ARG_WORKING_DIRECTORY][1] == 0)
; /* Nothing */
else if (_wchdir (wargv[ARG_WORKING_DIRECTORY]) < 0)
write_err_and_exit (child_err_report_fd, CHILD_CHDIR_FAILED);
- /* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
+ /* __ARGV[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
* upwards should be closed
*/
- if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y')
+ if (__ARGV[ARG_CLOSE_DESCRIPTORS][0] == 'y')
for (i = 3; i < 1000; i++) /* FIXME real limit? */
if (i != child_err_report_fd && i != helper_sync_fd)
if (_get_osfhandle (i) != -1)
@@ -360,16 +367,16 @@ main (int ignored_argc, char **ignored_argv)
child_err_report_fd = dup_noninherited (child_err_report_fd, _O_WRONLY);
helper_sync_fd = dup_noninherited (helper_sync_fd, _O_RDONLY);
- /* __argv[ARG_WAIT] is "w" to wait for the program to exit */
- if (__argv[ARG_WAIT][0] == 'w')
+ /* __ARGV[ARG_WAIT] is "w" to wait for the program to exit */
+ if (__ARGV[ARG_WAIT][0] == 'w')
mode = P_WAIT;
else
mode = P_NOWAIT;
- /* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */
+ /* __ARGV[ARG_USE_PATH] is "y" to use PATH, otherwise not */
- /* __argv[ARG_PROGRAM] is executable file to run,
- * __argv[argv_zero_offset]... is its argv. argv_zero_offset equals
+ /* __ARGV[ARG_PROGRAM] is executable file to run,
+ * __ARGV[argv_zero_offset]... is its argv. argv_zero_offset equals
* ARG_PROGRAM unless G_SPAWN_FILE_AND_ARGV_ZERO was used, in which
* case we have a separate executable name and argv[0].
*/
@@ -379,7 +386,7 @@ main (int ignored_argc, char **ignored_argv)
*/
protect_wargv (wargv + argv_zero_offset, &new_wargv);
- if (__argv[ARG_USE_PATH][0] == 'y')
+ if (__ARGV[ARG_USE_PATH][0] == 'y')
handle = _wspawnvp (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv);
else
handle = _wspawnv (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv);
--
1.8.4.2
Over!