天天看點

基于 Android NDK 的學習之旅目錄基于 Android NDK 的學習之旅目錄添加Android.mk4.   修改/bulid/target/product/generic.mk 把工程編譯到系統中

基于 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 就可以了。

繼續閱讀