Android新版NDK環境配置(免Cygwin)

原文連接:http://blog.csdn.net/codezjx/article/details/8879670html


前言:Android NDK r7及以上的版本已經集成了Cygwin編譯環境,也就是說,咱們徹底能夠拋棄龐大的Cygwin了。java


r6及如下版本,也能夠拋棄幾個G的完整版,使用精簡過的Mini-Cygwin來編譯,解壓後大小僅9M,但短小巧精悍,徹底能夠知足Android NDK的開發。android

下載地址:https://code.google.com/p/mini-cygwin/c++

Eclipse集成Cygwin編譯環境能夠參考個人這篇貼:http://blog.csdn.net/codezjx/article/details/8858825windows



下面進入正題,r7及以上版本,跟着個人這篇帖子,完成環境的升級吧!!!app

參考官網:http://tools.android.com/recent/usingthendkplugineclipse

一、首先確認本身的ADT版本,NDK plugin的支持是在ADT 20及之後的版本。ide

二、安裝Android Native Development Tools(該組件集成C/C++開發環境),既在安裝ADT工具的時候勾選NDK組件,一路next後重啓Eclipse使插件生效。函數


三、下載NDK工具http://developer.android.com/tools/sdk/ndk/index.html,我使用的是最新的android-ndk-r8e-windows-x86.zip,下載完後解壓縮。工具

四、Eclipse -> Window -> Preferences -> Android -> NDK,設置NDK爲剛剛解壓縮的工具包路徑。


侯注:作到這裏時,控制檯報出了一個錯誤:「Unable to launch cygpath. Is Cygwin on the path」,由於個人ndk是以前安裝的,並無專門設置環境變量。按照這個連接中的引導解決:

  1. Head to the project's properties. If you're using Windows, the shortcut is Alt + Enter; or simply right-click the project name to find its properties.

  2. Go to the C/C++ Build section; under Builder Settings tab in Build command: text box you're likely to find something similar to that below, if it's empty then type in the similar text - namely:${NDKROOT}/ndk-build.cmd where NDKROOT, as its name implies, refers to the path where your NDK root folder exists. enter image description here

  3. Now you must inform eclipse what NDKROOT equates to; as in, where is the NDK root path. You can do this by heading to (in your project's properties) C/C++ Build > Environment > press Add…

  4. Now add your environment variable named NDKROOT (the Name) with the relevant path (Value). Note that you're to repeat this per NDK project. You would get a window similar to that below. enter image description here

  5. Press OK to the New variable input window and then OK again to the properties window.


五、NDK環境基本上已經搭建好,新建一個普通Android項目測試NDK支持。項目右鍵->Android Tools->Add Native Support...,輸入.so庫名字後點擊Finish

(注意:若項目已是一個Jni項目,例如NDK example裏面的HelloJni,這一步中.so庫名字不用填)


六、如今已經能夠Build咱們的Jni項目了,選擇項目,Project->Build Project,編譯咱們的c/c++代碼,此時項目結構以下,NDK plugin已經爲咱們添加好了include,已經爲咱們生成了相應的Android.mk以及 cpp文件。(注意:這裏插件爲咱們生成的是cpp文件,若你不喜歡能夠改回.c,並在mk文件中進行相應更改)


七、這時,Android NDK環境已經完美搭建好,咱們能夠在cpp文件中流暢地書寫咱們的c/c++代碼。

(並且當你Alt+/時,已經可使用自動提示,各類爽歪歪有木有。若你不是用NDK plugin來構建JNI項目,而是選擇手動方式,Alt+/是不會提示的


八、關於編譯,默認狀況下:選擇項目,Project->Build Project,來從新編譯咱們的代碼。並且每次run項目的時候,也會自動編譯.so庫。




一些問題與解決方法:

問題一:Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml    (這個是NDK工具的一個BUG,若build Target大於minSdkVersion,則會報這個錯誤,致使沒法運行)
解決方法:
android-ndk-r8e/build/core/add-application.mk第128行把__ndk_warning改成__ndk_info;而後從新build一次項目便可消除錯誤。
原文:
this problem may be safely fixed by changing this line in add-application.mk from __ndk_warning to __ndk_info
連接:

https://code.google.com/p/android/issues/detail?id=39752



問題二:使用c++來編寫本地庫,會有一些兼容問題。

(1)直接黏貼HelloJni的stringFromJNI函數過來測試,提示Method 'NewStringUTF' could not be resolved
解決方法

改成:將(*env)->NewStringUTF(env, "Hello from JNI !")改成return env->NewStringUTF("Hello from JNI !")便可

緣由是:

NDK plugin默認爲咱們生成的是cpp文件,而C與C++調用函數的參數不一致,所以找不到函數,具體參考jni.h中的定義。cpp文件中形如(*env)->Method(env, XXX)改爲env->Method(XXX)便可。



(2)運行c++生成的.so庫,若報如下錯誤:(既找不到函數)

No implementation found for native Lcom/dgut/android/MainActivity;.stringFromJNI ()Ljava/lang/String;

java.lang.UnsatisfiedLinkError: stringFromJNI

at com.dgut.android.MainActivity.stringFromJNI(Native Method)

解決方法:

爲供Java調用的c++函數前加入extern "C" 修飾,如:(NDK example裏面的cpp文件也是這麼聲明的,參考hello-gl2)

[java]  view plain copy
  1. extern "C" {  
  2.     JNIEXPORT jstring JNICALL Java_com_dgut_android_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz );  
  3. }  
  4.   
  5. JNIEXPORT jstring JNICALL Java_com_dgut_android_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )  
  6. {  
  7.     return env->NewStringUTF("Hello from JNI bear c++");  
  8. }  
緣由是:

        被extern "C"修飾的變量和函數是按照C語言方式編譯和鏈接的。

        首先看看C++中對相似C的函數是怎樣編譯的:做爲一種面向對象的語言,C++支持函數重載,而過程式語言C則不支持。函數被C++編譯後在符號庫中的名字與C語言的不一樣。例如,假設某個函數的原型爲:void foo( int x, int y );該函數被C編譯器編譯後在符號庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不一樣的編譯器可能生成的名字不一樣,可是都採用了相同的機制,生成的新名字稱爲「mangled name」)。_foo_int_int這樣的名字包含了函數名、函數參數數量及類型信息,C++就是靠這種機制來實現函數重載的。例如,在C++中,函數voidfoo( int x, int y )與void foo( int x, float y )編譯生成的符號是不相同的,後者爲_foo_int_float。
        一樣地,C++中的變量除支持局部變量外,還支持類成員變量和全局變量。用戶所編寫程序的類成員變量可能與全局變量同名,咱們以"."來區分。而本質上,編譯器在進行編譯時,與函數的處理類似,也爲類中的變量取了一個獨一無二的名字,這個名字與用戶程序中同名的全局變量名字不一樣。

        所以,若咱們沒有使用extern "C"修飾函數,按照C語言方式編譯和鏈接,Jni調用將可能找不到該函數。

相關文章
相關標籤/搜索