
ac> New to Haskell, new to GHC. My initial intention in picking up ac> Haskell is to be able to write some functions in Haskell and then ac> compile them into .dlls for Win32 that I can call from programs ac> written in other languages. So before I get too deeply invested I ac> want to make sure that is possible.
It's certainly possible. I do it here all the time on a commercial project. I even volunteered a few months ago to write some better documentation, but I sadly have not had the time to do it.
As Sigbjorn says, adding -package base when linking the DLL with ghc will silence those errors from the linker.
Ok, "-package base" did the trick, and I was able to call the function from my other program.
The warning given when compiling the C code in dllMain.c comes from the declaration of __stginit_Adder as
EXTFUN(__stginit_Adder)
Which is not really the type that startupHaskell expects. Declare it instead as
extern void __stginit_Adder(void);
and the warning will be silenced.
Ok.
The much bigger gotcha is that the code in dllMain.c from Sect 11 of the user's guide will probably not work, because Windows forbids certain things from happening in dllMain (basically, anything that could possibly cause one to reattach to the DLL). That includes creating new threads, and that includes creating timers, and startupHaskell tries to do that. I don't remember at the moment if it is a problem when the GHC runtime is in a separate DLL, but it is certainly a problem when linking the GHC runtime into the same DLL.
I did not try statically linking all into a single dll yet. We'll see.
My typical solution is to provide entry points to explicitly startup and shutdown the Haskell runtime, outside of a call to dllMain. Here is an example, calling Adder from Java:
1. Write some Haskell code to implement the add function in the DLL.
Note that Java will expect a mangled name, which we supply manually:
==== Adder.hs module Adder (add) where
import Foreign (Ptr, Int32)
data JNIEnv data JClass
foreign export stdcall "Java_Adder_add" add :: Ptr JNIEnv -> Ptr JClass -> Int32 -> Int32 -> IO Int32
add :: Ptr JNIEnv -> Ptr JClass -> Int32 -> Int32 -> IO Int32 add _ _ m n = return (m + n) ====================
2. Compile. Don't forget -fglasgow-exts:
ghc -fglasgow-exts -c Adder.hs
3. Write C functions that can be called by Java (mangling the names again) and that can be used to startup and shutdown the Haskell runtime.
You can't do this directly from Java, because the FFI functions don't have the mangled names that Java expects, and you can't do it from Haskell code for obvious reasons.
==== ccode.c #include
#include extern void __stginit_Adder(void);
static char *args[] = { "ghcDll", 0 }; static int argc = 1; static char **argv = args;
JNIEXPORT void JNICALL Java_Adder_haskellInit(JNIEnv *e, jclass c) { hs_init(&argc, &argv); hs_add_root(__stginit_Adder); }
JNIEXPORT void JNICALL Java_Adder_haskellExit(JNIEnv *e, jclass c) { hs_exit(); } ====================
4. Compile it. JAVAHOME is presumed to be set to the root of your Java install (the directory containing the "include" subdirectory):
ghc -I$JAVAHOME/include -I$JAVAHOME/include/win32 -optc -mno-cygwin -c ccode.c
5. Link into DLL, using ghc (I generally call dllwrap directly, because it gives me finer (actually, just less verbose) control over DLL options):
ghc --mk-dll -optdll --add-stdcall-alias -o adder.dll Adder.o Adder_stub.o ccode.o -package base
"-optdll --add-stdcall-alias" is important, because Java can't find
the entries otherwise.
6. Write a Java driver that loads the native library (the DLL), initializes the Haskell runtime, calls our simple DLL function, and then shutdowns the Haskell runtime:
==== Adder.java public class Adder { static { System.loadLibrary("adder"); haskellInit(); }
public static native void haskellInit(); public static native void haskellExit();
public static native int add(int m, int n);
public static void main(String[] args) { try { System.out.println("Answer is: " + Adder.add(32, 10)); } finally { haskellExit(); }}} ====================
7. Compile the Java code:
javac -classpath . Adder.java
8. Enjoy:
java -classpath . Adder
----
Aha. I'll see if I can adapt that to my system. Thanks for all the help... Andy Serpa ac@onehorseshy.com