Search code examples
javajna

JNA loading many libraries with same method name


I have some problems when I use JNA to call different .so in my program. It seems that my native shared libraries can't declare a method with the same name.

Example : I have a native1.c :

#include <stdio.h>
int anotherMethod() {
    return 100;
}
int method() {
     return 1 + anotherMethod();
}

And a native2.c :

#include <stdio.h>
int anotherMethod() {
    return 200;
}
int method() {
    return 2 + anotherMethod();
}

Each are compiled in a shared library (libnative1.so and libnative2.so).

$ gcc -m64 -shared -fPIC -o linux-x86-64/libnative1.so native1.c
$ gcc -m64 -shared -fPIC -o linux-x86-64/libnative2.so native2.c

(I am on a 64bit linux)

So invoking method() should return :

  • 101 in native1
  • 202 in native2

I will try it in a small Java Main :

public static void main(String[] args) {
    Native1 native1 = (Native1) Native.loadLibrary("native1", Native1.class);
    Native2 native2 = (Native2) Native.loadLibrary("native2", Native2.class);
    System.out.println(native1.method());
    System.out.println(native2.method());
}

The libraries interfaces are minimalists:

public interface Native1 extends Library {
    int method();
}

And

public interface Native2 extends Library {
    int method();
}

I obtain :

101 // OK

102 // Should be 202 !

It means the good method() invoked, but when my native code calls anotherMethod(), only the one from native1 is invoked.

I think Native.loadLibrary() loads my shared libraries and flatten it so only the first "anotherMethod" symbol exists.

In my real world case, the C code isn't under my responsibility, it is provided by another editor, so the less I have to edit it is the best

Is there a way to easily separate each shared library, like in a namespace or maybe a gcc option I missed out ?


Solution

  • When calling Native.loadLibrary(), you can supply a Map of options including the key Library.OPTION_OPEN_FLAGS with a value corresponding to RTLD_LOCAL. That should fix your issue.

    Map options = new HashMap();
    int RTLD_LOCAL = 0x4; // or whatever value it has on your platform
    options.put(Library.OPTION_OPEN_FLAGS, RTLD_LOCAL);
    Mylib lib = Native.loadLibrary("mylib", Mylib.class, options);
    

    You can look up the value of RTLD_LOCAL with grep RTLD_LOCAL /usr/include/*.h on your target system.