I'm trying to create JVM usin JNI. I'm using win 7 64 bits OS. On line JNI_CreateJavaVM my program crashes. I decided to compile my program using 64 bit compiler and got following error:
Error 1 error LNK2001: unresolved external symbol __imp_JNI_CreateJavaVM
Where is the point I should start to look for linking problem and why my program crashes in 32 bit mode?
void createJVM()
{
JavaVMInitArgs vm_args;
JavaVMOption options[4];
int n = 0;
char * str;
str= new char[1000];
sprintf(str, "-Djava.class.path=%S\\tst.jar", myPath);
options[n++].optionString = str;
str= new char[1000];
sprintf(str, "-Djava.library.path=%S\\lib;%S", myPath, myPath);
options[n++].optionString = str;
str= new char[1000];
sprintf(str, "-Duser.dir=%S", myPath);
options[n++].optionString = str;
vm_args.version = JNI_VERSION_1_4;
vm_args.nOptions = n;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
}
have you added 'jvm.lib' as Additional Dependency in your project?
furthermore, you need to specify the location of jvm.lib in Additional Library Directories...
also please note that for 64-bit application, you would need to point to the 64-bit library, otherwise linker won't link
You can find those settings in the Configuration Properties->Linker area.
hope this information helps you out.
Cheers,
Since I can't wote up (still less than 15 reputation) I just want to confirm that Naytzyrhc solution worked for me.
Just to clarify it a bit more, in Visual Studio Express 2013 (v12) you should go to:
Project -> [YourProjectName] Properties... -> Linker -> General -> Additional Library Directories
for adding lib folder to additional library directories, and:
Project -> [YourProjectName] Properties... -> Linker -> Input -> Additional Dependencies
for adding jvm.lib to additional dependencies.
Related
I am running a Node application using GraalVM. My Node code contains both R and Java interop code.
I installed R using GraalVM Updater:
gu install r
Node program:
const express = require('express')
const app = express()
const BigInteger = Java.type('java.math.BigInteger')
app.get('/', function (req, res) {
var text = 'Hello World from Graal.js!<br> '
// Using Java standard library classes
text += BigInteger.valueOf(10).pow(100)
.add(BigInteger.valueOf(43)).toString() + '<br>'
// Using R methods to return arrays
text += Polyglot.eval('R',
'ifelse(1 > 2, "no", paste(1:42, c="|"))') + '<br>'
// Using R interoperability to create graphs
text += Polyglot.eval('R',
`svg();
require(lattice);
x <- 1:100
y <- sin(x/10)
z <- cos(x^1.3/(runif(1)*5+10))
print(cloud(x~y*z, main="cloud plot"))
grDevices:::svg.off()
`);
res.send(text)
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
Console output:
Example app listening on port 3000!
FastR unexpected failure: error loading libR from: /.sdkman/candidates/java/20.1.0.r11-grl/languages/R/lib/libR.so.
Message: libgfortran.so.3: cannot open shared object file: No such file or directory
Troubleshooting:
* Please run /home/.sdkman/candidates/java/20.1.0.r11-grl/languages/R/bin/configure_fastr. It will check that your system has the necessary dependencies and if not it will suggest how to install them.
* If this does not help, please open an issue on https://github.com/oracle/fastr/ or reach us on https://graalvm.slack.com.
/home/server.js:19
text += Polyglot.eval('R',
... other logs
I have also installed build-essential, gfortran, libxml2 and libc++-dev as suggested by GraalVm compiler.
Is it an issue with GraaLVM or Ubuntu FastR package installation does by GraalVM?
Please try again with the latest version of GraalVM. 20.1.0 is already several months old; if you try again with 20.3.0 you should get lots of bugfixed that where included in the newer version.
Also, note that the error message even tells you to run a specific command on your shell, /home/.sdkman/candidates/java/20.1.0.r11-grl/languages/R/bin/configure_fastr. Did you do that? Did that help? What was the output of that, was there an error?
Thanks,
Christian
JNI_CreateJavaVM function method does not work and cannot be debugged.
The development environment is win10 x64, jdk version is 1.8
Visual studio 2017 Community Edition Writing a C++ project
I am learning about JNI. I am trying to run The Invocation API. The following URL is an example of the official website documentation.
Click here!
I built the project and added a project dependency that contains jvm.lib. And I put jvm.dll in the project directory. I successfully run this program.
Main.test() is a method of print hello world. But the program exits when executing JNI_CreateJavaVM, the console shows that the return value is 1.
I can't get into debugging, I don't know what happened.
#include <jni.h>
int main() {
printf("begin..........\n");
JavaVM *jvm; /* denotes a Java VM */
JNIEnv *env; /* pointer to native method interface */
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
JavaVMOption* options = new JavaVMOption[1];
char optionString[] = "-Djava.class.path =D:/Program Files/Java/jdk1.8.0_191/lib/";
options[0].optionString = optionString;
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
* pointer in env */
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
printf("result=%d", res);
delete options;
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
/* We are done. */
jvm->DestroyJavaVM();
return 0;
}
I expect this jvm can be called, but it is forced to exit when the program is executed to `int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
Where am I wrong? Why is it not working?
Exit screenshot
enter image description here
jvm.dll location
enter image description here
jvm.lib linker additional library directories
enter image description here
jvm.lib linker additional Dependencies
enter image description here
Classpath
There is a space between key and equal sign. The space must be removed.
char optionString[] = "-Djava.class.path =D:/Program Files/Java/jdk1.8.0_191/lib/";
Classpath value
The java.class.path value must point to the base directory where your compiled .class files are located.
It looks like you're not using a package name, then it's the directory where Main.class is located, so probably it should look something like this:
char optionString[] = "-Djava.class.path=c:/Users/name/MyJavaPrograms/classes";
Access violation
SEGV (or exception 0xC0000005) is also generated intentionally on JVM startup to verify certain CPU/OS features.
see this fine answer: https://stackoverflow.com/a/36258856
In Visual Studio, when the exception dialog is shown, simply turn off that it breaks there. This will prevent you from seeing it again the next time you start the program again.
Java
Just for the sake of completeness: the Java method should look like this:
public class Main {
public static void test(int num) {
System.out.println("Java: test called with '" + num + "'");
}
...
Visual Studio Configuration
The jvm.dll needs to be found. In Visual Studio under Configuration Properties/Debugging/Environment add PATH=%PATH%;<path-to-jdk>\bin\server
For later deployment you could think about putting the whole JRE into a subfolder of your application and reference it with a relative path.
Demo
Finally a brief demo (added a \n here printf("result=%d\n", res); to have a separate line):
When I create a Java 8 JVM in C++ I usually use something like the following code to tell JVM the class path:
JavaVMOption* options = new JavaVMOption[1]; // JVM invocation options
options[0].optionString = (char *)"-Djava.class.path=.;./lib2"; // where to find java .class
vm_args.version = JNI_VERSION_1.8; // minimum Java version
vm_args.nOptions = 1; // number of options
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
But how to tell the Java 9 JVM about the module path? There is no java.module.path system property. The best I can find is something like:
JavaVMOption* options = new JavaVMOption[2]; // JVM invocation options
options[0].optionString = (char *)"-Djdk.module.path=.;./lib2"; // where to find java .class
options[1].optionString = (char *)"-Djdk.module.main=RemkaAgentService"; // where to find java .class
vm_args.version = JNI_VERSION_9; // minimum Java version
vm_args.nOptions = 2; // number of options
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
But this code does not work, it fails when I try to create JVM. I suppose it is because it does not support the options I try.
This is a late answer but persons that make searches about this problem may find it useful. There is indeed very few documentation to address this case, which is unfortunate.
I spent some time to investigate this problem and I found a way to make it work. Here are the steps to take.
Bundle your application packages within a custom JRE by using the 'jlink' tool provided by the JDK: https://docs.oracle.com/en/java/javase/11/tools/jlink.html
Use the class loader to find your main class. To do this in JNI, you can use the "FindClass()" function : https://docs.oracle.com/en/java/javase/11/docs/specs/jni/functions.html#findclass
The first step removes the requirement to define the '--module-path' flag that is not supported by JNI. Note that to properly bundle your application, all you jars must be converted to modular jars. Third-party jars may not be true modular jars but rather automatic modules, but automatic modules are not supported by jlink (Using jlink with automatic modules). Fortunately, there is a method to perform this automatically documented here : creating module-info for automatic modules with jdeps in java 9
The second step works even if your class lies within a module. Notes that the class name parameter for a class 'p1.p2.p3.MyClass' must be 'p1/p2/p3/MyClass'. I mentioned this as I wasted some time due to this difference in the convention.
I may publish an example if I can find some time for this but it may not happens in a short time-frame.
So the right options are the following
JavaVMOption* options = new JavaVMOption[2]; // JVM invocation options
options[0].optionString = (char *)"--module-path=.;./lib2"; // where to find java .class
options[1].optionString = (char *)"--add-modules=RemkaAgentService,spring.context";
vm_args.version = JNI_VERSION_9; // minimum Java version
vm_args.nOptions = 2; // number of options
vm_args.options = options;
vm_args.ignoreUnrecognized = false; // invalid options make the JVM init fail
I realize this is a question that has already been asked by a few people but their answers did not fix my problem.
I'm currently trying to make a QT application and I have some code written in Java that I'd like to use, so I decided to implement the JNI into my application.
I use the following code to initalize the VM:
JNIEnv* SokoSolver::createVM(JavaVM **JVM){
JNIEnv* Env;
JavaVMInitArgs args;
JavaVMOption options;
options.optionString = "-Djava.class.path=./";
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
args.options = &options;
args.ignoreUnrecognized = 0;
int returnValue = JNI_CreateJavaVM(JVM, (void**)&Env, &args);
if(returnValue < 0 || !Env){
cout << "Unable to launch JVM, Return Value: " << returnValue << endl;
}
return Env;
}
However whenever my code is run I get an error message:
Error occurred during initialization of VM Unable to load native library: Can't find dependent libraries.
I'm using the x86 version of the JVM.lib/JVM.dll, along with the relevant header files. As per the other answers I have changed the path variable in Windows to start with:
C:\Program Files (x86)\Java\jdk1.8.0_74\bin;
C:\Program Files (x86)\Java\jdk1.8.0_74\jre\bin\server;
But when I run my code I still get the exact same errors. Is there any other solutions to this problem? Does it have anything to do with:
options.optionString = "-Djava.class.path=./";
This may be a problem with jdk installed on your system.
Just reinstall jdk 8u92 and add the same path in environment path in your system.
There are lots of examples that Android C/C++ native calls Java APIs.
However, all of these examples I have read are the Android Java APIs call native
first and then the native calls other Java APIs by using the passed JNI-ENV.
Without the passed JNI-ENV, how can the C/C++ get it?
Is it possible that C/C++ native calls Java APIs without JNI-ENV?
Can you give an example or a link for it if it is possible?
Thanks!
You need to include jni.h first. This brings a ton of useful calls; with newer android releases you'll also need JniInvocation.h. To enable this:
LOCAL_C_INCLUDES += ${JNI_H_INCLUDE}
That certainly works with source tree, not sure about NDK, but should be fine, too.
Second, pretty important thing is to have proper signal chain lib selected. Art or Dalvik will load libsigchain.so, which is a stub and abort()s every time any of its methods are being called. On Android it's done with a little hack: local symbols are being exported to global symbol table, so that Art picks exec's symbols instead of loading shared lib. Here's how it's done:
# Enable native helper calls
LOCAL_SHARED_LIBRARIES += libnativehelper
# Include all of the Android's libsigchain symbols
LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain
# Export only libsigchain symbols to global symbol table.
LOCAL_LDFLAGS += \
-Wl,--export-dynamic \
-Wl,--version-script,art/sigchainlib/version-script.txt
Link your executable now. Double check that the required symbols are indeed exported:
% readelf -a <output_binary> | grep InitializeSignalChain
654: 0002cab1 211 FUNC GLOBAL PROTECTED 12 InitializeSignalChain
Done? things get simpler now:
Initialize the JNI (so that your code uses proper VM)
JniInvocation invocation;
if (invocation.Init(nullptr)) return;
Create JavaVM:
JavaVM* vm;
JNIEnv* env;
JavaVMInitArgs* args;
args.version = JNI_VERSION_1_4; // _5, _6
args.options = nullptr;
args.nOptions = 0;
args.ignoreUnrecognized = JNI_FALSE;
if (JNI_CreateJavaVM(&vm, &env, &args) < 0) return;
At this point your vm and env are ready to use. have fun.
Check for exceptions, if any
if (env->ExceptionCheck()) {
// ...
}
When you're done, clean up
vm->DetachCurrentThread();
vm->DestroyJavaVM();
More interesting stuff can be found here and DalvikVM Main is probably the best source of knowledge. Good luck!