I'm new to JNA and trying to put together a very minimal proof-of-concept for accessing structs from a C++ shared library. Unfortunately, it doesn't run and I cannot figure it out.
Here's my code:
Main.java:
import com.sun.jna.Structure;
import com.sun.jna.Native;
import com.sun.jna.Library;
import com.sun.jna.Structure.FieldOrder;
public class Main {
public interface MyCppLibrary extends Library {
MyCppLibrary INSTANCE = (MyCppLibrary) Native.load("mycpplib", MyCppLibrary.class);
@FieldOrder({"x", "y"})
class MyStruct extends Structure {
public int x;
public int y;
}
MyStruct getStruct();
}
public static void main(String[] args) {
MyCppLibrary lib = MyCppLibrary.INSTANCE;
MyCppLibrary.MyStruct myStruct = lib.getStruct();
System.out.println("x: " + myStruct.x);
System.out.println("y: " + myStruct.y);
}
}
MyStruct.cpp:
#include <iostream>
struct MyStruct {
int x;
double y;
};
extern "C" {
MyStruct* getStruct() {
return new MyStruct{10, 20.5};
}
}
I compile the C++ code into a shared library (using WSL2 Ubuntu 20.04):
g++ -v -shared -o libmycpplib.so my_struct.cpp
But when I run the Java class (of course including a recent JNA jar, jna-5.15.0.jar
, to my CLASSPATH) I get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'getStruct': /home/h3007/.vscode-server/data/User/workspaceStorage/af05c638282256cbf9a3f960fefbba02/redhat.java/jdt_ws/hassan-jna-struct_c38993c4/bin/libmycpplib.so: undefined symbol: getStruct
at com.sun.jna.Function.<init>(Function.java:255)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:618)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:594)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:580)
at com.sun.jna.Library$Handler.invoke(Library.java:248)
at jdk.proxy1/jdk.proxy1.$Proxy0.getStruct(Unknown Source)
at Main.main(Main.java:21)
I'm assuming I've done something silly. Apologies, but pointers to my error would be appreciated.
I managed to make your proposal work with command line with two modifications.
First, I had to compile MyStruct.cpp
with the -fPIC
option:
g++ -shared -o libmycpplib.so MyStruct.cpp -fPIC
Second, you have to be careful in the Main.java
file since the type of y
should be coherent with the type double
in the cpp file:
import com.sun.jna.Structure;
import com.sun.jna.Native;
import com.sun.jna.Library;
import com.sun.jna.Structure.FieldOrder;
public class Main
{
public interface MyCppLibrary extends Library
{
MyCppLibrary INSTANCE = (MyCppLibrary) Native.load("mycpplib", MyCppLibrary.class);
@FieldOrder({"x", "y"})
class MyStruct extends Structure
{
public int x;
public double y;
}
MyStruct getStruct();
}
public static void main(String[] args)
{
MyCppLibrary lib = MyCppLibrary.INSTANCE;
MyCppLibrary.MyStruct myStruct = lib.getStruct();
System.out.println("x: " + myStruct.x);
System.out.println("y: " + myStruct.y);
}
}
Then compile and launch with:
javac -classpath /usr/share/java/jna.jar Main.java
java -classpath /usr/lib/java/jna.jar:. Main
Possible output:
x: 10
y: 20.5