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"

I want to create a java wrapper ofer this .c code. I would like later to use this wrapper in an android demo.

I did the following:

$: swig -java test_app.i

GIVES:

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) */
    }
}

When running:

$: javac HelloWorld.java 
$ java HelloWorld

I have:

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)

What am I doing wrong?

just ME
  • 1,817
  • 6
  • 32
  • 53

2 Answers2

2

It seems you don't understand how jni works, check this tutorial:

Calling C code from Java using JNI

Your test_app_wrap doesn't exist, to use JNI you have to assign a particular name to your C functions, then make a Java class with native methods to call them i.e.

native String print_hello();

and, in the Java class, load the native library.

Then you will create a YourClass Java object and call the print_hello() native method

BackSlash
  • 21,927
  • 22
  • 96
  • 136
  • Thank you very much for your replay. When running swig -java test_app.i I get in return test_app_wrap.c, test_appJNI.java and SWIGTYPE_p_int.java. You are right about that native void print_hello. In my case print_hello method returns a STRING. I guess it will be native String print_hello(); Am I right? – just ME Mar 22 '13 at 08:50
  • Check the tutorial, it explains exactly what you have to do in order to get your JNI to work – BackSlash Mar 22 '13 at 08:52
  • I did check the tutorial. Thank you very much. In my case I do have the test_app_wrapper.c (created by swig). There is no need to create a new ctest.c (as it says in the tutorial). Could you tell me what is the path to the /path/to/jdk/headers ? Thank you! – just ME Mar 22 '13 at 09:01
1

When you execute swig -java test_app.i, it creates some Java glue classes that you must include in your Java project. The main interface generated is named test_app.java and looks like this:

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();
  }

}

As you can see, it delegates all the calls to test_appJNI, which is also automatically generated, and acts as a glue to the native code (using native methods):

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();
}

So, you should:

  • include both generated .java files in the project
  • ensure that you load the .so library with System.loadLibrary("test_app_wrap"); - you already do it
  • simply call test_app.print_hello()

Also, recommended reading: 21 SWIG and Java section from SWIG manual. The Preliminaries and A tour of basic C/C++ wrapping sections explain all the basics quite well.

The error you get indicates that JVM can't load the .so library. My first question would be if it compiled and linked properly. If you are sure you have libtest_app_wrap.so, it might not be on the path where JVM looks for it (check this - http://www.chilkatsoft.com/p/p_499.asp ). E.g. for me it was necessary to add -Djava.library.path=. to Java command line:

java -Djava.library.path=. HelloWorld

For reference - I've modified your HelloWorld.java file:

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

Hope that helps :)

Code Painters
  • 7,175
  • 2
  • 31
  • 47
  • I did edit my question. Can you please take a look? WHat do you mean by import test_app? THANK YOU! – just ME Mar 22 '13 at 09:07
  • I mean plain old Java `import test_app;`. – Code Painters Mar 22 '13 at 09:09
  • Oh wait, you don't need to import explicitly (I haven't used Java for ages now). – Code Painters Mar 22 '13 at 09:14
  • Just finished editing my answer - I think it's enough details now! – Code Painters Mar 22 '13 at 09:28
  • Thank you very much! You are a true HELPER!! I modified the HelloWorld.java file and run java -Djava.library.path= .HelloWorld from command line, but I still have the error: 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.(HelloWorld.java:3) – just ME Mar 22 '13 at 09:35
  • I MADE IT WORK!! It doesn t print any error messages, but test_app.print_hello() doesn't return the hello_world message. WHY?:( Do you have any ideea? – just ME Mar 22 '13 at 09:45
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/26712/discussion-between-just-me-and-code-painters) – just ME Mar 22 '13 at 09:53
  • I'ma bit too busy now for chatting - but really, you should continue on your own now. And why you see no message? Because nobody is printing it - your `print_hello()` returns a string, so you can e.g. `System.out.println(test_app.print_hello());`. Good luck! – Code Painters Mar 22 '13 at 10:09
  • THank you very much!! You were right. I managed to make it work. I do have a problem when calling add_pointer(2,3). add_pointer(SWIGTYPE_p_int,SWIGTYPE_p_int) in test_app cannot be applied to (int,int) System.out.println(test_app.add_pointer(2,3)); ^ – just ME Mar 22 '13 at 10:39