'What is libJvm.so, and when is it built?
I'm a bit surprised that I have to post a question that looks rather trivial and easy to look up.... but it apparently isn't.
Because it looks that my jni.h and the libJvm.so library are out of sync (or so I suspect), which shows up trying to load my Java application as a library into the C++ environment on Linux(with JNI_CreateJVM() and all that), I wonder which could be the culprit. The jni.h is just standard, containing all normal modules.... the libJvm.so however... I cannot see what the contents are.... I don't even know what it really is and how/ where it is built.
Can anybody give me an explanation/answer to this question?
P.S. the problems don't have to do with library path and related issues... the libJvm.so can be found. It is just hard to understand what goes wrong as long as I don't exeactly know all the components I'm working with....
Hereunder an update, following on comments that came in in reactions on my question (it is a very long update, because I decided it might be insightful to include the code that I'm working with)...
The code I'm working with (and experiencing the problem with), after the code I also say something about the environment/settings and circumstances....:
#include <jni.h>
#include "jvm.h"
#include <iostream>
#include <stdlib.h>
#include <dlfcn.h>
using namespace std;
//Create type for pointer to the JNI_CreateJavaVM function
typedef jint (*CreateJvmFuncPtr) (JavaVM**, void**, JavaVMInitArgs*);
//New method returns pointer to the JNI_CreateJavaVM function
CreateJvmFuncPtr findCreateJvm() {
CreateJvmFuncPtr createJvm = NULL;
void* jvmLib = dlopen("/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71.x86_64/jre/lib/amd64/server/libjvm.so", RTLD_LAZY); //Get handle to jvm shared library
char* error = dlerror(); //Check for errors on dlopen
if(jvmLib == NULL || error != NULL) {
printf("FailedToLoadJVM\n");
}
//Load pointer to the function within the shared library
createJvm = (CreateJvmFuncPtr) dlsym(jvmLib, "JNI_CreateJavaVM");
error = dlerror();
if(error != NULL) {
printf("Success\n");
}
return createJvm;
}
int main() {
// load and initialize JVM and JNI interface, in a test setting where JVM is "passive"
// (called/loaded as .dll) and the JNI env is not available yet from a Java/JVM call
// (which would be the caste in the normal setup/configuration).
//int jniLoadJvmAsDll()
//{
JavaVM *jvm; // Pointer to the JVM (Java Virtual Machine)
JNIEnv *env; // Pointer to native interface
//======== prepare loading of Java VM: assign init arguments for JVM init =========
JavaVMInitArgs vm_args; // Initialization arguments
// JavaVMOption* vmOptions = new JavaVMOption[1]; // JVM invocation options
JavaVMOption vmOptions[4];
// (=> comparable to lib path for System.load(libPath/libName)
vmOptions[0].optionString = "-Djava.compiler=NONE"; /* disable JIT */
vmOptions[1].optionString = "-Djava.class.path=/home/adminuser/workspace_Unit_Test_Java_Cpp/Unit_Test_Jni_Java/bin"; // which Java class to load
vmOptions[2].optionString = "-Djava.library.path=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71.x86_64/jre/lib/amd64/;/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71.x86_64/jre/lib/amd64/server";
vmOptions[3].optionString = "-verbose:jni"; /* print JNI-related messages */
vm_args.version = JNI_VERSION_1_6; // minimum Java version
vm_args.nOptions = 1; // number of options
vm_args.options = vmOptions;
vm_args.ignoreUnrecognized = false; // invalid options make the JVM init fail
//=============== load and initialize Java VM and JNI interface =============
// old code: jint retCrJvm = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); // YES !!
//New code:
CreateJvmFuncPtr createJVM = findCreateJvm();
printf("findCreateJVM() returned 0x%x\n", createJVM);
jint retCrJvm = createJVM(&jvm, (void**)&env, &vm_args);
//End new code
delete vmOptions; // we then no longer need the initialization options.
if (retCrJvm != JNI_OK) {
// TO DO: error processing...
cin.get();
exit(EXIT_FAILURE);
}
//====================handle multithread situatiation ========================
JavaVM * curVM = NULL; // JVM in current thread, should contain loaded VM
// otherwise we're not in the main thread
JNIEnv *curEnv;
int jvmLoadFailed = 1;
// handle situation that we're not in the main thread (current thread isnt't main thread)
if (jvm == NULL) {
env->GetJavaVM( &curVM ); // JVM should contain current/main thread JVM, otherwise
// we're not in the main thread
int vmStat = curVM->GetEnv((void **)&curEnv, JNI_VERSION_1_6);
if (vmStat == JNI_EDETACHED) //We are on a different thread, attach
curVM->AttachCurrentThread((void **) &curVM, NULL);
if( curVM == NULL )
return jvmLoadFailed; //Can't attach to java, bail out
}
//=============== Display JVM version =======================================
cout << "JVM load (as .so/.dll) succeeded: Version ";
jint ver = env->GetVersion();
std::cout << ((ver>>16)&0x0f) << "."<<(ver&0x0f) << endl;
// TO DO: add the code that will use JVM <============ (see next steps)
// insert the JNITools separate methods here.... for each separate graphical structure
// initially a test class is inserted.....
jclass clsTestPrint = env->FindClass("TestPrint"); // try to find the class
if(clsTestPrint == NULL) {
cerr << "ERROR: class not found !";
}
jmethodID ctor = env->GetMethodID(clsTestPrint, "<init>", "()V"); // find an object constructor for this class
if(ctor == NULL) {
cerr << "ERROR: constructor not found !" << endl;
}
else {
cout << "Object succesfully constructed !"<<endl;
jobject prtObj = env->NewObject(clsTestPrint, ctor); // invoke the object constructor: create print object
if (prtObj) {
jmethodID show = env->GetMethodID(clsTestPrint, "showId", "()V");
if(show == NULL)
cerr << "No showId method !!" << endl;
else env->CallVoidMethod(prtObj, show);
}
}
jvm->DestroyJavaVM();
cin.get();
return 0;
//}
}
Where "dlopen" and "dlsym" of course replace the "loadLibrary()" and "getProcaddress()" calls you would use on Windows to 1. load a .dll and get a handle to the appropriate JNI procedure... but I'm doing this on Linux, therefore the "equivalent translations"....
The "multithread" decoration is not really relevant here.... added it for possible future purposes.
After some experiments I succeeded in configuaring the build settings so that also the libjvm.so is found and within that the API JNI method JNI_CreateJavaVM().... For that I added (on Linux, using Eclipse) the following "GCC C++ Linker" settings: -- => "Libraries" => "Libraries (-l)" => "Jvm" and => "Library Search Path (-L)" => "/usr/lib/jvm/java-1.7.0.openjdk-1.7.0.71.x86_64/jre/lib/amd64/server"
-- => "Shared Library Settings" => "Shared Object Name " => "libjvm.so"
Other settings gave errors during compilation/linking.
With this, the environment can be built. The debugger is started and stops in main and I can step througt the C++ code as usual until.... I reach the JNI_CreateJavaVM() invocation. At that time the following error occurs.
relocation error: /home/adminuser/workspace_Unit_Test_Java_Cpp/Unit_Test_Jni_Cpp/Debug/Unit_Test_Jni_Cpp: symbol JNI_CreateJavaVM, version SUNWprivate_1.1 not defined in file libjvm.so with link time reference
I have hereby strong suspicions that either: 1. the jni header and the library (libJvm.so) are out of sync, or 2. the class path or lib path do not contain the correct value's 3. the Java .so (.dll) loaded (with "dlopen") is not what it should be....
Any idea's which value's to use?
This is the "background of my question: to determine wheter the jni and libJvm.so content are out of sync, is it very convenient to know what it is and where it is about....
Solution 1:[1]
a) make sure that /usr/lib/jvm/java-1.7.0.openjdk-1.7.0.71.x86_64/jre/lib/amd64/ is on your LD_LIBRARY_PATH
b) switch back to 'old code' loading libjvm.so implicitly without dlopen and stuff.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Alex Cohn |
