develooper Front page | perl.perl5.porters | Postings from February 2015

[perl #123794] Build failure on Win32 with gcc 4.7.2/4.8.1 from www.mingw.org

Thread Previous
From:
Steve Hay
Date:
February 11, 2015 08:58
Subject:
[perl #123794] Build failure on Win32 with gcc 4.7.2/4.8.1 from www.mingw.org
Message ID:
rt-4.0.18-6042-1423645124-180.123794-75-0@perl.org
# New Ticket Created by  Steve Hay 
# Please include the string:  [perl #123794]
# in the subject line of all future correspondence about this issue. 
# <URL: https://rt.perl.org/Ticket/Display.html?id=123794 >


In commit 0bcc29e72b I've just silenced some compiler warnings from
these compilers caused by #defines of fstat and stat in both
sys/stat.h and perl's win32/win32iop.h. They no longer complain about
these symbols being redefined, but the fact that they are #undef'd and
then re-#def'd still causes problems, including a build failure in C++
mode.

In a normal C build with the default configuration, doio.c now has
this warning, and likewise for some other fstat/stat calls in the same
file:

..\doio.c: In function 'S_openn_cleanup':
..\doio.c:651:2: warning: passing argument 2 of 'win32_fstat' from
incompatible pointer type [enabled by default]
In file included from ./win32.h:643:0,
                 from ..\perl.h:3065,
                 from ..\doio.c:27:
./win32iop.h:69:18: note: expected 'struct _stat64i32 *' but argument
is of type 'struct stat *'

In a C++ mode build that becomes an error:

..\doio.c: In function 'bool S_openn_cleanup(GV*, IO*, PerlIOl**,
char*, const char*, PerlIOl**, PerlIOl**, int, char, int, bool, const
char*)':
..\doio.c:651:6: error: cannot convert 'stat*' to '_stat64i32*' for
argument '2' to 'int win32_fstat(int, _stat64i32*)'

The problem is that the #undef/#define of stat (the stat() function!)
in perl's win32/win32iop.h interferes with these compilers' #define of
stat (the struct stat!) in sys/stat.h

doio.c includes perl.h, which includes the config.h (line 28), then
sys/stat.h (line1088), then dosish.h (line 2797), then win32.h (line
3065), and then intrpvar.h. The latter occurs on line 5542 rather than
5427 since the miniperl build does not have MULTIPLICITY defined since
the config.h for the miniperl build is the canned config.h, which is
set up for a minimal configuration. That canned config.h also does not
have USE_LARGE_FILES defined, so dosish.h gives us:

#define Stat_t struct stat

These compilers' sys/stat.h give us:

#ifndef _STAT_DEFINED
[...]
#if defined(_USE_32BIT_TIME_T)
#define _fstat      _fstat32
#define _fstati64   _fstat32i64
#define _stat       _stat32
#define _stati64    _stat32i64

#else  /* !_USE_32BIT_TIME_T */
#define _fstat      _fstat64i32
#define _fstati64   _fstat64
#define _stat       _stat64i32
#define _stati64    _stat64

#endif /* _USE_32BIT_TIME_T */
#define _STAT_DEFINED

#endif /* _STAT_DEFINED */

#if !defined(_NO_OLDNAMES) && !defined(__STRICT_ANSI__)
#define stat _stat
#define fstat _fstat
#endif /* !defined(_NO_OLDNAMES) && !defined(__STRICT_ANSI__) */

None of _STAT_DEFINED, USE_32BIT_TIME_T, _NO_OLDNAMES or
__STRICT_ANSI__ are defined, so the upshot is that Stat_t, and hence
struct stat, is struct _stat64132, so we therefore have this
declaration of win32_fstat from win32iop.h, included from win32.h:

DllExport  int      win32_fstat(int fd, struct _stat64i32 *sbufptr);

but the same file also then does this:

#if defined(UNDER_CE) || defined(__MINGW32__)
#  undef fstat
#endif
#define fstat(fd,bufptr)       win32_fstat(fd,bufptr)
#if defined(UNDER_CE) || defined(__MINGW32__)
#  undef stat
#endif
#define stat(pth,bufptr)       win32_stat(pth,bufptr)

and that last #undef/#define of stat messes with sys/stat.h's #define
of stat such that 'struct stat' is no longer mapped to 'struct
_stat64i32', but is instead left as a simple 'struct stat'.

Therefore, when we reach the #include of intrpvar.h nearing the end of
perl.h we end up with

struct stat PL_statbuf;

rather than the intended

struct _stat64i32 PL_statbuf

which then causes the compiler warning/error shown earlier about a
struct stat being passed to a function which expects a struct
_stat64i32.

I'm not sure how best to fix this.

I'm wondering if _USE_32BIT_TIME_T should actually be defined, as it
is for MSVC60/MSVC70 builds, but that wouldn't fix the problem anyway:
sys/stat.h would then give us struct stat == struct _stat32, which
win32iop.h would still wipe out.

I've also experimented with defining _NO_OLDNAMES and/or
__STRICT_ANSI__ but all hell breaks loose compiling every .c file with
those options!

The only workaround that I have at the moment is the slightly gross
hack of forcing the re-inclusion of sys/stat.h (including needing to
undefine its "include guard" define) just after win32iop.h has messed
with its definition of stat:

diff --git a/win32/win32iop.h b/win32/win32iop.h
index 842bc07..0cf9b59 100644
--- a/win32/win32iop.h
+++ b/win32/win32iop.h
@@ -296,6 +296,10 @@ END_EXTERN_C
 #  undef stat
 #endif
 #define stat(pth,bufptr)       win32_stat(pth,bufptr)
+#ifdef __MINGW32__
+#undef _STAT_H_
+#include <sys/stat.h>
+#endif
 #define longpath(pth)          win32_longpath(pth)
 #define ansipath(pth)          win32_ansipath(pth)
 #ifdef UNDER_CE


Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About