1. 程式人生 > >Android.mk 中的靜態庫和共享庫

Android.mk 中的靜態庫和共享庫

有些類似的問題碰到過很多次,但大腦裡總是各種碎片化的記憶,長時間記住這些碎片並不是人類大腦的強項,所以有事沒事就要捋捋,知道前因後果才
能記憶深刻。

Android.mk

Android.mk 只是GNU Makefile的一小部分,用來編譯module,這個module可以是app,也可以是library。Android.mk可能會被編譯系統解析多次,所以
要謹慎定義變數,建議儘量不要在其中定義變數。

靜態庫與共享庫的區別

簡單來講,靜態庫是在連線階段直接拷貝到程式碼中使用的,而共享庫是由載入器載入到記憶體,在執行時使用的。編譯出來的靜態庫(這裡指jar包)裡每
個java檔案對應的class檔案都單獨存在,可以直接匯入Eclipse等IDE使用,而編譯出來的共享庫(jar包),內部是Android位元組碼Dex格式的檔案,
一般無法匯入Eclipse等IDE使用。Android.mk中由BUILD_JAVA_LIBRARY指定生成共享庫,BUILD_STATIC_JAVA_LIBRARY指定生成靜態庫。

編譯靜態庫和共享庫

下面是兩個生成靜態庫和動態庫的例子。
生成靜態庫的mk檔案:
// 返回Android.mk所在的當前路徑
LOCAL_PATH:= $(call my-dir)
// 清理除LOCAL_PATH變數以外的LOCAL_XXX
include $(CLEAR_VARS)

// 生成靜態庫的name
LOCAL_MODULE := simple_game

// 設定在那個版本下編譯,user, eng, tests, optional(全版本編譯)
LOCAL_MODULE_TAGS := optional
// 簽名型別 testkey, media, platform, shared, 預設為testkey
LOCAL_CERTIFICATE := platform // 生成靜態庫使用的原始檔 LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src) // 設定生成靜態庫 include $(BUILD_STATIC_JAVA_LIBRARY)
 生成共享庫的mk檔案:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := simple_game

LOCAL_MODULE_TAGS
:= optional LOCAL_CERTIFICATE := platform LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src) // 安裝時需要一起安裝的模組 LOCAL_REQUIRED_MODULES := simple_game.xml // 設定生成共享庫 include $(BUILD_JAVA_LIBRARY) ################################################################ include $(CLEAR_VARS) LOCAL_MODULE := simple_game.xml // 定製LOCAL_MODULE_PATH變數的值 LOCAL_MODULE_CLASS := ETC // 設定安裝的路徑 LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/permissions LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := simple_game.xml // 將檔案預置進系統 include $(BUILD_PREBUILT)
共享庫需要一個xml檔案配置安裝的資訊,LOCAL_REQUIRED_MODULES設定了該檔案,當共享庫安裝時,LOCAL_REQUIRED_MODULES制定的模組也會安裝到系
統中。
安裝的位置由LOCAL_MODULE_PATH指定,當LOCAL_MODULE_PATH沒有設定時,系統將會根據LOCAL_MODULE_CLASS的值來判斷安裝的位置,
LOCAL_MODULE_CLASS變數將通過/build/core/base_rules.mk檔案設定預設的安裝目錄,常用的值有:

apk檔案: APPS
so檔案: SHARED_LIBRARIES
bin檔案: EXECUTABLES
其他檔案: ETC

當LOCAL_MODULE_PATH和LOCAL_MODULE_CLASS均沒有設定時,系統會根據編譯生成的不同模組(根據include$()判斷)來自動設定LOCAL_MODULE_CLASS的值,
但遇到include $(BUILD_PREBUILT)編譯選項時,系統不會設定模組的LOCAL_MODULE_CLASS,需要顯示設定。
最後針對單一檔案進行預編譯需要設定BUILD_PREBUILT,對於多檔案需要設定BUILD_MULTI_PREBUILT巨集。

靜態庫和共享庫的使用

完成了庫的編譯,接下來看看庫的使用方法。
靜態庫很多情況來自第三方,包括jar包和第三方工程。首先,獲得到jar後需要匯入專案程式碼,一般放在libs目錄下,接下來需要修改專案的mk,加入
編譯靜態庫的程式碼,類似一下XML:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

// 依賴靜態庫的名稱,可以隨便起名
LOCAL_STATIC_JAVA_LIBRARIES := simple_game
// 預編譯靜態庫,冒號之前名稱要和LOCAL_STATIC_JAVA_LIBRARIES一致,冒號後面是靜態庫路徑
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := simple_game:libs/simple_game.jar
include $(BUILD_MULTI_PREBUILT)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src)

// 定義生成apk名稱
LOCAL_PACKAGE_NAME := game
// 定義app是否要放在/system/priv-app
LOCAL_PRIVILEGED_MODULE := true

LOCAL_CERTIFICATE := platform
// 定義是否需要程式碼混淆
LOCAL_PROGUARD_ENABLED := disabled

// 編譯MODULE為apk
include $(BUILD_PACKAGE)
include $(BUILD_PACKAGE) 會結合LOCAL_PRIVILEGED_MODULE判斷生成的apk是最終安裝在/system/app下還是/system/priv-app下。
LOCAL_PROGUARD_ENABLED定義了編譯apk時是否進行程式碼混淆,預設為full,將工程程式碼全部混淆,也可以用LOCAL_PROGUARD_FLAG_FILES配置混淆規則。

靜態庫的使用比較簡單,下面來看看共享庫的使用。
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += $(call all-Iaidl-files-under, src)

LOCAL_PACKAGE_NAME := game
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_PROGUARD_ENABLED := disabled

// MODULE 依賴的共享庫
LOCAL_JAVA_LIBRARIES += simple_game
// 安裝時module時,共享庫需要一起安裝。
LOCAL_REQUIRED_MODULES := simple_game

include $(BUILD_PACKAGE)
上面是一個簡單使用共享庫的例子,LOCAL_JAVA_LIBRARIES定義了依賴的共享庫,全編譯時檢查到該選項系統會先編譯simple_game庫,然後檢查
LOCAL_REQUIRED_MODULES,決定是否安裝該庫(即是否在/system/framework下生成該庫),注意,單編時mm, mm -B, mmm均不會編譯module
使用的依賴檔案,需要使用m+module(如: m game)來編譯。

app在使用時千萬別忘了在AndroidManifest.xml中新增該共享庫:
<uses-library android:name="simple_game" android:required="false"/>
有很多同學不注意就忘了,然後查了半天才恍然大悟,切記切記!

最後,類似$(call my-dir)巨集函式的定義,可以在/build/core/definitions.mk中找到,其他變數定義可以在/build/core/base_rules.mk中找到。有
興趣的同學可以去檢視。