2013-06-05 79 views
5

我想熟悉JNI API,但無法獲得一個示例C++程序來編譯。我得到了相同的樣本來編譯和運行在Linux中(在下面的鏈接發佈問題後),但不能得到它在Windows編譯;我正在使用mingw g ++。我已將所有包含路徑更改爲windows路徑,並且jni.h位於編譯時,但不是jvm.dll。未定義的引用'JNI_CreateJavaVM'窗口

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 `[email protected]' 

和正在編譯的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?

+0

鏈接到使用g ++創建的MSVC庫可能會有問題。看到這個互操作性的帖子:http://www.mingw.org/wiki/MixingCompilers。你有沒有考慮過使用Visual Studio呢? – maba

+0

@ maba-我已經嘗試在視覺工作室,但我得到了同樣的結果。你知道jvm.dll是用MSVC構建的嗎?我猜這不是,但這只是一個猜測。 – RBI

+1

@RBI它是用MSVC構建的。函數名稱在輸出表中被破壞的方式是免費的。 – greatwolf

回答

3

您遇到的問題可以簡要歸結爲名稱裝飾問題。鏈接器找不到具有給定名稱的函數,因爲它在jvm.dll中的裝飾方式不同。

看着你得到了最初的錯誤:

undefined reference to '[email protected]' 

它暗示了兩件事情:

  1. @12後綴在最後指出JNI_CreateJavaVM supposely使用STDCALL約定。
  2. _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可以用符號從.a,MSVC的COFF工作GNU鏈接直接格式.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

+2

非常好的解釋,謝謝澄清這對我。 – RBI

+0

你好。我鏈接到jvm.lib文件,它仍然給我這個錯誤。任何想法?使用的命令是g ++「-LC:\\ Program Files \\ Java \\ jdk1.8.0_112 \\ lib」-o voce_synth.exe synthesisTest.o -ljvm – Renato

+0

@Renato'-ljvm'開關附加一個'lib * '輸入文件的前綴。 IOW用'-ljvm'查找'libjvm.a'。嘗試使用'-l:jvm.lib'或只傳遞完全路徑的文件名,因爲沒有'-l'。 – greatwolf

2

Got it!閱讀下面後,我能夠編譯和運行,以便在編譯命令附加鏈接樣品到jvm.lib鏈接後:

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

鏈接:Linking JNI to visual studio 2008

我沒有C/c + +專家,所以如果任何人想解釋爲什麼這個額外的鏈接是不需要的時候,我會很高興接受你的答案。