Win32 dlls -- how to do it?
Kevin S. Millikin
kmillikin@atcorp.com" <kmillikin@atcorp.com
Fri, 27 Jun 2003 14:35:15 -0500
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.
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.
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.
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 <jni.h>
#include <HsFFI.h>
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
----
Kevin S. Millikin Architecture Technology Corporation
Research Scientist Specialists in Computer Architecture
(952)829-5864 x162 http://www.atcorp.com