7

我正在尝试熟悉 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

和...

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

我得到的错误是:

undefined reference to `_imp__JNI_CreateJavaVM@12'

和正在编译的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();
}

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

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

mingw32/bin/ld.exe: cannot find -ljvm

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

4

2 回答 2

3

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

查看您得到的初始错误:

undefined reference to '_imp__JNI_CreateJavaVM@12'

它暗示了两件事:

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

中的函数原型jni.h

_JNI_IMPORT_OR_EXPORT_ 
jint JNICALL JNI_CreateJavaVM(JavaVM **, void **, void *);

预处理后大概是这样的:

__declspec(dllimport) jint __stdcall
JNI_CreateJavaVM(JavaVM **, void **, void *);

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

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

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

于 2013-06-05T20:25:28.060 回答
2

知道了!阅读下面的帖子后,我能够使用编译命令中的附加链接来编译和运行示例,以便链接 jvm.lib:

-L"C:\Program Files (x86)\Java\jdk1.7.0_21\lib"

链接:将 JNI 链接到 Visual Studio 2008

我不是 c/c++ 专家,所以如果有人想解释为什么这个附加链接不在 linux 中时需要它,我很乐意接受你的回答。

于 2013-06-05T16:59:02.433 回答