Under Linux, Call java from C++

T

tony_lincoln

Yes they are. U r right. I should look a little bit more about the
manual. Sorry.
Tony
 
T

tony_lincoln

It seems you have several java versions installed. You need to make
sure you compile and link against the correct (and same) one.

I think that you are right. But how to cehck if I compile and link
against the correct java version?
I tried in different computers, and it was the same: can not creat
JavaVM!
TOny
 
T

tony_lincoln

I really thank Gordon Beaton and others a lot! Actually he showed me
already how to do it in his answers:
Just add one line in jni.h, to define JNI_VERSION as 1_4_2_08. Then I
can call java codes from C++ under Linux!
Thanks again for all the hints, especially the ones from Gordon Beaton!
 
T

tony_lincoln

But still two quesions:

For the compiling and linking:
gcc -Wall -D_REENTRANT -I $JAVA_HOME/include -I
$JAVA_HOME/include/linux -c invoke.cpp
gcc -L $JAVA_HOME/jre/lib/i386/client invoke.o -lstdc++ -ljvm -lpthread
-o invoke

The parameters for gcc are really important. Without anyone of them,
the JNI calling can not work. But How do I know which parameter I
should choose?

Question two:
For the two libjvm.so,
/usr/lib/jvm/java-1.4.2-sun-1.4.2.05/jre/lib/i386/client/libjvm.so
/usr/lib/jvm/java-1.4.2-sun-1.4.2.05/jre/lib/i386/server/libjvm.so

I was told by Gordon that I should set the ID_LIBRARY_PATH like this:
/usr/lib/jvm/java-1.4.2-sun-1.4.2_05/jre/lib/i386/server
/usr/lib/jvm/java-1.4.2-sun-1.4.2_05/jre/lib/i386
But why?

Thanks a lot :)
 
G

Gordon Beaton

I really thank Gordon Beaton and others a lot! Actually he showed me
already how to do it in his answers:
Just add one line in jni.h, to define JNI_VERSION as 1_4_2_08. Then I
can call java codes from C++ under Linux!

Uhh, I don't recall suggesting you add your own JNI_VERSION to the
header file. My suggestion was to use one of the existing ones.

/gordon
 
G

Gordon Beaton

But still two quesions:

For the compiling and linking:
gcc -Wall -D_REENTRANT -I $JAVA_HOME/include -I
$JAVA_HOME/include/linux -c invoke.cpp
gcc -L $JAVA_HOME/jre/lib/i386/client invoke.o -lstdc++ -ljvm -lpthread
-o invoke

The parameters for gcc are really important. Without anyone of them,
the JNI calling can not work. But How do I know which parameter I
should choose?

Question two:
For the two libjvm.so,
/usr/lib/jvm/java-1.4.2-sun-1.4.2.05/jre/lib/i386/client/libjvm.so
/usr/lib/jvm/java-1.4.2-sun-1.4.2.05/jre/lib/i386/server/libjvm.so

I was told by Gordon that I should set the ID_LIBRARY_PATH like this:
/usr/lib/jvm/java-1.4.2-sun-1.4.2_05/jre/lib/i386/server
/usr/lib/jvm/java-1.4.2-sun-1.4.2_05/jre/lib/i386
But why?

There are two versions of libjvm.so, a server and a client version,
and you need to link against one of them. I can't say exactly what the
difference is (some optimization details I think), but you can check
the documentation for the java command line options -server and
-client.

At runtime there are additional dependencies on library files found in
$JAVA_HOME/jre/lib/i386 (common to both server and client). So at your
library path needs at least two directories, the server (or client),
and the common one.

/gordon
 
J

James McIninch

<posted & mailed>

It's not likely that the Linux code will need the Windows JVM library. Why
not use the Linux one. The errors also indicate that you didn't include
jni.h, including the headers might be helpful too.

Dear Friends,

Under Linux, I tried to call java from C++ using JNI. The following is
the C++ code which calls one java class named Menu_3D.
When I compiled it using g++, there were many mistakes like:

.......
invoke.cpp:26: error: 'struct JavaVMInitArgs' has no member named
'version'
invoke.cpp:26: error: `JNI_VERSION_1_4' undeclared (first use this
function)
invoke.cpp:27: error: 'struct JavaVMInitArgs' has no member named
'nOptions'
invoke.cpp:31: error: `jint' undeclared (first use this function)
invoke.cpp:31: error: syntax error before `=' token
invoke.cpp:32: error: `res' undeclared (first use this function)
invoke.cpp:41: error: `FindClass' undeclared (first use this function)
invoke.cpp:50: error: `GetStaticMethodID' undeclared (first use this
function)
invoke.cpp:56: error: `NewObjectArray' undeclared (first use this
function)
invoke.cpp:60: error: `CallStaticVoidMethod' undeclared (first use this
function)
invoke.cpp:73: error: `DestroyJavaVM' undeclared (first use this
function)
.......

The above errors are only one part of the whole errors. I know that I
am wrong in this line:
"#pragma comment
(lib,"E:\\Programme\\Java\\jdk1.5.0_02\\lib\\jvm.lib")"

But how can I find the jvm.lib? I tried and I can not. Does invoke.cpp
need jvm.lib under Linux?

Or are there other reasons to cause the errors?
Thanks a lot
tony


__________________________________________________________________________
/*for C++,debugged with Visual C++ 6.0*/

#ifndef __cplusplus
#define __cplusplus
#endif

#include "jni.h"
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#pragma comment (lib,"E:\\Programme\\Java\\jdk1.5.0_02\\lib\\jvm.lib")

void main() {

JavaVM *jvm;
JNIEnv *env;

JavaVMInitArgs vm_args;
JavaVMOption options[3];

options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.classpath=.";
options[2].optionString = "-verbose:jni";

vm_args.version = JNI_VERSION_1_4;
vm_args.nOptions = 3;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;

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


// jclass cls = env->FindClass("DemoMain");
// This sentence can work. Just put it into the same directory as
invoke.cpp.

jclass cls = env->FindClass("Menu_3D");
if (cls == 0) printf("Sorry, I can't find the class");

fprintf(stdout, "This is invokeSimplified4.\n");

jmethodID get_main_id;

if(cls != NULL)
{
get_main_id =
env->GetStaticMethodID(cls,"main","([Ljava/lang/String;)V");
fprintf(stdout, "This is invokeSimplified5.\n");

if(get_main_id != NULL )
{
jclass string = env->FindClass("java/lang/String");
jobjectArray args = env->NewObjectArray(0,string, NULL);

fprintf(stdout, "This is invokeSimplified6.\n");

env->CallStaticVoidMethod(cls, get_main_id, args);
/*
if (env->ExceptionOccurred())
{
env->ExceptionDescribe();
env->ExceptionClear();
}
*/ fprintf(stdout, "This is invokeSimplified7.\n");
}// end IF.

}// end IF.


jvm->DestroyJavaVM();
fprintf(stdout, "Java VM destory\n");
}//end main.
______________________________________________________codes end.
 
T

tony_lincoln

No, u did not suggest that I should add my own JNI_VERSION to the
header file. It was my idea. But this idea was initiated by your and
other's words. Thanks a lot.
Tony
 
O

Owen Jacobson

No, u did not suggest that I should add my own JNI_VERSION to the
header file. It was my idea. But this idea was initiated by your and
other's words. Thanks a lot.
Tony

Modifying library headers is almost never the right way to fix problems
using the library. You're likely to introduce subtle bugs into your code
that way (eg., by using a constant value outside the expected range of
values).
 
T

tony_lincoln

But in my library headers there is only:
#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002
There is no definition for JNI_VERSION_1_4 at all. As my current java
version is 1.4, I guess that I should add this new definition into the
header.
Another alternative is, to download a new jni.h which has the
definition for JNI_VERSION_1_4, I guess.
Am I right?
 
T

tony_lincoln

a new question: how to call just one java method.
In the codes that I showed at the beginning, the c++ codes called the
main() method of java codes. Now the question is, how to call the
normal(not main()) method:
I tried like this (do_it is the java static void method that I would
like to call from C++):
....
jmethodID get_main_id;
jmethodID get_do_it_id;

if(cls != NULL)
{
get_main_id =
env->GetStaticMethodID(cls,"main","([Ljava/lang/String;)V");
get_do_it_id =
env->GetStaticMethodID(cls,"do_it","([Ljava/lang/String;)V");

if(get_main_id != NULL )
{
jclass string = env->FindClass("java/lang/String");
jobjectArray args = env->NewObjectArray(0,string, NULL);
env->CallStaticVoidMethod(cls, get_main_id, args);
}

if(get_do_it_id!= NULL )
{
jclass string = env->FindClass("java/lang/String");
jobjectArray args = env->NewObjectArray(0,string, NULL);
env->CallStaticVoidMethod(cls, get_do_it_id, args);
}
}
....

These codes can be compiled and linked. But when I run it, there is
following error:
_____________________________________________________________________________________
Unexpected Signal : 11 occurred at PC=0x402B420F
Function=(null)+0x402B420F
Library=/usr/lib/jvm/java-1.4.2-sun-1.4.2.05/jre/lib/i386/client/libjvm.so

NOTE: We are unable to locate the function name symbol for the error
just occurred. Please refer to release documentation for possible
reason and solutions.
Current Java thread:
....
_______________________________________________________________________________

I guess that I used the wrong method in JNIEnv to call Java method?
 
T

tony_lincoln

If I put the same parameter list in do_it() as in main(), that is,
String[] args, it can work.
But if the argument list in do_it() is not same as in main(), what is
the correct code?
 
G

Gordon Beaton

If I put the same parameter list in do_it() as in main(), that is,
String[] args, it can work.
But if the argument list in do_it() is not same as in main(), what is
the correct code?

Regardless of what arguments do_it() needs (i.e. either the same as
main() or different), you need to pass the correct signature to
GetStaticMethodId(), and you need to create the correct type of
argument for the call. Be more specific if this doesn't answer the
question.

/gordon
 
G

Gordon Beaton

Unexpected Signal : 11 occurred at PC=0x402B420F

If either of the calls to GetStaticMethodID() fails (leaving NULL in
the correspoding id variable) then you are not free to continue
calling JNI functions until you clear the pending exception.

/gordon
 
C

Chris Uppal

But in my library headers there is only:
#define JNI_VERSION_1_1 0x00010001
#define JNI_VERSION_1_2 0x00010002
There is no definition for JNI_VERSION_1_4 at all. As my current java
version is 1.4, I guess that I should add this new definition into the
header.

No definitely not, it means that you are looking at a version of jni.h that
does not belong to your jdk1.4.2 installation. Find the right jni.h (it should
be in <jdk>/include/jni.h) and include that.

BTW, the numbers correspond to the version of the JNI spec, and do not relate
to the version number of the JDK in use. For instance, in JDK1.5.0, the most
recent value of JNI version is still JNI_VERSION_1_4.

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top