Java包装器用于.C代码

4

I have the following c code:

test.c

#include <stdio.h>
#include <math.h>

int add (int a, int b)
{
    a=4;
    b=4;
    return a+b;
}

int add_pointer (int *a, int *b)
{
    printf("values of a,b: %d,%d \n",*a,*b);
return ((*a)+(*b));
}

char* print_hello()
{
    return "hello_world";
}

test.h

#ifndef TEST_H_
#define TEST_H_

int add(int a, int b);
int add_pointer (int *a, int *b);
char *print_hello();

#endif

main.c

#include "test.h"
#include <stdio.h>
#include <math.h>

int main()
{
    int a,b,c,d;
    char* rez;

    a=5;
    b=2;

    //int *r=&a;
    c= add(a,b);
    d=add_pointer(&a,&b);
    rez=print_hello();

    printf("sum is: %d and : %s %d \n",c,rez,d);
    return 0;
}

test_app.i

%module test_app

%{
#include "test.h"
%}

%include "test.h"

我希望创建一个Java包装器,用于这个 .c 代码。稍后我想在 Android 演示中使用此包装器。

我已经完成了以下工作:

$: swig -java test_app.i

提供:

test_app_wrapper.c
test_app.java
test_appJNI.java
SWIGTYPE_p_int.java 

$: gcc -fpic -c test.c test_app_wrap.c -I /usr/lib/jvm/java-7-openjdk-amd64/include -I /usr/lib/jvm/java-7-openjdk-amd64/include/linux
$: gcc -shared test.o test_app_wrap.o -o libtest_app_wrap.so

UPDATE:

HelloWorld.java

      public class HelloWorld {
    native String print_hello(); /* (1) */
    static {
        System.loadLibrary("test_app_wrap"); /* (2) */
    }
    static public void main(String argv[]) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.print_hello(); /* (3) */
    }
}

当运行时:

$: javac HelloWorld.java 
$ java HelloWorld

我有:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no test_app_wrap in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1856)
    at java.lang.Runtime.loadLibrary0(Runtime.java:845)
    at java.lang.System.loadLibrary(System.java:1084)
    at HelloWorld.<clinit>(HelloWorld.java:4)

我做错了什么?


你确定生成的文件没问题吗?对我来说,swig 也生成了 test_app.java (是的,我已经尝试编译您的模块)。 - Code Painters
是的,你说得对。我忘了提到test_app.java文件。 - just ME
2个回答

2

看起来你不理解jni的工作原理,可以查看这个教程:

使用JNI从Java调用C代码

你的test_app_wrap不存在,要使用JNI,你需要给你的C函数指定一个特定的名称,然后创建一个具有本地方法的Java类来调用它们。

native String print_hello();

在Java类中加载本地库。

接下来,您将创建一个YourClass Java对象并调用print_hello()本地方法。


非常感谢您的回复。当运行swig -java test_app.i时,我会得到test_app_wrap.c、test_appJNI.java和SWIGTYPE_p_int.java。您关于本地void print_hello的说法是正确的。在我的情况下,print_hello方法返回一个字符串。我猜应该是native String print_hello();,我是对的吗? - just ME
请查看教程,它会准确地解释你需要做什么才能让你的JNI正常工作。 - BackSlash
我已经查看了教程。非常感谢。在我的情况下,我确实有test_app_wrapper.c(由swig创建)。无需创建新的ctest.c(如教程中所说)。您能告诉我/path/to/jdk/headers的路径是什么吗?谢谢! - just ME

1
当你执行swig -java test_app.i时,它会创建一些Java粘合类,你必须将它们包含在你的Java项目中。生成的主接口名为test_app.java,如下所示:
public class test_app {
  public static int add(int a, int b) {
    return test_appJNI.add(a, b);
  }

  public static int add_pointer(SWIGTYPE_p_int a, SWIGTYPE_p_int b) {
    return test_appJNI.add_pointer(SWIGTYPE_p_int.getCPtr(a), SWIGTYPE_p_int.getCPtr(b));
  }

  public static String print_hello() {
    return test_appJNI.print_hello();
  }

}

正如您所看到的,它将所有调用委托给test_appJNI,这也是自动生成的,并充当将本地代码粘合在一起的接口(使用native方法):
public class test_appJNI {
  public final static native int add(int jarg1, int jarg2);
  public final static native int add_pointer(long jarg1, long jarg2);
  public final static native String print_hello();
}

因此,您应该:

  • 在项目中包含生成的.java文件
  • 确保使用System.loadLibrary("test_app_wrap");加载.so库——您已经这样做了
  • 简单地调用test_app.print_hello()

另外,建议阅读:SWIG手册的21 SWIG and Java部分。其中的PreliminariesA tour of basic C/C++ wrapping部分很好地解释了所有基础知识。

您收到的错误表明JVM无法加载.so库。我的第一个问题是它是否已经编译和链接正确。如果您确定已经有了libtest_app_wrap.so,则它可能不在JVM寻找它的路径上(检查一下-http://www.chilkatsoft.com/p/p_499.asp)。例如,对我来说,需要在Java命令行中添加-Djava.library.path=.

java -Djava.library.path=. HelloWorld

供参考 - 我已经修改了您的HelloWorld.java文件:

public class HelloWorld {
    static {
        System.loadLibrary("test_app_wrap"); 
    }
    static public void main(String argv[]) {
        test_app.print_hello();
    }
}

希望这有所帮助 :)

我修改了我的问题。你能看一下吗? import test_app 是什么意思?谢谢! - just ME
哦,等等,你不需要显式地导入(我已经很久没用Java了)。 - Code Painters
刚刚完成了我的回答编辑-我认为现在详细程度已经足够了! - Code Painters
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/26712/discussion-between-just-me-and-code-painters - just ME
我现在有点忙,没时间聊天 - 但是真的,你应该自己继续。为什么你看不到消息?因为没有人打印它 - 你的 print_hello() 返回一个字符串,所以你可以像这样使用 System.out.println(test_app.print_hello());。祝你好运! - Code Painters
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接