Search code examples
javacjna

Linux, JNA: UnsatisfiedLinkError on liblo second method call


I like to control 'sooperlooper' from java, a sound looper. This uses the OSC protocol. First try was the Java OSC lib, but this doesn't do anything. Now I'm trying JNA to wrap liblo.so

The program I'm trying to replicate in JAVA is very simple (of course with different commands from "record"):

static lo_address addr;

int main(int argc, char *argv[])
{
        addr = lo_address_new(<IP>, "9951");
        lo_send(addr, "/sl/-1/down", "s", "record");
}

The C declaration of the failing method is (https://github.com/radarsat1/liblo/blob/master/lo/lo.h.in):

int lo_send(lo_address targ, const char *path, const char *type, ...);

If I understand correctly, the lo_address is some void pointer type declared elsewhere. My library interface is:

public interface LibLo extends Library {
    Pointer lo_address_new(String host, String port);
    int lo_send(Pointer address, String command, String a, String... params);
}

And my caller code is this:

System.setProperty("jna.debug_load", "true");
System.setProperty("jna.debug_load.jna", "true");
LibLo libLo = Native.loadLibrary("liblo", LibLo.class);

Pointer pointer = libLo.lo_address_new(<IP>, "9951");
libLo.lo_send(pointer, "/sl/-1/down","s", "record");

It perfectly gets through the lo_address_new call. 'pointer' does have some value. I think my arguments are correct. And I discovered even with incorrect arguments, it gets past the lo_address_new call.

My stdout is:

...
Found library 'liblo' at /usr/lib/x86_64-linux-gnu/liblo.so.7.3.0
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'lo_send': /usr/lib/x86_64-linux-gnu/liblo.so.7.3.0: undefined symbol: lo_send
    at com.sun.jna.Function.<init>(Function.java:245)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:566)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:542)
    at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:528)
    at com.sun.jna.Library$Handler.invoke(Library.java:228)
    at com.sun.proxy.$Proxy0.lo_send(Unknown Source)
    at nl.ronaldteune.coverdownloader.Main.main(Main.java:30)

Other questions about UnsatisfiedLinkError point to more thorough problems. I can't find 'lo_send' when opening the lib with vim, I can find lo_send_message though - but it's more low level. However, I think my C program is using the same lib (compiled with -llo) and it doesn't have problems to run. So... I'm stuck. Anyone know how I can debug further?


Solution

  • You can't map lo_send() to JNA (and it doesn't appear in your vim output) because it's a macro:

    #define lo_send(targ, path, types...) \
            lo_send_internal(targ, __FILE__, __LINE__, path, types, \
                 LO_MARKER_A, LO_MARKER_B)
    

    You could, in theory, map lo_send_internal() but the source code comments for it say:

    /* Don't call lo_send_internal directly, use lo_send, a macro wrapping this
     * function with appropriate values for file and line */
    

    Which makes sense as it needs to know the source code __FILE__ and __LINE__ number at compile time, and any hack you'd make in JNA for these values would have to assume you have the correct source code used to compile your binary .so. You'd also need the markers but they are at least constants, amusing words spelled out in hex code.

    You could probably just toss in dummy values for the file and line to make your code work, but otherwise, your C wrapper function calling lo_send() looks like the best workaround in this case.