當前位置:
首頁 > 最新 > Android NDK開發掃盲及最新CMake的編譯使用

Android NDK開發掃盲及最新CMake的編譯使用

本篇文章旨在簡介 Android 中 是什麼以及重點講解最新 Android Studio 編譯工具 的使用

1 NDK 簡介

在介紹 之前還是首推 Android 官方 文檔。傳送門(https://developer.android.com/ndk/guides/index.html)

官方文檔分別從以下幾個方面介紹了

的基礎概念

如何編譯 項目

是什麼以及不同 CPU 指令集支持哪些

如何使用您自己及其他預建的庫

本節將會對文檔進行總結和補充。所以建議先瀏覽一遍文檔,或者看完本篇文章再回頭看一遍文檔。

1.1 NDK 基礎概念

首先先用簡單的話分別解釋下 、, 以及分別和 Android 開發、c/c++ 開發的配合。在解釋過程中會對 、、、、這些常見名詞進行掃盲。

JNI(Java Native Interface):Java本地介面。是為了方便Java調用c、c++等本地代碼所封裝的一層介面(也是一個標準)。大家都知道,Java的優點是跨平台,但是作為優點的同時,其在本地交互的時候就編程了缺點。Java的跨平台特性導致其本地交互的能力不夠強大,一些和操作系統相關的特性Java無法完成,於是Java提供了jni專門用於和本地代碼交互,這樣就增強了Java語言的本地交互能力。上述部分文字摘自任玉剛的 Java JNI 介紹(http://blog.csdn.net/singwhatiwanna/article/details/9061545)

NDK(Native Development Kit) : 原生開發工具包,即幫助開發原生代碼的一系列工具,包括但不限於編譯工具、一些公共庫、開發IDE等。

工具包中提供了完整的一套將 c/c++ 代碼編譯成靜態/動態庫的工具,而 和 你可以認為是描述編譯參數和一些配置的文件。比如指定使用c++11還是c++14編譯,會引用哪些共享庫,並描述關係等,還會指定編譯的 。只有有了這些 中的編譯工具才能準確的編譯 c/c++ 代碼。

文件是 Android NDK r4 中引入的一個 shell 腳本。其用途是調用正確的 構建腳本。其實最終還是會去調用 自己的編譯工具。

那 又是什麼呢。脫離 Android 開發來看,c/c++ 的編譯文件在不同平台是不一樣的。Unix 下會使用 文件編譯,Windows 下會使用 文件編譯。而 則是一個跨平台的編譯工具,它並不會直接編譯出對象,而是根據自定義的語言規則()生成 對應 或 文件,然後再調用底層的編譯。

在Android Studio 2.2 之後,工具中增加了 的支持,你可以這麼認為,在 Android Studio 2.2 之後你有2種選擇來編譯你寫的 c/c++ 代碼。一個是 + + 組合,另一個是 + 組合。這2個組合與Android代碼和c/c++代碼無關,只是不同的構建腳本和構建命令。本篇文章主要會描述後者的組合。(也是Android現在主推的)

1.2 ABI 是什麼

(Application binary interface)應用程序二進位介面。不同的CPU 與指令集的每種組合都有定義的 (應用程序二進位介面),一段程序只有遵循這個介面規範才能在該 CPU 上運行,所以同樣的程序代碼為了兼容多個不同的CPU,需要為不同的 構建不同的庫文件。當然對於CPU來說,不同的架構並不意味著一定互不兼容。

armeabi設備只兼容armeabi;

armeabi-v7a設備兼容armeabi-v7a、armeabi;

arm64-v8a設備兼容arm64-v8a、armeabi-v7a、armeabi;

X86設備兼容X86、armeabi;

X8664設備兼容X8664、X86、armeabi;

mips64設備兼容mips64、mips;

mips只兼容mips;

具體的兼容問題可以參見這篇文章。Android SO文件的兼容和適配(http://blog.coderclock.com/2017/05/07/android/Android-so-files-compatibility-and-adaptation/)

當我們開發 Android 應用的時候,由於 Java 代碼運行在虛擬機上,所以我們從來沒有關心過這方面的問題。但是當我們開發或者使用原生代碼時就需要了解不同 以及為自己的程序選擇接入不同 的庫。(庫越多,包越大,所以要有選擇)

下面我們來看下一共有哪些 以及對應的指令集

2 CMake 的使用

這一節將重點介紹 的規則和使用,以及如何使用 編譯自己及其他預建的庫。

2.1 Hello world

我們通過一個Hello World項目來理解

首先創建一個新的包含原生代碼的項目。在 New Project 時,勾選 Include C++ support

項目創建好以後我們可以看到和普通Android項目有以下4個不同。

下面增加了 目錄,即放置 c/c++ 代碼的地方

module-level 的 有修改

增加了 文件

多了一個 目錄

build.gradle

由於 的命令集成在了 - 中,所以在 中有2個地方配置 。

外面的 ,指明了 的路徑; 裡面的 ,主要填寫 的命令參數。即由 中的參數最後轉化成一個可執行的 的命令,可以在 中查到。如下

更多的可以填寫的命令參數和含義可以參見Android NDK-CMake文檔(https://developer.android.com/ndk/guides/cmake.html)

CMakeLists.txt

中主要定義了哪些文件需要編譯,以及和其他庫的關係等。

看下新項目中的

這其實是一個最基本的 ,其實 裡面可以非常強大,比如自定義命令、查找文件、頭文件包含、設置變數等等。建議結合 的官方文檔(https://cmake.org/documentation/)使用。同時在這推薦一個中文翻譯的簡易的CMake手冊(https://www.zybuluo.com/khan-lau/note/254724)

2.2 CMake 使用自己及其他預建的庫

當你需要引入已有的靜態庫/動態庫(FFMpeg)或者自己編譯核心部分並提供出去時就需要考慮如何在 中使用自己及其他預建的庫。

Android NDK 官網的使用現有庫(https://developer.android.com/ndk/guides/libs.html)的文檔中還是使用 + + 組合的說明文檔。(其實官方文檔中大部分都是的,並沒有使用 )

幸運的是, Github上的官方示例(https://github.com/googlesamples/android-ndk) 裡面有個項目 hello-libs(https://github.com/googlesamples/android-ndk/tree/master/hello-libs) 實現了如何創建出靜態庫/動態庫,並引用它。現在我們把代碼拉下來看下具體是如何實現的。

我們先看下Github上的README介紹:

app - 從 中使用一個靜態庫和一個動態庫

gen-libs - 生成一個動態庫和一個靜態庫並複製到 目錄,你不需要再編譯這個庫,二進位文件已經保存在了項目中。當然,如果有需要你也可以編譯自己的源碼,只需要去掉 和 中的注釋,然後執行一次,接著注釋回去,防止在 build 的過程中不受影響。

我們採用自底向上的方式分析模塊,先看下 模塊。

gen-libs/build.gradle

查詢文檔(https://developer.android.com/ndk/guides/cmake.html) 可以知道 中 代表編譯的 android 平台,文檔建議直接設置 就行了,所以這個參數可忽略。另一個參數 , 一共有2種編譯工具鏈 - 和 , 已經廢棄, 是默認的。

代表編譯哪些項目。(不填就是都編譯)

cpp/CMakeLists.txt

外層的 裡面核心就是 ,查詢 CMake 官方文檔(https://cmake.org/documentation/) 可以知道這條命令的作用是為構建添加一個子路徑。子路徑中的 也會被執行。即會去分別執行 和 中的

cpp/gmath/CMakeLists.txt

這個是其中一個靜態庫的 ,另一個跟他很像。只是把 改成了 (動態庫)。

之前用到過,編譯出一個靜態庫,源文件是

命令的意思是設置目標的一些屬性來改變它們構建的方式。這個命令中設置了 的 屬性。也就是改變了輸出路徑。

命令是自定義命令。命令中把頭文件也複製到了 中。

以上就是一個靜態庫/動態庫的編譯過程。總結以下3點

編譯靜態庫/動態庫

修改輸出路徑

複製暴露的頭文件

接著,我們看下 模塊是如何使用預建好的靜態庫/動態庫的。

app/src/main/cpp/CMakeLists.txt

我將解釋放在了注釋中。可以看下基本上分成了4個步驟引入:

分別創建靜態庫/動態庫,直接引用已經有的 .a 文件 或者 .so 文件

創建自己應用的庫

加入之前暴露頭文件

鏈接上靜態庫/動態庫

還是很好理解的。編輯好並 後,你就可以發現 中的c/c++代碼可以引用暴露的頭文件調用內部方法了。

3 資料文獻

首推 Android NDK 官方文檔(https://developer.android.com/ndk/guides/index.html),雖然很多都不完整,但是絕對是必須看一遍的東西。

當初次接觸 開發又覺得新建的 Hello World 項目過於簡單時。建議把 googlesamples - android-ndk(https://github.com/googlesamples/android-ndk) 項目拉下來。裡面有多個實例參考,比官方文檔完整很多。

當你發現示例里的一些NDK配置滿足不了你的需求後,你就需要到 CMake 官方文檔(https://cmake.org/documentation/) 去查詢完整的支持的函數,同時這裡也提供一個中文翻譯的簡易的CMake手冊(https://www.zybuluo.com/khan-lau/note/254724)。

以上文檔資料僅為了解決 NDK 開發過程中編譯配置問題,具體 c/c++ 的邏輯編寫、jni等不在此範疇。

彩蛋

文末獻上一組彩蛋,將 或者 開發過程中遇到的坑和小技巧以 Q&A 的方式列出。持續更新

Q1:怎麼指定 C++標準?

A:在 中,配置

Q2:add_library 如何編譯一個目錄中所有源文件?

A: 使用 方法將路徑列表全部放到一個變數中。

Q3:怎麼調試 CMakeLists.txt 中的代碼?

A:使用 方法

然後運行後在 中查看 log。

Q4:什麼時候 CMakeLists.txt 裡面會執行?

A:測試了下,好像在 sync 的時候會執行。執行一次後會生成 的文件緩存之類的東西放在 中。所以如果 中沒有修改的話再次同步好像是不會重新執行的。(或者刪除 目錄)

真正編譯的時候好像只是讀取 目錄中已經解析好的 去編譯。不會再去執行

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Tsy遠 的精彩文章:

TAG:Tsy遠 |

您可能感興趣

Discuz API JSON 適用於IOS及Android移動端開發
谷歌開發新系統Fuchsia 計劃取代Android和Chrome OS
CollPlant加入ReMDO行動計劃為3D列印器官開發bioink
蘋果與台積電合作開發MicroLED 將用於Apple Watch和AR
Block.one宣布推出Demux,可簡化複雜的DAPP開發
即將發售!UNIQLO 與遊戲開發商 Blizzard Entertainment 攜手推出全新 UT 系列
《Pokemon Go》開發商收購AR API製作公司EscherReality
BCH新開發者平台Developer.bitcoin上線,加速BCH應用開發
DeepMind和Unity合作,開發虛擬環境訓練AI
Made in Space為NASA開發可在太空混合3D列印系統
Kanye West 與 Kid Cudi 合作專輯《Kids See Ghost》試聽會周邊商品公開發售
Realtek藉助Cadence Innovus成功開發DTV SoC解決方案
使用C#開發Android應用之WebApp
使用 Visual Studio Code 搭建 C/C+開發和調試環境
Python web開發:Flask的URL和視圖
Neurala與CSDN宣布戰略合作,將一站式AI平台BrainBuilder帶給中國開發者
Google的DeepMind開發AI 可將2D圖片渲染成3D
UNIQLO 與遊戲開發商 Blizzard Entertainment 攜手推出全新 UT 系列
無人機開發商PrecisionHawk收購Droners、AirVid,建造行業專才網路
開發者再爆料:LCD版的iPhone就是iPhoneSE2