Linux,JNA:liblo第二个方法调用上出现UnsatisfiedLinkError

时间:2019-02-23 20:15:47

标签: java c jna

我喜欢从Java(声音循环器)控制“ sooperlooper”。这使用OSC协议。首先尝试使用Java OSC库,但这没有任何作用。现在,我正在尝试JNA包装liblo.so

我要在JAVA中复制的程序非常简单(当然使用“ 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");
}

失败方法的C声明为(https://github.com/radarsat1/liblo/blob/master/lo/lo.h.in):

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

如果我理解正确,lo_address是在其他地方声明的某种空指针类型。 我的图书馆界面是:

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

我的呼叫者代码是这样:

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");

它完美地通过了lo_address_new调用。 “指针”确实有一些价值。我认为我的论点是正确的。 而且我发现即使参数不正确,它也会超出lo_address_new调用。

我的标准输出是:

...
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)

有关UnsatisfiedLinkError的其他问题指出了更彻底的问题。使用vim打开lib时找不到'lo_send',虽然我可以找到lo_send_message-但级别较低。但是,我认为我的C程序正在使用相同的库(与-llo编译),并且运行没有问题。 所以...我被卡住了。有人知道我可以进一步调试吗?

2 个答案:

答案 0 :(得分:1)

好的,我解决了这个问题...使用包装器lib:

#include <lo/lo.h>
static lo_address addr;

lo_address slGetAddress() {
        return lo_address_new("IP", "9951");

}

void slSendFull(lo_address addr, const char *command) {
        lo_send(addr, "/sl/-1/down", "s", command);
}

void slSendSimple(const char *command) {
        addr = slGetAddress();
        lo_send(addr, "/sl/-1/down", "s", command);
}

和此编译脚本:

#!/bin/bash
# sudo ln -s /usr/lib/arm-linux-gnueabihf/liblo.so.7 /usr/local/lib/liblo.so
# sudo ln -s /usr/lib/x86_64-linux-gnu/liblo.so.7 /usr/local/lib/liblo.so

gcc -c -Wall -O2 -fPIC lowrapper.c -llo
ld -shared lowrapper.o /usr/local/lib/liblo.so -o lowrapper.so
sudo cp lowrapper.so /usr/local/lib/

现在正在工作。仍然对真正的答案感兴趣,但不再急于此:)

答案 1 :(得分:1)

您不能将/:name/status/:id 映射到JNA(并且它不会出现在lo_send()输出中),因为它是一个宏:

vim

从理论上讲,您可以映射#define lo_send(targ, path, types...) \ lo_send_internal(targ, __FILE__, __LINE__, path, types, \ LO_MARKER_A, LO_MARKER_B) ,但其源代码注释为:

lo_send_internal()

这很有意义,因为它需要在编译时知道源代码/* Don't call lo_send_internal directly, use lo_send, a macro wrapping this * function with appropriate values for file and line */ __FILE__的数量,并且您在JNA中为这些值所做的任何破解都必须假定您具有正确的用于编译二进制__LINE__的源代码。您还需要标记,但是它们至少是常量,可以用十六进制代码拼出有趣的单词。

您可能只需要为文件和行输入虚拟值以使代码正常工作,否则,在这种情况下,调用.so的C包装函数看起来是最好的解决方法。