[project @ 2000-05-12 15:59:37 by sewardj]
authorsewardj <unknown>
Fri, 12 May 2000 15:59:37 +0000 (15:59 +0000)
committersewardj <unknown>
Fri, 12 May 2000 15:59:37 +0000 (15:59 +0000)
Cygwin support machinery for manufacturing DietHEP.dll and building a
small demo program (dh_demo.exe).

ghc/interpreter/DietHEP.def [new file with mode: 0644]
ghc/interpreter/Makefile-DietHEP [new file with mode: 0644]
ghc/interpreter/Makefile.DLLs [new file with mode: 0644]
ghc/interpreter/dh_demo.c [new file with mode: 0644]

diff --git a/ghc/interpreter/DietHEP.def b/ghc/interpreter/DietHEP.def
new file mode 100644 (file)
index 0000000..8feafbd
--- /dev/null
@@ -0,0 +1,4 @@
+EXPORTS
+DietHEP_impure_ptr = _impure_ptr
+DH_GetProcAddress
+DH_LoadLibrary
diff --git a/ghc/interpreter/Makefile-DietHEP b/ghc/interpreter/Makefile-DietHEP
new file mode 100644 (file)
index 0000000..b64c281
--- /dev/null
@@ -0,0 +1,126 @@
+
+# --------------------------------------------------------------------------- #
+# $Id: Makefile-DietHEP,v 1.1 2000/05/12 15:59:37 sewardj Exp $                      #
+# --------------------------------------------------------------------------- #
+
+TOP = ..
+include $(TOP)/mk/boilerplate.mk
+SUBDIRS = lib
+
+# --------------------------------------------------------------------- #
+# interpreter and relevant .a/.so files                                 #
+# --------------------------------------------------------------------- #
+
+ifeq "$(TARGETPLATFORM)" "i386-unknown-cygwin32"
+DYN_EXT=.dll
+LIB_DL=
+else
+DYN_EXT=.so
+LIB_DL=-ldl
+endif
+
+ifeq "$(HaveLibGmp)$" "YES"
+LIB_GMP=-lgmp
+else
+LIB_GMP=../rts/gmp/libgmp.a
+endif
+
+YACC = bison -y
+%.c: %.y
+       -$(YACC) $<
+       mv y.tab.c $@
+       rm -f input.o
+
+HS_SRCS =
+
+Y_SRCS = parser.y
+C_SRCS = link.c type.c static.c storage.c derive.c input.c compiler.c subst.c \
+     translate.c codegen.c lift.c free.c stgSubst.c output.c   \
+     hugs.c dynamic.c stg.c sainteger.c object.c interface.c
+
+SRC_CC_OPTS = -I$(GHC_INTERPRETER_DIR) -I$(GHC_INCLUDE_DIR) -I$(GHC_RUNTIME_DIR) -D__HUGS__ -DCOMPILING_RTS -DNO_REGS -Wall -Wstrict-prototypes -Wno-unused -DDEBUG -Winline -g -DDIET_HEP
+
+GHC_LIBS_NEEDED = $(GHC_RUNTIME_DIR)/libHSrts.a \
+                  $(GHC_RUNTIME_DIR)/gmp/libgmp.a
+
+all :: parser.c $(GHC_LIBS_NEEDED) nHandle$(DYN_EXT) dh_demo.exe
+
+dh_demo.exe: DietHEP.dll
+       gcc -Wall -g -o dh_demo.exe dh_demo.c DietHEP_dll.a
+
+### EXTREMELY hacky
+DietHEP.a: $(C_OBJS)
+       rm -f DietHEP.o
+       ld -r -o DietHEP.o $^ $(GHC_LIBS_NEEDED)
+       rm -f DietHEP.a
+       ar clq DietHEP.a DietHEP.o
+       rm -f DietHEP.o
+
+foobar:
+       rm -f ../rts/libHSrts.a  ../rts/libHSrts_u.a
+       rm -f ../rts/StgCRun.o ../rts/StgCRun.u_o
+       make all
+
+nHandle$(DYN_EXT): nHandle.c
+ifeq "$(TARGETPLATFORM)" "i386-unknown-cygwin32"
+       gcc -mno-cygwin -O -Wall -o nHandle.o -c nHandle.c
+       dllwrap -mno-cygwin --target=i386-mingw32 -o nHandle.dll \
+                -def nHandle.def nHandle.o
+else
+       gcc -O -Wall -shared -fPIC -o nHandle.so nHandle.c
+endif
+
+$(GHC_RUNTIME_DIR)/libHSrts.a:
+       (cd $(GHC_RUNTIME_DIR) ; make clean ; make EXTRA_CC_OPTS=-I$(GHC_INTERPRETER_DIR))
+
+cleanish:
+       /bin/rm *.o
+rtsclean:
+       (cd $(GHC_RUNTIME_DIR) ; make clean)
+
+binaries:
+       tar cvzf stghugs.tar.gz hugs$(exeext) nHandle$(DYN_EXT) lib/*lhs lib/Prelude.hs
+
+snapshot:
+       /bin/rm -f snapshot.tar
+       tar cvf snapshot.tar Makefile *.[chy] \
+             ../rts/Assembler.c ../rts/Evaluator.c ../rts/Disassembler.c \
+             ../rts/ForeignCall.c ../rts/Printer.c ../rts/QueueTemplate.h \
+             ../includes/options.h ../includes/Assembler.h nHandle.c \
+             ../includes/Assembler.h ../rts/Bytecodes.h ../includes/ClosureMacros.h \
+             lib/*.hs runnofib runallnofib
+
+
+# --------------------------------------------------------------------- #
+# Testing                                                               #
+# --------------------------------------------------------------------- #
+
+check :: all
+       ./test/runtests test/static/*.hs
+       ./test/runtests test/typechecker/*.hs
+       ./test/runtests test/runtime/*.hs
+       ./test/runtests test/std/*.hs
+       ./test/runtests test/exts/*.hs
+
+checkrun: all
+       ./test/runtests test/runtime/*.hs
+       ./test/runtests test/std/*.hs
+       ./test/runtests test/exts/*.hs
+
+# --------------------------------------------------------------------- #
+# Cleanery & misc                                                       #
+# --------------------------------------------------------------------- #
+
+CLEAN_FILES += hugs nHandle.dll
+CLEAN_FILES += $(TOP)/ghc/rts/libHSrts.a $(TOP)/ghc/rts/*.o
+CLEAN_FILES += parser.c
+
+INSTALL_LIBEXECS = hugs
+
+depend :: parser.c $(LOOPS) $(SRCS_UGNHS)
+
+
+include $(TOP)/mk/target.mk
+
+
+include Makefile.DLLs
diff --git a/ghc/interpreter/Makefile.DLLs b/ghc/interpreter/Makefile.DLLs
new file mode 100644 (file)
index 0000000..ca9613c
--- /dev/null
@@ -0,0 +1,180 @@
+#-----------------------------------------------------------------------------#
+
+# Makefile.DLLs, version 0.7.
+
+# 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 makefiles 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
+
+# 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: %.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 DLL's entry function (below) will initialize the _impure_ptr variable
+# in the DLL so that they point to the main program's reent_data struct.
+
+%_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($(USE_DLL_MACRO))"                  >> $@
+       echo "    #define $(IMP_MACRO)(name)    __imp_##name"   >> $@
+       echo "    #define $(GLOBAL_MACRO)(name) (*$(IMP_MACRO)(name))" >> $@
+       echo "    #include \"$*_globals.h\""                    >> $@
+       echo "  #endif /* $(USE_DLL_MACRO) */"                  >> $@
+       echo "#endif /* __GNUC__ && __CYGWIN32__ */"            >> $@
+       echo ""                                                 >> $@
+       echo "#endif /* $(GUARD_MACRO) */"                      >> $@
+
+%_globals.h: %.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_dll.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 %_dll.a : %.def
+       dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*)              \
+               --def $<                                        \
+               --dllname $*.dll                                \
+               --output-exp $*.exp                             \
+               --output-lib $*_dll.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@g' -e 's@\\\\\\\\@/@g' \` ` \
+       -L`dirname \`gcc -print-file-name=libcygwin.a | \
+       sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
+       -L`dirname \`gcc -print-file-name=libkernel32.a | \
+       sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
+       -lgcc -lcygwin -lkernel32 -lgcc)
+
+# Making relocatable DLLs doesn't seem to work.
+# Not 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 %.a %_dll.o dll_init.o dll_fixup.o
+       $(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $*.base                 \
+               -e _dll_entry@12                                        \
+               $*.exp $*.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@12                                        \
+               $*.exp $*.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@12                                        \
+               $*.exp $*.a $*_dll.o                                    \
+               dll_init.o dll_fixup.o                                  \
+               $(LDLIBS) $(LDLIBS-$*)                                  \
+               $(CYGWIN32_LIBS)
+       rm -f $*.base
+
+else
+
+%.dll: %.exp %.a %_dll.o dll_fixup.o dll_init.o
+       $(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $@                      \
+               -e _dll_entry@12                                        \
+               $*.exp $*.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'          >> 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 initializes `_impure_ptr'.
+dll_init.c:
+       echo '#include <stdio.h>'                               > dll_init.c
+       echo 'extern struct _reent *_impure_ptr;'               >> dll_init.c
+       echo 'extern struct _reent *__imp_reent_data;'          >> dll_init.c
+       echo '__attribute__((stdcall))'                         >> dll_init.c
+       echo 'int dll_entry(int handle, int reason, void *ptr)' >> dll_init.c
+       echo '{ _impure_ptr=__imp_reent_data; 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
diff --git a/ghc/interpreter/dh_demo.c b/ghc/interpreter/dh_demo.c
new file mode 100644 (file)
index 0000000..86c41f0
--- /dev/null
@@ -0,0 +1,24 @@
+
+
+#include <stdio.h>
+#include <assert.h>
+#include <windows.h>
+#include "../includes/DietHEP.h"
+
+int main ( int argc, char** argv )
+{
+   {
+   DH_MODULE hModule;
+   void(*proc)(int);
+
+   hModule = DH_LoadLibrary("FooBar");   /* note no .hs */
+   assert(hModule != 0);
+   proc = DH_GetProcAddress ( dh_ccall, hModule, "wurble" );
+   assert(proc);
+
+   proc(44);
+   proc(45);
+   proc(46);
+   }
+   return 0;
+}