www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how to invoke D from java through JNI ? [ Linux ]

reply outersky <outersky gmail.com> writes:
Content-Type: text/plain; charset=GB2312
Content-Transfer-Encoding: 7bit

hi, all
    I'm using ubuntu gutsy and jdk6 ,  and can run  D and java programs.
    Now I can call c functions from java through JNI.
    I need convert .o file to .so  for c files. But when I did so with D
files, It did not work, and output the error message as :

-------------8<---Error message----------------

     java.lang.UnsatisfiedLinkError:
/mnt/work/dev/d/java/jni3/libfunc.so:
/mnt/work/dev/d/java/jni3/libfunc.so: undefined symbol: _Dmodule_ref
java: symbol lookup error: /mnt/work/dev/d/java/jni3/libhello.so:
undefined symbol: hello

-------------8<---Error message----------------

I don't know how to write JNI application with D directly, so I call D
from C , and call C from java  :)

Following is my source code, and the attachment jni.zip has the same
content , and is for your convinence to test.


-------------8<------Hello.java-------------8<------------------
public class Hello{
    static{
        try{
            System.loadLibrary("hello");
            System.loadLibrary("func");
        }catch(UnsatisfiedLinkError e){
            System.err.println( "Cannot load library:\n " +e.toString() );
        }
    }

    public Hello(){
    }

    public native void SayHello(String strName);
}
-------------8<------Hello.java-------------8<------------------

and java generate Hello.h as

-------------8<------Hello.h-------------8<------------------
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Hello */

#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Hello
 * Method:    SayHello
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_Hello_SayHello
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif
-------------8<------Hello.h-------------8<------------------

-------------8<------Hello.c-------------8<------------------

#include "Hello.h"
#include <string.h>

// want to call hello written in D
extern void hello(const char* name);

JNIEXPORT void JNICALL Java_Hello_SayHello
(JNIEnv * env, jobject arg, jstring string){
  const char *str = (*env)->GetStringUTFChars(env, string, 0);
  //printf("Hello:%s\n",str);
  hello(str);
}
-------------8<------Hello.c-------------8<------------------

-------------8<----- func.d-------------8<------------------
extern(C){
  void hello(const char* name){
    printf("Hello from D: %s",name);
  }
}
-------------8<------func.d-------------8<------------------

  Here is my build file:

-------------8<------build-------------8<------------------
#!/bin/sh
echo "Compiling Hello.java ..."
javac Hello.java

echo "Generate Hello.h ..."
javah Hello

echo "Compile Hello.c , Generate Hello.o ..."
gcc -I/mnt/soft/jdk/include -I/mnt/soft/jdk/include/linux -fPIC -c Hello.c

echo "Compile func.d ..."
dmd -g -c func.d

echo "Generate shared library libhello.so.1.0"
gcc -shared -W1,-soname,libhello.so.1 -o libhello.so.1.0 Hello.o

echo "Generate shared library libfunc.so.1.0"
gcc -shared -W1,-soname,libfunc.so.1 -o libfunc.so.1.0 func.o

echo "copy libhello.so.1.0 to libhello.so"
cp libhello.so.1.0 libhello.so

echo "copy libfunc.so.1.0 to libfunc.so"
cp libfunc.so.1.0 libfunc.so


echo "Set LD_LIBRARY_PATH ..."
export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
echo "Now: LD_LIBRARY_PATH=$LD_LIBRARY_PATH"

echo "Compile Main.java ..."
javac Main.java

echo "Run java Main ..."
java Main

-------------8<------build-------------8<------------------

  Note : My jdk is installed in /mnt/soft/jdk , you should correct this
if you want to run the build file.


  Thanks!

outerky
Nov 07 2007
parent Frank Benoit <keinfarbton googlemail.com> writes:
Hi

I think you will not succeed with JNI.
The ultimative problem is, both Java and D have Garbage Collectors.
They both need to have control over which threads are running or not. So
this is a really hard problem.

Better solution is to make inter process communication.

I am working on a DBus binding for D. And actually i am already using it
in an application.
In the moment this enable you to call D from Java. The other direction
will follow in some time.

you can download the source with mercurial version control:
hg clone http://hg.assembla.com/dbus-d

Frank
Nov 08 2007