Calling Julia from Java: Image Not Found

Hello, I asked this on StackOverflow, but this is a better place :slight_smile:

I am calling Julia from Java via JNI.

I have successfully compiled and linked my Julia into a dylib using instructions here:

julia ~/dev/PackageCompiler.jl/juliac.jl -vas f.jl`

https://docs.julialang.org/en/v1/manual/embedding/index.htm

I link with a thin layer of C++ to implement the JNI interface. I got the flags from

julia/share/julia/julia-config.jl --allflags

JAVA_LINK_FLAGS = -shared

JULIA_LINK_LIBS = -Wl,-rpath,‘/Applications/Julia-1.0.app/Contents/Resources/julia/lib’ -Wl,-rpath,‘/Applications/Julia-1.0.app/C
ontents/Resources/julia/lib/julia’ -ljulia

libTest.jnilib: Test.o builddir/f.dylib
gcc $JAVA_LINK_FLAGS $JULIA_LINK_FLAGS -o libTest.jnilib Test.o builddir/f.dylib JULIA_LINK_LIBS

Test.o: Test.cpp
gcc -c JULIA_C_FLAGS JAVA_C_FLAGS Test.cpp

Everything compiles and links with no complaint, but when I try to call it from Java I get this

Exception in thread “main” java.lang.UnsatisfiedLinkError:
/Users/xxx/dev/ie/julia/libTest.jnilib:
dlopen(/Users/xxx/dev/ie/julia/libTest.jnilib, 1): Library not
loaded: @rpath/f.dylib
Referenced from: /Users/xxx/dev/ie/julia/libTest.jnilib
Reason: image not found
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1861)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at Test.(Test.java:3)

I can’t find anything in the docs. I thought PackageCompiler and julia-config would take care of including everything I need. What am I missing?

Thanks Peter

Is f.dylib in the same directory as libTest.jnilib ? Is that your current working directory?

No f.dylib is in builddir and libTest.jnilib is in my current dir. Should I cause them to be in the same place?

Well, the error message suggests that they should be in the same place: @rpath/f.dylib

That didn’t fix it. Can you explain @rpath? How is it set?

Also, am I correct in thinking that my libTest.jnilib is finding f.dylib like any other dylib. But on loading Julia is trying to load an ‘image’ which it is not finding? That image is inside f.dylib

For those that come after. I eventually found code that works. See below.

Two important items:

  1. I was unable to get the .dylib to work, however PackageCompiler also generates a static .a library. I was able to link with this and run successfully

  2. The example code with PackageCompiler did not work for me, neither did the documentation on calling from C++. Once I am less of a N00B perhaps I will write up something, but for now the code below seems to work

I hope this helps others who want to call Julia from C++/Python/Java etc

#include <jni.h>        // JNI header provided by JDK                                                                                                                                                              
#include <stdio.h>      // C Standard IO Header                                                                                                                                                                    
#include <julia.h>      // Julia API                                                                                                                                                                               
#include "Test.h"       // Generated                                                                                                                                                                               

#ifdef JULIA_DEFINE_FAST_TLS // only available in Julia v0.7 and above                                                                                                                                             
JULIA_DEFINE_FAST_TLS()
#endif

/*                                                                                                                                                                                                                 
 * Class:     Test                                                                                                                                                                                                 
 * Method:    f                                                                                                                                                                                                    
 * Signature: (I)I                                                                                                                                                                                                 
 */
JNIEXPORT jint JNICALL Java_Test_f(JNIEnv *env, jobject cls, jint x) {

  libsupport_init();

  jl_init_with_image("/Applications/Julia-1.0.app/Contents/Resources/julia/bin","/Users/peter.wolf/dev/ie/julia/builddir/f.dylib");

  // f(x::Int32)::Int32 = x + 3                                                                                                                                                                                    
  jl_function_t *func = jl_get_function(jl_main_module, "f");

  int y = 0;
  if(func) {
      jl_value_t *argument = jl_box_int32(3);
      jl_value_t *ret = jl_call1(func, argument);
      y = jl_unbox_int32(ret);
  }

  jl_atexit_hook(0);
  return y;
}

2 Likes