Android.mk 基本應用
如果是在android源碼裡面編譯我們自己的應用,就需要這個android.mk檔案,這個檔案就告訴android系統應用如何來編譯這個應用以及這個應用它所依賴哪些檔案等等資訊。我對android.mk的瞭解也不是很多,我把我們平時經常需要的東西說一下,順便也是協助自一個己作一下筆記。 其實我們用得最多就是編譯庫檔案(.so檔案),jar包,apk應用以及bin檔案等等,下來看看下面的代碼 複製代碼LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS :=optional LOCAL_STATIC_JAVA_LIBRARIES := static-library LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := myTest LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED :=disabledinclude $(BUILD_PACKAGE)複製代碼看上面的MK檔案就是編譯一個簡單的APK檔案, LOCAL_PATH := $(call my-dir)這句話代表的當前根目錄下,每一個Android.mk檔案都必須有這個命令而且是在開頭 include $(CLEAR_VARS)宏CLEAR_VARS 由編譯系統提供,指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變數(例如 LOCAL_MODULE, LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。這是必要的,因為所有的編譯控制檔案都在同一個GNU MAKE執行環境中,所有的變數都是全域的。所以我們每一次設定一個目標檔案相關的資訊之前都要先清空所有變數的設定,這個也是防止這些變數會影響到我們設定的結果,記住在Android.mk中可以定義多個編譯模組,什麼叫多個模組?就是我這個檔案不知產生apk檔案還會產生.so檔案或者.a檔案,這個後面會講到,那麼這個時候每個編譯模組都是以include $(CLEAR_VARS)開始 LOCAL_MODULE_TAGS :=optional這個一共有四個值可以設定的LOCAL_MODULE_TAGS :=user eng tests optional user: 指該模組只在user版本下才編譯 eng: 指該模組只在eng版本下才編譯 tests: 指該模組只在tests版本下才編譯 optional:指該模組在所有版本下都編譯 一般情況下我們都是選擇optional LOCAL_STATIC_JAVA_LIBRARIES := static-library這個表示的這個APK所依賴的jar包,從上面的代碼中可以看出jar包的名字是static-library.jar。 LOCAL_SRC_FILES := $(call all-subdir-java-files)這個就是這個源檔案,all-subdir-java-files說明編譯這個目錄下的所有.java檔案,當然這個檔案我們也可以手動指定,比如LOCAL_SRC_FILES :=my.java \ test.java等等,但是這樣顯然就會比較麻煩 LOCAL_PACKAGE_NAME := myTest這個就是我們要產生這個APK的名字,我們編譯好之後這個APK的名字就是myTest.apk,我們可以在源碼裡面out目錄下system/app裡面看得到 LOCAL_CERTIFICATE := platform編譯一個需要platform key簽名的APK 註:LOCAL_CERTIFICATE 後面應該是簽名檔案的檔案名稱,比如編譯一個需要特殊vendor key簽名的APK , LOCAL_CERTIFICATE := vendor/example/certs/app LOCAL_PROGUARD_ENABLED :=disabled這個就是表示是否要混淆,混淆就是防止別人破解你的代碼,這裡是不需要要的,如果我們需要混淆就把上面的這句話替換成下面這兩句話 LOCAL_PROGUARD_ENABLED :=fullLOCAL_PROGUARD_FLAG_FILES :=proguard.cfgLOCAL_PROGUARD_FLAG_FILES這個檔案指定的proguard.cfg是一個混淆檔案,如果我們應用中訪問一個已經提供好的jar包介面,但是這個jar包有和JNI打交道的話,我們需要把這個jar包相應的類去掉混淆,java檔案和jni打交道一般都是有 public natve......等字樣的,如果有那麼這個類就不能進行混淆,不然的話就會出現無法運行程式,如何在proguard.cfg去掉指定的混淆呢?,看下面的代碼: -keep public class com.it.cheng.a{*;}這個就是表示對a類去掉混淆的意思,我們就添加在最後就可以了 include $(BUILD_PACKAGE)這句話就一個執行語句,把上面的設定好的變數開始執行,BUTLD_PACKAGE這個就是表示編譯成一個APK,後面還會有編譯成庫檔案等等,這句話介紹就是表示一個模組結束了。我們再來看看編譯一個庫檔案是形式(.so檔案) 複製代碼LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := hello.c LOCAL_MODULE :=helloinclude $(BUILD_SHARED_LIBRARY)複製代碼上面就是編譯一個庫檔案,這個內容和上面的差不多是一樣的,唯一不同的就是最後一句BUILD_SHARED_LIBRARY這個表示的是編譯成動態庫的意思, include $(BUILD_STATIC_LIBRARY)表示編譯成靜態庫 (*.a) include $(BUILD_SHARED_LIBRARY)表示編譯成動態庫。 include $(BUILD_EXECUTABLE)表示編譯成可執行程式 在編譯庫檔案的時候可能還會經常加一些條件,比如: LOCAL_C_INCLUDES 這個表示加入所需要包含的標頭檔路徑 LOCAL_LDLIBS 本次編譯的連結選項,相當於gcc -l後的參數 LOCAL_CFLAGS 同樣是編譯選項,相當於gcc -O後面的參數 在我們的android源碼下一般都是放在system/lib目錄下面的,還有一種情況就是第三方的已經把庫檔案產生好了,只是需要我們放到指定的目錄下,如system/lib目錄下 複製代碼LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS :=optionalLOCAL_MODULE :=liba.soLOCAL_MODULE_CLASS :=LIBLOCAL_MODULE_PATH :=$(TARGET_OUT)/libLOCAL_SRC_FILES :=liba.soinclude $(BUILD_PREBUILT)複製代碼上面這段代碼的意思就是將一個liba.so庫檔案放到system/bin目錄下的,先說一下這個LOCAL_MODULE 定義的名字,如果是庫檔案預設為a.so,然後我們在定義LOCAL_MODULE :=a.so名字時,在編譯完成之後我們在system/lib目錄下看到的名字是liba.so,也就是在前面自動的加上了lib作為首碼,但是如果我們在定義LOCAL_MODULE是寫出liba.so,那麼在編譯完成之後就不會在前面自動給你加上的lib的首碼名,關於這個名字的問題還有一個,如果 本地模組指定了LOCAL_MODULE_STEM的話,它的值就 是$(LOCAL_MODULE_STEM)$(LOCAL_MODULE_SUFFIX),如果沒有指定了的話就 是$(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX),所以說上面的命名也可以寫成這樣 LOCAL_MODULE=liba LOCAL_MODULE_SUFFIX=.so LOCAL_MODULE_CLASS :=LIBLOCAL_MODULE_PATH :=$(TARGET_OUT)/lib這兩個從字面的意思都是自定編譯完之後所產生的檔案放在哪個目錄下,LOCAL_MODULE_CLASS 標識了所編譯模組最後放置的位置,如果不指定,不會放到系統中,之後放在最後的obj目錄下的對應目錄中。上面中我們放在LIB目錄下也可以這麼寫 LOCAL_MODULE_CLASS := SHARED_LIBRARIES #放在/system/lib下 LOCAL_MODULE_CLASS := ETC #表示放於system/etc目錄 LOCAL_MODULE_CLASS := EXECUTABLES #放於/system/bin 其實這個的定義就是這樣,我們編譯完一個檔案一般是放在system目錄的下的摸個目錄裡面的,比如如果我放在system/vensor/lib目錄下那麼我們的LOCAL_MODULE_CLASS可以這樣定義為LOCAL_MODULE_CLASS :=VENSOR,放在system/bin目錄下我們也可以這樣定義為LOCAL_MODULE_CLASS :=BIN,就是說這個值就是system下的一個子目錄,要大寫,LOCAL_MODULE_PATH這個值也是指定要安裝的目錄,我們可以通過給它賦值來強制指定安裝的目錄,比如說要安裝在system/etc /permissions目錄,則可以強制指定它的值為$(TARGET_OUT_ETC)/permissions,這樣模組就會被強制安裝在這個目錄 了,給LOCAL_MODULE_PATH賦值的情況主要應用在prebuilt模組的編譯上,其他的應該盡量採用其預設值。至於這兩個的區別我也搞得不是很清楚,從其它網站上看是這麼解釋的: “。LOCAL_MODULE_PATH是有 個很有用的變數,首先我們看看當我們在本地模組沒有指定這個值的時候,它的值實際上是:LOCAL_MODULE_PATH := $($(my_prefix)OUT$(use_data)_$(LOCAL_MODULE_CLASS)),如果你的模組定義了TAGS := TESTS則user_data的值是DATA,這樣的模組會被安裝在data/目錄下,那麼通過替換我們就知道這個LOCAL_MODULE_PATH := TARGET_OUT_$(LOCAL_MODULE_CLASS)。這個LOCAL_MODULE_CLASS在特定的類型編譯會被google賦值成 固定內容,但是在prebuilt的編譯中它是由你自己來賦值的,它的值就會用來定義產生的目錄,比如LOCAL_MODULE_CLASS := ETC的時候,則就會被安裝在/system/etc目錄。那麼我們就知道如何來定義prebuilt模組裡面的CLASS了” $(TARGET_OUT)表示的就是我們的android源碼的system系統目錄 TARGET_ROOT_OUT:表示根檔案系統out/target/product/generic/root。 TARGET_OUT:表示system檔案系統out/target/product/generic/system。 TARGET_OUT_DATA:表示data檔案系統out/target/product/generic/data。 這些都是表示不同的變數。 BUILD_PREBUILT表示的就是執行命令的意思。 這裡說完之後我們日常中可能還會用到下面一些編譯的時候常用的命令 1。all-makefiles-under 擷取某個目錄下及子目錄的所有Android.mk include $(call all-makefiles-under,a b); 上面這句話就是表示分別擷取a和b目錄下所以android.mk檔案進行編譯當然我們也可以這樣 include $(call all-makefiles-under,$(LOCAL_PATH));這個表示擷取目前的目錄以及子目錄下的android.mk檔案,注意擷取到之後就會自動編譯產生我們需要的目標資訊的。 2。all-named-subdir-makefiles 這個表示的是在目前的目錄下的一組子目錄下尋找Android.mk,用法和上面的那個相同, 3。all-c-files-under 指定子目錄下找C代碼 SRC_FILES := $(call all-c-files-under,src tests) 這個就是自定在src和tests目錄下尋找c代碼 4。LOCAL_C_INCLUDES 表示標頭檔的搜尋路徑,預設的情況下是在當前的目錄下 5。LOCAL_JNI_SHARED_LIBRARIES 定義了要包含的so庫檔案的名字,如果程式沒有採用jni,不需要 LOCAL_JNI_SHARED_LIBRARIES := libxxx 這樣在編譯的時候,NDK自動會把這個libxxx打包進apk; 放在youapk/lib/目錄下