未定义对“JNI_CreateJavaVM”窗口的引用

Posted

技术标签:

【中文标题】未定义对“JNI_CreateJavaVM”窗口的引用【英文标题】:undefined reference to `JNI_CreateJavaVM' windows 【发布时间】:2013-06-05 02:23:15 【问题描述】:

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

undefined reference to `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,我还缺少什么?

【问题讨论】:

从 g++ 链接到使用 MSVC 构建的库可能会出现问题。请参阅此互操作性帖子:mingw.org/wiki/MixingCompilers。您是否考虑过改用 Visual Studio? @maba- 我也在 Visual Studio 中尝试过,但我得到了相同的结果。你知道 jvm.dll 是用 MSVC 构建的吗?我猜它不是,但这只是一个猜测。 @RBI 它是用 MSVC 构建的。函数名称在导出表中被破坏的方式是一种赠品。 【参考方案1】:

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

查看您得到的初始错误:

undefined reference to '_imp__JNI_CreateJavaVM@12'

它暗示了两件事:

    末尾的@12 后缀表示JNI_CreateJavaVM 假定使用stdcall 约定。 _imp_ 前缀表示此函数来自导入库,该库重定向到外部加载的 dll,该 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的符号了。在您的原始命令中,它仅在提供的搜索路径 (-L ...) 中找到 jvm.dll,因此它尝试使用它。

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

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

【讨论】:

解释得很好,感谢您为我澄清这一点。 你好。我正在链接到 jvm.lib 文件,但它仍然给我这个错误。任何的想法?使用的命令是 g++ "-LC:\\Program Files\\Java\\jdk1.8.0_112\\lib" -o voce_synth.exe synthesisTest.o -ljvm @Renato -ljvm 开关将lib* 前缀附加到导入文件。带有-ljvm g++ 的 IOW 查找libjvm.a。尝试-l:jvm.lib 或只传递带有完整路径的文件名,而没有-l @greatwolf 仍然有与 -l:jvm.lib 相同的问题。两件事..我正在使用 mingw64 和 java 64 位。但由于某种原因,它给了我“@12”后缀,据说是 32 位的。 您可能必须使用nmobjdump 之类的东西检查jvm.lib 中的符号表。确保未解析的名称在那里。在 64 位下,修饰可能略有不同。【参考方案2】:

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

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

链接:Linking JNI to visual studio 2008

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

【讨论】:

以上是关于未定义对“JNI_CreateJavaVM”窗口的引用的主要内容,如果未能解决你的问题,请参考以下文章

架构 x86_64 的未定义符号:JNI_CreateJavaVM OS-X Xcode

引用了未解析的外部符号 __imp__JNI_CreateJavaVM@12

Mac上解决dose not contain the JNI_CreateJavaVM symbol

Mac上解决dose not contain the JNI_CreateJavaVM symbol

JNI_CreateJavaVM 上的段错误

linux 上的 JNI_CreateJavaVM 会破坏堆栈?