idea java jni 调试_IntelliJ IDEA平台下JNI编程(一)—HelloWorld篇
JNI(Java Native Interface),出于學習JNI的目的,為了能夠更方便快速地運行程序。本文的是在IDEA中進行,而不在AndroidStudio,這樣能夠對NDK的工作過程有個更深刻的認識,同時也能對JNI的原理有更深的理解。雖然本文是HelloWorld篇,但是其中涉及到很多內容。博主將遇到的坑都記錄下來了,希望能夠幫到大家。這篇文章可能是2016年的最后一篇文章了,接下來JNI相關系列文章明年推出,歡迎大家關注。
1. 搭建GCC編譯環境
既然使用的了JNI,那就不可避免地需要將C/C++文件編譯成dll(windows)或so(Linux)文件。因為我是在Windows平臺下開發,可以有如下選擇:
使用VC(或VS)編譯成dll
使用GCC編譯成dll
因為開發Android應用肯定是需要編譯成Linux平臺的so文件,因此,為了后面開發Android程序的兼容,使用GCC編譯器比較好。而Windows平臺下的GCC又可以有如下選擇:
使用MinGW
使用Cygwin
這里我選擇了MinGW,不管選擇哪個,只要能讓本地有GCC編譯環境即可。
注意:搭建GCC編譯環境時,一定要選擇正確的GCC編譯版本(32位和64位)。如果你本地安裝的JDK是64位的,那么選擇64位GCC,否則選擇32位。這是為了使得編譯后的庫文件跟JVM的位一致,否則后面JVM無法調用dll(或so)。
1.1 安裝MinGW
指定解壓路徑
其本質也是解壓縮,把需要的MinGW庫和程序解壓到指定目錄。如果懶的去看英文,我這里將我解壓后的重新壓縮了下,大家去下載并且解壓即可直接使用。
解壓完成后,剛才指定的解壓目錄中的bin加入到path環境變量中。例如上面圖中解壓到E:\MinGw,那么應當將E:\MinGw\bin加入到環境變量path中。注意,請確保bin目錄確實在E:\MinGw中,如果不在,可能在更深一層目錄中,自行確定bin的目錄。
做完后,打開控制臺,輸入:gcc -v,如下:
2. 開始編碼
2.1 編寫Java文件
新建一個Java Project,創建包com.huachao.java,如下:
創建項目
在包com.huachao.java下編寫HelloJNI類:
函數System.loadLibrary()是加載dll(windows)或so(Linux)庫,只需名稱即可,無需加入文件名后綴(.dll或.so)。native關鍵字將函數sayHello()聲明為本地函數,由C/C++實現。具體的實現就在hello.dll(Windows平臺)或hello.so(Linux平臺)中
2.2 生成JNI頭文件
2.2.1 手動輸入javah指令
JNI生成頭文件是通過JDK中提供的javah來完成,javah在 {JDKHome}/bin目錄中。用法如下:
例如,將E:\Porject\out\com\huachao\java目錄中的HelloJNI.class生成頭文件,并放入到E:\Project\jni中:
需要注意的是,使用javah來生成頭文件(.h)時,-classpath指定的是編譯后的java文件(.class)的目錄,而不是源文件(.java)的目錄,因此在使用javah指令之前,先build一下項目(或直接運行一下)。此時會生稱out目錄,所有編譯后的文件都會存放在這個目錄中。
out目錄
接下來,直接在IDEA的Terminal窗口運行javah:
執行javah指令
此時在jni目錄中生成了頭文件com_huachao_java_HelloJNI.h
自動生成頭文件
內容如下:
接下來我們只需實現Java_com_huachao_java_HelloJNI_sayHello(JNIEnv *, jobject)即可。仔細觀察就會發現這個函數名稱是有規律的,即Java___,JNIEXPORT和JNICALL這兩個宏定義暫時不用管。JNIEnv 和jobject后面系列文章會詳細介紹,這里暫時不理會。
2.2.2 一鍵生成頭文件
在2.2.1小節中,介紹了輸入javah生成頭文件方法。但是如果目錄層次很深,或者是有多個需要生成頭文件的class文件,這工作量太大了,當然你可以通過寫個小程序來實現。但是這里有個更便捷的方法。點擊File>Settings>Tools>External Tools:
External Tools
添加一個先的External Tools:
添加一個先的External Tools
在HelloJNI.java文件中點擊右鍵>External Tools>Generate Header File,
點擊生成頭文件
點擊生成,可以看到Terminal窗口會自動運行指令。跟2.2.1小節的指令一模一樣。
3. 編寫C文件并編譯成dll(或so)文件
3.1 手動輸入命令生成
在jni目錄中新建HelloJNI.c文件,如下:
新建C文件
編輯HelloJNI.c如下:
接下來就是使用GCC對HelloJNI.c編譯,在Terminal窗口輸入如下:
發現報錯,找不到jni.h頭文件,將JDK目錄中的include目錄加入,即為:
又報找不到jni_md.h錯誤,繼續將JDK目錄中的include/win32加入,即:
完成編譯。此時在項目中會生成HelloJNI.o文件。接下來是將HelloJNI.o轉為HelloJNI.dll,即轉為windows平臺下的動態鏈接庫。在Terminal中輸入如下:
此時項目目錄中生成了hello.dll文件:
生成dll
3.2 一鍵生成dll
有了前面使用External Tools一鍵生成頭文件的經驗后,我們可以將編譯成dll的過程命令也加入到External Tools中。前面將c文件編譯鏈接成dll文件分了2個命令,這里我們直接通過一個命令來完成:
這樣就將c文件編譯成了dll,在這里把生成的dll文件加入到了lib目錄中,而不是像之前那直接放到項目底下。因此在java.library.path應該指定目錄為lib。
有了上面的命令后,可以很輕松的加入到External Tools中了。按照前面的方法,點擊File>Settings>Tools>External Tools>+,輸入內容如下:
name:Generate DLL
Program:
Parameters:-Wl,--add-stdcall-alias -I"$JDKPath$\include" -I"$JDKPath$\include\win32" -shared -o ./lib/$FileNameWithoutExtension$.dll ./jni/$FileNameWithoutExtension$.c
Working Directory:$ProjectFileDir$
添加External Tools
在HelloJNI.c中點擊右鍵,選擇External Tools>Generate DLL。此時,在lib目錄中會得到dll文件。
4. 運行
運行HelloJNI.java類后,如下:
運行結果
5 可能出現的錯誤
5.1 java.library.path找不到dll的錯誤
此時,點擊直接運行HelloJNI.java類時,依然還會有錯誤:
即找不到我們生成的dll文件。因為在Windows中JVM的java.library.path屬性即為環境變量Path指定的目錄,而我們生成的dll并未放入到Path指定的任何一個目錄中,因此我們需要告訴JVM,dll文件在哪個目錄中。點擊Run > Edit Configurations...,如下:
修改Edit Configurations
在VM options中加入java.library.path,指定dll(或so)文件所在的目錄,比如本文中dll放在項目目錄中的lib中,如下:
如下圖所示:
修改VM options
5.2 無法識別__int64類型錯誤
錯誤如下:
出現這個錯誤的人一般是使用Cygwin GCC的人,這是因為Cygwin GCC不認識__int64類型,找到/include/win32/jni_md.h,找到typedef __int64 jlong;并修改為:
或者是編譯時將__int64加入,如下:
5.3 64-bit mode not compiled
錯誤如下:
出現這個錯誤是因為,JDK版本是64位,而GCC編譯器編譯出的dll(或so)是32位,只需換個64位版本的GCC即可。
name:Generate DLL
Program:F:\MinGW\mingw64\bin\gcc.exe
Parameters:-Wl,--add-stdcall-alias -I"$JDKPath$\include" -I"$JDKPath$\include\win32" -shared -o $ModuleFileDir$/lib/$FileNameWithoutExtension$.dll $ModuleFileDir$/jni/$FileNameWithoutExtension$.cpp -lstdc++Working Directory:$ProjectFileDir$
name:Generate Header File
Program:$JDKPath$/bin/javah
Parameters:-jni -classpath $OutputPath$ -d $ModuleFileDir$/jni $FileClass$
Working Directory:$ProjectFileDir$
參考資料
總結
以上是生活随笔為你收集整理的idea java jni 调试_IntelliJ IDEA平台下JNI编程(一)—HelloWorld篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 是不是不能八普通人,只能八明星不然就被扎
- 下一篇: 求违开头的成语接龙!