JNA 调用c++函数的出错,java能加载库,但是找不到c++写的函数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JNA 调用c++函数的出错,java能加载库,但是找不到c++写的函数相关的知识,希望对你有一定的参考价值。
void func(char*);这是c++的函数;
jna 接口中对应的函数为void func(string a);
能加载so文件,但是找不到这个函数,报错如下:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'func': /lib/libfunc.so: undefined symbol: func
c++源码的include和extern c这些地方是不是有些要注意的关键细节?
系统:ubuntu 14.04
调用C++编译的代码能调用到库但是找不到函数,应该是因为C++编译器会破坏函数的名称。
对此,一般网上能查到两种方法解决:
用extern C ,功能是将部分代码用C编译器进行编译,因为 C编译器不会改变函数的函数名,Java中就可以用代码中的函数名调用了。
用def模板
注1:这里说的方法你需要自己去查一下,别人的文章会写得比较清楚,看完整的文章能学到更多。
注2: 对于C和C++编译器对函数名的影响,这里和你说一下如何查看:你想看看C++编译器编译的DLL的方法名可以用depends反编译程序,把dll拖进depends程序窗口,左边会有依赖树,点击最顶端你的“库名.dll”,右边就能看到dll中函数被C++编译之后的名字。如下图:
用C编译的DLL:
2. 用C++编译的DLL:
参考技术A import com.sun.jna.Library;import com.sun.jna.Native;
public class TestSo
public interface LgetLib extends Library
// 调用linux下面的so文件,注意,这里只要写test就可以了,不要写libtest,也不要加后缀
LgetLib INSTANCE = (LgetLib) Native.loadLibrary("test",LgetLib.class);
int add(int a,int b);
public int add(int a,int b)
return LgetLib.INSTANCE.add(a,b);
public static void main(String[] args)
TestSo ts = new TestSo();
int c = ts.add(10,20);
System.out.println("10+20="+c);
从 JNA 调用 libc 函数
【中文标题】从 JNA 调用 libc 函数【英文标题】:Call libc function from JNA 【发布时间】:2015-01-26 20:24:30 【问题描述】:我从 Java 到 JNA 使用了一个 C 库,但一个函数没有正确刷新(因为输出在程序结束时同时出现)。我试过 Java 端 System.out.flush();
没有运气。
简而言之,我想从 Java 调用 C fflush(stdout)
。 JNA 已经存在(因此如果没有额外的库会更喜欢)并且没有 C 来编写。
我知道 this question 中的 JNA 库映射,但这对我来说似乎有点过头了。
【问题讨论】:
【参考方案1】:JNA 库的包装方式代码实际上并没有那么重(至少对于刷新所有行为)。
protected interface CLibrary extends Library
static CLibrary clib = (CLibrary) Native.loadLibrary ("c", CLibrary.class);
int fflush (Pointer stream);
/* ... */
CLibrary.clib.fflush (null);
JNA 还提供 后期绑定 方法,这些 oneliners 会做你想做的事
NativeLibrary.getInstance ("c").getFunction ("fflush").invokeInt (new Object[]0);
// even shorter
Function.getFunction ("c", "fflush").invokeInt (new Object[]0);
当您想将刷新限制为stdout
时,就会出现乏味的部分。您必须处理vendor-specific code(stdout 定义为扩展为数组Amtel avr-libc、函数调用Microsoft msvcrt 或GNU libc 中的指针的宏)。
对于 libc,您可以使用(两行代码便于阅读)
Pointer stdout = NativeLibrary.getInstance ("c").getGlobalVariableAddress ("stdout").getPointer (0);
Function.getFunction ("c", "fflush").invokeInt (new Object[]stdout);
【讨论】:
【参考方案2】:为 Win32 / Win64 用户添加此答案,补充 FabienAndre 的 GNU libc。
通过 jna 选择性地刷新调用系统的 c 库的 fflush
方法的 stdout 流既困难又麻烦。正如 FabienAndre 已经提到的,很难掌握 stdout
宏定义。对于 msvcrt(Win32 / Win64 C 库),它是通过对__iob_func()
的函数调用来定义的;后者返回指向FILE
结构数组的指针。索引 0 是标准输入,索引 1 是标准输出,索引 2 是标准错误。所以对于flush stdout你甚至需要知道FILE
结构的大小,当然Win32和Win64是不同的......
以下示例在 Win64 下进行了测试,但应该可以在 Win32 下运行。它的灵感来自线程 JNA solutions to catch stdout/stderr of DLL。
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
public class JnaTest
public interface CLibrary extends Library
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("msvcrt" , CLibrary.class);
Pointer __iob_func();
void printf(String format, Object... args);
int fflush (Pointer stream);
public static void main(String[] args)
int sizeOfFileStructure = Platform.is64Bit() ? 48 : 32;
Pointer stdout = CLibrary.INSTANCE.__iob_func().share(sizeOfFileStructure);
CLibrary.INSTANCE.printf("Hello, World\n");
CLibrary.INSTANCE.fflush(stdout);
【讨论】:
以上是关于JNA 调用c++函数的出错,java能加载库,但是找不到c++写的函数的主要内容,如果未能解决你的问题,请参考以下文章