在命令行下用CMake交叉編譯可在android中運(yùn)行的so包
最近在寫一個(gè)通過(guò)錄屏生成gif的小應(yīng)用,由于要用到NDK,所以開(kāi)始去解這方面的知識(shí),總的來(lái)講也還算簡(jiǎn)單,不過(guò)對(duì)于之前從沒(méi)接觸過(guò)ndk的小白來(lái)說(shuō),一切都是需要摸索的,在一個(gè)不熟悉的領(lǐng)域有時(shí)候一個(gè)微小的問(wèn)題也能讓你摸個(gè)半天才能搞明白。我寫博客的大部分原因就是為了記錄下這些摸索的過(guò)程,以后要是忘記了還可以翻出來(lái)看,當(dāng)然,要是還能幫到其他跟我一樣的小白那就更好了。
下面進(jìn)入正題,對(duì)于陌生的東西,當(dāng)然是先google一翻了,隨后發(fā)現(xiàn)Android Studio已經(jīng)幫我們做了很多工作了,我們只需要做些簡(jiǎn)單的配置就可以做NDK開(kāi)發(fā)了。大致有以下幾步(具體的細(xì)節(jié)這里不講):
- 1、下載好NDK、CMake
- 2、新建一個(gè)android工程
- 3、在build.gradle文件中配置c文件相關(guān)的路徑以及CMakelists.txt路徑等等
- 4、創(chuàng)建一個(gè)帶native方法的java類
- 5、再編寫一個(gè)與上述類對(duì)應(yīng)的c文件
- 6、編寫CMakeLists.txt文件
然后跑起來(lái)就差不多了,流程基本上就這樣了,剩下的就是業(yè)務(wù)上的事了。
不過(guò)對(duì)于小白來(lái)說(shuō),照著教程做了一遍,工程跑起來(lái)了,預(yù)期結(jié)果也達(dá)到了,但還是一臉懵懂,不知道來(lái)龍去脈。用Android Studio的好處是高度智能化,開(kāi)發(fā)者借助它可以快速地完成一些與業(yè)務(wù)無(wú)關(guān)的事,但也有一點(diǎn)我個(gè)人不喜歡,那就是不知道它到底做了些什么,像個(gè)黑盒子,只看到結(jié)果,看不到過(guò)程。所以幾乎從一開(kāi)始我就很想知道如果不依賴android studio 怎么才能把我要的so包編譯出來(lái)呢?就好比不需要eclipse,直接在命令行下編譯運(yùn)行java程序一樣。不得不說(shuō),為了搞明白這點(diǎn)事,我摸了很久,并且曾暫停了一段時(shí)間。下面就來(lái)說(shuō)一下不用android studio怎么編譯so包,說(shuō)出來(lái)之后會(huì)覺(jué)得很簡(jiǎn)單,但沒(méi)搞清楚之前卻是讓我非常抓狂。
在命令行下執(zhí)行交叉編譯有兩種方式
- 一是用NDK自帶的工具鏈
- 二是使用獨(dú)立工具鏈
第一種簡(jiǎn)單點(diǎn),第二種麻煩點(diǎn),不過(guò)簡(jiǎn)單的卻花了我更多的時(shí)間和精力,因?yàn)闆](méi)有在網(wǎng)上找到現(xiàn)成的資料。本文講第一種,使用獨(dú)立工具鏈的方式再另寫一文來(lái)介紹。
注:本文的例子是在Ubuntu操作系統(tǒng)下完成的
一、按照J(rèn)NI的實(shí)現(xiàn)方式建一個(gè)工程
JNI的實(shí)現(xiàn)大概有以下幾步:
- 編寫帶有 native 方法的 Java 類
- 生成該類擴(kuò)展名為 .h 的頭文件
- 創(chuàng)建該頭文件的 C/C++ 文件,實(shí)現(xiàn) native 方法
- 將該 C/C++ 文件編譯成動(dòng)態(tài)鏈接庫(kù)
- 在Java 程序中加載該動(dòng)態(tài)鏈接庫(kù)
最后建好的工程目錄如下圖所示
[圖片上傳失敗...(image-5ac0c9-1514633487045)]
MyJni類是一個(gè)帶native方法的java類
Navive.c是實(shí)現(xiàn)native方法的本地類
內(nèi)容如下:
[圖片上傳失敗...(image-c530bc-1514633487045)]
僅打印了一句日志。
CMakeLists.txt的內(nèi)容如下:
[圖片上傳失敗...(image-a71634-1514633487045)]
添加了一個(gè)myso的動(dòng)態(tài)庫(kù),輸出到c目錄下的lib目錄中(實(shí)際輸出的名字叫:libmyso.so)
至此,如果不需要交叉編譯的話進(jìn)入build目錄下執(zhí)行下面兩條命令就可以生成so包了(目前build只是個(gè)空目錄)
$ cmake ..
$ make
不過(guò)這個(gè)so包只能在當(dāng)前pc上使用,不能用在手機(jī)上(實(shí)際上這個(gè)例子按上面的方法執(zhí)行是會(huì)報(bào)錯(cuò)的,因?yàn)橛玫搅薬ndroid的日志,會(huì)找不到頭文件的,這里只是說(shuō)明一下本地編譯與交叉編譯的區(qū)別)。如果要交叉編譯就要配置交叉編譯環(huán)境,這就是今天的重頭戲。
二、配置交叉編譯環(huán)境
寫一個(gè)腳本來(lái)記錄這些參數(shù),在build目錄下新建configuer.sh文件,內(nèi)容如下:
[圖片上傳失敗...(image-e22098-1514633487045)]
這里對(duì)各個(gè)參數(shù)作個(gè)解釋:
ANDROID_ABI 是cpu架構(gòu)
ANDROID_PLATFORM是支持的最低android平臺(tái)
ANDROID_NDK是ndk的根目錄
CMAKE_TOOLCHAIN _FILE是工具鏈文件,這個(gè)參數(shù)非常重要,這里面還配置了很多其它參數(shù)。
ANDROID_TOOLCHAIN是C/C++編譯器,可選Clang和gcc,官網(wǎng)推薦clang
最后還有兩個(gè)點(diǎn),代表上一級(jí)目錄,即CMakeLists.txt所在的目錄
在build目錄下執(zhí)行這個(gè)腳本,再執(zhí)行make命令,可用于android的so包就出來(lái)了。
[圖片上傳失敗...(image-d9de94-1514633487045)]
[圖片上傳失敗...(image-8a6948-1514633487045)]
驗(yàn)證
下面來(lái)驗(yàn)證一下,看看這個(gè)so能否在android工程中使用。
創(chuàng)建一個(gè)android工程,將so包拷到j(luò)niLibs目錄下,MyJni.java拷到對(duì)應(yīng)的目錄下。
[圖片上傳失敗...(image-a1c59b-1514633487045)]
在MainActivity中調(diào)用:
[圖片上傳失敗...(image-c18471-1514633487045)]
看一下日志:
[圖片上傳失敗...(image-119460-1514633487045)]
可以看到已經(jīng)成功調(diào)到了so包里的方法,第一句就是從Native.c文件輸出的。第二句是在MainActivity里面輸出的。
源碼
https://github.com/MingHuang1024/CrossCompileForAndroidUseCommand
驗(yàn)證的那個(gè)android工程就不上了,如果要的話就聯(lián)系我。
由于水平有限,如果文中存在錯(cuò)誤之處,請(qǐng)大家批評(píng)指正,歡迎大家一起來(lái)分享、探討!
博客:http://blog.csdn.net/MingHuang2017
GitHub:https://github.com/MingHuang1024
Email:MingHuang1024@foxmail.com
微信:724360018