未定义的对"JNI_CreateJavaVM"窗口的引用

RBI*_*RBI 7 c++ windows java-native-interface

我正在尝试熟悉JNI API,但无法获得要编译的示例c ++程序.我得到了相同的样本来编译并在linux中运行(在下面的链接中发布问题后)但是无法在windows中编译它; 我正在使用mingw g ++.我已经将所有包含路径更改为Windows路径,并且jni.h位于编译时,而不是jvm.dll.

未定义引用`JNI_CreateJavaVM'linux

这是我尝试用来编译的命令:

g++ -g -I"C:\Program Files (x86)\Java\jdk1.7.0_21\include" -I"C:\Program Files (x86)\Java\jdk1.7.0_21\include\win32" -L"C:\Program Files (x86)\Java\jdk1.7.0_21\jre\bin\server" callJava.cpp -ljvm
Run Code Online (Sandbox Code Playgroud)

和...

**same as above with the additional** : -L"C:\Program Files (x86)\Java\jdk1.7.0_21\lib"
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

undefined reference to `_imp__JNI_CreateJavaVM@12'
Run Code Online (Sandbox Code Playgroud)

和正在编译的cpp:

#include <jni.h>

int main(){

    //firstTest();
    JavaVM *jvm;
    JNIEnv *env;

    JavaVMInitArgs vm_args;
    JavaVMOption options[1];
    options[0].optionString = "-Djava.class.path=C:/Users/Ron/Dropbox/jni/simple/ctojava/win";
    vm_args.version = JNI_VERSION_1_6;
    vm_args.options = options;
    vm_args.nOptions = 1;
    vm_args.ignoreUnrecognized = JNI_FALSE;

    int res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);

    jclass cls = env->FindClass("Hello");
    jmethodID mid = env->GetStaticMethodID(cls, "staticInt", "(I)I");
    env->CallStaticVoidMethod(cls, mid,10);

    jvm->DestroyJavaVM();
}
Run Code Online (Sandbox Code Playgroud)

我看了很多例子,但仍然无法找到解决方案.任何帮助表示赞赏!

更新:我很确定jvm.dll被定位,因为如果我删除-L"path_to_jvm"然后我得到错误:

mingw32/bin/ld.exe: cannot find -ljvm
Run Code Online (Sandbox Code Playgroud)

就像我说的,这个确切的方法适用于linux,我还缺少什么用于Windows?

gre*_*olf 4

您遇到的问题可以简单地总结为名称修饰问题。链接器找不到具有给定名称的函数,因为它在jvm.dll.

查看您得到的初始错误:

undefined reference to '_imp__JNI_CreateJavaVM@12'
Run Code Online (Sandbox Code Playgroud)

它暗示了两件事:

  1. @12末尾的后缀表示可能JNI_CreateJavaVM使用 stdcall 约定。
  2. 前缀_imp_表示该函数来自导入库,该库重定向到外部加载的 dll,该函数在其导出表中可见。

函数原型如下jni.h

_JNI_IMPORT_OR_EXPORT_ 
jint JNICALL JNI_CreateJavaVM(JavaVM **, void **, void *);
Run Code Online (Sandbox Code Playgroud)

预处理后可能看起来像这样:

__declspec(dllimport) jint __stdcall
JNI_CreateJavaVM(JavaVM **, void **, void *);
Run Code Online (Sandbox Code Playgroud)

现在,mingw 附带的 gnu 链接器可以直接使用、.amsvc 的 COFF 格式的符号。在您的原始命令中,它仅在提供的搜索路径()中找到,因此它尝试使用它。.lib.dlljvm.dll-L ...

问题在于,在jvm.dll导出表中, 该JNI_CreateJavaVM函数未经过修饰,因此它看起来像 cdecl 函数。该名称与链接器期望的名称不匹配,因此您会收到未定义的引用错误。

从 Java Dev Kit 来看,它包含一个导入库,其中jdk1.7.0_21\lib\jvm.lib具有该符号的正确名称修饰。您修改后的命令有效,因为通过添加-L jdk1.7.0_21\lib到搜索路径,它现在链接到jvm.lib而不是jvm.dll.

  • 解释得很好,感谢您为我澄清这一点。 (2认同)