]> git.ipfire.org Git - thirdparty/make.git/commitdiff
Fix interfacing with and remaking dynamic objects on MS-Windows.
authorEli Zaretskii <eliz@gnu.org>
Fri, 3 May 2013 13:09:12 +0000 (16:09 +0300)
committerEli Zaretskii <eliz@gnu.org>
Fri, 3 May 2013 13:09:12 +0000 (16:09 +0300)
 load.c (load_object, load_file): Accept an additional argument
 DLP and return in it a pointer that can be used to unload the
 dynamic object.
 read.c (eval): Call load_file with an additional argument, and
 record the pointer returned there in the 'struct file' object of
 dynamic objects in that object's 'struct file'.
 commands.c (execute_file_commands): Unload dynamic objects
 before remaking them, to avoid failure to remake if the OS doesn't
 allow overwriting objects that are in use.
 filedef.h (struct file): New member dlopen_ptr.
 gnumake.h (GMK_EXPORT): Define to dllexport/dllimport
 decorations for Windows and to nothing on other platforms.
 (gmk_eval, gmk_expand, gmk_add_function): Add GMK_EXPORT qualifier
 to prototypes.
 makeint.h (MAIN): Define before including gnumake.h, to give
 correct dllexport decorations to exported functions.
 (load_file): Adjust prototype.
 loadapi.c: Don't include gnumake.h, since makeint.h already
 includes it, and takes care of defining MAIN before doing so.
 build_w32.bat (LinkGCC): Produce an import library for functions
 exported by Make for loadable dynamic objects.

 w32/compat/posixfcn.c (dlclose): New function.
 w32/include/dlfcn.h (dlclose): Add prototype.

 scripts/features/load: Fix signatures of testload_gmk_setup and
 explicit_setup, to bring them in line with the documentation.

13 files changed:
ChangeLog
build_w32.bat
commands.c
filedef.h
gnumake.h
load.c
loadapi.c
makeint.h
read.c
tests/ChangeLog
tests/scripts/features/load
w32/compat/posixfcn.c
w32/include/dlfcn.h

index e8033d6f01231dd0e1c2a19f39283ce0b0aeaae8..786ae4db8e7cbc44042db96428f1eb99b0461ff5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2013-05-03  Eli Zaretskii  <eliz@gnu.org>
+
+       * load.c (load_object, load_file): Accept an additional argument
+       DLP and return in it a pointer that can be used to unload the
+       dynamic object.
+
+       * read.c (eval): Call load_file with an additional argument, and
+       record the pointer returned there in the 'struct file' object of
+       dynamic objects in that object's 'struct file'.
+
+       * commands.c (execute_file_commands): Unload dynamic objects
+       before remaking them, to avoid failure to remake if the OS doesn't
+       allow overwriting objects that are in use.
+
+       * filedef.h (struct file): New member dlopen_ptr.
+
+       * gnumake.h (GMK_EXPORT): Define to dllexport/dllimport
+       decorations for Windows and to nothing on other platforms.
+       (gmk_eval, gmk_expand, gmk_add_function): Add GMK_EXPORT qualifier
+       to prototypes.
+
+       * makeint.h (MAIN): Define before including gnumake.h, to give
+       correct dllexport decorations to exported functions.
+       (load_file): Adjust prototype.
+
+       * loadapi.c: Don't include gnumake.h, since makeint.h already
+       includes it, and takes care of defining MAIN before doing so.
+
+       * build_w32.bat (LinkGCC): Produce an import library for functions
+       exported by Make for loadable dynamic objects.
+
+       * w32/compat/posixfcn.c (dlclose): New function.
+
+       * w32/include/dlfcn.h (dlclose): Add prototype.
+
 2013-05-01  Eli Zaretskii  <eliz@gnu.org>
 
        * job.c (start_job_command) [WINDOWS32]: Make the same fix for
index 27ac3dba9b31a2baf1b6c8e66f8c4b790072fa56..43ae6e2df8026c3d7ba6e362390adc1ce3980a57 100644 (file)
@@ -290,8 +290,10 @@ set GUILEOBJ=guile.o
 echo on\r
 gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% %GUILECFLAGS% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c guile.c\r
 :LinkGCC\r
+Rem The version NN of libgnumake-NN.dll.a should be bumped whenever\r
+Rem the API changes in binary-incompatible manner.\r
 @echo on\r
-gcc -mthreads -gdwarf-2 -g3 -o gnumake.exe variable.o rule.o remote-stub.o commands.o file.o getloadavg.o default.o signame.o expand.o dir.o main.o getopt1.o %GUILEOBJ% job.o read.o version.o getopt.o arscan.o remake.o misc.o hash.o strcache.o ar.o function.o vpath.o implicit.o loadapi.o load.o glob.o fnmatch.o pathstuff.o posixfcn.o w32_misc.o sub_proc.o w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32\r
+gcc -mthreads -gdwarf-2 -g3 -o gnumake.exe variable.o rule.o remote-stub.o commands.o file.o getloadavg.o default.o signame.o expand.o dir.o main.o getopt1.o %GUILEOBJ% job.o read.o version.o getopt.o arscan.o remake.o misc.o hash.o strcache.o ar.o function.o vpath.o implicit.o loadapi.o load.o glob.o fnmatch.o pathstuff.o posixfcn.o w32_misc.o sub_proc.o w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -Wl,--out-implib=libgnumake-1.dll.a\r
 @GoTo BuildEnd\r
 :Usage\r
 echo Usage: %0 [options] [gcc]\r
index 698816fab500c7b8ea10dac5afc4fdb951186127..e8a9f1c2d0e1af512957260e618cbc297a2e564c 100644 (file)
@@ -14,6 +14,8 @@ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 You should have received a copy of the GNU General Public License along with
 this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
+#include <dlfcn.h>
+
 #include "makeint.h"
 #include "dep.h"
 #include "filedef.h"
@@ -468,6 +470,12 @@ execute_file_commands (struct file *file)
 
   set_file_variables (file);
 
+  /* If this is a loaded dynamic object, unload it before remaking.
+     Some systems don't allow to overwrite a loaded shared
+     library.  */
+  if (file->dlopen_ptr)
+    dlclose (file->dlopen_ptr);
+
   /* Start the commands running.  */
   new_job (file);
 }
index b6ba2420eafdb917811a72c007cbcd5ce16b88bc..50eec74b98bf89e5fee48428f8c832b348a63072 100644 (file)
--- a/filedef.h
+++ b/filedef.h
@@ -61,6 +61,8 @@ struct file
     int command_flags;         /* Flags OR'd in for cmds; see commands.h.  */
     char update_status;         /* Status of the last attempt to update,
                                   or -1 if none has been made.  */
+    void *dlopen_ptr;          /* For dynamic loaded objects: pointer to
+                                  pass to dlclose to unload the object.  */
     enum cmd_state             /* State of the commands.  */
       {                /* Note: It is important that cs_not_started be zero.  */
        cs_not_started,         /* Not yet started.  */
index c6f7bd82a58bd17919d6b3b92f47d514db307918..a6308fe09ef8f0be068df71792b298ccffb74e49 100644 (file)
--- a/gnumake.h
+++ b/gnumake.h
@@ -26,13 +26,23 @@ typedef struct
     unsigned long lineno;
   } gmk_floc;
 
+#ifdef _WIN32
+# ifdef MAIN
+#  define GMK_EXPORT  __declspec(dllexport)
+# else
+#  define GMK_EXPORT  __declspec(dllimport)
+# endif
+#else
+# define GMK_EXPORT
+#endif
+
 
 /* Run $(eval ...) on the provided string BUFFER.  */
-void gmk_eval (const char *buffer, const gmk_floc *floc);
+void GMK_EXPORT gmk_eval (const char *buffer, const gmk_floc *floc);
 
 /* Run GNU make expansion on the provided string STR.
    Returns an allocated buffer that the caller must free.  */
-char *gmk_expand (const char *str);
+char * GMK_EXPORT gmk_expand (const char *str);
 
 /* Register a new GNU make function NAME (maximum of 255 chars long).
    When the function is expanded in the makefile, FUNC will be invoked with
@@ -49,8 +59,9 @@ char *gmk_expand (const char *str);
    If EXPAND_ARGS is 0, the arguments to the function will not be expanded
    before FUNC is called.  If EXPAND_ARGS is non-0, they will be expanded.
 */
-void gmk_add_function (const char *name,
-                       char *(*func)(const char *nm, int argc, char **argv),
-                       int min_args, int max_args, int expand_args);
+void GMK_EXPORT gmk_add_function (const char *name,
+                                 char *(*func)(const char *nm,
+                                               int argc, char **argv),
+                                 int min_args, int max_args, int expand_args);
 
 #endif  /* _GNUMAKE_H_ */
diff --git a/load.c b/load.c
index 9a83829934037d7de68955506994415fc30e4bc3..f20c1c794edd69dc39bc978d5c112841d7dd84cf 100644 (file)
--- a/load.c
+++ b/load.c
@@ -32,11 +32,13 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 static load_func_t
 load_object (const gmk_floc *flocp, int noerror,
-             const char *ldname, const char *symname)
+             const char *ldname, const char *symname, void **dlp)
 {
   static void *global_dl = NULL;
   load_func_t symp;
 
+  *dlp = NULL;
+
   if (! global_dl)
     {
       global_dl = dlopen (NULL, RTLD_NOW|RTLD_GLOBAL);
@@ -46,7 +48,6 @@ load_object (const gmk_floc *flocp, int noerror,
 
   symp = (load_func_t) dlsym (global_dl, symname);
   if (! symp) {
-    void *dlp = NULL;
 
     /* If the path has no "/", try the current directory first.  */
     if (! strchr (ldname, '/')
@@ -54,14 +55,14 @@ load_object (const gmk_floc *flocp, int noerror,
        && ! strchr (ldname, '\\')
 #endif
        )
-      dlp = dlopen (concat (2, "./", ldname), RTLD_LAZY|RTLD_GLOBAL);
+      *dlp = dlopen (concat (2, "./", ldname), RTLD_LAZY|RTLD_GLOBAL);
 
     /* If we haven't opened it yet, try the default search path.  */
-    if (! dlp)
-      dlp = dlopen (ldname, RTLD_LAZY|RTLD_GLOBAL);
+    if (! *dlp)
+      *dlp = dlopen (ldname, RTLD_LAZY|RTLD_GLOBAL);
 
     /* Still no?  Then fail.  */
-    if (! dlp)
+    if (! *dlp)
       {
         if (noerror)
           DB (DB_BASIC, ("%s", dlerror()));
@@ -70,7 +71,7 @@ load_object (const gmk_floc *flocp, int noerror,
         return NULL;
       }
 
-    symp = dlsym (dlp, symname);
+    symp = dlsym (*dlp, symname);
     if (! symp)
       fatal (flocp, _("Failed to load symbol %s from %s: %s"),
              symname, ldname, dlerror());
@@ -80,7 +81,7 @@ load_object (const gmk_floc *flocp, int noerror,
 }
 
 int
-load_file (const gmk_floc *flocp, const char **ldname, int noerror)
+load_file (const gmk_floc *flocp, const char **ldname, int noerror, void **dlp)
 {
   int nmlen = strlen (*ldname);
   char *new = alloca (nmlen + CSTRLEN (SYMBOL_EXTENSION) + 1);
@@ -90,6 +91,8 @@ load_file (const gmk_floc *flocp, const char **ldname, int noerror)
   int r;
   load_func_t symp;
 
+  *dlp = NULL;
+
   /* Break the input into an object file name and a symbol name.  If no symbol
      name was provided, compute one from the object file name.  */
   fp = strchr (*ldname, '(');
@@ -165,7 +168,7 @@ load_file (const gmk_floc *flocp, const char **ldname, int noerror)
   DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, *ldname));
 
   /* Load it!  */
-  symp = load_object(flocp, noerror, *ldname, symname);
+  symp = load_object(flocp, noerror, *ldname, symname, dlp);
   if (! symp)
     return 0;
 
index f2823e1d90ca1bc875178ba667c3ac44392ee81e..d79c41c6cd34de3dd85da172a35dccf41ace2a82 100644 (file)
--- a/loadapi.c
+++ b/loadapi.c
@@ -14,8 +14,6 @@ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 You should have received a copy of the GNU General Public License along with
 this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include "gnumake.h"
-
 #include "makeint.h"
 
 #include "filedef.h"
index 812ead18cc097c696a84277faadc2cd883ee02ef..535db1d6f46b55d0ab5c5b9f7cfa1d23a9a687e8 100644 (file)
--- a/makeint.h
+++ b/makeint.h
@@ -48,8 +48,12 @@ char *alloca ();
 #endif
 
 /* Include the externally-visible content.
-   Be sure to use the local one, and not one installed on the system.  */
+   Be sure to use the local one, and not one installed on the system.
+   Define MAIN for proper selection of dllexport/dllimport declarations
+   for MS-Windows.  */
+#define MAIN
 #include "gnumake.h"
+#undef MAIN
 
 #ifdef  CRAY
 /* This must happen before #include <signal.h> so
@@ -476,7 +480,8 @@ int guile_gmake_setup (const gmk_floc *flocp);
 
 /* Loadable object support.  Sets to the strcached name of the loaded file.  */
 typedef int (*load_func_t)(const gmk_floc *flocp);
-int load_file (const gmk_floc *flocp, const char **filename, int noerror);
+int load_file (const gmk_floc *flocp, const char **filename, int noerror,
+              void **dlp);
 
 #ifdef  HAVE_VFORK_H
 # include <vfork.h>
diff --git a/read.c b/read.c
index b74e4a9a5e27b8bcd51f3364a9085a59bb28de1f..50f8414eded11c2669a3959660cb91e19adf8288 100644 (file)
--- a/read.c
+++ b/read.c
@@ -937,11 +937,12 @@ eval (struct ebuffer *ebuf, int set_default)
               struct nameseq *next = files->next;
               const char *name = files->name;
               struct dep *deps;
+              void *dlp;
 
               free_ns (files);
               files = next;
 
-              if (! load_file (&ebuf->floc, &name, noerror) && ! noerror)
+              if (! load_file (&ebuf->floc, &name, noerror, &dlp) && ! noerror)
                 fatal (&ebuf->floc, _("%s: failed to load"), name);
 
               deps = alloc_dep ();
@@ -950,6 +951,7 @@ eval (struct ebuffer *ebuf, int set_default)
               deps->file = lookup_file (name);
               if (deps->file == 0)
                 deps->file = enter_file (name);
+              deps->file->dlopen_ptr = dlp;
             }
 
           continue;
index 98c597053224b642b839c9c4ee400f981576b91e..0a72ebfda7bc577190036b7263d70f23abdccb20 100644 (file)
@@ -1,3 +1,8 @@
+2013-05-03  Eli Zaretskii  <eliz@gnu.org>
+
+       * scripts/features/load: Fix signatures of testload_gmk_setup and
+       explicit_setup, to bring them in line with the documentation.
+
 2013-04-28  Paul Smith  <psmith@gnu.org>
 
        * scripts/features/output-sync (output_sync_set): Add tests for
index 47267feea254d1178dd9802210f2dd95c8b34da4..78d5c512bb363ebde03fd4d100e69d21bc6a3679 100644 (file)
@@ -21,14 +21,14 @@ print $F <<'EOF' ;
 #include "gnumake.h"
 
 int
-testload_gmk_setup ()
+testload_gmk_setup (gmk_floc *pos)
 {
     gmk_eval ("TESTLOAD = implicit", 0);
     return 1;
 }
 
 int
-explicit_setup ()
+explicit_setup (gmk_floc *pos)
 {
     gmk_eval ("TESTLOAD = explicit", 0);
     return 1;
index cafc8649fa81640716579ca6ca2dcad1328c9f34..0a08c652d973b1f525a50be1988adfde47dcf426 100644 (file)
@@ -338,6 +338,17 @@ dlsym (void *handle, const char *name)
   return (void *)addr;
 }
 
+int
+dlclose (void *handle)
+{
+  if (!handle || handle == INVALID_HANDLE_VALUE)
+    return -1;
+  if (!FreeLibrary (handle))
+    return -1;
+
+  return 0;
+}
+
 
 #endif /* MAKE_LOAD */
 
index c95fee2bca322131d5d2ba68110df0bfdbfb0fdc..c8523ad11fdca39475d35b89288f107975d53015 100644 (file)
@@ -9,5 +9,6 @@
 extern void *dlopen (const char *, int);
 extern void *dlsym (void *, const char *);
 extern char *dlerror (void);
+extern int   dlclose (void *);
 
 #endif /* DLFCN_H */