Support dynamic object loading on MS-Windows.
authorEli Zaretskii <eliz@gnu.org>
Mon, 29 Apr 2013 16:26:06 +0000 (19:26 +0300)
committerEli Zaretskii <eliz@gnu.org>
Mon, 29 Apr 2013 16:26:06 +0000 (19:26 +0300)
 w32/include/dlfcn.h: New file.
 w32/compat/posixfcn.c: Include dlfcn.h.
 (dlopen, dlerror, dlsym) [MAKE_LOAD]: New functions, in support of
 dynamic loading.

 config.h.W32.template (MAKE_LOAD): Define.
 load.c (load_object) [HAVE_DOS_PATHS]: Support backslashes and
 drive letters in file names of dynamic objects.

ChangeLog
config.h.W32.template
load.c
w32/compat/posixfcn.c
w32/include/dlfcn.h [new file with mode: 0644]

index e297795dc3b8b5993d379ff3dbf0e5475c638628..6badda8339a35eba9c275ea0953e04de825a720c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2013-04-29  Eli Zaretskii  <eliz@gnu.org>
 
+       * w32/include/dlfcn.h: New file.
+
+       * w32/compat/posixfcn.c: Include dlfcn.h.
+       (dlopen, dlerror, dlsym) [MAKE_LOAD]: New functions, in support of
+       dynamic loading.
+
+       * config.h.W32.template (MAKE_LOAD): Define.
+
+       * load.c (load_object) [HAVE_DOS_PATHS]: Support backslashes and
+       drive letters in file names of dynamic objects.
+
        * job.c (construct_command_argv_internal) [WINDOWS32]: Return
        right after generating new_argv for one_shell case.  This fixes
        the Windows build for both Unixy shell and stock Windows shells.
index 8818a76a968cd1ed009e3a937bd18c9a654fc688..8d59a139c8002755022b3a0e14d93dfe240b5e52 100644 (file)
@@ -366,6 +366,9 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 /* Define to 1 to enable job server support in GNU make. */
 #define MAKE_JOBSERVER 1
 
+/* Define to 1 to enable 'load' support in GNU make. */
+#define MAKE_LOAD 1
+
 /* Define to 1 to enable symbolic link timestamp checking. */
 /* #undef MAKE_SYMLINKS */
 
diff --git a/load.c b/load.c
index 95529c22cca076cc74b2a16d779c528b172bcbef..9a83829934037d7de68955506994415fc30e4bc3 100644 (file)
--- a/load.c
+++ b/load.c
@@ -49,7 +49,11 @@ load_object (const gmk_floc *flocp, int noerror,
     void *dlp = NULL;
 
     /* If the path has no "/", try the current directory first.  */
-    if (! strchr (ldname, '/'))
+    if (! strchr (ldname, '/')
+#ifdef HAVE_DOS_PATHS
+       && ! strchr (ldname, '\\')
+#endif
+       )
       dlp = dlopen (concat (2, "./", ldname), RTLD_LAZY|RTLD_GLOBAL);
 
     /* If we haven't opened it yet, try the default search path.  */
@@ -134,6 +138,20 @@ load_file (const gmk_floc *flocp, const char **ldname, int noerror)
       char *p = new;
 
       fp = strrchr (*ldname, '/');
+#ifdef HAVE_DOS_PATHS
+      if (fp)
+       {
+         const char *fp2 = strchr (fp, '\\');
+
+         if (fp2 > fp)
+           fp = fp2;
+       }
+      else
+       fp = strrchr (*ldname, '\\');
+      /* The (improbable) case of d:foo.  */
+      if (fp && *fp && fp[1] == ':')
+       fp++;
+#endif
       if (!fp)
         fp = *ldname;
       else
index 90534d094c7b012a8a22bf61bd6f1c6f437df5e0..cafc8649fa81640716579ca6ca2dcad1328c9f34 100644 (file)
@@ -21,6 +21,8 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <errno.h>
 #include <windows.h>
 
+#include "dlfcn.h"
+
 #include "makeint.h"
 #include "job.h"
 
@@ -256,3 +258,86 @@ same_stream (FILE *f1, FILE *f2)
 }
 
 #endif /* OUTPUT_SYNC */
+
+#if MAKE_LOAD
+
+/* Support for dynamic loading of objects.  */
+
+
+static DWORD last_err;
+
+void *
+dlopen (const char *file, int mode)
+{
+  char dllfn[MAX_PATH], *p;
+  HANDLE dllhandle;
+
+  if ((mode & ~(RTLD_LAZY | RTLD_NOW | RTLD_GLOBAL)) != 0)
+    {
+      errno = EINVAL;
+      last_err = ERROR_INVALID_PARAMETER;
+      return NULL;
+    }
+
+  if (!file)
+    dllhandle = GetModuleHandle (NULL);
+  else
+    {
+      /* MSDN says to be sure to use backslashes in the DLL file name.  */
+      strcpy (dllfn, file);
+      for (p = dllfn; *p; p++)
+       if (*p == '/')
+         *p = '\\';
+
+      dllhandle = LoadLibrary (dllfn);
+    }
+  if (!dllhandle)
+    last_err = GetLastError ();
+
+  return dllhandle;
+}
+
+char *
+dlerror (void)
+{
+  static char errbuf[1024];
+  DWORD ret;
+
+  if (!last_err)
+    return NULL;
+
+  ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
+                      | FORMAT_MESSAGE_IGNORE_INSERTS,
+                      NULL, last_err, 0, errbuf, sizeof (errbuf), NULL);
+  while (ret > 0 && (errbuf[ret - 1] == '\n' || errbuf[ret - 1] == '\r'))
+    --ret;
+
+  errbuf[ret] = '\0';
+  if (!ret)
+    sprintf (errbuf, "Error code %lu", last_err);
+
+  last_err = 0;
+  return errbuf;
+}
+
+void *
+dlsym (void *handle, const char *name)
+{
+  FARPROC addr = NULL;
+
+  if (!handle || handle == INVALID_HANDLE_VALUE)
+    {
+      last_err = ERROR_INVALID_PARAMETER;
+      return NULL;
+    }
+
+  addr = GetProcAddress (handle, name);
+  if (!addr)
+    last_err = GetLastError ();
+
+  return (void *)addr;
+}
+
+
+#endif /* MAKE_LOAD */
+
diff --git a/w32/include/dlfcn.h b/w32/include/dlfcn.h
new file mode 100644 (file)
index 0000000..c95fee2
--- /dev/null
@@ -0,0 +1,13 @@
+/* dlfcn.h replacement for MS-Windows build.  */
+#ifndef DLFCN_H
+#define DLFCN_H
+
+#define RTLD_LAZY   1
+#define RTLD_NOW    2
+#define RTLD_GLOBAL 4
+
+extern void *dlopen (const char *, int);
+extern void *dlsym (void *, const char *);
+extern char *dlerror (void);
+
+#endif /* DLFCN_H */