Java Forum / General / October 2005
Under Linux, Call java from C++
tony_lincoln@yahoo.com - 29 Sep 2005 23:19 GMT 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.
Roedy Green - 30 Sep 2005 00:13 GMT On 29 Sep 2005 15:19:01 -0700, tony_lincoln@yahoo.com wrote or quoted
>But how can I find the jvm.lib? check out updatedb and locate.
It is one of the slickest features of linux. It is so fast.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Again taking new Java programming contracts.
tony_lincoln@yahoo.com - 30 Sep 2005 15:06 GMT What do you mean "updatedb and locate"?
Roedy Green - 30 Sep 2005 21:33 GMT On 30 Sep 2005 07:06:42 -0700, tony_lincoln@yahoo.com wrote or quoted
>What do you mean "updatedb and locate"? Are those not standard Linux commands? I has been a while. Look in a bash manual.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Again taking new Java programming contracts.
tony_lincoln@yahoo.com - 01 Oct 2005 16:33 GMT Yes they are. U r right. I should look a little bit more about the manual. Sorry. Tony
Gordon Beaton - 30 Sep 2005 08:34 GMT > 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 I don't get the errors you report, but there are some things that need to be fixed:
- main() must return int, not void.
- #include <windows.h> isn't necessary at all, remove it (anyway I suspect you don't have such a file on linux).
- normally you should include the system header files first, followed by jni.h and finally your own header files.
- the pragma is unknown to g++
After making the above changes, the code compiles fine using the following commands:
(compile: invoke.cpp -> invoke.o) gcc -Wall -D_REENTRANT -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -c invoke.cpp
(link: invoke.o -> invoke) gcc -L $JAVA_HOME/jre/lib/i386/client invoke.o -lstdc++ -ljvm -lpthread -o invoke
(note that each of these two commands is exactly one line, even though my newsreader or yours may have broken them)
To run the program you need to have the following directories in your LD_LIBRARY_PATH:
$JAVA_HOME/jre/lib/i386/client $JAVA_HOME/jre/lib/i386
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Roedy Green - 30 Sep 2005 09:22 GMT >LD_LIBRARY_PATH what is LD_LIBRARY_PATH? a system property, a SET environment parameter? just a name for the path? I was looking for signs of it today earlier on my Windows machine. Nothing. I vaguely recall seeing it earlier..
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Again taking new Java programming contracts.
Gordon Beaton - 30 Sep 2005 09:38 GMT > what is LD_LIBRARY_PATH? a system property, a SET environment > parameter? just a name for the path? I was looking for signs of it > today earlier on my Windows machine. Nothing. I vaguely recall seeing > it earlier.. One of several enviroment variables that can be used to control the dynamic linker/loader. They are described on the relevant man pages (e.g. man ld.so on linux).
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
tony_lincoln@yahoo.com - 30 Sep 2005 14:57 GMT Hi Friends and especially Gordon,
Thanks a lot for the words. I did the following: 1.changed the path setting : export LD_LIBRARY_PATH=$JAVA_HOME/jre/lib/i386/client:$JAVA_HOME/jre/lib/i386. 2. changed "void main()" into "int main()"
THen the erros are like this: ____________________________________________________________________ rakta:~/jniLinux$ gcc -Wall -D_REENTRANT -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -c invokeLinux.cpp invokeLinux.cpp: In function `int main()': invokeLinux.cpp:24: error: `JNI_VERSION_1_4' undeclared (first use this function) invokeLinux.cpp:24: error: (Each undeclared identifier is reported only once for each function it appears in.) __________________________________________________________________________________
line 24 in invokeLinux.cpp is: vm_args.version = JNI_VERSION_1_4;
Is there anything wrong with the version of JVM? Thanks in advance. tony
tony_lincoln@yahoo.com - 30 Sep 2005 16:28 GMT When I remove this line, vm_args.version = JNI_VERSION_1_4;
I can get invoke.o and invoke. But when I typed invoke, there is one error: error while loading shared libraries: libjvm.so: cannot open shared object file: No such file or directory
I guess that is the problem about LD_LIBRARY_PATH. But I set it already in bashrc file... Why?
Gordon Beaton - 30 Sep 2005 16:40 GMT > When I remove this line, > vm_args.version = JNI_VERSION_1_4; It sounds like you are using an earlier version of java - try using JNI_VERSION_1_2, or check the value of JAVA_HOME.
What does "java -version" say?
> I can get invoke.o and invoke. But when I typed invoke, there is one > error: [quoted text clipped - 3 lines] > I guess that is the problem about LD_LIBRARY_PATH. But I set it already > in bashrc file... LD_LIBRARY_PATH is what I'd check too. Where does JAVA_HOME point? Can you find libjvm.so yourself somewhere in or below JAVA_HOME?
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
tony_lincoln@yahoo.com - 30 Sep 2005 16:53 GMT I found 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 know that they are different. But what is the difference?
Roedy Green - 30 Sep 2005 21:35 GMT On 30 Sep 2005 08:53:55 -0700, tony_lincoln@yahoo.com wrote or quoted
>I know that they are different. But what is the difference? there are two versions of java.exe and its attendant dlls. You control which one you get with the -server command line option.
The -server version is slower to start, but presumes it will keep running the same code for a long time, so spends more time optimising it.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Again taking new Java programming contracts.
tony_lincoln@yahoo.com - 30 Sep 2005 16:52 GMT I set the path like this:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/jvm/java-1.4.2-sun-1.4.2.05/jre/lib/i386/server/
This time I can compile it and got invoke.o and invoke. But when I type invoke then the new information comes: Can't create Java VM
I really wonder why?
Gordon Beaton - 30 Sep 2005 16:55 GMT > I set the path like this: > [quoted text clipped - 7 lines] > > I really wonder why? You need to add *two* directories to LD_LIBRARY_PATH:
/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
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
tony_lincoln@yahoo.com - 30 Sep 2005 16:59 GMT You are right. My java version is 1.4.2_05. So I changed the codes into vm_args.version = JNI_VERSION_1_4_2_05;
But the error kept the same:
rakta:~/GAQ$ gcc -Wall -D_REENTRANT -I /home/gao/java/j2sdk1.4.2_08/include -I /home/gao/java/j2sdk1.4.2_08/include/linux-c invokeLinux.cpp invokeLinux.cpp: In function `int main()': invokeLinux.cpp:24: error: `JNI_VERSION_1_4_2_05' undeclared (first use this function) invokeLinux.cpp:24: error: (Each undeclared identifier is reported only once for each function it appears in.)
:-( Gordon Beaton - 30 Sep 2005 17:07 GMT > You are right. My java version is 1.4.2_05. > So I changed the codes into [quoted text clipped - 12 lines] > once > for each function it appears in.) The only valid values are (AFAIK) JNI_VERSION_1_4, JNI_VERSION_1_2 and JNI_VERSION_1_1, they are listed in jni.h.
The paths you mention in the example above don't agree with what you've posted elsewhere, where you mentioned /usr/lib/jvm/java-1.4.2-sun-1.4.2_05.
It seems you have several java versions installed. You need to make sure you compile and link against the correct (and same) one.
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
tony_lincoln@yahoo.com - 01 Oct 2005 16:45 GMT >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
tony_lincoln@yahoo.com - 01 Oct 2005 17:57 GMT 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!
tony_lincoln@yahoo.com - 01 Oct 2005 18:30 GMT 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 :-)
Gordon Beaton - 02 Oct 2005 09:39 GMT > But still two quesions: > [quoted text clipped - 17 lines] > /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
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Gordon Beaton - 02 Oct 2005 08:06 GMT > 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
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
tony_lincoln@yahoo.com - 03 Oct 2005 17:43 GMT 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
Owen Jacobson - 04 Oct 2005 06:34 GMT On Mon, 03 Oct 2005 09:43:04 -0700, tony_lincoln wrote:
> 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).
tony_lincoln@yahoo.com - 04 Oct 2005 10:04 GMT 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?
Chris Uppal - 04 Oct 2005 13:57 GMT > 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
tony_lincoln@yahoo.com - 04 Oct 2005 10:11 GMT 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?
tony_lincoln@yahoo.com - 04 Oct 2005 10:22 GMT 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?
Gordon Beaton - 04 Oct 2005 10:44 GMT > 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
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Gordon Beaton - 04 Oct 2005 10:46 GMT > 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
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
tony_lincoln@yahoo.com - 30 Sep 2005 17:03 GMT Yes. I changed the path into:
rakta:~/GAQ$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/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
Then compile it, and the error kept the same:
invokeLinux.cpp: In function `int main()': invokeLinux.cpp:24: error: `JNI_VERSION_1_4_2_05' undeclared (first use this function) invokeLinux.cpp:24: error: (Each undeclared identifier is reported only once for each function it appears in.)
If I remove the line "vm_args.version = JNI_VERSION_1_4_2_05", I can compile it, but the final result kept the same: "Can't create Java VM"
Sorry for my questions.
Gordon Beaton - 30 Sep 2005 17:09 GMT > Yes. I changed the path into: > > rakta:~/GAQ$ export > LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/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 > > Then compile it, and the error kept the same: LD_LIBRARY_PATH has nothing to do with compiling the code. It's only there to help find the libraries that are needed when you *run* the program.
> invokeLinux.cpp: In function `int main()': > invokeLinux.cpp:24: error: `JNI_VERSION_1_4_2_05' undeclared (first use [quoted text clipped - 7 lines] > I can compile it, but the final result kept the same: > "Can't create Java VM" I've responded to this in another post. This JNI_VERSION isn't valid.
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
tony_lincoln@yahoo.com - 30 Sep 2005 17:14 GMT Thanks. I think that you are correct. I will try to compile and link against the correct (and same) version tomorrow. Thanks a lot and Have a nice weekend. tony
Jeff Schwab - 30 Sep 2005 15:35 GMT >>LD_LIBRARY_PATH > > what is LD_LIBRARY_PATH? a system property, a SET environment > parameter? just a name for the path? I was looking for signs of it > today earlier on my Windows machine. Nothing. I vaguely recall seeing > it earlier.. LD_LIBRARY_PATH is an environment variable used to tell some linkers where to look for libraries. I have found it useful with the GNU tools on various flavors of Unix.
James McIninch - 03 Oct 2005 04:46 GMT <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, > [quoted text clipped - 112 lines] > }//end main. > ______________________________________________________codes end.
 Signature Remove '.nospam' from e-mail address to reply by e-mail
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|