changes for DLL support

Fergus Henderson fjh at hydra.cs.mu.oz.au
Fri Aug 29 03:33:33 AEST 1997


Hi,

Here's a cleaned-up version of DLL support for Windows.
I haven't tested this cleaned-up version on Windows yet,
so it is possible that I have introduced a few bugs in
the clean-up.  However, I've tested that this doesn't
break things on Linux.

Anyone who wants to is welcome to review this one.

--------------------

Implement support for DLLs on Windows.
The changes consisted of

1.  Adding `Makefile.DLLs', which is a file I wrote contains
    GNU Make rules for building DLLs.  Making sure that
    the various Mmakefiles include that one.

2.  Making sure we #include the "libfoo_dll.h" header file
    generated by `Makefile.DLLs' before every place that
    references a global variable.

3.  Making sure that code which defines the DLLs is
    compiled with -Dlibfoo_DEFINE_DLL.  
 
5.  Changing various places to explicitly register the data
    segment as a root set with the conservative garbage collector.
    This was necessary to get GC working with DLLs under Windows
    (there doesn't seem to be any way of automatically finding
    the data segments of DLLs under win32).

6.  Changing the way names are mangled to ensure that the assembler
    names always contain a leading underscore, since `dlltool'
    on gnu-win32 requires this.

TODO:
- Document how users can create their own DLLs.
- Add support for that to Mmake.

configure.in:
Mmake.common.in:
	Add USE_DLLS variable.  (Most of the Makefile changes below are
	conditionalized on this variable.)

boehm_gc/Makefile:
	Add dependency $(OBJS) : libgc_dll.h.
	Add `-DGC_DEFINE_DLL' to CFLAGS.
	Include Mmakefile.DLLs.
	Add new targets `dll' and `test_dll'.

boehm_gc/Mmakefile:
	Add stuff to install libgc_dll.h and libgc_globals.h.

boehm_gc/gc.h:
	For __CYGWIN32__, #include "libgc_dll.h".
	This is necessary to handle global variables in DLLs on Windows.
	For __CYGWIN32__, define GC_INIT() to add the
	data segment of the current DLL or executable as
	a new root set.

library/Mmakefile:
	Add stuff needed for building DLLs.

runtime/wrapper.mod:
library/io.m:
	Add call to GC_INIT() to register the root set for
	libmer.dll and libmercury.dll respectively.
	In wrapper.mod, move the call to GC_is_visible
	_after_ the calls to GC_INIT().

runtime/Mmakefile:
	Add stuff needed for building DLLs.

runtime/init.h:
runtime/imp.h:
runtime/dummy.c:
runtime/label.c:
runtime/memory.c:
runtime/table.c:
	For __CYGWIN32__, make sure we #include "libmer_dll.h".
	before defining global variables.
	This is necessary to handle global variables in DLLs
	on Windows.

runtime/goto.h:
util/mdemangle.c:
prof/demangle.m:
	Change the way names are mangled to ensure that the assembler
	names always contain a leading underscore, since `dlltool'
	on gnu-win32 requires this.

util/mkinit.c:
	For __CYGIN32__, when using DLLs, make sure we initialize the
	_impure_ptr of the DLLs that we're using.

library/Mmake:
runtime/Mmake:
	Compile with -Dlibfoo_USE_DLL options.
	Add code to install libfoo_dll.h and libfoo_globals.h.
	Include Mmakefile.DLLs.

cvs diff: Diffing .
Index: Mmake.common.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/Mmake.common.in,v
retrieving revision 1.22
diff -u -u -r1.22 Mmake.common.in
--- Mmake.common.in	1997/07/28 08:51:47	1.22
+++ Mmake.common.in	1997/08/28 14:45:37
@@ -50,8 +50,12 @@
 
 # Specify EXT_FOR_SHARED_LIB as `so' if the operating system
 # supports `.so' shared libraries,
+# `.dll' if it supports DLLs,
 # or as `a' if it doesn't.
 EXT_FOR_SHARED_LIB	= @EXT_FOR_SHARED_LIB@
+
+# Specify USE_DLLs as `yes' if the OS supports Windows-style DLLs
+USE_DLLS		= @USE_DLLS@
 
 # Specify any special flags to pass to the C compiler when creating objects
 # for a shared library (e.g. -fpic or -fPIC for gcc).
Index: configure.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/configure.in,v
retrieving revision 1.103
diff -u -u -r1.103 configure.in
--- configure.in	1997/08/09 10:44:31	1.103
+++ configure.in	1997/08/28 15:17:00
@@ -1303,6 +1303,7 @@
 CFLAGS_FOR_PIC="-fpic -DPIC"
 EXT_FOR_PIC_OBJECTS=pic_o
 EXT_FOR_SHARED_LIB=a
+USE_DLLS=no
 
 case "$host" in
 	i?86-*-linux|i?86-*-linux-gnu)
@@ -1388,6 +1389,15 @@
 			AC_MSG_RESULT(Read README.IRIX-5)
 		fi
 		;;
+	*-cygwin-*)
+		# disabled for now, since it hasn't been tested
+		# AC_MSG_RESULT(yes)
+		# EXT_FOR_SHARED_LIB=dll
+		# USE_DLLS=yes
+		AC_MSG_RESULT(disabled for now, because it is untested)
+
+		CFLAGS_FOR_PIC=
+		;;
 	*)
 		# CFLAGS_FOR_PIC is used by boehm_gc/Makefile when creating
 		# libgc.a.  If the system doesn't support shared libraries,
@@ -1417,6 +1427,7 @@
 AC_SUBST(CFLAGS_FOR_PIC)
 AC_SUBST(EXT_FOR_PIC_OBJECTS)
 AC_SUBST(EXT_FOR_SHARED_LIB)
+AC_SUBST(USE_DLLS)
 AC_SUBST(SHARED_LIBS)
 AC_SUBST(LIBRARY_RM_C)
 #-----------------------------------------------------------------------------#
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
Index: boehm_gc/Makefile
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/Makefile,v
retrieving revision 1.29
diff -u -u -r1.29 Makefile
--- Makefile	1997/02/09 05:47:24	1.29
+++ Makefile	1997/08/28 15:27:23
@@ -5,6 +5,7 @@
 # and changed the rule for libgc.so to use the $(LINK_SHARED_LIB) macro
 # defined in ../Mmake.common.
 # I've change the definitions of CC, AS, and CFLAGS.
+# I've also added support for DLLs on gnu-win32
 #	- fjh.
 #-----------------------------------------------------------------------------#
 
@@ -38,7 +39,7 @@
 # CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT \
 # 	  -DATOMIC_UNCOLLECTABLE
 CFLAGS= -DSILENT -DDONT_DEFINE_READ -DNO_DEBUGGING \
-	$(CFLAGS_FOR_PIC) $(EXTRA_CFLAGS)
+	$(CFLAGS_FOR_PIC) $(DLL_CFLAGS) $(EXTRA_CFLAGS)
 # Note that the `mgnuc' script also passes -DNO_SIGNALS, unless
 # profiling was enabled.
 # We need $(CFLAGS_FOR_PIC) because we might be building a shared library.
@@ -180,14 +181,14 @@
 	make -f PCR-Makefile
 
 $(OBJS) test.o dyn_load.o dyn_load_sunos53.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
-    $(srcdir)/config.h $(srcdir)/gc_typed.h Makefile
+    $(srcdir)/config.h $(srcdir)/gc_typed.h $(LIBGC_DLL_H) Makefile
 # The dependency on Makefile is needed.  Changing
 # options such as -DSILENT affects the size of GC_arrays,
 # invalidating all .o files that rely on gc_priv.h
 
 mark.o typd_mlc.o finalize.o: $(srcdir)/gc_mark.h
 
-libgc$(PROF).a: gc.a
+libgc$(PROF)$(DLL_DEF_LIB).a: gc.a
 	rm -f libgc$(PROF).a
 	# `ln -s' here doesn't work with gnu-win32, so we use `cp' instead
 	cp gc.a libgc$(PROF).a
@@ -386,3 +387,28 @@
 		sed s/_GC_/GC_/g < $$file > tmp; \
 		cp tmp $$file; \
 		done
+
+#-----------------------------------------------------------------------------#
+# support for DLLs using gnu-win32
+#-----------------------------------------------------------------------------#
+ifeq ($(USE_DLLS),yes)
+
+LIBGC_DLL_H = libgc_dll.h 
+LIBGC_GLOBALS_H = libgc_globals.h 
+
+DLL_CFLAGS = -DGC_DEFINE_DLL
+
+.PHONY: dll
+dll: libgc.dll libgc.a libgc_dll.h libgc_globals.h
+
+test_dll.o: test.c libgc_dll.h libgc_globals.h
+	$(CC) $(CFLAGS) -UGC_DEFINE_DLL -c test.c -o test_dll.o
+
+test_dll: test_dll.o libgc.a libgc.dll
+	$(CC) test_dll.o -L$(ABSDIR) -lgc -o test_dll
+
+SYM_PREFIX-libgc=GC
+include ../Makefile.DLLs
+
+endif
+#-----------------------------------------------------------------------------#
Index: boehm_gc/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/Mmakefile,v
retrieving revision 1.2
diff -u -u -r1.2 Mmakefile
--- Mmakefile	1997/07/27 14:59:08	1.2
+++ Mmakefile	1997/08/28 15:54:47
@@ -20,6 +20,8 @@
 
 libgc$(PROF).so: submake
 
+libgc$(PROF).dll: submake
+
 #	We need to export MAKEFLAGS="" to avoid passing the `-r' (suppress
 #	builtin rules) supplied by Mmake to the boehm_gc Makefile, which
 #	needs the builtin rules. 
@@ -47,9 +49,19 @@
 # As well as installing gc.h, we also install gc_inl.h (and hence
 # private/gc_priv.h, private/gc_hdrs.h, and private/config.h),
 # for use with `-DINLINE_ALLOC'.
+# If we're using DLLs, we also want libgc_dll.h and libgc_globals.h.
 
-HEADERS=gc.h include/gc_inl.h
+HEADERS=gc.h include/gc_inl.h $(LIBGC_DLL_H) $(LIBGC_GLOBALS_H)
 PRIVATE_HEADERS=gc_priv.h gc_hdrs.h config.h
+
+ifeq ($(USE_DLLS),yes)
+
+LIBGC_DLL_H = libgc_dll.h 
+LIBGC_GLOBALS_H = libgc_globals.h 
+
+endif
+#-----------------------------------------------------------------------------#
+
 
 .PHONY: install_headers
 install_headers:
Index: boehm_gc/gc.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/gc.h,v
retrieving revision 1.14
diff -u -u -r1.14 gc.h
--- gc.h	1996/12/06 11:48:21	1.14
+++ gc.h	1997/08/28 13:35:45
@@ -25,6 +25,10 @@
  * Everything else is best ignored unless you encounter performance
  * problems.
  */
+
+/*
+ * I added support for Windows DLLs using gnu-win32.  -fjh.
+ */
  
 #ifndef _GC_H
 
@@ -32,6 +36,9 @@
 # define __GC
 # include <stddef.h>
 
+#if defined(__CYGWIN32__)
+#include "libgc_dll.h"
+#endif
 
 #if defined(_MSC_VER) && defined(_DLL)
 #ifdef GC_BUILD
@@ -615,7 +622,6 @@
 # define pthread_create GC_pthread_create
 # define pthread_sigmask GC_pthread_sigmask
 # define pthread_join GC_pthread_join
-
 #endif /* IRIX_THREADS */
 
 #if defined(SOLARIS_THREADS) || defined(IRIX_THREADS)
@@ -638,6 +644,16 @@
 #   define GC_INIT() { extern end, etext; \
 		       extern void GC_noop(void *, void *); \
 		       GC_noop(&end, &etext); }
+/*
+ * Similarly GC_INIT() is also required for gnu-win32 DLLs.
+ * I don't know any other method for figuring out the start and
+ * end of the main program's global data from inside a DLL.
+ */
+#elif defined(__CYGWIN32__) && defined(GC_USE_DLL)
+#   define GC_INIT() { \
+		extern int _bss_start__, _data_end__; \
+		GC_add_roots((void *)&_bss_start__, (void *)&_data_end__); \
+    }
 #else
 #   define GC_INIT()
 #endif
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/Mmakefile,v
retrieving revision 1.3
diff -u -u -r1.3 Mmakefile
--- Mmakefile	1997/07/27 14:59:47	1.3
+++ Mmakefile	1997/08/28 15:02:39
@@ -99,8 +99,8 @@
 
 #-----------------------------------------------------------------------------#
 
-tags		: $(MTAGS) $(mercury_compile.ms) $(LIBRARY_DIR)/*.m
-	$(MTAGS) $(mercury_compile.ms) $(LIBRARY_DIR)/*.m
+tags		: $(mercury_compile.ms) $(LIBRARY_DIR)/*.m
+	$(MTAGS) $(MTAGSFLAGS) $(mercury_compile.ms) $(LIBRARY_DIR)/*.m
 
 mercury_compile.stats : source_stats.awk $(mercury_compile.ms)
 	awk -f `vpath_find source_stats.awk` \
cvs diff: Diffing compiler/notes
cvs diff: Diffing doc
cvs diff: Diffing extras
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/Togl-1.2
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing library
Index: library/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/Mmakefile,v
retrieving revision 1.12
diff -u -u -r1.12 Mmakefile
--- Mmakefile	1997/07/29 04:19:49	1.12
+++ Mmakefile	1997/08/28 15:05:52
@@ -56,12 +56,32 @@
 		--cflags "-I$(RUNTIME_DIR) -I$(BOEHM_GC_DIR) $(EXTRA_CFLAGS)" \
 		--intermodule-optimization
 MGNUC	=	MERCURY_C_INCL_DIR=$(RUNTIME_DIR) $(SCRIPTS_DIR)/mgnuc
-MGNUCFLAGS =	-I$(RUNTIME_DIR) -I$(BOEHM_GC_DIR) $(EXTRA_CFLAGS)
+MGNUCFLAGS =	-I$(RUNTIME_DIR) -I$(BOEHM_GC_DIR) \
+		$(DLL_CFLAGS) $(EXTRA_CFLAGS)
+LDFLAGS	=	-L$(BOEHM_GC_DIR) -L$(RUNTIME_DIR)
+LDLIBS	=	-lmer							\
+		` case "$(GRADE)" in 					\
+		    *.gc.prof)	echo "-lgc_prof" ;;			\
+		    *.gc)	echo "-lgc" ;;				\
+		  esac							\
+		`
 
 MTAGS	=	$(SCRIPTS_DIR)/mtags
 
 #-----------------------------------------------------------------------------#
 
+# Stuff for Windows DLLS using gnu-win32
+
+ifeq ($(USE_DLLS),yes)
+
+DLL_CFLAGS = -Dlibmercury_DEFINE_DLL
+
+include $(MERCURY_DIR)/Makefile.DLLs
+
+endif
+
+#-----------------------------------------------------------------------------#
+
 NU_LIBRARY_NOS = \
 	io.nu.no require.nu.no std_util.nu.no string.nu.no term_io.nu.no \
 	int.nu.no float.nu.no char.nu.no mercury_builtin.nu.no library.nu.no
@@ -140,7 +160,7 @@
 libmercury : tree234.o
 libmercury : libmercury.a libmercury.$(EXT_FOR_SHARED_LIB) libmercury.init
 
-libmercury.a : $(library.os)
+libmercury$(DLL_DEF_LIB).a : $(library.os)
 	rm -f libmercury.a
 	ar cr libmercury.a $(library.os)
 	$(RANLIB) libmercury.a
@@ -151,13 +171,7 @@
 libmercury.so : $(library.pic_os)
 	$(LINK_SHARED_OBJ) -o libmercury.so $(library.pic_os)		\
 		$(RPATH_1)$(RPATH_2)					\
-		-L$(RUNTIME_DIR) -lmer 					\
-		-L$(BOEHM_GC_DIR)					\
-		` case "$(GRADE)" in					\
-			*.gc.prof) echo "-lgc_prof" ;;			\
-			*.gc) echo "-lgc" ;;				\
-		  esac							\
-		`							\
+		$(LDFLAGS) $(LDLIBS)					\
 		$(SHARED_LIBS)
 
 libmercury.init: library.dep
Index: library/io.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/io.m,v
retrieving revision 1.134
diff -u -u -r1.134 io.m
--- io.m	1997/08/05 04:37:51	1.134
+++ io.m	1997/08/28 16:31:54
@@ -2111,6 +2111,7 @@
    The handwritten code below is almost equivalent to
 
 	io__run :-
+		gc_init,
 		initial_external_state(IO0),
 		program_entry_point(IO0, IO),
 		final_io_state(IO).
@@ -2129,6 +2130,9 @@
 	init_label(mercury__io__run_0_0_i2);
 BEGIN_CODE
 Define_entry(mercury__io__run_0_0);
+
+	GC_INIT();
+
         mkframe(""mercury__io__run_0_0"", 0, ENTRY(do_fail));
 	r1 = initial_external_state();
 	noprof_call(ENTRY(mercury__io__init_state_2_0),
cvs diff: Diffing lp_solve
cvs diff: Diffing lp_solve/lp_examples
cvs diff: Diffing profiler
Index: profiler/demangle.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/profiler/demangle.m,v
retrieving revision 1.1
diff -u -u -r1.1 demangle.m
--- demangle.m	1997/07/26 11:41:48	1.1
+++ demangle.m	1997/08/28 12:54:06
@@ -42,11 +42,14 @@
 :- pred demangle_from_asm(string, string).
 :- mode demangle_from_asm(in, out) is semidet.
 demangle_from_asm -->
-	% skip any leading underscore inserted by the C compiler
-	maybe_remove_prefix("_"),
-
-	% skip the `entry_' prefix, if any
-	maybe_remove_prefix("entry_"),
+	% skip any leading underscore inserted by the C compiler,
+	% and skip the `_entry_' prefix, if any.
+	( remove_prefix("_entry_") ->
+		[]
+	;
+		maybe_remove_prefix("_"),
+		maybe_remove_prefix("_entry_")
+	),
 
 	demangle_from_c.
 
cvs diff: Diffing runtime
Index: runtime/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/Mmakefile,v
retrieving revision 1.9
diff -u -u -r1.9 Mmakefile
--- Mmakefile	1997/08/23 22:34:08	1.9
+++ Mmakefile	1997/08/28 15:12:22
@@ -14,7 +14,7 @@
 #-----------------------------------------------------------------------------#
 
 CFLAGS		= -I$(MERCURY_DIR)/runtime -I$(MERCURY_DIR)/boehm_gc -g \
-		  $(EXTRA_CFLAGS)
+		  $(DLL_CFLAGS) $(EXTRA_CFLAGS)
 MGNUC		= MERCURY_C_INCL_DIR=. $(SCRIPTS_DIR)/mgnuc
 MGNUCFLAGS	= --no-ansi $(CFLAGS)
 MOD2C		= $(SCRIPTS_DIR)/mod2c
@@ -22,14 +22,19 @@
 #-----------------------------------------------------------------------------#
 
 #		  keep this list in alphabetical order, please
-HDRS		= misc.h calls.h conf.h context.h \
+HDRS		= calls.h conf.h context.h \
 		  deep_copy.h dlist.h debug.h dummy.h \
 		  engine.h getopt.h goto.h heap.h imp.h init.h label.h \
 		  memory.h mercury_float.h mercury_string.h mercury_trail.h \
-		  mercury_types.h \
+		  mercury_types.h misc.h \
 		  overflow.h prof.h prof_mem.h regorder.h regs.h \
 		  spinlock.h std.h stacks.h \
-		  table.h tags.h timing.h type_info.h wrapper.h
+		  table.h tags.h timing.h type_info.h wrapper.h \
+		  $(LIBMER_DLL_H)
+# Note that `libmer_globals.h' cannot be part of $(HDR),
+# since it depends on libmer_def.a, and $(OBJ) : $(HDR) would create a
+# circular dependency.
+
 
 MACHHDRS	= machdeps/no_regs.h machdeps/i386_regs.h \
 		  machdeps/mips_regs.h machdeps/sparc_regs.h \
@@ -48,6 +53,29 @@
 # 		  memory.o table.o timing.o
 PIC_OBJS	= $(OBJS:.o=.$(EXT_FOR_PIC_OBJECTS))
 
+LDFLAGS		= -L$(BOEHM_GC_DIR)
+LDLIBS		= \
+		` case "$(GRADE)" in 					\
+		    *.gc.prof)	echo "-lgc_prof" ;;			\
+		    *.gc)	echo "-lgc" ;;				\
+		  esac							\
+		`
+
+#-----------------------------------------------------------------------------#
+
+# Stuff for Windows DLLs
+
+ifeq ($(USE_DLLS),yes)
+
+DLL_CFLAGS	= -Dlibmer_DEFINE_DLL
+
+LIBMER_DLL_H	 = libmer_dll.h
+LIBMER_GLOBALS_H = libmer_globals.h
+
+include $(MERCURY_DIR)/Makefile.DLLs
+
+endif
+
 #-----------------------------------------------------------------------------#
 
 $(OBJS) $(PIC_OBJS): $(HDRS) $(MACHHDRS)
@@ -55,9 +83,10 @@
 #-----------------------------------------------------------------------------#
 
 .PHONY: lib
-lib: libmer.a libmer.$(EXT_FOR_SHARED_LIB) runtime.init
+lib: libmer.a libmer.$(EXT_FOR_SHARED_LIB) runtime.init \
+	$(LIBMER_DLL_H) $(LIBMER_GLOBALS_H)
 
-libmer.a: $(OBJS)
+libmer$(DLL_DEF_LIB).a: $(OBJS)
 	rm -f libmer.a
 	ar cr libmer.a $(OBJS)
 	$(RANLIB) libmer.a
@@ -65,12 +94,7 @@
 libmer.so: $(PIC_OBJS)
 	$(LINK_SHARED_OBJ) -o libmer.so $(PIC_OBJS)			\
 		$(SHLIB_RPATH_OPT)$(INSTALL_MERC_GC_LIB_DIR) 		\
-		-L$(BOEHM_GC_DIR)					\
-		` case "$(GRADE)" in 					\
-		    *.gc.prof)	echo "-lgc_prof" ;;			\
-		    *.gc)	echo "-lgc" ;;				\
-		  esac							\
-		`							\
+		$(LDFLAGS) $(LDLIBS)					\
 		$(SHARED_LIBS)
 
 runtime.init: $(MOD_CS)
@@ -106,10 +130,10 @@
 install: install_headers install_init install_lib
 
 .PHONY: install_headers
-install_headers: $(HDRS) $(MACHHDRS)
+install_headers: $(HDRS) $(MACHHDRS) $(LIBMER_GLOBALS_H)
 	-[ -d $(INSTALL_INC_DIR)/machdeps ] || \
 		mkdir -p $(INSTALL_INC_DIR)/machdeps
-	cp `vpath_find $(HDRS)` $(INSTALL_INC_DIR)
+	cp `vpath_find $(HDRS) $(LIBMER_GLOBALS_H)` $(INSTALL_INC_DIR)
 	chmod u+w $(INSTALL_INC_DIR)/conf.h
 	cp `vpath_find $(MACHHDRS)` $(INSTALL_INC_DIR)/machdeps
 
Index: runtime/dummy.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/dummy.c,v
retrieving revision 1.10
diff -u -u -r1.10 dummy.c
--- dummy.c	1997/07/27 15:08:12	1.10
+++ dummy.c	1997/08/27 14:28:36
@@ -5,6 +5,7 @@
 */
 
 #include "dummy.h"
+#include "imp.h"	/* we need libmer_globals.h for Windows DLLs */
 
 /*
 ** This dummy function is in a file of its own to ensure
Index: runtime/goto.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/goto.h,v
retrieving revision 1.31
diff -u -u -r1.31 goto.h
--- goto.h	1997/07/27 15:08:17	1.31
+++ goto.h	1997/08/27 14:28:36
@@ -40,7 +40,7 @@
 
 #define paste(a,b) a##b
 #define stringify(string) #string
-#define entry(label) paste(entry_,label)
+#define entry(label) paste(_entry_,label)
 #define skip(label) paste(skip_,label)
 
 #ifdef SPLIT_C_FILES
@@ -188,7 +188,7 @@
   */
   #ifdef __ELF__
     #define INLINE_ASM_ENTRY_LABEL_TYPE(label) \
-	"	.type entry_" stringify(label) ", at function\n"
+	"	.type _entry_" stringify(label) ", at function\n"
   #endif
 
 #elif defined (__sparc)
@@ -249,7 +249,7 @@
   ** Hence the `.type' directive below.
   */
   #define INLINE_ASM_ENTRY_LABEL_TYPE(label) \
-	"	.type entry_" stringify(label) ",#function\n"
+	"	.type _entry_" stringify(label) ",#function\n"
 
 #endif
 
@@ -290,7 +290,7 @@
 */
 #ifndef INLINE_ASM_GLOBALIZE_LABEL
 #define INLINE_ASM_GLOBALIZE_LABEL(label) \
-	"	.globl entry_" stringify(label) "\n"
+	"	.globl _entry_" stringify(label) "\n"
 #endif
 
 /*
@@ -308,7 +308,7 @@
 */
 #ifndef INLINE_ASM_ENTRY_LABEL
 #define INLINE_ASM_ENTRY_LABEL(label)	\
-	"entry_" stringify(label) ":\n"
+	"_entry_" stringify(label) ":\n"
 #endif
 
 /*
@@ -433,9 +433,9 @@
 
   #if defined(USE_ASM_LABELS)
     #define Declare_entry(label)	\
-	extern void label(void) __asm__("entry_" stringify(label))
+	extern void label(void) __asm__("_entry_" stringify(label))
     #define Declare_static(label)	\
-	static void label(void) __asm__("entry_" stringify(label))
+	static void label(void) __asm__("_entry_" stringify(label))
     #define Define_extern_entry(label)	Declare_entry(label)
     #define Define_entry(label)		\
 		ASM_ENTRY(label)	\
Index: runtime/imp.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/imp.h,v
retrieving revision 1.110
diff -u -u -r1.110 imp.h
--- imp.h	1997/08/23 22:34:07	1.110
+++ imp.h	1997/08/27 14:28:36
@@ -19,6 +19,14 @@
 #ifndef IMP_H
 #define IMP_H
 
+/*
+** The following must come before any definitions of global variables.
+** This is necessary to support DLLs on Windows.
+*/
+#ifdef __CYGWIN32__
+  #include "libmer_dll.h"
+#endif
+
 #include	"regs.h"	/* must come before system headers */
 
 #include	"conf.h"
Index: runtime/init.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/init.h,v
retrieving revision 1.16
diff -u -u -r1.16 init.h
--- init.h	1997/07/27 15:08:21	1.16
+++ init.h	1997/08/27 14:28:36
@@ -12,6 +12,14 @@
 #ifndef	INIT_H
 #define	INIT_H
 
+/*
+** The following must come before any definitions of global variables.
+** This is necessary to support DLLs on Windows.
+*/
+#if defined(__CYGWIN32__)
+  #include "libmer_dll.h"
+#endif
+
 #include "goto.h"		/* for Declare_entry */
 #include "mercury_types.h"	/* for `Code *' */
 #include "wrapper.h"		/* for do_init_modules() */
Index: runtime/label.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/label.c,v
retrieving revision 1.21
diff -u -u -r1.21 label.c
--- label.c	1997/07/27 15:08:22	1.21
+++ label.c	1997/08/27 14:28:36
@@ -16,6 +16,7 @@
 
 #include	"label.h"
 
+#include	"imp.h"		/* we need libmer_globals.h for Windows DLLs */
 #include	"table.h"	/* for `Table' */
 #include	"prof.h"	/* for prof_output_addr_decls() */
 #include	"engine.h"	/* for `progdebug' */
Index: runtime/memory.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/memory.c,v
retrieving revision 1.74
diff -u -u -r1.74 memory.c
--- memory.c	1997/08/23 22:34:15	1.74
+++ memory.c	1997/08/27 14:28:36
@@ -29,6 +29,9 @@
 
 /*---------------------------------------------------------------------------*/
 
+#ifdef __CYGWIN32__
+  #include "libmer_dll.h"
+#endif
 #include "regs.h"	/* must come first, due to global register vars */
 #include "conf.h"	/* must come second */
 
Index: runtime/table.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/table.c,v
retrieving revision 1.15
diff -u -u -r1.15 table.c
--- table.c	1997/07/27 15:08:45	1.15
+++ table.c	1997/08/28 12:45:29
@@ -15,6 +15,10 @@
 
 #define	HASHDEBUG
 
+#ifdef __CYGWIN32__
+  #include	"libmer_dll.h"
+#endif
+
 #include	<stdio.h>
 #include	"std.h"
 #include	"dlist.h"
Index: runtime/wrapper.mod
===================================================================
RCS file: /home/staff/zs/imp/mercury/runtime/wrapper.mod,v
retrieving revision 1.77
diff -u -u -r1.77 wrapper.mod
--- wrapper.mod	1997/08/23 22:34:13	1.77
+++ wrapper.mod	1997/08/28 13:01:48
@@ -148,13 +148,23 @@
 #ifdef CONSERVATIVE_GC
 	GC_quiet = TRUE;
 
+	/*
+	** Call GC_INIT() to tell the garbage collector about this DLL.
+	** (This is necessary to support Windows DLLs using gnu-win32.)
+	*/
+	GC_INIT();
+
+	/*
+	** call the init_gc() function defined in <foo>_init.c,
+	** which calls GC_INIT() to tell the GC about the main program.
+	** (This is to work around a Solaris 2.X (X <= 4) linker bug,
+	** and also to support Windows DLLs using gnu-win32.)
+	*/
+	(*address_of_init_gc)();
+
 	/* double-check that the garbage collector knows about
 	   global variables in shared libraries */
 	GC_is_visible(fake_reg);
-
-	/* call the init_gc() function defined in <foo>_init.c - */
-	/* this is to work around a Solaris 2.X (X <= 4) linker bug */
-	(*address_of_init_gc)();
 
 	/* The following code is necessary to tell the conservative */
 	/* garbage collector that we are using tagged pointers */
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing scripts
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/general
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trial
cvs diff: Diffing util
Index: util/mdemangle.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/util/mdemangle.c,v
retrieving revision 1.20
diff -u -u -r1.20 mdemangle.c
--- mdemangle.c	1997/07/27 15:09:58	1.20
+++ mdemangle.c	1997/08/28 12:51:30
@@ -84,7 +84,7 @@
 
 static void 
 demangle(char *name) {
-	static const char entry[]   = "entry_";
+	static const char entry[]   = "_entry_";
 	static const char mercury[] = "mercury__";
 	static const char func_prefix[] = "fn__"; /* added for functions */
 	static const char unify[]   = "__Unify___";
@@ -119,13 +119,15 @@
 
 	/*
 	** skip any leading underscore inserted by the C compiler
+	** (but don't skip it if it came from the `_entry_' prefix)
 	*/
-	if (*start == '_') start++;
+	if (*start == '_' && strncmp(start, entry, strlen(entry)) != 0) {
+		start++;
+	}
 
 	/*
-	** skip the `entry_' prefix, if any
+	** skip the `_entry_' prefix, if any
 	*/
-
 	strip_prefix(&start, entry);
 
 	/*
Index: util/mkinit.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/util/mkinit.c,v
retrieving revision 1.17
diff -u -u -r1.17 mkinit.c
--- mkinit.c	1997/07/27 15:09:59	1.17
+++ mkinit.c	1997/08/27 14:28:36
@@ -83,6 +83,19 @@
 	"extern char *GC_stackbottom;\n"
 	"#endif\n"
 	"\n"
+	"#if defined(__CYGWIN32__)\n"
+	"  #if defined(libmer_USE_DLL)\n"
+	"       #define libmer_impure_ptr \\\n"
+	"		(*__imp_libmer_impure_ptr)\n"
+	"	extern void *libmer_impure_ptr;\n"
+	"  #endif\n"
+	"  #if defined(libmercury_USE_DLL)\n"
+	"       #define libmercury_impure_ptr \\\n"
+	"		(*__imp_libmercury_impure_ptr)\n"
+	"	extern void *libmercury_impure_ptr;\n"
+	"  #endif\n"
+	"#endif\n"
+	"\n"
 	"int mercury_main(int argc, char **argv, char *stackbottom)\n"
 	"{\n"
 	"\n"
@@ -94,6 +107,20 @@
 	"	** it may also be helpful on other systems.\n"
 	"	*/\n"
 	"	GC_stackbottom = stackbottom;\n"
+	"#endif\n"
+	"\n"
+	"/*\n"
+	"** If we're using DLLs on gnu-win32, then we need\n"
+	"** to take special steps to initialize _impure_ptr\n"
+	"** for the DLLs.\n"
+	"*/\n"
+	"#if defined(__CYGWIN32__)\n"
+	"  #if defined(libmer_USE_DLL)\n"
+	"	libmer_impure_ptr = _impure_ptr;\n"
+	"  #endif\n"
+	"  #if defined(libmercury_USE_DLL)\n"
+	"	libmercury_impure_ptr = _impure_ptr;\n"
+	"  #endif\n"
 	"#endif\n"
 	"\n"
 	"	address_of_mercury_init_io = mercury_init_io;\n"


#-----------------------------------------------------------------------------#
# Copyright (C) 1997 The University of Melbourne. 
# This file may only be copied under the terms of the GNU General
# Public Licence - see the file COPYING in the Mercury distribution.
#-----------------------------------------------------------------------------#

# Makefile.DLLs, version 0.5b.

# This Makefile contains rules for creating DLLs on Windows using gnu-win32.

#-----------------------------------------------------------------------------#

# The SYM_PREFIX is used as a prefix for the symbols in the files
# that this makefile automatically generates.
#
# The default SYM_PREFIX for libfoo.dll is `libfoo'.
# But you can override this by setting `SYM_PREFIX-libfoo = blah'.

SYM_PREFIX = $(firstword $(SYM_PREFIX-$*) $*)

GUARD_MACRO =		$(SYM_PREFIX)_GLOBALS_H
DEFINE_DLL_MACRO =	$(SYM_PREFIX)_DEFINE_DLL
USE_DLL_MACRO =		$(SYM_PREFIX)_USE_DLL
IMP_MACRO =		$(SYM_PREFIX)_IMP
GLOBAL_MACRO =		$(SYM_PREFIX)_GLOBAL
IMPURE_PTR =		$(SYM_PREFIX)_impure_ptr

# You should change your rule for creating `foo.a' to instead
# create `foo$(DLL_DEF_LIB).a'.  Then this makefile will create
# `foo.a' from `foo_def.a'.
DLL_DEF_LIB = _def

# This rule creates a `.def' file, which lists the symbols that are exported
# from the DLL.  We use `nm' to get a list of all the exported text (`T')
# symbols and data symbols -- including uninitialized data (`B'),
# initialized data (`D'), read-only data (`R'), and common blocks (`C').
# We also export `_impure_ptr', suitably renamed, so that the 
# main program can do the necessary initialization of the DLL's _impure_ptr.
# (Since there can be more than one DLL, we must rename _impure_ptr as
# $(SYM_PREFIX)_impure_ptr to prevent name collisions.)
%.def: %_def.a
	echo EXPORTS > $@
	echo $(IMPURE_PTR) = _impure_ptr >> $@
	nm $< | sed -n '/^........ [BCDRT] _/s/[^_]*_//p' >> $@

# We need to use macros to access global data:
# the user of the DLL must refer to `bar' as `(*__imp_bar)'.
# This rule creates a pair of files `foo_dll.h' and `foo_globals.h'
# which contains macros for doing this.
#
# The DLL may also contain some references to _impure_ptr
# (e.g. stdin is defined as a macro which expands to _impure_ptr.stdin).
# We need to provide a definition for this (otherwise it will link in
# the definition in libccrt.o, which causes lots of problems,
# eventually leading to undefined symbol `WinMain').
# The main program needs to initialize all the _impure_ptr variables
# for the DLLs with its _impure_ptr.

%_dll.h:
	echo "/* automatically generated by Makefile.DLLs */"	> $@
	echo "#ifndef $(GUARD_MACRO)"				>> $@
	echo "#define $(GUARD_MACRO)"				>> $@
	echo ""							>> $@
	echo "#if defined(__GNUC__) && defined(__CYGWIN32__)"	>> $@
	echo "  #if !defined($(DEFINE_DLL_MACRO))"		>> $@
	echo "    #define $(IMP_MACRO)(name)	__imp_##name" 	>> $@
	echo "    #define $(GLOBAL_MACRO)(name)	(*$(IMP_MACRO)(name))" >> $@
	echo "    #include \"$*_globals.h\""			>> $@
	echo "  #endif /* $(DEFINE_DLL_MACRO) */"		>> $@
	echo "#endif /* __GNUC__ && __CYGWIN32__ */"		>> $@
	echo ""							>> $@
	echo "#endif /* $(GUARD_MACRO) */"			>> $@

%_globals.h: %_def.a
	echo "/* automatically generated by Makefile.DLLs */"	> $@
	for sym in $(IMPURE_PTR) \
		`nm $< | grep '^........ [BCDR] _' | sed 's/[^_]*_//'`; \
	do \
		echo "#define $$sym	$(GLOBAL_MACRO)($$sym)"	>> $@; \
	done

%_dll.c:
	echo "/* automatically generated by Makefile.DLLs */"	> $@
	echo "void *_impure_ptr;"				>> $@

# This rule creates the export object file (`foo.exp') which contains the
# jump table array; this export object file becomes part of the DLL. 
# This rule also creates the import library (`foo.a') which contains small
# stubs for all the functions exported by the DLL which jump to them via the
# jump table.  Executables that will use the DLL must be linked against this
# stub library.
%.exp %.a : %.def
	dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*)		\
		--def $<					\
		--dllname $*.dll				\
		--output-exp $*.exp				\
		--output-lib $*.a

# The `sed' commands below are to convert DOS-style `C:\foo\bar'
# pathnames into Unix-style `//c/foo/bar' pathnames.
CYGWIN32_LIBS = $(shell echo					\
	-L`dirname \`gcc -print-file-name=libgcc.a |		\
	sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1 at g' -e 's@\\\\\\\\@/@g' \` ` \
	-L`dirname \`gcc -print-file-name=libcygwin.a |	\
	sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1 at g' -e 's@\\\\\\\\@/@g' \` ` \
	-L`dirname \`gcc -print-file-name=libkernel32.a | \
	sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1 at g' -e 's@\\\\\\\\@/@g' \` ` \
	-lgcc -lcygwin -lkernel32 -lgcc)

# Making relocatable DLLs doesn't seem to work.
# Note quite sure why.  The --image-base values below
# where chosen at random, they seem to work on my machine.
RELOCATABLE=no
LDFLAGS-libgc +=	--image-base=0x2345000
LDFLAGS-libmer +=	--image-base=0x1234000
LDFLAGS-libmercury +=	--image-base=0x3456000

ifeq "$(strip $(RELOCATABLE))" "yes"

# to create relocatable DLLs, we need to do two passes
# (warning: this is untested)
%.dll: %.exp %_def.a %_dll.o dll_init.o dll_fixup.o
	$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $*.base			\
		-e _dll_entry at 12					\
		$*.exp $*_def.a $*_dll.o				\
		dll_init.o dll_fixup.o					\
		$(LDLIBS) $(LDLIBS-$*)					\
		$(CYGWIN32_LIBS)
	# untested
	dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*)		\
		--def $*.def					\
		--dllname $*.dll				\
		--base-file $*.base				\
		--output-exp $*.exp
	$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $*.base			\
		-e _dll_entry at 12					\
		$*.exp $*_def.a $*_dll.o				\
		dll_init.o dll_fixup.o					\
		$(LDLIBS) $(LDLIBS-$*)					\
		$(CYGWIN32_LIBS)
	dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*)		\
		--def $*.def					\
		--dllname $*.dll				\
		--base-file $*.base				\
		--output-exp $*.exp
	# end untested stuff
	$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll --base-file $*.base -o $@	\
		-e _dll_entry at 12 					\
		$*.exp $*_def.a $*_dll.o 				\
		dll_init.o dll_fixup.o					\
		$(LDLIBS) $(LDLIBS-$*)					\
		$(CYGWIN32_LIBS)
	rm -f $*.base

else

%.dll: %.exp %_def.a %_dll.o dll_fixup.o dll_init.o
	$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $@			\
		-e _dll_entry at 12 					\
		$*.exp $*_def.a $*_dll.o 				\
		dll_init.o dll_fixup.o					\
		$(LDLIBS) $(LDLIBS-$*)					\
		$(CYGWIN32_LIBS)

endif

# This black magic piece of assembler needs to be linked in in order to
# properly terminate the list of imported DLLs.
dll_fixup.s:
	echo '.section .idata$$3' 	> dll_fixup.s
	echo '.long 0,0,0,0, 0,0,0,0'	>> dll_fixup.s

dll_fixup.o: dll_fixup.s
	$(AS) $(ASFLAGS) -o dll_fixup.o dll_fixup.s

# Windows requires each DLL to have an initialization function
# that is called at certain points (thread/process attach/detach).
# This one just doesn't do anything.
dll_init.c:
	echo '__attribute__((stdcall))' > dll_init.c
	echo 'int dll_entry(int handle, int reason, void *ptr)' >> dll_init.c
	echo '{ return 1; }' >> dll_init.c

# The following rule is just there to convince gcc
# to keep otherwise unused intermediate targets around.
dont_throw_away: dll_fixup.o dll_init.o

.PHONY: clean
clean: clean_dll

.PHONY: clean_dll
clean_dll
	-rm -f dll_init.c dll_init.o dll_fixup.s dll_fixup.o

#-----------------------------------------------------------------------------#

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list