diff options
author | Eli Zaretskii <eliz@gnu.org> | 2013-05-03 16:09:12 +0300 |
---|---|---|
committer | Eli Zaretskii <eliz@gnu.org> | 2013-05-03 16:09:12 +0300 |
commit | a66469e003526679b793f2d4623219aab2230b2f (patch) | |
tree | a8f532fab0ab0dcc11221c06896dbaf99fba5cc5 | |
parent | b5ea49bae7e5074e472605e5d0c2413e62461718 (diff) | |
download | gunmake-a66469e003526679b793f2d4623219aab2230b2f.tar.gz |
Fix interfacing with and remaking dynamic objects on MS-Windows.
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.
-rw-r--r-- | ChangeLog | 35 | ||||
-rw-r--r-- | build_w32.bat | 4 | ||||
-rw-r--r-- | commands.c | 8 | ||||
-rw-r--r-- | filedef.h | 2 | ||||
-rw-r--r-- | gnumake.h | 21 | ||||
-rw-r--r-- | load.c | 21 | ||||
-rw-r--r-- | loadapi.c | 2 | ||||
-rw-r--r-- | makeint.h | 9 | ||||
-rw-r--r-- | read.c | 4 | ||||
-rw-r--r-- | tests/ChangeLog | 5 | ||||
-rw-r--r-- | tests/scripts/features/load | 4 | ||||
-rw-r--r-- | w32/compat/posixfcn.c | 11 | ||||
-rw-r--r-- | w32/include/dlfcn.h | 1 |
13 files changed, 105 insertions, 22 deletions
@@ -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 diff --git a/build_w32.bat b/build_w32.bat index 27ac3db..43ae6e2 100644 --- a/build_w32.bat +++ b/build_w32.bat @@ -290,8 +290,10 @@ set GUILEOBJ=guile.o echo on
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% %GUILECFLAGS% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c guile.c
:LinkGCC
+Rem The version NN of libgnumake-NN.dll.a should be bumped whenever
+Rem the API changes in binary-incompatible manner.
@echo on
-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
+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
@GoTo BuildEnd
:Usage
echo Usage: %0 [options] [gcc]
@@ -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); } @@ -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. */ @@ -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_ */ @@ -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; @@ -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" @@ -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> @@ -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; diff --git a/tests/ChangeLog b/tests/ChangeLog index 98c5970..0a72ebf 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -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 diff --git a/tests/scripts/features/load b/tests/scripts/features/load index 47267fe..78d5c51 100644 --- a/tests/scripts/features/load +++ b/tests/scripts/features/load @@ -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; diff --git a/w32/compat/posixfcn.c b/w32/compat/posixfcn.c index cafc864..0a08c65 100644 --- a/w32/compat/posixfcn.c +++ b/w32/compat/posixfcn.c @@ -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 */ diff --git a/w32/include/dlfcn.h b/w32/include/dlfcn.h index c95fee2..c8523ad 100644 --- a/w32/include/dlfcn.h +++ b/w32/include/dlfcn.h @@ -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 */ |