Linux,JNA:liblo 第二次方法调用时出现 UnsatisfiedLinkError
Linux, JNA: UnsatisfiedLinkError on liblo second method call
我喜欢用 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 调用。 'pointer' 确实有一定的价值。我认为我的论点是正确的。
我发现即使参数不正确,它也会通过 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 打开库时我找不到 'lo_send',但我可以找到 lo_send_message - 但它的级别更低。但是,我认为我的 C 程序正在使用相同的库(使用 -llo 编译)并且它没有 运行 的问题。
所以...我卡住了。有人知道我该如何进一步调试吗?
好的,我解决了它...使用包装库:
#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/
现在可以了。仍然对真正的答案感兴趣,但不再着急:)
您不能将 lo_send()
映射到 JNA(它不会出现在您的 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__
和 __LINE__
编号,并且您在 JNA 中为这些值所做的任何 hack 都必须假设您有用于编译二进制文件的正确源代码 .so
。您还需要标记,但它们至少是常量,用十六进制代码拼出的有趣单词。
您可能只是为文件和行添加虚拟值以使您的代码正常工作,但除此之外,您的 C 包装函数调用 lo_send()
看起来是这种情况下的最佳解决方法。
我喜欢用 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 调用。 'pointer' 确实有一定的价值。我认为我的论点是正确的。 我发现即使参数不正确,它也会通过 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 打开库时我找不到 'lo_send',但我可以找到 lo_send_message - 但它的级别更低。但是,我认为我的 C 程序正在使用相同的库(使用 -llo 编译)并且它没有 运行 的问题。 所以...我卡住了。有人知道我该如何进一步调试吗?
好的,我解决了它...使用包装库:
#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/
现在可以了。仍然对真正的答案感兴趣,但不再着急:)
您不能将 lo_send()
映射到 JNA(它不会出现在您的 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__
和 __LINE__
编号,并且您在 JNA 中为这些值所做的任何 hack 都必须假设您有用于编译二进制文件的正确源代码 .so
。您还需要标记,但它们至少是常量,用十六进制代码拼出的有趣单词。
您可能只是为文件和行添加虚拟值以使您的代码正常工作,但除此之外,您的 C 包装函数调用 lo_send()
看起来是这种情况下的最佳解决方法。