基于 Android NDK 的學習之旅目錄
來源:Linux社群 作者:Linux
Android是一個專為移動裝置設計的軟體平台,它包括一個作業系統、中間件和一些關鍵性的平台應用。目前釋出的Android SDK提供了使用Java語言開發Android平台應用的必要工具和API。
基于 Android NDK 的學習之旅目錄
基于 Android NDK 的學習之旅-----序言 http://www.linuxidc.com/Linux/2011-08/40814.htm
基于 Android NDK 的學習之旅-----環境搭建 http://www.linuxidc.com/Linux/2011-08/40812.htm
基于 Android NDK 的學習之旅-----Android.mk 介紹 http://www.linuxidc.com/Linux/2011-08/40811.htm
基于 Android NDK 的學習之旅-----HelloWorld (附源碼) http://www.linuxidc.com/Linux/2011-08/40816.htm
基于 Android NDK 的學習之旅-----JNI LOG 列印(附源碼) http://www.linuxidc.com/Linux/2011-08/40817.htm
基于 Android NDK 的學習之旅-----JNI 資料類型 http://www.linuxidc.com/Linux/2011-08/40815.htm
基于 Android NDK 的學習之旅-----Java 調用 C(附源碼) http://www.linuxidc.com/Linux/2011-08/40810.htm
基于 Android NDK 的學習之旅----- C調用Java(附源碼) http://www.linuxidc.com/Linux/2011-08/41173.htm
基于 Android NDK 的學習之旅----- Java 方法映射到C中的簽名(附源碼) http://www.linuxidc.com/Linux/2011-08/41174.htm
基于 Android NDK 的學習之旅-----資料傳輸一(基本資料類型和數組傳輸)(附源碼) http://www.linuxidc.com/Linux/2011-08/41175.htm
基于 Android NDK 的學習之旅-----資料傳輸二(引用資料類型)(附源碼) http://www.linuxidc.com/Linux/2011-08/41176.htm
基于 Android NDK 的學習之旅-----資源釋放http://www.linuxidc.com/Linux/2011-08/41278.htm
以下是一些GNU Make的宏‘函數’,必須通過這樣的形式調用:'$(call<function>)'。
函數傳回文本資訊。
my-dir
傳回放置目前Android.mk的檔案夾相對于NDK生成系統根目錄的路徑。可用來
在Android.mk的開始處定義LOCAL_PATH的值:
LOCAL_PATH := $(callmy-dir)
all-subdir-makefiles
傳回‘my-dir’子目錄下的所有Android.mk。比如,代碼的結構如下:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
如果sources/foo/Android.mk裡有這樣一行:
include $(call all-subdir-makefiles)
那麼,它将會自動地includesources/foo/lib1/Android.mk和sources/foo/lib2/Android.mk
這個函數能将深層嵌套的代碼檔案夾提供給生成系統。注意,預設情況下,NDK僅在
source/*/Android.mk裡尋找檔案。
this-makefile
傳回目前Makefile(譯者注:指的應該是GNU Makefile)的路徑(即,這個函數是在哪裡調用的)
parent-makefile
傳回在列入樹(inclusion tree)中的父makefile的路徑。
即,包含目前makefile的那個makefile的路徑。
grand-parent-makefile
猜猜看...(譯者注:原文為Guess what...)
元件描述相關的變量:
- - - - - - - - - -
以下的變量是用來向生成系統描述你的元件的。你應該在'include $(CLEAR_VARS)'
和'include$(BUILD_XXXXX)'之間定義其中的一些變量。正如在前面所說的,$(CLEAR_VARS)
是一個将會取消所有這些變量的腳本,除非在對變量的描述時有顯式的說明。
LOCAL_PATH
這個變量用來設定目前檔案的路徑。你必須在Android.mk的開始處定義它,比如:
LOCAL_PATH:= $(call my-dir)
這個變量不會被$(CLEAR_VARS)消除,是以每個Android.mk僅需一個定義(以防你在
同一個檔案裡定義幾個元件)。
LOCAL_MODULE
定義元件的名稱。對于所有的元件名,它必須是唯一,且不能包含空格。
在include$(BUILD_XXX)之前你必須定義它。
這個元件名決定生成的檔案(譯者注:即庫名)。比如,lib<foo>,即這個元件的名稱
為<foo>。但是在你的NDK生成檔案(不管是Android.mk還是Application.mk)中
你隻能通過‘正常’的名稱(如,<foo>)來引用其它的元件。
LOCAL_SRC_FILES
用它來定義所有用來生成元件的源檔案。僅須列出傳給編譯器的檔案,因為
生成系統會自動地計算它們的互相依賴關系。
注意,所有檔案名都是相對于LOCAL_PATH的,你可以用到路徑元件(path component)
如:
LOCAL_SRC_FILES := foo.c \ (譯者注:‘\’為連接配接符)
toto/bar.c
LOCAL_CPP_EXTENSION
這是一個可選的變量,可用它來指明C++源檔案的擴充名。預設情況下是'.cpp',
但你可以改變它。比如:
LOCAL_CPP_EXTENSION := .cxx
LOCAL_C_INCLUDES
一個相對于相對于NDK*根*目錄可選的路徑名單,當編譯所有的源檔案(C,C++和彙編)時,
它将被添加進include搜尋路徑。例如:
LOCAL_C_INCLUDES := sources/foo
或者甚至:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
LOCAL_CFLAGS
一個可選的編譯标記集,在生成C與C++源檔案時,将解析它。
對指定額外的宏定義或編譯選項很有用。
重要:不要試圖改變你Android.mk裡的optimization/debuggin level,通過
在你的Android.mk裡指定合适的資訊,它将被自動處理,并使NDK生成
調試時可用的有用的資料檔案。
注意:在android-ndk-1.5_r1,相應的标記(flags)隻适用于C源檔案,對C++
源檔案并不适用。為了适用于完整的Android生成系統的特性,已作了修
正。(現在,你可以使用LOCAL_CPPFLAGS為C++檔案指定标記)
LOCAL_CXXFLAGS
LOCAL_CPPFLAGS的别名。注意,不建議使用這個變量,因為在未來的NDK版本中,
它可能會消失。
LOCAL_CPPFLAGS
一個可選的編譯标記集,*僅*在生成C++源檔案時解析它。在編譯器的指令行裡
它将在LOCAL_CFLAGS之後出現。
注意:在android-ndk-1.5_r1,相應的标記(flags)适用于C與C++源檔案。
為了适用于完整的Android生成系統的特性,已作了修
正。(現在,你可以使用LOCAL_CFLAGS為C和C++源檔案指定标記)
LOCAL_STATIC_LIBRARIES
一份staticlibraries元件的名單(以BUILD_STATIC_LIBRARY的方式生成),它将被
連接配接到欲生成的元件上。這僅在生成shared library元件時有意義。(譯者注:将指定
的一個或多個staticlibrary module轉化為一個shared library module)
LOCAL_SHARED_LIBRARIES
一份該元件在運作期依賴于它的shared libraries *元件*。在連接配接時間(link time)裡
與及為該生成的檔案嵌入相應的資訊都要用到它。
注意,它并不将這份元件名單添加入生成圖表(build graph)。即,在你的Android.mk
裡,你仍應該将它們加入到你的應用程式要求的元件。
LOCAL_LDLIBS
一份能在生成你的元件時用到的額外的連接配接器标記(linkerflags)的名單。在傳遞
有“-l”字首的特殊系統庫的名稱時很有用。比如,下面的語句會告訴連接配接器在裝載
時間(loadtime)裡生成連接配接到/system/lib/libz.so的元件。
LOCAL_LDLIBS := -lz
若想知道在這個NDK版本可以連接配接哪些暴露的系統庫(exposed system libraries),
請參見docs/STABLE-APIS。
LOCAL_ALLOW_UNDEFINED_SYMBOLS
預設值情況下,當嘗試生成一個shared library遇到沒有定義的引用時,會導緻“undefined
symbol”error。這對在你的源代碼裡捕捉bugs有很大的幫助。
但是,因為一些原因你須要disable這個檢查,将這個變量設定為'true’。注意,相應
的sharedlibrary可能在運作期裝載失敗。
LOCAL_ARM_MODE
預設值情況下,ARM目标二進制将會以‘thumb’模式生成,這時每個指令都是16-bit寬的。
如果你想強迫元件的object檔案以‘arm’(32位的指令)的模式生成,你可以将這個變量
定義為'arm'。即:
LOCAL_ARM_MODE := arm
注意,你也可以通過将‘.arm’字尾添加到源檔案名字的後面訓示生成系統将指定的
源檔案以arm模式生成。例如:
LOCAL_SRC_FILES := foo.c bar.c.arm
告訴生成系統總是以arm模式編譯‘bar.c’,但根據LOCAL_ARM_MODE的值生成foo.c
注意:在你的Application.mk裡将APP_OPTIM設定為'debug',這也會強迫生成ARM二進制
代碼。這是因為工具鍊的排程器有bugs,它對thumb碼的處理不是很好。
怎樣添加一個子產品
LOCAL_PATH:= $(call my-dir)
#編譯靜态庫
include $(CLEAR_VARS)
LOCAL_MODULE = libhellos
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = hellos.c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_COPY_HEADERS_TO := libhellos
LOCAL_COPY_HEADERS := hellos.h
include $(BUILD_STATIC_LIBRARY)
#編譯動态庫
include $(CLEAR_VARS)
LOCAL_MODULE = libhellod
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = hellod.c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_COPY_HEADERS_TO := libhellod
LOCAL_COPY_HEADERS := hellod.h
include $(BUILD_SHARED_LIBRARY)
BUILD_TEST=true
ifeq ($(BUILD_TEST),true)
#使用靜态庫
include $(CLEAR_VARS)
LOCAL_MODULE := hellos
LOCAL_STATIC_LIBRARIES := libhellos
LOCAL_SHARED_LIBRARIES :=
LOCAL_LDLIBS += -ldl
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := mains.c
LOCAL_C_INCLUDES := $(INCLUDES)
include $(BUILD_EXECUTABLE)
#使用動态庫
include $(CLEAR_VARS)
LOCAL_MODULE := hellod
LOCAL_MODULE_TAGS := debug
LOCAL_SHARED_LIBRARIES := libc libcutils libhellod
LOCAL_LDLIBS += -ldl
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := maind.c
LOCAL_C_INCLUDES := $(INCLUDES)
include $(BUILD_EXECUTABLE)
endif # ifeq ($(WPA_BUILD_SUPPLICANT),true)
########################
#local_target_dir := $(TARGET_OUT)/etc/wifi
#include $(CLEAR_VARS)
#LOCAL_MODULE := wpa_supplicant.conf
#LOCAL_MODULE_TAGS := user
#LOCAL_MODULE_CLASS := ETC
#LOCAL_MODULE_PATH := $(local_target_dir)
#LOCAL_SRC_FILES := $(LOCAL_MODULE)
#include $(BUILD_PREBUILT)
########################
系統變量解析
LOCAL_MODULE - 編譯的目标對象
LOCAL_SRC_FILES - 編譯的源檔案
LOCAL_C_INCLUDES - 需要包含的頭檔案目錄
LOCAL_SHARED_LIBRARIES - 連結時需要的外部庫
LOCAL_PRELINK_MODULE - 是否需要prelink處理
BUILD_SHARED_LIBRARY - 指明要編譯成動态庫
LOCAL_PATH - 編譯時的目錄
$(call 目錄,目錄….) 目錄引入操作符
如該目錄下有個檔案夾名稱 src,則可以這樣寫 $(call src),那麼就會得到 src 目錄的完整路徑
include $(CLEAR_VARS) -清除之前的一些系統變量
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
在 build/core/config.mk 定義 CLEAR_VARS:=$(BUILD_SYSTEM)/clear_vars.mk
通過include 包含自定義的.mk檔案(即是自定義編譯規則)或是引用系統其他的.mk檔案(系統定義的編譯規則)。
LOCAL_SRC_FILES - 編譯的源檔案
可以是.c, .cpp, .java, .S(彙編檔案)或是.aidl等格式
不同的檔案用空格隔開。如果編譯目錄子目錄,采用相對路徑,如子目錄/檔案名。也可以通過$(call目錄),指明編譯某目錄
下所有.c/.cpp/.java/.S/ .aidl檔案.追加檔案 LOCAL_SRC_FILES += 檔案
LOCAL_C_INCLUDES - 需要包含的頭檔案目錄
可以是系統定義路徑,也可以是相對路徑. 如該編譯目錄下有個include目錄,寫法是include/*.h
LOCAL_SHARED_LIBRARIES - 連結時需要的外部共享庫
LOCAL_STATIC_LIBRA RIES - 連結時需要的外部外部靜态
LOCAL_JAVA_LIBRARIES 加入jar包
LOCAL_MODULE - 編譯的目标對象
module 是指系統的 native code,通常針對c,c++代碼
./system/core/sh/Android.mk:32:LOCAL_MODULE:= sh
./system/core/libcutils/Android.mk:71:LOCAL_MODULE :=libcutils
./system/core/cpio/Android.mk:9:LOCAL_MODULE := mkbootfs
./system/core/mkbootimg/Android.mk:8:LOCAL_MODULE :=mkbootimg
./system/core/toolbox/Android.mk:61:LOCAL_MODULE:=toolbox
./system/core/logcat/Android.mk:10:LOCAL_MODULE:= logcat
./system/core/adb/Android.mk:65:LOCAL_MODULE := adb
./system/core/adb/Android.mk:125:LOCAL_MODULE := adbd
./system/core/init/Android.mk:20:LOCAL_MODULE:= init
./system/core/vold/Android.mk:24:LOCAL_MODULE:= vold
./system/core/mountd/Android.mk:13:LOCAL_MODULE:= mountd
LOCAL_PACKAGE_NAME
Java 應用程式的名字用該變量定義
./packages/apps/Music/Android.mk:9:LOCAL_PACKAGE_NAME :=Music
./packages/apps/Browser/Android.mk:14:LOCAL_PACKAGE_NAME :=Browser
./packages/apps/Settings/Android.mk:8:LOCAL_PACKAGE_NAME :=Settings
./packages/apps/Stk/Android.mk:10:LOCAL_PACKAGE_NAME :=Stk
./packages/apps/Contacts/Android.mk:10:LOCAL_PACKAGE_NAME :=Contacts
./packages/apps/Mms/Android.mk:8:LOCAL_PACKAGE_NAME :=Mms
./packages/apps/Camera/Android.mk:8:LOCAL_PACKAGE_NAME :=Camera
./packages/apps/Phone/Android.mk:11:LOCAL_PACKAGE_NAME :=Phone
./packages/apps/VoiceDialer/Android.mk:8:LOCAL_PACKAGE_NAME :=VoiceDialer
BUILD_SHARED_LIBRARY - 指明要編譯成動态庫。
編譯的目标,用include 操作符
UILD_STATIC_LIBRARY來指明要編譯成靜态庫。
如果是java檔案的話,會用到系統的編譯腳本host_java_library.mk,用BUILD_PACKAGE來指明。三個編譯
-------------------
include $(BUILD_STATIC_LIBRARY)
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
-------------------
include $(BUILD_SHARED_LIBRARY)
./build/core/config.mk:50:BUILD_SHARED_LIBRARY:=$(BUILD_SYSTEM)/shared_library.mk
-------------------
include $(BUILD_HOST_SHARED_LIBRARY)
BUILD_HOST_SHARED_LIBRARY:=$(BUILD_SYSTEM)/host_shared_library.mk
-------------------
include $(BUILD_EXECUTABLE)
build/core/config.mk:51:BUILD_EXECUTABLE:=$(BUILD_SYSTEM)/executable.mk
-------------------
include $(BUILD_HOST_EXECUTABLE)
./build/core/config.mk:53:BUILD_HOST_EXECUTABLE:=$(BUILD_SYSTEM)/host_executable.mk
-------------------
BUILD_HOST_JAVA_LIBRARY:=$(BUILD_SYSTEM)/host_java_library.mk
-------------------
BUILD_JAVA_LIBRARY
./build/core/config.mk:58:BUILD_JAVA_LIBRARY:=$(BUILD_SYSTEM)/java_library.mk
------------------
BUILD_STATIC_JAVA_LIBRARY 編譯靜态JAVA庫
./build/core/config.mk:59:BUILD_STATIC_JAVA_LIBRARY:=$(BUILD_SYSTEM)/static_java_library.mk
------------------
BUILD_HOST_JAVA_LIBRARY 編譯本機用的JAVA庫
./build/core/config.mk:60:BUILD_HOST_JAVA_LIBRARY:=$(BUILD_SYSTEM)/host_java_library.mk
------------------
BUILD_HOST_STATIC_LIBRARY:=$(BUILD_SYSTEM)/host_static_library.mk
BUILD_HOST_SHARED_LIBRARY:=$(BUILD_SYSTEM)/host_shared_library.mk
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
BUILD_RAW_STATIC_LIBRARY :=$(BUILD_SYSTEM)/raw_static_library.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk
BUILD_HOST_EXECUTABLE:=$(BUILD_SYSTEM)/host_executable.mk
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
BUILD_STATIC_JAVA_LIBRARY:=$(BUILD_SYSTEM)/static_java_library.mk
BUILD_HOST_JAVA_LIBRARY:=$(BUILD_SYSTEM)/host_java_library.mk
BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk
============
LOCAL_PRELINK_MODULE
Prelink利用事先連結代替運作時連結的方法來加速共享庫的加載,它不僅可以加快起動速度,還可以減少部分記憶體開銷,
是各種Linux架構上用于減少程式加載時間、縮短系統啟動時間和加快應用程式啟動的很受歡迎的一個工具。程式運作時的
動态連結尤其是重定位(relocation)的開銷對于大型系統來說是很大的。
動态連結和加載的過程開銷很大,并且在大多數的系統上, 函數庫并不會常常被更動, 每次程式被執行時所進行的連結
動作都是完全相同的,對于嵌入式系統來說尤其如此。是以,這一過程可以改在運作時之前就可以預先處理好,即花一些時間
利用Prelink工具對動态共享庫和可執行檔案進行處理,修改這些二進制檔案并加入相應的重定位等資訊,節約了本來在程式
啟動時的比較耗時的查詢函數位址等工作,這樣可以減少程式啟動的時間,同時也減少了記憶體的耗用。
Prelink的這種做法當然也有代價:每次更新動态共享庫時,相關的可執行檔案都需要重新執行一遍Prelink才能保
證有效,因為新的共享庫中的符号資訊、位址等很可能與原來的已經不同了,這就是為什麼 androidframework代碼一改動,
這時候就會導緻相關的應用程式重新被編譯。
這種代價對于嵌入式系統的開發者來說可能稍微帶來一些複雜度,不過好在對使用者來說幾乎是可以忽略的。
--------------------
變量設定為false那麼将不做prelink操作
LOCAL_PRELINK_MODULE := false
預設是需要prlink的,同時需要在 build/core/prelink-linux-arm.map 中加入
libhellod.so 0x96000000
這個map檔案好像是制定動态庫的位址的,在前面注釋上面有一些位址範圍的資訊,注意庫與庫之間的間隔數,
如果指定不好的話編譯的時候會提示說位址空間沖突的問題。另外,注意排序,這裡要把數大的放到前面去,
按照大小降序排序。
解析 LOCAL_PRELINK_MODULE 變量
build/core/dynamic_binary.mk:94:ifeq($(LOCAL_PRELINK_MODULE),true)
ifeq ($(LOCAL_PRELINK_MODULE),true)
$(prelink_output): $(prelink_input) $(TARGET_PRELINKER_MAP)$(APRIORI)
$(transform-to-prelinked)
transform-to-prelinked定義:
./build/core/definitions.mk:1002:definetransform-to-prelinked
define transform-to-prelinked
@mkdir -p $(dir [email protected])
@echo "target Prelink: $(PRIVATE_MODULE) ([email protected])"
$(hide) $(APRIORI) \
--prelinkmap $(TARGET_PRELINKER_MAP) \
--locals-only \
--quiet \
$< \
--output [email protected]
endef
./build/core/config.mk:183:APRIORI :=$(HOST_OUT_EXECUTABLES)/apriori$(HOST_EXECUTABLE_SUFFIX)
prelink工具不是常用的prelink而是apriori,其源代碼位于”<your_android>/build/tools/apriori”
參考文檔:
動态庫優化——Prelink(預連接配接)技術
http://www.eefocus.com/article/09-04/71629s.html
===============
LOCAL_ARM_MODE := arm
目前Android大部分都是基于Arm處理器的,Arm指令用兩種模式Thumb(每條指令兩個位元組)和arm指令(每條指令四個位元組)
LOCAL_CFLAGS += -O3 -fstrict-aliasing-fprefetch-loop-arrays
通過設定編譯器操作,優化級别,-O0表示沒有優化,-O1為預設值,-O3優化級别最高
LOCAL_CFLAGS += -W -Wall
LOCAL_CFLAGS += -fPIC -DPIC
LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall-Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE-DSH_HISTORY
LOCAL_CFLAGS += -DUSEOVERLAY2
根據條件選擇相應的編譯參數
ifeq ($(TARGET_ARCH),arm)
LOCAL_CFLAGS += -DANDROID_GADGET=1
LOCAL_CFLAGS := $(PV_CFLAGS)
endif
ifeq ($(TARGET_BUILD_TYPE),release)
LOCAL_CFLAGS += -O2
endif
LOCAL_LDLIBS := -lpthread
LOCAL_LDLIBS += -ldl
ifdef USE_MARVELL_MVED
LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_mpeg4aspdecmved_wmmx2lnxlib_il_h264decmved_wmmx2lnx
LOCAL_SHARED_LIBRARIES += libMrvlMVED
else
LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_h264dec_wmmx2lnxlib_il_mpeg4aspdec_wmmx2lnx
endif
============================================
添加Android.mk
完成了上一步,可以知道,Android.mk在編譯中起着至關重要的作用,這其實就是Android編譯環境中的makefile。為了完成我們的工作,需要在源代碼中添加Android.mk。添加自己的Android.mk可以仿照SimpleJNI中的Android.mk,稍微修改即可。我們首先看看SimpleJNI目錄下的兩個Android.mk的内容:
- 根 目錄下的Android.mk
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
LOCAL_PATH:= $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := samples
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := SimpleJNI
LOCAL_JNI_SHARED_LIBRARIES := libsimplejni
LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)
#============================================================
# Also build all of the sub-targets under this one: the sharedlibrary.
include $(call all-makefiles-under,$(LOCAL_PATH))
根目錄下的Android.mk決定了整個工程編譯的配置,其中,
LOCAL_PATH 定義了目前的目錄
LOCAL_MUDULE_TAGS定義了目前子產品的類型,編譯器在編譯時會根據類型的不同有些差别,有些tags的module甚至不會被編譯至系統中。LOCAL_MUDULE_TAGS主要有如下幾種:user debug eng tests optional samplesshell_ashshell_mksh。optional表示在所有版本的編譯條件下都被編譯至image中,剩下的表示在該版本中才會被編譯隻image中,如user表示在user版本下才會被編譯至image中。
對于包含LOCAL_PACKAGE_NAME的mk檔案,該項預設為optinal,具體可以參看build/core/package.mk。SimpleJNI中定義為samples的具體作用我也不太清楚,為了保險起見,我自己的apk一般定義為optional。
LOCAL_SRC_FILES 定義了編譯apk所需要的java代碼的目錄
LOCAL_PACKAGE_NAME 這裡需要改成自己的package的名字
LOCAL_JNI_SHARED_LIBRARIES定義了要包含的so庫檔案的名字,如果你的程式沒有采用JNI,這行不需要。
LOCAL_PROGUARD_ENABLED定義了Java開發中的ProGuard壓縮方法,主要用來分析壓縮程式的,在我自己的應用中我沒有加這行。
include $(BUILD_PACKAGE) 這行是build的關鍵,表示目前java代碼build成apk
include $(call all-makefiles-under,$(LOCAL_PATH))表示需要build該目錄下的子目錄的檔案,這樣編譯系統就會在目前目錄下的子目錄尋找Android.mk來編譯so等其它程式。
根據上述所寫,建立我自己的Android.mk如下:
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
LOCAL_PATH:= $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := TestJniApp
LOCAL_JNI_SHARED_LIBRARIES := libtestjniapp
include $(BUILD_PACKAGE)
#============================================================
# Also build all of the sub-targets under this one: the sharedlibrary.
include $(call all-makefiles-under,$(LOCAL_PATH))
看起來很簡單吧,基本不需要改動即可。
- Jni目錄下的Android.mk
由于我們的TestJniApp是用JNI完成的,包含C源代碼,是以也需要一個jni目錄下的Android.mk。同樣首先看看SimpleJNI中jni目錄下的Android.mk的内容:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := samples
# This is the target being built.
LOCAL_MODULE:= libsimplejni
# All of the source files that we will compile.
LOCAL_SRC_FILES:= /
native.cpp
# All of the shared libraries we link against.
LOCAL_SHARED_LIBRARIES := /
libutils
# No static libraries.
LOCAL_STATIC_LIBRARIES :=
# Also need the JNI headers.
LOCAL_C_INCLUDES += /
$(JNI_H_INCLUDE)
# No special compiler flags.
LOCAL_CFLAGS +=
# Don't prelink this library. For more efficientcode, you may want
# to add this library to the prelink map and set this to true.However,
# it's difficult to do this for applications that are not suppliedas
# part of a system image.
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
LOCAL_MODULE 目前子產品的名字,即編譯後的so檔案的名字
LOCAL_SRC_FILES 所要編譯的檔案
LOCAL_SHARED_LIBRARIES, LOCAL_STATIC_LIBRARIES該子產品要連結的動态庫和靜态庫。
LOCAL_C_INCLUDES 要包含的頭檔案
LOCAL_CFLAGS C語言編譯選項
LOCAL_PRELINK_MODULE定義是否使用prelink工具,它用事先連結代替運作時連結的方法來加速共享庫的加載,不僅可以加快起動速度,還可以減少部分記憶體開銷。
經過修改後,我自己的TestJniApp中jni目錄下的Android.mk如下:
LOCAL_PATH := $(callmy-dir)
include$(CLEAR_VARS)
LOCAL_MODULE :=libtestjniapp
LOCAL_SRC_FILES :=com_test_app_Jni.c
LOCAL_C_INCLUDES +=$(JNI_H_INCLUDE)
LOCAL_PRELINK_MODULE :=false
include$(BUILD_SHARED_LIBRARY)
這裡有一點需要注意,如果要将so檔案編譯入image,必須要修改LOCAL_MODULE_TAGS,将原有的值samples修改為user,或者可以直接删掉 。删掉是因為對于包含LOCAL_MODULE的mk檔案,如果沒有指定LOCAL_MODULE_TAGS,該項預設為user,而隻有定義為user的情況下,才會将so檔案編譯入image,具體定義可以參看build/core/base_rule.mk。
4. 修改/bulid/target/product/generic.mk 把工程編譯到系統中
至此,還有最後一部工作。為了将工程編譯進入image,還需要在/bulid/target/product/generic.mk檔案中将packagename添加進去
PRODUCT_PACKAGES := /
AccountAndSyncSettings /
CarHome/
DeskClock/
……
SyncProvider/
TestJniApp
完成上面這些步驟後,在 sourcetree 根目錄下編譯 image 就可以了。