From 6212ebc63f8e0a92744e4970f548034f51614593 Mon Sep 17 00:00:00 2001 From: sewardj Date: Fri, 12 May 2000 15:59:37 +0000 Subject: [PATCH] [project @ 2000-05-12 15:59:37 by sewardj] Cygwin support machinery for manufacturing DietHEP.dll and building a small demo program (dh_demo.exe). --- ghc/interpreter/DietHEP.def | 4 + ghc/interpreter/Makefile-DietHEP | 126 ++++++++++++++++++++++++++ ghc/interpreter/Makefile.DLLs | 180 ++++++++++++++++++++++++++++++++++++++ ghc/interpreter/dh_demo.c | 24 +++++ 4 files changed, 334 insertions(+) create mode 100644 ghc/interpreter/DietHEP.def create mode 100644 ghc/interpreter/Makefile-DietHEP create mode 100644 ghc/interpreter/Makefile.DLLs create mode 100644 ghc/interpreter/dh_demo.c diff --git a/ghc/interpreter/DietHEP.def b/ghc/interpreter/DietHEP.def new file mode 100644 index 0000000..8feafbd --- /dev/null +++ b/ghc/interpreter/DietHEP.def @@ -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 index 0000000..b64c281 --- /dev/null +++ b/ghc/interpreter/Makefile-DietHEP @@ -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 index 0000000..ca9613c --- /dev/null +++ b/ghc/interpreter/Makefile.DLLs @@ -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 ' > 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 index 0000000..86c41f0 --- /dev/null +++ b/ghc/interpreter/dh_demo.c @@ -0,0 +1,24 @@ + + +#include +#include +#include +#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; +} -- 1.7.10.4