Android.mk解析

一 簡介

Android NDK的構(gòu)建系統(tǒng)是基于GUN Makefile的,Android.mk其實(shí)就是一個(gè)用于向Android NDK構(gòu)建系統(tǒng)描述NDK項(xiàng)目的GUN Makefile片段。
在編寫涉及JNI的項(xiàng)目時(shí),往往需要自己配置Android.mk:主要通過makefile語法,使用變量或語句對(duì)用到的工具鏈、要編譯生成的庫名稱、生成庫所依賴的源文件、生成動(dòng)態(tài)庫或靜態(tài)庫等信息進(jìn)行描述...
下面從變量開始認(rèn)識(shí)Android.mk

二 Android.mk中的常用變量

1、LOCAL_PATH
LOCAL_PATH :=$(call my-dir)
Android構(gòu)建系統(tǒng)利用LOCAL_PATH來定位源文件,Android構(gòu)建系統(tǒng)要求,Android.mk文檔必須以該變量的定義開頭。
my-dir是宏功能,這里將該變量設(shè)置為my-dir的返回值,即設(shè)置為當(dāng)前目錄
my-dir就是該Android.mk所在目錄,一般就是我們的jni目錄

2、Include &(CLEAR_VARS)
Android構(gòu)建系統(tǒng)在單次執(zhí)行中解析多個(gè)構(gòu)建文件,
LOCAL_<name>是全局變量,這條語句在每個(gè)模塊開頭使用,可以幫助清除 除了LOCAL_PATH以外的其他LOCAL_<name>變量,避免模塊間變量沖突,
例如可以清除如下文件:LOCAL_MODULELOCAL_SRC_FILES

3、LOCAL_MODULE
LOCAL_MODULE變量,簡單理解就是給生成的so庫文件設(shè)置的名稱,如:
LOCAL_MODULE : = hello-jni,表示生成名為hello-jni的模塊,
因?yàn)槟K名稱也被用于給構(gòu)建過程生成的文件命名,
因此,構(gòu)建系統(tǒng)加上適當(dāng)?shù)那熬Y,最終生成libhello-jni.so

4、LOCAL_SRC_FILES
該變量定義了生成庫文件的源文件列表:
LOCAL_SRC_FILES := hello-jni.cpp
這里hello-jni只由一個(gè)源文件生成,包含多個(gè)源文件,注意用空格分開:
LOCAL_SRC_FILES := hello-jni.cpp hello-ndk.cpp

5、LOCAL_C_INCLUDES:
表示頭文件的搜索路徑,用來指定在編譯時(shí)即將使用的頭文件的位置,
一般在使用預(yù)編譯庫構(gòu)建so時(shí)使用,用于包含第三方源文件對(duì)應(yīng)的頭文件
例:

LOCAL_C_INCLUDES := $(LOCAL_PATH) \
            $(ClientCommon_Path)/basecore/a2/framecore/include \
            $(ClientCommon_Path)/include/android/client \
            $(ClientCommon_Path)/basecore/a2/appshare/include/ \
            $(ClientCommon_Path)/basecore/a2/avcore/include/avcore \
            $(ClientCommon_Path)/include/android/meetingcore \
            $(ClientCommon_Path)/include/android/uithreadhandler \
            $(ClientCommon_Path)/include/android/MultiWhiteBoard \
            $(ClientCommon_Path)/include/android/terminalonlinemanager \
            $(ClientCommon_Path)/protocol 

6、LOCAL_LDLIBS:
用于告訴鏈接器,生成的模塊要在加載時(shí)鏈接到的庫,表示編譯模塊時(shí)要使用的附加的鏈接器選項(xiàng)。
使用‘-l’前綴傳遞指定庫的名字
例:
LOCAL_LDLIBS := -lz表示告訴鏈接器生成的模塊要在加載時(shí)鏈接到
/system/lib/libz.so/system/lib/libz.a(可鏈接到動(dòng)態(tài)庫或靜態(tài)庫)

例:
要與NDK日志庫鏈接:
LOCAL_LDLIBS:= -llog

連接到多個(gè)靜態(tài)庫或動(dòng)態(tài)庫(用空格隔開):
LOCAL_LDLIBS:= -ltinyxml32 -luithreadhandler -lxmlprotocolparser32

7、 自定義新的變量
MyLibrary_Path := $(LOCAL_PATH)/../../library
( ../ 表示上一級(jí)目錄)
注意:以LOCAL和NDK前綴開頭的名稱預(yù)留給Android NDK構(gòu)建系統(tǒng)使用,自定義變量應(yīng)避免使用這兩個(gè)前綴

三 構(gòu)建動(dòng)態(tài)庫(xxx.so)

為了建立可供主應(yīng)用程序使用的模塊,必須將該模塊變成動(dòng)態(tài)庫,只有動(dòng)態(tài)庫才能被安裝/復(fù)制到APK包中。
構(gòu)建動(dòng)態(tài)庫,在Android.mk中相應(yīng)模塊下添加如下描述語句即可:

include &(BUILD_SHARED_LIBRARY)

比如在一個(gè)工程中定義兩個(gè)動(dòng)態(tài)庫:

LOCAL_PATH := &(call my-dir)

//模塊1:
include &(CLEAR_VARS)

LOCAL_MODULE := module1
LOCAL_SRC_FILES := moudel1.cpp
include &(BUILD_SHARED_LIBRARY)
----------------------------------------------------
//模塊2:
include &(CLEAR_VARS)

LOCAL_MODULE := module2
LOCAL_SRC_FILES := moudel2.cpp
include &(BUILD_SHARED_LIBRARY)

定義完成后,NDK構(gòu)建系統(tǒng)將會(huì)產(chǎn)生兩個(gè)動(dòng)態(tài)庫:moudel1.so、moudel2.so

四 構(gòu)建靜態(tài)庫(xxx.a)

構(gòu)建靜態(tài)庫,在Android.mk相應(yīng)模塊添加描述語句:
include $(BUILD_STATIC_LIBRARY) (生成靜態(tài)庫)

Android應(yīng)用程序不直接使用靜態(tài)庫,且apk中也不包含靜態(tài)庫,但靜態(tài)庫可以用來構(gòu)建動(dòng)態(tài)庫
例如:
開放某個(gè)核心庫的功能給他人使用時(shí),無須將核心源代碼提供給客戶,而是將這些代碼編譯成靜態(tài)庫,用戶只需并入他們的動(dòng)態(tài)庫就可使用了

//編譯.a靜態(tài)庫
LOCAL_PATH := &(call my-dir)
include &(CLEAR_VARS)

LOCAL_MODULE := avilib
LOCAL_SRC_FILES := avilib.cpp  platform.cpp
include &(BUILD_STATIC_LIBRARY)   //編譯生成靜態(tài)庫

第三方使用這個(gè)靜態(tài)庫構(gòu)建自己的動(dòng)態(tài)庫在應(yīng)用程序中使用:
用庫名稱為變量LOCAL_STATIC_LIBRARY賦值,即可引用靜態(tài)庫:
LOCAL_STATIC_LIBRARY:靜態(tài)庫名稱

//原生模塊
LOCAL_PATH := &(call my-dir)
include &(CLEAR_VARS)

LOCAL_MODULE := module2
LOCAL_SRC_FILES := module2.cpp
LOCAL_STATIC_LIBRARIES := avilib   //引用編譯好的.a靜態(tài)庫
include &(BUILD_SHARED_LIBRARY)
五 用動(dòng)態(tài)庫構(gòu)建通用模塊

承接上一個(gè)靜態(tài)庫的示例代碼,多個(gè)動(dòng)態(tài)庫與同一個(gè)靜態(tài)庫相連時(shí),會(huì)產(chǎn)生重復(fù)連接,增加了apk大小
所以,當(dāng)有多個(gè)動(dòng)態(tài)庫都使用某個(gè)庫時(shí),一般將該模塊建立為動(dòng)態(tài)庫,避免重復(fù)連接。

LOCAL_PATH := &(call my-dir)

//編譯動(dòng)態(tài)庫
include &(CLEAR_VARS)

LOCAL_MODULE := avilib
LOCAL_SRC_FILES := avilib.cpp  platform.cpp
include &(BUILD_SHARED_LIBRARY)     //多個(gè)moduel使用,構(gòu)建成動(dòng)態(tài)庫

多個(gè)模塊引用同一個(gè)動(dòng)態(tài)庫:
使用變量LOCAL_SHARED_LIBRARIES引用動(dòng)態(tài)庫:
LOCAL_SHARED_LIBRARIES :動(dòng)態(tài)庫名稱

//原生模塊1
include &(CLEAR_VARS)

LOCAL_MODULE := module1
LOCAL_SRC_FILES := module1.cpp
LOCAL_SHARED_LIBRARIES := avilib    //引用1
include &(BUILD_SHARED_LIBRARY)
----------------------------------------------------
//原生模塊2
include &(CLEAR_VARS)

LOCAL_MODULE := module2
LOCAL_SRC_FILES := module2.cpp
LOCAL_SHARED_LIBRARIES := avilib    //引用2
include &(BUILD_SHARED_LIBRARY)
六 使用Rebuild庫完成預(yù)構(gòu)建

Prebuid:預(yù)構(gòu)建
NDK R5以后包含Rebuid庫,在Rebuild庫的支持下,可以依賴編譯好的so生成動(dòng)態(tài)庫

1、聲明預(yù)編譯庫的模塊
Android.mk可以寫成如下形式:

LOCAL_PATH := &(call my-dir)
COMMON_LIBS_PATH := ../../ClientCommon

// 預(yù)構(gòu)建庫
include &(CLEAR_VARS)
LOCAL_MODULE := avnet       //生成的預(yù)編譯庫名稱(名稱可不與依賴庫相同)
LOCAL_SRC_FILES := $(COMMON_LIBS_PATH)/basecore/libavnet.so
include &(PREBUILT_SHARED_LIBRARY)

說明:
1)LOCAL_SRC_FILES變量不再指向源文件,而是直接指向so庫文件
2)預(yù)構(gòu)建庫的聲明語句:
include &(PREBUILT_SHARED_LIBRARY)生成預(yù)構(gòu)建動(dòng)態(tài)庫
include &(PREBUILT_STATIC_LIBRARY)生成預(yù)構(gòu)建靜態(tài)庫

2、在其他模塊引用這個(gè)預(yù)編譯庫:
與引用普通動(dòng)態(tài)庫的方式相同
預(yù)編譯靜態(tài)庫的名字賦值給變量LOCAL_STATIC_LIBRARIES
預(yù)編譯動(dòng)態(tài)庫的名字賦值給變量LOCAL_SHARED_LIBRARIES

3、將預(yù)編譯庫的頭文件導(dǎo)出:LOCAL_C_INCLUDES
得到預(yù)編譯庫后,一般需要提供它對(duì)應(yīng)的頭文件,
因?yàn)橐蕾噹焐深A(yù)編譯庫時(shí),需要將它的頭文件提供給NDK構(gòu)建系統(tǒng)
例:
依賴libavnet.so生成預(yù)編譯庫時(shí),有對(duì)應(yīng)的avnet.h頭文件在include子目錄,
那么在Android.mk中需要使用LOCAL_C_INCLUDES變量指定該頭文件或直接指定該目錄:
LOCAL_C_INCLUDES := $(LOCAL_PATH) /include

4、優(yōu)點(diǎn)
利用Prebuild預(yù)編譯,依賴so庫生成最終的so庫
1)可不發(fā)布源代碼,只將so庫發(fā)布給第三方開發(fā)人員
2)直接指向so庫文件,稱之為預(yù)構(gòu)建,可以加速構(gòu)建過程

七 條件操作

針對(duì)不同的平臺(tái),可能使用不同的代碼,使用條件操作可進(jìn)行區(qū)分處理
例:

ifeq (&(TARGET_ARCH),arm)
LOCAL_SRC_FILES += armonly.c
else
LOCAL_SRC_FILES += generic.c
endif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,818評(píng)論 25 708
  • Android游戲開發(fā)實(shí)踐(1)之NDK與JNI開發(fā)02 承接上篇Android游戲開發(fā)實(shí)踐(1)之NDK與JNI...
    AlphaGL閱讀 3,773評(píng)論 0 24
  • 最近,喜歡上了余華,文字簡單,意蘊(yùn)不簡單,讀了一遍不夠,第二遍時(shí)發(fā)現(xiàn)遺落許多精彩情節(jié),這個(gè)情節(jié),每每讀起,讓...
    春妮寶貝閱讀 307評(píng)論 0 0
  • 重新閱讀團(tuán)長的《只因目中無人》,讀的過程有了更深的感受。首先自己語言表達(dá)能力比較弱,通過讀一定程度上對(duì)自己有所幫助...
    墨韻閱讀 248評(píng)論 0 0
  • 你試過酒醉后寫東西嗎 嗯 就是這樣。
    留子堯閱讀 207評(píng)論 0 2