Subject: Re: bug#10474: Building guile 2.x under mingw + msys

From: Eli Zaretskii <[email-masked]>
Date: Thu, 02 Feb 2012 19:34:49 +0200

> From: Andy Wingo <[email-masked]>
> Cc: [email-masked] (Ludovic Courtès),  [email-masked],
>  [email-masked]
> Date: Thu, 02 Feb 2012 01:59:21 +0100
> 
> I will assume that the canonicalize_file_name issues will get resolved
> eventually in gnulib, once your assignment completes.  I will go
> through the rest of the issues.

As promised, the diffs that I suggest to install to take care of the
problems I bumped into are at the end of this message.

For your convenience, I grouped the changes into several related
groups, in case you'd like to make them separate commits.  Each group
is preceded by a short description (a candidate for a commit log
message) and ChangeLog entries for the changes.

In addition to the diffs, there are a few other changes for which I
don't show my changes, because they were ad-hoc and not very clean.
Instead, I describe what I think should be the "right" solutions for
them:

 . lib/canonicalize-lgpl.c -- does not support Windows absolute file
                              names.  Will be fixed in gnulib.

 . libguile/dynl.c -- lacks setenv.  Gnulib's setenv should be used.

 . libguile/expand.c -- Defines CONST and VOID.  Should define
                        SCM_CONST and SCM_VOID (or some other, less
                        ubiquitous, symbols) instead.

 . libguile/fports.c -- Doesn't implement fport_input_waiting when
                        neither poll nor select nor FIONREAD are
                        available, without which interactive guile
                        won't start.  Should use the gnulib select
                        module.

 . libguile/socket.c -- Lacks implementation of `times' for
                        MS-Windows, without which guile.exe aborts
                        during startup.  Should use the gnulib times
                        module.

 . module/ice-9/boot-9.scm -- absolute-path? does not support Windows
                              file names with drive letters.  Windows
                              absolute file names match the regex
                              "\([a-zA-Z]:\)?[\\/]".  I don't know
                              Scheme well enough to write this in a
                              clean way, sorry...

Here are the diffs:

	Fix startup of guile.exe on MS-Windows.

	* module/system/base/compile.scm (call-with-output-file/atomic):
	Call close-port before deleting the temporary file name, otherwise
	deletion fails on MS-Windows (cannot delete a file that is still
	open).

	* libguile/load.c (scm_init_load_path) [__MINGW32__]: Convert
	backslashes to forward slashes in values of GUILE_LOAD_PATH and
	GUILE_LOAD_COMPILED_PATH.

--- module/system/base/compile.scm~0	2011-10-08 01:49:48.000000000 +0200
+++ module/system/base/compile.scm	2012-01-19 16:49:26.528084600 +0200
@@ -61,6 +61,7 @@
            (close-port tmp)
            (rename-file template filename))
          (lambda args
+	   (close-port tmp)
            (delete-file template)))))))
 
 (define (ensure-language x)

--- libguile/load.c~0	2011-10-08 01:49:48.000000000 +0200
+++ libguile/load.c	2012-01-17 16:47:19.325381400 +0200
@@ -310,10 +309,36 @@ scm_init_load_path ()
   }
 
   env = getenv ("GUILE_LOAD_PATH");
+#ifdef __MINGW32__
+  if (env)
+    {
+      char *p = env;
+
+      while (*p)
+	{
+	  if (*p == '\\')
+	    *p = '/';
+	  p++;
+	}
+    }
+#endif
   if (env)
     path = scm_parse_path (scm_from_locale_string (env), path);
 
   env = getenv ("GUILE_LOAD_COMPILED_PATH");
+#ifdef __MINGW32__
+  if (env)
+    {
+      char *p = env;
+
+      while (*p)
+	{
+	  if (*p == '\\')
+	    *p = '/';
+	  p++;
+	}
+    }
+#endif
   if (env)
     cpath = scm_parse_path (scm_from_locale_string (env), cpath);

	Avoid compiler warnings on MS-Windows.

	* libguile/print.c (display_string_using_iconv): Cast 2nd arg of
	`iconv' to `const char **', to avoid compiler warnings.

	* libguile/ports.c (get_iconv_codepoint): Cast 2nd arg of `iconv'
	to `const char **', to avoid compiler warnings.

	* libguile/deprecation.c (vsnprintf) [__MINGW32__]: Don't redefine
	if already defined.  Avoids compiler warnings.

	* libguile/filesys.c (mkdir) [__MINGW32__]: Don't redefine if
	GNULIB_defined_rpl_mkdir is defined, meaning that the gnulib
	replacement is being used.
	(fchmod) [__MINGW32__]: Define to zero, to avoid gratuitous failures
	of many file operations on MS-Windows.

--- libguile/print.c~0	2011-10-08 01:49:48.000000000 +0200
+++ libguile/print.c	2012-01-15 15:10:51.450848400 +0200
@@ -899,7 +899,7 @@ display_string_using_iconv (const void *
       output = encoded_output;
       output_left = sizeof (encoded_output);
 
-      done = iconv (pt->output_cd, &input, &input_left,
+      done = iconv (pt->output_cd, (const char **)&input, &input_left,
 		    &output, &output_left);
 
       output_len = sizeof (encoded_output) - output_left;

--- libguile/ports.c~0	2011-10-08 01:49:48.000000000 +0200
+++ libguile/ports.c	2012-01-15 15:11:11.856706600 +0200
@@ -1305,7 +1305,7 @@ get_iconv_codepoint (SCM port, scm_t_wch
       input_left = bytes_consumed + 1;
       output_left = sizeof (utf8_buf);
 
-      done = iconv (pt->input_cd, &input, &input_left,
+      done = iconv (pt->input_cd, (const char **)&input, &input_left,
 		    &output, &output_left);
       if (done == (size_t) -1)
 	{

--- libguile/deprecation.c~0	2011-07-07 02:49:59.000000000 +0300
+++ libguile/deprecation.c	2012-01-15 14:48:55.966092400 +0200
@@ -36,7 +36,7 @@

 /* Windows defines. */
-#ifdef __MINGW32__
+#if defined (__MINGW32__) && !defined (vsnprintf)
 #define vsnprintf _vsnprintf
 #endif
 
--- libguile/filesys.c~0	2011-10-08 01:49:48.000000000 +0200
+++ libguile/filesys.c	2012-01-18 08:29:49.629722000 +0200
@@ -116,11 +116,24 @@
 
 /* Some more definitions for the native Windows port. */
 #ifdef __MINGW32__
-# define mkdir(path, mode) mkdir (path)
+/* When configured to use the gnulib replacement, don't redefine
+   mkdir, as it is already redirected to the replacement, see
+   lib/sys/stat.h.  */
+# if !GNULIB_defined_rpl_mkdir
+#  define mkdir(path, mode) mkdir (path)
+# endif
 # define fsync(fd) _commit (fd)
-# define fchmod(fd, mode) (-1)
+# define fchmod(fd, mode) (0)
 #endif /* __MINGW32__ */
 
+#ifndef O_BINARY
+# ifdef _O_BINARY
+#  define O_BINARY _O_BINARY
+# else
+#  define O_BINARY 0
+# endif
+#endif
+
 /* dirfd() returns the file descriptor underlying a "DIR*" directory stream.
    Found on MacOS X for instance.  The following definition is for Solaris
    10, it's probably not right elsewhere, but that's ok, it shouldn't be

	Read and write *.go files and copy files in binary mode on
	MS-Windows.

	* libguile/objcodes.c (O_BINARY): Define on all platforms.
	(make_objcode_from_file): Zero out errno before calling full_read,
	to make sure the value after the call reflects errors inside
	full_read.
	(scm_load_objcode): Open objcode files in binary mode, so that
	*.go files are read verbatim on MS-Windows.

	* libguile/mkstemp.c (O_BINARY): Define for all platforms.
	(mkstemp): Open the temporary file in binary mode, so that
	compiled *.go files are written verbatim on MS-Windows.

	* libguile/filesys.c (O_BINARY): Define for all platforms.
	(scm_copy_file): Use O_BINARY in the call to open_or_open64.

--- libguile/objcodes.c~0	2011-10-08 01:49:48.000000000 +0200
+++ libguile/objcodes.c	2012-01-18 08:47:46.857202700 +0200
@@ -39,6 +39,14 @@
 #include "programs.h"
 #include "objcodes.h"
 
+#ifndef O_BINARY
+# ifdef _O_BINARY
+#  define O_BINARY _O_BINARY
+# else
+#  define O_BINARY 0
+# endif
+#endif
+
 /* SCM_OBJCODE_COOKIE, defined in _scm.h, is a magic value prepended
    to objcode on disk but not in memory.
 
@@ -169,9 +177,10 @@ make_objcode_from_file (int fd)
   {
     SCM bv = scm_c_make_bytevector (st.st_size - sizeof cookie);
 
+    errno = 0;
     if (full_read (fd, cookie, sizeof cookie) != sizeof cookie
-        || full_read (fd, SCM_BYTEVECTOR_CONTENTS (bv),
-                      SCM_BYTEVECTOR_LENGTH (bv)) != SCM_BYTEVECTOR_LENGTH (bv))
+	|| full_read (fd, SCM_BYTEVECTOR_CONTENTS (bv),
+		      SCM_BYTEVECTOR_LENGTH (bv)) != SCM_BYTEVECTOR_LENGTH (bv))
       {
         int errno_save = errno;
         (void) close (fd);
@@ -295,7 +304,7 @@ SCM_DEFINE (scm_load_objcode, "load-objc
   SCM_VALIDATE_STRING (1, file);
 
   c_file = scm_to_locale_string (file);
-  fd = open (c_file, O_RDONLY | O_CLOEXEC);
+  fd = open (c_file, O_RDONLY | O_BINARY | O_CLOEXEC);
   free (c_file);
   if (fd < 0) SCM_SYSERROR;

--- libguile/mkstemp.c~0	2010-12-08 11:07:02.000000000 +0200
+++ libguile/mkstemp.c	2012-01-18 08:46:36.123280400 +0200
@@ -43,6 +43,14 @@
 #include <process.h>
 #endif
 
+#ifndef O_BINARY
+# ifdef _O_BINARY
+#  define O_BINARY _O_BINARY
+# else
+#  define O_BINARY 0
+# endif
+#endif
+
 #ifndef TMP_MAX
 #define TMP_MAX 16384
 #endif
@@ -112,7 +120,7 @@ mkstemp (template)
       v /= 62;
       XXXXXX[5] = letters[v % 62];
 
-      fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600);
+      fd = open (template, O_RDWR|O_BINARY|O_CREAT|O_EXCL, 0600);
       if (fd >= 0)
 	/* The file does not exist.  */
 	return fd;

--- libguile/filesys.c~0	2011-10-08 01:49:48.000000000 +0200
+++ libguile/filesys.c	2012-01-18 08:29:49.629722000 +0200
@@ -1118,7 +1131,7 @@ SCM_DEFINE (scm_copy_file, "copy-file", 
   c_newfile = scm_to_locale_string (newfile);
   scm_dynwind_free (c_newfile);
 
-  oldfd = open_or_open64 (c_oldfile, O_RDONLY);
+  oldfd = open_or_open64 (c_oldfile, O_RDONLY | O_BINARY);
   if (oldfd == -1)
     SCM_SYSERROR;
 
@@ -1131,7 +1144,7 @@ SCM_DEFINE (scm_copy_file, "copy-file", 
     goto err_close_oldfd;
 
   /* use POSIX flags instead of 07777?.  */
-  newfd = open_or_open64 (c_newfile, O_WRONLY | O_CREAT | O_TRUNC,
+  newfd = open_or_open64 (c_newfile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC,
                           oldstat.st_mode & 07777);
   if (newfd == -1)
     {

	Fix compilation warnings and errors on MS-Windows when
	compiling network-related code due to missing macros and
	prototypes.

	* libguile/net_db.c [HAVE_WINSOCK2_H]: Add !GNULIB_TEST_SOCKET to
	the condition, to include sys/socket.h and netdb.h when gnulib's
	socket module is being used.  Fixes compiler warnings and errors
	on MS-Windows.

	* libguile/socket.c: Likewise.

--- libguile/net_db.c~0	2011-07-07 02:49:59.000000000 +0300
+++ libguile/net_db.c	2012-01-15 16:22:56.366898100 +0200
@@ -49,8 +49,11 @@
 
 #include <sys/types.h>
 
-#ifdef HAVE_WINSOCK2_H
+#if HAVE_WINSOCK2_H && !GNULIB_TEST_SOCKET
 #include <winsock2.h>
+# if HAVE_WS2TCPIP_H
+#  include <ws2tcpip.h>
+# endif
 #else
 #include <sys/socket.h>
 #include <netdb.h>

--- libguile/socket.c~0	2011-10-08 01:49:48.000000000 +0200
+++ libguile/socket.c	2012-01-15 16:40:46.891296700 +0200
@@ -58,7 +58,7 @@
 #include <unistd.h>
 #endif
 #include <sys/types.h>
-#ifdef HAVE_WINSOCK2_H
+#if HAVE_WINSOCK2_H && !GNULIB_TEST_SOCKET
 #include <winsock2.h>
 #else
 #include <sys/socket.h>