Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

JNI on Linux

28 views
Skip to first unread message

Amadan

unread,
Feb 7, 2002, 10:19:48 AM2/7/02
to
Hi.

I've already asked this on comp.lang.java, but no luck, and I'm on a
deadline, so I hope you'll forgive if you had to read this twice. Anyway,
can anybody help with this?

I am trying to make a C wrapper for my Java code which would then call my
Java application. So for the first try I mostly copied the Sun's tutorial
example on JNI JVM invocation. The code is below. I compile it with

gcc -shared -o
testjni -I/usr/lib/jdk1.3/include -I/usr/lib/jdk1.3/include/linux -L/us
r/lib/jdk1.3/jre/lib/i386 -ljava testjni.c

(the directories are correct AFAICS), and when I run the resulting
executable, I get Segmentation fault. I have tried to put a printf at the
top of the code, before any of the JNI stuff, and it doesn't even reach
that, so I guess it's a compilation/linking problem. I'm running JDK 1.3 and
SuSE 7.1.

What am I doing wrong?

Thanks, people!

Goran

----------
#include <jni.h>

#define USER_CLASSPATH "."

main() {
JNIEnv *env;
JavaVM *jvm;
JDK1_1InitArgs vm_args;
jint res;
jclass cls;
jstring jstr;
jmethodID mid;
jobjectArray args;
char classpath[1024];

vm_args.version = 0x00010200;

JNI_GetDefaultJavaVMInitArgs(&vm_args);

sprintf(classpath, "%s:%s", vm_args.classpath,
USER_CLASSPATH);
vm_args.classpath = classpath;
res = JNI_CreateJavaVM(&jvm, (void *) &env, &vm_args);
if(res < 0) {
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}

cls = (*env)->FindClass(env, "TestJNI");
if(cls == 0) {
fprintf(stderr, "Can't find TestJNI.main\n");
exit(1);
}

mid = (*env)->GetStaticMethodID(env, cls, "main",
"([Ljava/lang/String;)V");
if(mid == 0) {
fprintf(stderr, "Out of memory\n");
exit(1);
}

jstr = (*env)->NewStringUTF(env, "/l:ap.log");
if(jstr == 0) {
fprintf(stderr, "Out of memory\n");
exit(1);
}

args = (*env)->NewObjectArray(env, 1,
(*env)->FindClass(env, "java/lang/String"), jstr);
if(args == 0) {
fprintf(stderr, "Out of memory\n");
exit(1);
}

(*env)->CallStaticVoidMethod(env, cls, mid, args);

(*jvm)->DestroyJavaVM(jvm);
}

Gordon Beaton

unread,
Feb 7, 2002, 12:38:04 PM2/7/02
to
On Thu, 7 Feb 2002 16:19:48 +0100, Amadan wrote:
> I am trying to make a C wrapper for my Java code which would then
> call my Java application. So for the first try I mostly copied the
> Sun's tutorial example on JNI JVM invocation. The code is below. I
> compile it with
>
> gcc -shared -o
> testjni -I/usr/lib/jdk1.3/include -I/usr/lib/jdk1.3/include/linux -L/us
> r/lib/jdk1.3/jre/lib/i386 -ljava testjni.c
>
> (the directories are correct AFAICS), and when I run the resulting
> executable, I get Segmentation fault. I have tried to put a printf
> at the top of the code, before any of the JNI stuff, and it doesn't
> even reach that, so I guess it's a compilation/linking problem. I'm
> running JDK 1.3 and SuSE 7.1.

Don't specify -shared when you compile. What does "file testjni" say?

Also, you have specified 1.2 but are using a 1.1 style argument
struct. Use the 1.2 struct instead, described here:

http://java.sun.com/j2se/1.3/docs/guide/jni/jni-12.html#JNI_CreateJavaVM

/gordon

--
[ do not send me private copies of your followups ]
g o r d o n . b e a t o n @ e r i c s s o n . c o m

Amadan

unread,
Feb 8, 2002, 3:19:32 AM2/8/02
to
>> gcc -shared -o
>> testjni -I/usr/lib/jdk1.3/include -I/usr/lib/jdk1.3/include/linux -L/us
>> r/lib/jdk1.3/jre/lib/i386 -ljava testjni.c

>Don't specify -shared when you compile.

I have to, because otherwise it doesn't compile at all: I get these
messages:

$ gcc -g -o


testjni -I/usr/lib/jdk1.3/include -I/usr/lib/jdk1.3/include/linux -L/usr/li
b/jdk1.3/jre/lib/i386 -ljava testjni.c

/usr/i486-suse-linux/bin/ld: warning: libjvm.so, needed by
/usr/lib/jdk1.3/jre/lib/i386/libjava.so, not found (try using -rpath
or -rpath-link)
/usr/i486-suse-linux/bin/ld: warning: libverify.so, needed by
/usr/lib/jdk1.3/jre/lib/i386/libjava.so, not found (try using -rpath
or -rpath-link)

And then a bunch of "undefined reference" errors from libjava.so.

> What does "file testjni" say?

$ file testjni

testjni: ELF 32-bit LSB shared object, Intel 80386, version 1, not stripped

>Also, you have specified 1.2 but are using a 1.1 style argument
>struct. Use the 1.2 struct instead, described here:
>
> http://java.sun.com/j2se/1.3/docs/guide/jni/jni-12.html#JNI_CreateJavaVM

Did that, didn't help - still getting Segmentation fault. The code crashes
before it runs the first line.

Thanks,

Goran

-------
#include <jni.h>

#define USER_CLASSPATH "."

main() {
JNIEnv *env;
JavaVM *jvm;

JavaVMInitArgs vm_args;
JavaVMOption opts[1];


jint res;
jclass cls;
jstring jstr;
jmethodID mid;
jobjectArray args;
char classpath[1024];

sprintf(classpath, "-Djava.class.path=%s", USER_CLASSPATH);
opts[0].optionString = classpath;
vm_args.options = opts;
vm_args.nOptions = 1;
vm_args.version = JNI_VERSION_1_2;

res = JNI_CreateJavaVM(&jvm, (void *) &env, &vm_args);
if(res < 0) {
fprintf(stderr, "Can't create Java VM\n");
exit(1);
}

cls = (*env)->FindClass(env, "AutoProcessor");
if(cls == 0) {
fprintf(stderr, "Can't find AutoProcessor.main\n");

Gordon Beaton

unread,
Feb 8, 2002, 4:36:12 AM2/8/02
to
> >Don't specify -shared when you compile.
>
> I have to, because otherwise it doesn't compile at all: I get these
> messages:

It's not the right solution - you've told it to build a shared object,
not an executable.

> $ file testjni
> testjni: ELF 32-bit LSB shared object, Intel 80386, version 1, not stripped

There you go.

This works for me:

export JDK=...

gcc -I $JDK/include -I $JDK/include/linux -c test.c
gcc -L $JDK/jre/lib/i386/client test.o -o test -ljvm

You will need to set LD_LIBRARY_PATH when you run the program, or use
some additional link flags (-R) to store the library locations in the
executable itself:

export LD_LIBRARY_PATH=$JDK/jre/lib/i386:$JDK/jre/lib/i386/client

Gordon Beaton

unread,
Feb 8, 2002, 4:57:32 AM2/8/02
to
On Fri, 8 Feb 2002 09:19:32 +0100, Amadan wrote:
> cls = (*env)->FindClass(env, "AutoProcessor");
> if(cls == 0) {
> fprintf(stderr, "Can't find AutoProcessor.main\n");
> exit(1);
> }
>
> mid = (*env)->GetStaticMethodID(env, cls, "main",
> "([Ljava/lang/String;)V");
> if(mid == 0) {
> fprintf(stderr, "Out of memory\n");
> exit(1);
> }

Just a tip...

When any of these functions fail, you can use

if ((*env)->ExceptionOccurred(env)) {
(*env)-> ExceptionDescribe(env);
}

to see the real reason for the failure, instead of just blindly
assuming the problem is "out of memory" every time.

Amadan

unread,
Feb 8, 2002, 5:43:04 AM2/8/02
to
>It's not the right solution - you've told it to build a shared object,
>not an executable.

Thanks! This is better... But I still have problems :(

> gcc -I $JDK/include -I $JDK/include/linux -c test.c
> gcc -L $JDK/jre/lib/i386/client test.o -o test -ljvm

This compiles just fine. The Sun's tutorial says to include java library,
but here we use jvm? Why is that? (except for the rather obvious reason that
with -ljava it does not work)?

I exported LD_LIBRARY_PATH, and then run my program, and it broke on

JNI_CreateJavaVM(&jvm, (void *) &env, &vm_args);

saying

Error occurred during initialization of VM
Unable to load native library: shared object not open

What now?

Goran

Gordon Beaton

unread,
Feb 8, 2002, 6:59:43 AM2/8/02
to
On Fri, 8 Feb 2002 11:43:04 +0100, Amadan wrote:
> This compiles just fine. The Sun's tutorial says to include java library,
> but here we use jvm? Why is that? (except for the rather obvious reason that
> with -ljava it does not work)?

Well that's a good enough reason for me (I don't consider the tutorial
to be an authoritative source).

Actually -ljava works too if you set the library path before
compiling, but I don't like the compile time dependency on the
environment.

> I exported LD_LIBRARY_PATH, and then run my program, and it broke on
>
> JNI_CreateJavaVM(&jvm, (void *) &env, &vm_args);
>
> saying
>
> Error occurred during initialization of VM
> Unable to load native library: shared object not open
>
> What now?

Recheck the LD_LIBRARY_PATH. You need $JDK/jre/lib/i386, one of the
client or server subdirectories, and one of the threads
subdirectories.

You can use ldd to examine the executable (with the path set) to see
what libraries it depends on and whether the loader can find them. You
shouldn't get any "not found". You can also use ldd on each of those
libraries to see what libraries *they* depend on, and again you
shouldn't get any "not found".

Juergen Kreileder

unread,
Feb 8, 2002, 10:02:44 AM2/8/02
to
Gordon Beaton <n...@for.email> writes:

> This works for me:
>
> export JDK=...
>
> gcc -I $JDK/include -I $JDK/include/linux -c test.c
> gcc -L $JDK/jre/lib/i386/client test.o -o test -ljvm

Additionally you should define _REENTRANT and link with libpthread on
Linux.

BTW, our J2SDK contains "j2sdk-config" which helps to get the right values,
e.g.:

,----
| % j2sdk-config --cflags
| -D_REENTRANT -D_GNU_SOURCE -I/usr/lib/j2se/1.3/include -I/usr/lib/j2se/1.3/include/linux
|
| % j2sdk-config --libs
| -L/usr/lib/j2se/1.3/jre/lib/i386/client -ljvm -lpthread
|
| % j2sdk-config --ld-library-path
| /usr/lib/j2se/1.3/jre/lib/i386:/usr/lib/j2se/1.3/jre/lib/i386/native_threads:/usr/lib/j2se/1.3/jre/lib/i386/client:/usr/lib/j2se/1.3/lib/i386${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
|
| % j2sdk-config -server --ld-library-path
| /usr/lib/j2se/1.3/jre/lib/i386:/usr/lib/j2se/1.3/jre/lib/i386/native_threads:/usr/lib/j2se/1.3/jre/lib/i386/server:/usr/lib/j2se/1.3/lib/i386${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
`----

Juergen

--
Juergen Kreileder, Blackdown Java-Linux Team
http://www.blackdown.org/java-linux.html
Run Java 2 SE v1.3.1 on your iPAQ:
http://www.handhelds.org/pipermail/ipaq/2001-June/007221.html

Amadan

unread,
Feb 8, 2002, 11:12:58 AM2/8/02
to
Gordon,

Thank you very much, you have been *so* helpful. The code works now, and I
can actually implement something useful.

Goran


0 new messages