Re: Building sharutils 4.13.4 with MinGW

Eli Zaretskii <[email protected]>
Newsgroups gmane.comp.gnu.utils.bugs,gmane.comp.lib.gnulib.bugs
Message-ID <[email protected]>
Here are the MinGW-specific problems with building and testing this
release (copy to gnulib list, because many issues are related to
gnulib modules).

1. Compilation fails in lib/:

     gcc -DHAVE_CONFIG_H -I. -I..  -I../intl -Id:/usr/include  -g3 -O2 -Wno-format-contains-nul -MT idcache.o -MD -MP -MF .deps/idcache.Tpo -c -o idcache.o idcache.c

     In file included from idcache.c:21:0:
     idcache.h:6:23: error: unknown type name 'uid_t'
     idcache.h:7:24: error: unknown type name 'gid_t'
     idcache.h:8:1: error: unknown type name 'uid_t'
     idcache.h:9:1: error: unknown type name 'gid_t'
     idcache.c:25:17: fatal error: pwd.h: No such file or directory
     compilation terminated.
     make[4]: *** [idcache.o] Error 1

   This is because idcache.h includes sys/types.h, but gnulib's
   sys/types.h does not define uid_t and gid_t, and also there are no
   pwd.h and grp.h in lib/.

   My solution was to add private pwd.h and grp.h to lib/, and modify
   idcache.h to include them.  But I guess a better solution would be
   to import more from gnulib, or perhaps enhance the corresponding
   gnulib modules.

2. Compilation warning in lib/:

     gcc -DHAVE_CONFIG_H -I. -I..  -I../intl -Id:/usr/include  -g3 -O2 -Wno-format-contains-nul -MT idcache.o -MD -MP -MF .deps/idcache.Tpo -c -o idcache.o idcache.c

     idcache.c: In function 'getuser':
     idcache.c:85:30: warning: initialization makes pointer from integer without a cast [enabled by default]
     idcache.c: In function 'getgroup':
     idcache.c:167:29: warning: initialization makes pointer from integer without a cast [enabled by default]

   This is because functions getpwuid and getgrgid are unavailable and
   there are no replacements for them in gnulib.

   To solve this, I added the missing functions to idcache.c:

--- sharutils-4.13.4.orig/lib/idcache.c	2013-03-31 21:03:14.000000000 +0300
+++ sharutils-4.13.4/lib/idcache.c	2013-04-03 12:51:30.807618000 +0300
@@ -62,6 +62,70 @@ static struct userid *group_alist;
 /* Each entry on list is a group name for which the first lookup failed.  */
 static struct userid *nogroup_alist;
 
+#ifdef __MINGW32__
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <lmcons.h>
+uid_t
+getuid (void)
+{
+  return 42;
+}
+
+struct passwd *
+getpwuid (uid_t uid)
+{
+  static char uname[UNLEN+1];
+  static char homedir[FILENAME_MAX];
+  DWORD unsz = sizeof (uname);
+  static struct passwd user_rec;
+
+  if (uname[0] == '\0')
+    GetUserName (uname, &unsz);
+  if (homedir[0] == '\0')
+    {
+      char *home = getenv ("HOME");
+
+      if (home)
+	strcpy (homedir, home);
+      else
+	{
+	  home = getenv ("HOMEDRIVE");
+	  if (home)
+	    strcpy (homedir, home);
+	  home = getenv ("HOMEPATH");
+	  if (home)
+	    strcat (homedir, home);
+	}
+    }
+  user_rec.pw_uid = uid;
+  user_rec.pw_name = uname;
+  user_rec.pw_dir = homedir;
+
+  return &user_rec;
+}
+
+struct passwd *
+getpwnam (const char *user)
+{
+  return getpwuid (1004);
+}
+
+struct group *
+getgrgid (gid_t gid)
+{
+  static struct group grp_rec = { 42, "Users" };
+
+  return &grp_rec;
+}
+
+struct group *
+getgrnam (const char *group)
+{
+  return getgrgid (42);
+}
+#endif
+
 /* Translate UID to a login name, with cache, or NULL if unresolved.  */
 
 char *


3. Compilation warnings in src/shar.c:

     gcc -DLOCALEDIR=\"d:/usr/share/locale\" -DHAVE_CONFIG_H -I. -I..  -I../libopts -I. -I.. -I../lib -I../intl -Id:/usr/include -Wno-format-contains-nul -g3 -O2 -Wno-format-contains-nul -MT shar.o -MD -MP -MF .deps/shar.Tpo -c -o shar.o shar.c
     shar.c: In function 'walktree':
     shar.c:595:18: warning: assignment makes pointer from integer without a cast [enabled by default]
     shar.c: In function 'set_submitter':
     shar.c:1943:18: warning: initialization makes pointer from integer without a cast [enabled by default]
     make[2]: *** [shar.o] Error 1

   The problem here is with basename and dirname, whose declarations
   are absent.  My solution was to add "#include <libgen.h>" to
   lib/system.h (libgen.h in MinGW declares basename and dirname).
   However, I wonder if gnulib has a better solution.

4. Link errors for shar.exe:

     gcc -Wno-format-contains-nul -g3 -O2 -Wno-format-contains-nul   -o shar.exe shar.o encode.o shar-opts.o -lws2_32 -lws2_32 ../libopts/libopts.a ../lib/libgnu.a ../intl/libintl.a d:/usr/lib/libiconv.dll.a -Ld:/usr/lib -lpthread ../lib/libgnu.a -lregex
     shar.o: In function `shar':
     d:\usr\eli\utils\sharutils-4.13.4\src/shar.c:1760: undefined reference to `wait'
     shar.o: In function `open_shar_input':
     d:\usr\eli\utils\sharutils-4.13.4\src/shar.c:1308: undefined reference to `pipe'
     d:\usr\eli\utils\sharutils-4.13.4\src/shar.c:1312: undefined reference to `fork'
     shar.o: In function `set_submitter':
     d:\usr\eli\utils\sharutils-4.13.4\src/shar.c:1943: undefined reference to `getuid'
     ../lib/libgnu.a(idcache.o): In function `getuidbyname':
     d:\usr\eli\utils\sharutils-4.13.4\lib/idcache.c:147: undefined reference to `getpwnam'
     ../lib/libgnu.a(idcache.o): In function `getgidbyname':
     d:\usr\eli\utils\sharutils-4.13.4\lib/idcache.c:229: undefined reference to `getgrnam'
     ../lib/libgnu.a(gethostname.o): In function `rpl_gethostname':
     d:\usr\eli\utils\sharutils-4.13.4\lib/gethostname.c:97: undefined reference to `gethostname@8'
     ../lib/libgnu.a(gethostname.o): In function `set_winsock_errno':
     d:\usr\eli\utils\sharutils-4.13.4\lib/w32sock.h:37: undefined reference to `WSAGetLastError@0'
     ../lib/libgnu.a(sockets.o): In function `close_fd_maybe_socket':
     d:\usr\eli\utils\sharutils-4.13.4\lib/sockets.c:51: undefined reference to `WSAEnumNetworkEvents@12'
     d:\usr\eli\utils\sharutils-4.13.4\lib/sockets.c:59: undefined reference to `closesocket@4'
     ../lib/libgnu.a(sockets.o): In function `set_winsock_errno':
     d:\usr\eli\utils\sharutils-4.13.4\lib/w32sock.h:37: undefined reference to `WSAGetLastError@0'
     ../lib/libgnu.a(sockets.o): In function `ioctl_fd_maybe_socket':
     d:\usr\eli\utils\sharutils-4.13.4\lib/sockets.c:88: undefined reference to `WSAEnumNetworkEvents@12'
     d:\usr\eli\utils\sharutils-4.13.4\lib/sockets.c:92: undefined reference to `ioctlsocket@12'
     ../lib/libgnu.a(sockets.o): In function `set_winsock_errno':
     d:\usr\eli\utils\sharutils-4.13.4\lib/w32sock.h:37: undefined reference to `WSAGetLastError@0'
     ../lib/libgnu.a(sockets.o): In function `gl_sockets_startup':
     d:\usr\eli\utils\sharutils-4.13.4\lib/sockets.c:120: undefined reference to `WSAStartup@8'
     ../lib/libgnu.a(sockets.o): In function `gl_sockets_cleanup':
     d:\usr\eli\utils\sharutils-4.13.4\lib/sockets.c:148: undefined reference to `WSACleanup@0'
     collect2.exe: error: ld returned 1 exit status
     make[2]: *** [shar.exe] Error 1
     make[2]: Leaving directory `/d/usr/eli/utils/sharutils-4.13.4/src'
     make[1]: *** [all-recursive] Error 1
     make[1]: Leaving directory `/d/usr/eli/utils/sharutils-4.13.4'
     make: *** [all] Error 2

   The winsock-related errors are because of incorrect order of
   libraries on the link command line:

     -lws2_32 -lws2_32 ../libopts/libopts.a ../lib/libgnu.a ../intl/libintl.a d:/usr/lib/libiconv.dll.a -Ld:/usr/lib -lpthread ../lib/libgnu.a -lregex

   Solution: reorder in src/Makefile.in:

     LDADD = $(top_builddir)/libopts/libopts.a $(top_builddir)/lib/libgnu.a \
	 $(LIBINTL) $(top_builddir)/lib/libgnu.a $(GETHOSTNAME_LIB) $(LIBSOCKET)

   For the other errors: I wrote emulations for fork (always fails),
   wait (always fails) and pipe (calls _pipe), and also add getuid,
   getpwnam and getgrnam to idcache.c.  However, I think gnulib has
   replacements for at least some of these functions.

5. Link errors for unshar.exe:

     gcc -Wno-format-contains-nul -g3 -O2 -Wno-format-contains-nul   -o unshar.exe unshar.o encode.o unshar-opts.o ../libopts/libopts.a ../lib/libgnu.a ../intl/libintl.a d:/usr/lib/libiconv.dll.a -Ld:/usr/lib -lpthread ../lib/libgnu.a -lws2_32 -lws2_32 -lregex
     unshar.o: In function `load_file':
     d:\usr\eli\utils\sharutils-4.13.4\src/unshar.c:310: undefined reference to `mkstemp'
     collect2.exe: error: ld returned 1 exit status
     make[2]: *** [unshar.exe] Error 1

   Solution: add mkstemp to unshar.c.  Again, I think gnulib has a
   module for that, so importing it will solve this.

6. uutest-1 test fails because the begin line doesn't match.  This is
   because the mode bits on Windows are not real, beyond the user-read
   and user-write bits.  So it would be nice if on Windows Diff would
   be invoked like this:

     DIFF="diff -I^begin"

7. shar-4 fails because it uses cmp to compare results with expected
   ones, which fails due to line endings.  Suggest to use Diff
   instead.

8. The configure script botches the popen-binary test: the test
   program does not include stdio.h, so the compilation fails for
   reasons that have no relation to the issue being tested.

9. Using -! or --more-help triggers an error message:

     d:\usr\eli\utils\sharutils-4.13.4>uuencode -!
     uuencode: illegal option -- !
     uuencode (GNU sharutils) - encode a file into email friendly text
     Usage:  uuencode [ -<flag> | --<name> ]... [<in-file>] <output-name>
     Try 'uuencode --help' for more information.

     d:\usr\eli\utils\sharutils-4.13.4>uuencode --more-help
     uuencode: illegal option -- more-help
     uuencode (GNU sharutils) - encode a file into email friendly text
     Usage:  uuencode [ -<flag> | --<name> ]... [<in-file>] <output-name>
     Try 'uuencode --help' for more information.

   This is confusing because --help does show these options as available.

   The reason is that uuencode-options.c does this:

     #if HAVE_WORKING_FORK
     #define MORE_HELP_DESC  (uuencode_opt_strs+1045)
     #define MORE_HELP_name  (uuencode_opt_strs+1090)
     #define MORE_HELP_FLAGS (OPTST_IMM | OPTST_NO_INIT)
     #else
     #define MORE_HELP_DESC  NULL  <<<<<<<<<<<<<<<<<<<<<<<<<
     #define MORE_HELP_name  NULL  <<<<<<<<<<<<<<<<<<<<<<<<<
     #define MORE_HELP_FLAGS (OPTST_OMITTED | OPTST_NO_INIT)
     #endif

   which is unnecessary, since the relevant libopts code already knows
   how to handle the case of !HAVE_WORKING_FORK.

   => Fixed by enabling the !HAVE_WORKING_FORK block above.

   Same in shar-opts.c and uudecode-opts.c.

10.shar fails while processing files:

     d:\usr\eli\utils\sharutils-4.13.4>src\shar src\encode.c > foo.shar
     shar: Saving src/encode.c (text)
     The system cannot find the path specified.

   This is because emit_char_ct_validation invokes 'wc' with bad
   redirection:

     set LC_ALL=C & wc -c < 'src/encode.c'

   The file from which stdin is redirected uses forward slashes and is
   quoted with '..'.

   Solution: use a slightly different command for MinGW to run 'wc'
   locally:

     set LC_ALL=C & wc -c "src/encode.c"

--- sharutils-4.13.4.orig/src/shar.c	2013-03-23 00:23:48.000000000 +0200
+++ sharutils-4.13.4/src/shar.c	2013-04-07 13:41:14.742531000 +0300
@@ -1065,14 +1097,27 @@ emit_char_ct_validation (
   /* Shell command able to count characters from its standard input.
      We have to take care for the locale setting because wc in multi-byte
      character environments gets different results.  */
+#ifdef __MINGW32__
+  /* Windows needs a slightly different format to run wc locally:
+     redirection will fail because the file uses Unix forward
+     slashes.  */
+  static char const local_cmd[] = "set LC_ALL=C & wc -c";
+#endif
   static char const cct_cmd[] = "LC_ALL=C wc -c <";
 
   FILE *pfp;
   char wc[16 /* log MAX_INT + a few extra */];
-  char *command = alloca (sizeof(cct_cmd) + strlen (quoted_name) + 2);
  
+#ifdef __MINGW32__
+  /* On Windows, disregard Unix-style shell quoting and quote by hand
+     using "..".  */
+  char *command = alloca (sizeof(local_cmd) + strlen (local_name) + 2);
+  sprintf (command, "%s \"%s\"", local_cmd, local_name);
+#else
+  char *command = alloca (sizeof(cct_cmd) + strlen (quoted_name) + 2);
   sprintf (command, "%s %s", cct_cmd, quoted_name);
-  pfp = popen (command, "r");
+#endif
+  pfp = popen (command, freadonly_mode);
   if (pfp == NULL)
     die (SHAR_EXIT_FAILED, _("Could not popen command"), command);
 

11.shar.c uses /dev/null in freopen, but does not use the gnulib
   freopen module, which makes /dev/null work on MS-Windows.

There are a few other, less important issues, like with using binary
I/O in some places.  let me know if you want me to send diffs for
those.

HTH
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.