Discussion:
MinGW compilation errors with Gnulib wchar.h and wctype.h
(too old to reply)
Eli Zaretskii
2016-10-09 11:41:05 UTC
Permalink
Raw Message
Hi,

I recently upgraded to the latest version 3.22.2 of the MinGW runtime
from mingw.org. Building GDB 7.12 with the updated system headers
produces many compilation errors of the following 2 kinds:

1. Problems with wchar.h:

gcc -DHAVE_CONFIG_H -I. -I../.././gnulib/import -I.. -O2 -gdwarf-4 -g3 -D__USE_MINGW_ACCESS -MT dirname-lgpl.o -MD -MP -MF .deps/dirname-lgpl.Tpo -c -o dirname-lgpl.o ../.././gnulib/import/dirname-lgpl.c
In file included from ../.././gnulib/import/dirname-lgpl.c:23:0:
./wchar.h:514:1: error: unknown type name 'mbstate_t'
_GL_FUNCDECL_RPL (mbsinit, int, (const mbstate_t *ps));
^
./wchar.h:539:1: error: unknown type name 'mbstate_t'
_GL_FUNCDECL_RPL (mbrtowc, size_t,
^
./wchar.h:593:1: error: unknown type name 'mbstate_t'
_GL_FUNCDECL_RPL (mbsrtowcs, size_t,
^

2. Problems with wctype.h:

gcc -DHAVE_CONFIG_H -I. -I../.././gnulib/import -I.. -O2 -gdwarf-4 -g3 -D__USE_MINGW_ACCESS -MT fnmatch.o -MD -MP -MF .deps/fnmatch.Tpo -c -o fnmatch.o ../.././gnulib/import/fnmatch.c
In file included from ./wctype.h:59:0,
from d:\usr\include\ctype.h:55,
from ../.././gnulib/import/fnmatch.c:33:
d:\usr\include\wctype.h:140:43: error: redefinition of 'iswalnum'
__CRT_INLINE __cdecl __MINGW_NOTHROW int iswalnum (wint_t wc)
^
In file included from ./wctype.h:59:0,
from d:\usr\include\wchar.h:61,
from ./wchar.h:84,
from ./wctype.h:45,
from d:\usr\include\ctype.h:55,
from ../.././gnulib/import/fnmatch.c:33:
d:\usr\include\wctype.h:140:43: note: previous definition of 'iswalnum' was here

__CRT_INLINE __cdecl __MINGW_NOTHROW int iswalnum (wint_t wc)
^

And the same for many other isw* functions.

Both of these problems happen because MinGW headers sometimes exclude
portions of their content, depending on which other standard header
included them. Specifically, if wchar.h is included from string.h,
only a part of wchar.h is processed, and that part doesn't include the
definition of mbstate_t. Similarly, if wctype.h is included from
ctype.h, the wctype.h's idempotency guard is not processed, so
wctype.h could be processed again if included later, causing conflicts
with itself.

The corresponding Gnulib headers, wchar.h and wctype.c, don't expect
that to happen. When they #include_next the corresponding system
header, they assume that all of it was processed, and all of the
symbols, macros, data types, and prototypes defined by the C standard
for those headers are now defined, and can be used after
#include_next. The latest MinGW runtime violates that assumption,
which causes the above errors.

I'm not sure what would be the best way of avoiding these errors, but
I certainly hope some Gnulib solution could be found and implemented,
because otherwise many projects will fail to compile with MinGW.

TIA.
Paul Eggert
2016-10-09 17:10:38 UTC
Permalink
Raw Message
Post by Eli Zaretskii
I'm not sure what would be the best way of avoiding these errors
The usual method is to alter the gnulib .h file so that it merely include_next's
the system .h file when it detects that its partial inclusion is desired.
Something like this:

#ifdef __need_FILE
# @INCLUDE_NEXT@ @NEXT_STDIO_H@
#elif !defined _GL_STDIO_H
# @INCLUDE_NEXT@ @NEXT_STDIO_H@
# define _GL_STDIO_H
/* our own fixups */
#endif

It often gets more complicated than this (see lib/stdio.in.h), but that's the
basic idea.

It would be nicer if MinGW didn't have the problem in question. They could do
that by altering their include-file practices.
Eli Zaretskii
2016-10-09 17:31:53 UTC
Permalink
Raw Message
Date: Sun, 9 Oct 2016 10:10:38 -0700
Post by Eli Zaretskii
I'm not sure what would be the best way of avoiding these errors
The usual method is to alter the gnulib .h file so that it merely include_next's
the system .h file when it detects that its partial inclusion is desired.
#ifdef __need_FILE
#elif !defined _GL_STDIO_H
# define _GL_STDIO_H
/* our own fixups */
#endif
I'm not sure I understand how this is different from what
e.g. Gnulib's wchar.h already does. Can you point out the crucial
differences?
It would be nicer if MinGW didn't have the problem in question. They could do
that by altering their include-file practices.
I agree.

Thanks.
Paul Eggert
2016-10-09 17:35:14 UTC
Permalink
Raw Message
Post by Eli Zaretskii
I'm not sure I understand how this is different from what
e.g. Gnulib's wchar.h already does. Can you point out the crucial
differences?
Ah, I didn't look at lib/wchar.in.h. Yes, it's already doing that, with a
complicated ifdef that is supposed to work on MinGW. It isn't working for you, I
suppose because MinGW's include-file internals have changed. So, what's
different about your MinGW's include-file internals?

Maybe you're using a 64-bit MinGW, say? wchar.in.h seems to know only about 32-bit.
Eli Zaretskii
2016-10-09 17:47:38 UTC
Permalink
Raw Message
Date: Sun, 9 Oct 2016 10:35:14 -0700
Post by Eli Zaretskii
I'm not sure I understand how this is different from what
e.g. Gnulib's wchar.h already does. Can you point out the crucial
differences?
Ah, I didn't look at lib/wchar.in.h. Yes, it's already doing that, with a
complicated ifdef that is supposed to work on MinGW. It isn't working for you, I
suppose because MinGW's include-file internals have changed. So, what's
different about your MinGW's include-file internals?
Maybe you're using a 64-bit MinGW, say? wchar.in.h seems to know only about 32-bit.
No, I'm using 32-bit MinGW, just the latest release of their runtime
and headers.

What changed is that now MinGW string.h includes wchar.h, and wchar.h
has a special treatment of that inclusion. Here are the important
parts, indented 2 spaces:

#ifndef _WCHAR_H
#pragma GCC system_header

/* This header declares prototypes for wchar_t string functions, as are
* prescribed by ISO-C, but which MSVC also expects, (in contravention of
* ISO-C prescriptions), to find in <string.h>. To accommodate this MSVC
* anomaly, we make provision for <string.h> to include a selected subset
* of <wchar.h>; thus, we do not immediately define _WCHAR_T...
*/
#ifndef __STRING_H_SOURCED__
/* ...but defer it until we have confirmed that this is NOT inclusion for
* only this subset of <wchar.h> declarations.
*/
#define _WCHAR_H

[...]

#endif /* !__STRING_H_SOURCED__ */

/* This completes the set of declarations which are to be duplicated by
* inclusion of <string.h>; revert the declarative condition, to make it
* specific to <wchar.h> alone.
*/
#endif /* !(RC_INVOKED || (_WCHAR_H && _STRING_H)) */
#if defined _WCHAR_H && ! defined RC_INVOKED

#ifndef __STRICT_ANSI__
typedef wchar_t _Wint_t;
#endif

typedef int mbstate_t;
[...]

As you see, when wchar.h is included from string.h, only part of it is
processed, and that part doesn't include, for example, the definition
of mbstate_t, and all the prototypes of wchar.h functions after that.

What happens in many Gnulib files (for example, dirname-lgpl.c) is
that Gnulib's string.h is included, it includes MinGW string.h, which
includes Gnulib's wchar.h, and that in turn includes MinGW wchar.h.
But because string.h was included, __STRING_H_SOURCED__ is defined,
and MinGW's wchar.h doesn't define mbstate_t. Gnulib's wchar.h
doesn't expect that, and uses mbstate_t after #include_next.

Previously, MinGW string.h didn't include wchar.h, but instead
duplicated the relevant parts. So this problem didn't happen.
Paul Eggert
2016-10-09 18:07:46 UTC
Permalink
Raw Message
Post by Eli Zaretskii
But because string.h was included, __STRING_H_SOURCED__ is defined,
and MinGW's wchar.h doesn't define mbstate_t. Gnulib's wchar.h
I suggest adding a __STRING_H_SOURCED__ check to Gnulib's lib/wchar.in.h's
complicated test for the special invocation convention.
Eli Zaretskii
2016-10-10 13:26:53 UTC
Permalink
Raw Message
Date: Sun, 9 Oct 2016 11:07:46 -0700
Post by Eli Zaretskii
But because string.h was included, __STRING_H_SOURCED__ is defined,
and MinGW's wchar.h doesn't define mbstate_t. Gnulib's wchar.h
I suggest adding a __STRING_H_SOURCED__ check to Gnulib's lib/wchar.in.h's
complicated test for the special invocation convention.
Thanks for the guidance. Indeed, the two patches below fix both
issues for me. Please consider this for inclusion in Gnulib.


2016-10-08 Eli Zaretskii <***@gnu.org>

Fix wchar.h and wctype.h for MinGW 3.22.2

* lib/wchar.in.h [__MINGW32__]: Add one more condition for
special invocation, to fix issues with MinGW 3.22.2 wchar.h
when included from <string.h>.

* lib/wctype.in.h [__MINGW32__]: Add special invocation
convention for MinGW 3.22.2, to solve issues with their
wctype.h when included from <ctype.h>.

--- lib/wchar.in.h~0 2016-08-01 18:50:20.000000000 +0300
+++ lib/wchar.in.h 2016-10-10 15:44:45.178750000 +0300
@@ -35,6 +35,7 @@
|| (defined __hpux \
&& ((defined _INTTYPES_INCLUDED && !defined strtoimax) \
|| defined _GL_JUST_INCLUDE_SYSTEM_WCHAR_H)) \
+ || (defined __MINGW32__ && defined __STRING_H_SOURCED__) \
|| defined _GL_ALREADY_INCLUDING_WCHAR_H)
/* Special invocation convention:
- Inside glibc and uClibc header files, but not MinGW.
@@ -44,6 +45,8 @@
and once directly. In both situations 'wint_t' is not yet defined,
therefore we cannot provide the function overrides; instead include only
the system's <wchar.h>.
+ - With MinGW 3.22, when <string.h> includes <wchar.h>, only some part of
+ <wchar.h> is actually processed, and that doesn't include 'mbstate_t'.
- On IRIX 6.5, similarly, we have an include <wchar.h> -> <wctype.h>, and
the latter includes <wchar.h>. But here, we have no way to detect whether
<wctype.h> is completely included or is still being included. */


--- lib/wctype.in.h~0 2016-08-01 18:50:20.000000000 +0300
+++ lib/wctype.in.h 2016-10-10 15:55:32.350625000 +0300
@@ -25,13 +25,25 @@
* wctrans_t, and wctype_t are not yet implemented.
*/

-#ifndef ***@GUARD_PREFIX@_WCTYPE_H
-
#if __GNUC__ >= 3
@PRAGMA_SYSTEM_HEADER@
#endif
@PRAGMA_COLUMNS@

+#if (defined __MINGW32__ && defined __CTYPE_H_SOURCED__)
+
+/* Special invocation convention:
+ - With MinGW 3.22, when <ctype.h> includes <wctype.h>, only some part of
+ <wctype.h> is being processed, which doesn't include the idempotency
+ guard. */
+
+#@INCLUDE_NEXT@ @NEXT_WCTYPE_H@
+
+#else
+/* Normal invocation convention. */
+
+#ifndef ***@GUARD_PREFIX@_WCTYPE_H
+
#if @HAVE_WINT_T@
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.
Tru64 with Desktop Toolkit C has a bug: <stdio.h> must be included before
@@ -512,3 +524,4 @@

#endif /* ***@GUARD_PREFIX@_WCTYPE_H */
#endif /* ***@GUARD_PREFIX@_WCTYPE_H */
+#endif
Paul Eggert
2016-10-10 15:07:35 UTC
Permalink
Raw Message
Thanks, I installed that into Gnulib.
Eli Zaretskii
2016-10-10 15:55:16 UTC
Permalink
Raw Message
Date: Mon, 10 Oct 2016 08:07:35 -0700
Thanks, I installed that into Gnulib.
Great, thanks a lot.

Loading...