Android編譯系統(tǒng)分析
概要
由于Android編譯系統(tǒng)的復(fù)雜和使用了不熟悉的Python,所以對(duì)其一直望而卻步;工作中使用Android.mk也僅僅是拷貝修改。最近由于工作需要解決一個(gè)編譯方面的問題1,瀏覽了一下編譯系統(tǒng);另外,項(xiàng)目上的編譯控制是使用在Android編譯系統(tǒng)基礎(chǔ)之上的一個(gè)sh腳本,由于腳本維護(hù)滯后和Android源碼目錄增加刪除修改的原因,該sh已經(jīng)不能用來編譯SDK。在解決 問題1之后,一股沖動(dòng),要編譯出SDK供調(diào)試程序使用,就學(xué)習(xí)研究了一下Android編譯系統(tǒng),根據(jù)product makefile修改sdk.mk,終于編譯出了SDK。
下面是學(xué)習(xí)研究過程中,參考的一些資料匯總。針對(duì)工作的使用,加了體會(huì)和注釋。
編譯腳本及系統(tǒng)變量
轉(zhuǎn)自 http://blog.csdn.net/yili_xie/archive/2009/11/30/4906865.aspx
本文檔主要描述envsetup.sh和Android.mk使用的LOCAL_XX和BUILD_XX變量。
build/envsetup.sh腳本分析
在編譯源代碼之前通常需要在android源代碼頂層目錄執(zhí)行 . ./build/envsetup.sh目的是為了使用腳本 envsetup.sh里面定義了一些函數(shù):
function help()
function get_abs_build_var()
function get_build_var()
function check_product()
function check_variant()
function setpaths()
function printconfig()
function set_stuff_for_environment()
function set_sequence_number()
function settitle()
function choosetype()
function chooseproduct()
function choosevariant()
function tapas()
function choosecombo()
function print_lunch_menu()
function lunch()
function gettop
function m()
function findmakefile()
function mm()
function mmm()
function croot()
function pid()
function gdbclient()
function jgrep()
function cgrep()
function resgrep()
function getprebuilt
function tracedmdump()
function runhat()
function getbugreports()
function startviewserver()
function stopviewserver()
function isviewserverstarted()
function smoketest()
function runtest()
function runtest_py()
function godir ()
choosecombo 命令分析:
function choosecombo()
{
choosesim $1
echo
echo
choosetype $2
echo
echo
chooseproduct $3
echo
echo
choosevariant $4
echo
set_stuff_for_environment
printconfig
}
會(huì)依次進(jìn)行如下選擇:
Build for the simulator or the device?
1. Device
2. Simulator ----- Emulator is not Simulator! Select 1.
Which would you like? [1]
Build type choices are:
1. release
2. debug
Which would you like? [1]
Product choices are:
1. emulator
2. generic
3. sim
4. littleton
You can also type the name of a product if you know it.
Which would you like? [littleton]
Variant choices are:
1. user
2. userdebug
3. eng
Which would you like? [eng] user
默認(rèn)選擇以后會(huì)出現(xiàn):
TARGET_PRODUCT=littleton
TARGET_BUILD_VARIANT=user
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID= 2.3.A.8.9
==========
function chooseproduct()函數(shù)分析:
choices=(`/bin/ls build/target/board/*/BoardConfig.mk vendor/*/*/BoardConfig.mk 2> /dev/null`)
讀取 build/target/board/* 目錄下的板配置文件:BoardConfig.mk
讀取 vendor/*/*/目錄下的板配置文件:BoardConfig.mk
choices 的值為:
build/target/board/emulator/BoardConfig.mk
build/target/board/generic/BoardConfig.mk
build/target/board/sim/BoardConfig.mk
vendor/marvell/littleton/BoardConfig.mk
經(jīng)過:
for choice in ${choices[@]}
do
# The product name is the name of the directory containing
# the makefile we found, above.
prodlist=(${prodlist[@]} `dirname ${choice} | xargs basename`)
done
的處理,prodlist的值為:
emulator generic sim littleton
所以選擇菜單為:
Product choices are:
1. emulator
2. generic
3. sim
4. littleton
如果選擇 4,那么 TARGET_PRODUCT被賦值為: littleton。
board_config_mk := /
$(strip $(wildcard /
$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk /
vendor/*/$(TARGET_DEVICE)/BoardConfig.mk /
))
Note:
ICS是讀取AndroidProduct.mk,而不是BoardConfig.mk,但功能是一樣的,即搜索平臺(tái)名稱,列表,供選擇,賦值TARGET_PRODUCT,輸出變量。
268#
269# This function chooses a TARGET_PRODUCT by picking a product by name.
270# It finds the list of products by finding all theAndroidProducts.mk
271# files and looking for the product specific filenames in them.
272#
273functionchooseproduct()
274{
275# Find the list of all products by looking for allAndroidProducts.mk files under the
276# device/, vendor/ andbuild/target/product/ directories and look for the format
277# LOCAL_DIR/<ProductSpecificFile.mk> and extract the name ProductSpecificFile from it.
278# This will give the list of all products that can be built using choosecombo
279
280 local -aprodlist
281
282# Find allAndroidProducts.mk files under the dirs device/,build/target/ and vendor/
283# Extract lines containing .mk from them
284# Extract lines containing LOCAL_DIR
285# Extract the name of the product specific file
286
287 prodlist=(`/usr/bin/finddevice/build/target/vendor/ -nameAndroidProducts.mk2>/dev/null|
288 xargsgrep -h \.mk|
289 grepLOCAL_DIR|
290 cut -d'/' -f2|cut -d' ' -f1|sort|uniq|cut -d'.' -f1`)
291
292 localindex=1
293 local p
294 echo"Product choices are:"
295 for pin ${prodlist[@]}
296 do
297 echo" $index. $p"
298 let"index = $index + 1"
299 done
300
301 if ["x$TARGET_PRODUCT" != x ] ;then
302 default_value=$TARGET_PRODUCT
303 else
304 default_value=full
305 fi
306
307 exportTARGET_PRODUCT=
308 localANSWER
309 while [ -z"$TARGET_PRODUCT" ]
310 do
311 echo"You can also type the name of a product if you know it."
312 echo -n"Which product would you like? [$default_value] "
313 if [ -z"$1" ] ;then
314 readANSWER
315 else
316 echo $1
317 ANSWER=$1
318 fi
319
320 if [ -z"$ANSWER" ] ;then
321 exportTARGET_PRODUCT=$default_value
322 elif (echo -n $ANSWER | grep -q -e "^[0-9][0-9]*$") ;then
323 localpoo=`echo -n $ANSWER`
324 if [$poo -le ${#prodlist[@]} ] ; then
325 exportTARGET_PRODUCT=${prodlist[$(($ANSWER-1))]}
326 else
327 echo"** Bad product selection:$ANSWER"
328 fi
329 else
330 ifcheck_product$ANSWER
331 then
332 exportTARGET_PRODUCT=$ANSWER
333 else
334 echo"** Not a valid product: $ANSWER"
335 fi
336 fi
337 if [ -n"$1" ] ;then
338 break
339 fi
340 done
341
342 set_stuff_for_environment
343}
怎樣添加一個(gè)模塊
LOCAL_PATH:= $(call my-dir)
#編譯靜態(tài)庫
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)
#編譯動(dòng)態(tài)庫
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)
#使用靜態(tài)庫
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)
#使用動(dòng)態(tài)庫
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)
Note:
CLEAR_VARS用來將這些Shell變量的值清空,達(dá)到LOCAL的目的。
系統(tǒng)變量解析
LOCAL_MODULE -編譯的目標(biāo)對(duì)象
LOCAL_SRC_FILES -編譯的源文件
LOCAL_C_INCLUDES -需要包含的頭文件目錄
LOCAL_SHARED_LIBRARIES - 鏈接時(shí)需要的共享庫
LOCAL_PREBUILT_LIBS - 預(yù)編譯好的靜態(tài)庫或動(dòng)態(tài)庫,可用于集成第三方庫
LOCAL_LDLIBS - 鏈接時(shí)需要的外部庫
LOCAL_PRELINK_MODULE - 是否需要prelink處理
LOCAL_JAVA_LIBRARIES - 編譯JAVA程序時(shí)需要的jar包
LOCAL_PACKAGE_NAME-編譯JAVA APK放入目標(biāo)PACKAGE名字
可以看出這些變量就是Make系統(tǒng)的參數(shù),完全就是編譯器和鏈接器和其他二進(jìn)制工具的控制參數(shù)。
BUILD_STATIC_LIBRARY-編譯成靜態(tài)庫的控制腳本
BUILD_SHARED_LIBRARY -編譯成動(dòng)態(tài)庫的控制腳本
BUILD_EXECUTABLE -編譯成可執(zhí)行文件的控制腳本
BUILD_PACKAGE -指明編譯成Java APK包
另外的,
LOCAL_MODULE_TAGS - 是控制編譯出的該模塊加入到特定編譯Varient(user/ud/eng)中。
下面是函數(shù)或變量的詳細(xì)內(nèi)容。
LOCAL_PATH - 編譯時(shí)的目錄
$(call 目錄,目錄….) 目錄引入操作符
如該目錄下有個(gè)文件夾名稱 src,則可以這樣寫 $(call src),那么就會(huì)得到 src目錄的完整路徑
include $(CLEAR_VARS) -清除之前的一些系統(tǒng)變量
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
在 build/core/config.mk 定義 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
通過include 包含自定義的.mk文件(即是自定義編譯規(guī)則)或是引用系統(tǒng)其他的.mk文件(系統(tǒng)定義的編譯規(guī)則)。
LOCAL_SRC_FILES - 編譯的源文件
可以是.c, .cpp, .java, .S(匯編文件)或是.aidl等格式
不同的文件用空格隔開。如果編譯目錄子目錄,采用相對(duì)路徑,如子目錄/文件名。也可以通過$(call目錄),指明編譯某目錄下所有.c/.cpp/.java/.S/ .aidl文件.追加文件 LOCAL_SRC_FILES +=文件
LOCAL_C_INCLUDES - 需要包含的頭文件目錄
可以是系統(tǒng)定義路徑,也可以是相對(duì)路徑. 如該編譯目錄下有個(gè)include目錄,寫法是include/*.h
LOCAL_MODULE - 編譯的目標(biāo)對(duì)象
module 是指系統(tǒng)的 native code,通常針對(duì)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 應(yīng)用程序的名字用該變量定義,如
./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_XXXX_YYYY_ZZZZ宏在build/core/config.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
使用時(shí),只需要在Android.mk中include $(BUILD_XXXX_YYYY_ZZZZ)即可。
作用從名稱可以看出,包括HOST和TARGET的可執(zhí)行程序或庫或二進(jìn)制工具鏈。
============
LOCAL_PRELINK_MODULE
Prelink利用事先鏈接代替運(yùn)行時(shí)鏈接的方法來加速共享庫的加載,它不僅可以加快起動(dòng)速度,還可以減少部分內(nèi)存開銷,是各種Linux架構(gòu)上用于減少程序加載時(shí)間、縮短系統(tǒng)啟動(dòng)時(shí)間和加快應(yīng)用程序啟動(dòng)的很受歡迎的一個(gè)工具。程序運(yùn)行時(shí)的動(dòng)態(tài)鏈接尤其是重定位(relocation)的開銷對(duì)于大型系統(tǒng)來說是很大的。
動(dòng)態(tài)鏈接和加載的過程開銷很大,并且在大多數(shù)的系統(tǒng)上,函數(shù)庫并不會(huì)常常被更動(dòng),每次程序被執(zhí)行時(shí)所進(jìn)行的鏈接動(dòng)作都是完全相同的,對(duì)于嵌入式系統(tǒng)來說尤其如此。因此,這一過程可以改在運(yùn)行時(shí)之前就可以預(yù)先處理好,即花一些時(shí)間利用Prelink工具對(duì)動(dòng)態(tài)共享庫和可執(zhí)行文件進(jìn)行處理,修改這些二進(jìn)制文件并加入相應(yīng)的重定位等信息,節(jié)約了本來在程序啟動(dòng)時(shí)的比較耗時(shí)的查詢函數(shù)地址等工作,這樣可以減少程序啟動(dòng)的時(shí)間,同時(shí)也減少了內(nèi)存的耗用。
Prelink的這種做法當(dāng)然也有代價(jià):每次更新動(dòng)態(tài)共享庫時(shí),相關(guān)的可執(zhí)行文件都需要重新執(zhí)行一遍Prelink才能保證有效,因?yàn)樾碌墓蚕韼熘械姆?hào)信息、地址等很可能與原來的已經(jīng)不同了,這就是為什么 android framework代碼一改動(dòng),這時(shí)候就會(huì)導(dǎo)致相關(guān)的應(yīng)用程序重新被編譯。
這種代價(jià)對(duì)于嵌入式系統(tǒng)的開發(fā)者來說可能稍微帶來一些復(fù)雜度,不過好在對(duì)用戶來說幾乎是可以忽略的。
--------------------
變量設(shè)置為false那么將不做prelink操作
LOCAL_PRELINK_MODULE := false
默認(rèn)是需要prlink的,同時(shí)需要在 build/core/prelink-linux-arm.map中加入
libhellod.so 0x96000000
這個(gè)map文件好像是制定動(dòng)態(tài)庫的地址的,在前面注釋上面有一些地址范圍的信息,注意庫與庫之間的間隔數(shù),如果指定不好的話編譯的時(shí)候會(huì)提示說地址空間沖突的問題。另外,注意排序,這里要把數(shù)大的放到前面去,按照大小降序排序。
解析 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:define transform-to-prelinked
define transform-to-prelinked
@mkdir -p $(dir $@)
@echo "target Prelink: $(PRIVATE_MODULE) ($@)"
$(hide) $(APRIORI) /
--prelinkmap $(TARGET_PRELINKER_MAP) /
--locals-only /
--quiet /
$< /
--output $@
endef
./build/core/config.mk:183:
APRIORI := $(HOST_OUT_EXECUTABLES)/apriori$(HOST_EXECUTABLE_SUFFIX)
prelink工具不是常用的prelink而是apriori,其源代碼位于”<your_android>/build/tools/apriori”。 ANDROIDOC也是Android自己定制過的DOCGEN。
參考文檔:
動(dòng)態(tài)庫優(yōu)化——Prelink(預(yù)連接)技術(shù)
http://www.eefocus.com/article/09-04/71629s.html
===============
LOCAL_ARM_MODE := arm
目前Android大部分都是基于Arm處理器的,Arm指令用兩種模式Thumb(每條指令兩個(gè)字節(jié))和arm指令(每條指令四個(gè)字節(jié))
LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays
通過設(shè)定編譯器操作,優(yōu)化級(jí)別,-O0表示沒有優(yōu)化,-O1為缺省值,-O3優(yōu)化級(jí)別最高
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
根據(jù)條件選擇相應(yīng)的編譯參數(shù)
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_wmmx2lnx \ lib_il_h264decmved_wmmx2lnx
LOCAL_SHARED_LIBRARIES += libMrvlMVED
else
LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_h264dec_wmmx2lnx \ lib_il_mpeg4aspdec_wmmx2lnx
endif
PACKAGE OVERLAYS
PRODUCT_COPY_FILES
OVERRIDEN_PACKAGES
本小段是工作中用到的點(diǎn)的記錄.
PRODUCT_PACKAGES
Lists the APKs to install. Such as Calendar Contacts Phone.
PRODUCT_COPY_FILES
List of words like source_path:destination_path.
The file at the source path should be copied to the destination path whenbuilding this product. It can be used to copy third party apk to /system/app/ to deploy the apps.
The rules for the copy steps are defined in config/Makefile.
PRODUCT_PROPERTY_OVERRIDES
List of property assignments in the format "key=value"
PRODUCT_PACKAGE_OVERLAYS, DEVICE_PACKAGE_OVERLAYS
Indicate whether to use default resources or add any product specific overlays;
The two overlays are really doing the same thing but at different priorities.
The product overlays take priority over device overlays.
PRODUCT_BUILD_PROP_OVERRIDES := PRODUCT_NAME=mysidspr BUILD_ID=ICL53F
LOCAL_OVERRIDES_PACKAGES one package can override multi packages.
Use strip function to strip them, which means make only one space between the package names.
OVERRIDE_BUILT_MODULE_PATH
Use strip function to strip multi paths, which means make only one space between the many path names.
Snippets from main.mk
# Some packages may override others using LOCAL_OVERRIDES_PACKAGES.
# Filter out (do not install) any overridden packages.
overridden_packages := $(call get-package-overrides,$(modules_to_install))
ifdef overridden_packages
# old_modules_to_install := $(modules_to_install)
modules_to_install := /
$(filter-out $(foreach p,$(overridden_packages),$(p) %/$(p).apk), /$(modules_to_install))
endif
> In cupcake you can definePRODUCT_PACKAGE_OVERLAYS in your product makefile
> to specify one or more directories that will be merged in withthebase platform directories.
For example:
> PRODUCT_PACKAGE_OVERLAYS := vendor/mycompany/prod_overlay \
> vendor/mycompany/base_overlay
> Now you can replace or add framework resources by putting them in either of these:
> vendor/mycompany/base_overlay/frameworks/base/core/res/res/
> vendor/mycompany/prod_overlay/frameworks/base/core/res/res/
> You can use this to replace any resource in the tree, both in the framework and in specific packages, by just putting them in a directory corresponding to the same path where you find them in the platform tree.
> Also whenadding new resources to the frameworks that you want to use in your own apps that are built into the system image, you can use the magic syntax "@*android:type/name" to reference them without having to make them public. You can likewise find private resources in Java at com.android.internal.R.
> Obviously, changing a source file will force the rebuild of the specific part affected, but what about changing device overlays, initrc files or resources for example ?
For overlays and resources, have a look at build/core/package.mk. More specifically, here are the relevant snippets:
LOCAL_RESOURCE_DIR := \
$(wildcard $(foreach dir, $(PRODUCT_PACKAGE_OVERLAYS), \
$(addprefix $(dir)/, $(LOCAL_RESOURCE_DIR)))) \
$(wildcard $(foreach dir, $(DEVICE_PACKAGE_OVERLAYS), \
$(addprefix $(dir)/, $(LOCAL_RESOURCE_DIR)))) \
$(LOCAL_RESOURCE_DIR)
...
all_resources := $(strip \
$(foreach dir, $(LOCAL_RESOURCE_DIR), \
$(addprefix $(dir)/, \
$(patsubst res/%,%, \
$(call find-subdir-assets,$(dir)) \
) \
) \
))
...
all_res_assets := $(strip $(all_assets) $(all_resources))
...
$(R_file_stamp): $(all_res_assets) $(full_android_manifest) $(AAPT) | $(ACP)
So, basically, if you change a resource, whether it be an overlay or not, it should trigger the rebuilding of the encompassing package. For initrc files, it depends how it's getting included I guess. For the main init.rc file in system/core/rootdir/init.rc, the corresponding mk (system/core/rootdir/Android.mk) has this snippet:
ifneq ($(TARGET_PROVIDES_INIT_RC),true)
file := $(TARGET_ROOT_OUT)/init.rc
$(file) : $(LOCAL_PATH)/init.rc | $(ACP)
$(transform-prebuilt-to-target)
ALL_PREBUILT += $(file)
$(INSTALLED_RAMDISK_TARGET): $(file)
endif
INSTALLED_RAMDISK_TARGET is what generates the RAM disk image, and it's made here to depend on init.rc. So if you touch this file, it will cause the RAM disk image to be regenerated. As you can see, though, the dependencies aren't centralized.
> Do we need to do a whole "make clean" or is a more specific target
> availaible ?
There's a "make installclean" which will wipe out just the stuff that changes from one make target to another (i.e. if you switch from "make droid" (a.k.a. plain "make") to "make sdk".) Here's what it actually does (from build/core/cleanbuild.mk):
installclean_files := \
$(HOST_OUT)/obj/NOTICE_FILES \
$(HOST_OUT)/sdk \
$(PRODUCT_OUT)/*.img \
$(PRODUCT_OUT)/*.txt \
$(PRODUCT_OUT)/*.xlb \
$(PRODUCT_OUT)/*.zip \
$(PRODUCT_OUT)/data \
$(PRODUCT_OUT)/obj/APPS \
$(PRODUCT_OUT)/obj/NOTICE_FILES \
$(PRODUCT_OUT)/obj/PACKAGING \
$(PRODUCT_OUT)/recovery \
$(PRODUCT_OUT)/root \
$(PRODUCT_OUT)/system \
$(PRODUCT_OUT)/dex_bootjars \
$(PRODUCT_OUT)/obj/JAVA_LIBRARIES
...
installclean: FILES := $(installclean_files)
installclean: dataclean
$(hide) rm -rf $(FILES)
@echo "Deleted images and staging directories."
In other words, that list up there gets nucked every time you switch make targets. My only regret is that there isn't an "imagesclean" target which just wipes out $(PRODUCT_OUT)/*.img and corresponding source dirs
($(PRODUCT_OUT)/{root,system,data}).
Android 的編譯系統(tǒng)
轉(zhuǎn)自:http://www.360doc.com/content/11/0609/14/474846_122680003.shtml
本文主要從編譯全局控制的角度描述。
以下主要流程都在build/core/main.mk里安排。
初始化相關(guān)的參數(shù)設(shè)置(buildspec.mk、envsetup.mk、config.mk)
檢測(cè)編譯環(huán)境和目標(biāo)環(huán)境
讀取product的配置信息及目標(biāo)平臺(tái)信息
清除輸出目錄
檢查版本號(hào)
讀取Board的配置
讀取所有Module的配置
根據(jù)配置產(chǎn)生必要的規(guī)則(build/core/Makefile)
生成image
主要配置和實(shí)現(xiàn)文件:
build/core/config.mk summary of config
build/core/envsetup.mk generate dir config and so on
build/target/product product config
build/target/board board config
build/core/combo build flags config
這里解釋下這里的board和product目錄。
board目錄主要是設(shè)計(jì)到硬件芯片的配置,比如是否提供硬件的某些功能,比如說GPU等等,或者芯片支持浮點(diǎn)運(yùn)算等等。
product目錄是指針對(duì)當(dāng)前的芯片配置定義你將要生產(chǎn)產(chǎn)品的個(gè)性配置,主要是指APK方面的配置,哪些APK會(huì)包含在哪個(gè)product中,哪些APK在當(dāng)前product中是不提供的。
config.mk是一個(gè)總括性的東西,它里面定義了各種module編譯所需要使用的HOST工具以及如何來編譯各種模塊,比如說 BUILT_PREBUILT就定義了如何來編譯預(yù)編譯模塊。envsetup.mk主要會(huì)讀取由envsetup.sh寫入環(huán)境變量中的一些變量來配置編譯過程中的輸出目錄,combo里面主要定義了各種Host和Target結(jié)合的編譯器和編譯選項(xiàng)。
配置部分主要完成以下幾個(gè)工作:
a) 基于Android 產(chǎn)品的配置(product config):選擇構(gòu)建安裝的運(yùn)行程序(user package)
b) 設(shè)置 target 等相關(guān)變量TARGET_ARCH, TARGET_OS,TARGET_BUILD_TYPE,
TARGET_PREBUILT_TAG
c) 根據(jù)編譯環(huán)境設(shè)置 host等相關(guān)變量HOST_OS, HOST_ARCH,HOST_BUILD_TYPE,
HOST_PREBUILT_TAG
d) 編譯 target上運(yùn)行程序所需的工具鏈及編譯參數(shù)設(shè)置,如linux-arm-cc,cflag,include目錄等。
e) 編譯 host上運(yùn)行程序所需的工具鏈及編譯參數(shù)設(shè)置。
下圖簡(jiǎn)要介紹了Android build system的配置部分的主要構(gòu)成及相互關(guān)系。
在main.mk里,簡(jiǎn)單設(shè)置幾個(gè)主要編譯路徑的變量后,來到config.mk:
——————————————config.mk——————————————
其中設(shè)置了源文件的一系列路徑,包括頭文件、庫文件、服務(wù)、API已經(jīng)編譯工具的路徑(前36行)。
從40行開始,定義一些編譯模塊的生成規(guī)則:
除了CLEAR_VARS是清楚本地變量之外,其他所有的都對(duì)應(yīng)了一種模塊的生成規(guī)則,每一個(gè)本地模塊最后都會(huì)include其中的一種來生成目標(biāo)模塊。
回到config.mk,接著會(huì)嘗試讀取buildspec.mk的設(shè)置:
如同注釋所說,會(huì)嘗試查找buildspec.mk,如果文件不存在會(huì)自動(dòng)使用環(huán)境變量的設(shè)置,如果仍然未定義,會(huì)按arm默認(rèn)的設(shè)置去build。
這里的buildspec.mk可以自己創(chuàng)建,也可以將原先build/下的buildspec.mk.default直接命名為buildspec.mk并移到根目錄。
實(shí)際上,buildspec.mk配置都被屏蔽了,我們可以根據(jù)需要直接打開和修改一些變量。在這里我們可以加入自己的目標(biāo)產(chǎn)品信息:
ifndef TARGET_PRODUCT
TARGET_PRODUCT:=generic_x86
endif
以及輸出目錄設(shè)置:
OUT_DIR:=$(TOPDIR)generic_x86
回到config.mk,接著進(jìn)行全局變量設(shè)置,進(jìn)入envsetup.mk:
——————————————envsetup.mk——————————————
里面的大部分函數(shù)都在build/envsetup.sh中定義。
首先,設(shè)置版本信息,(11行)在build/core/version_defaults.mk中具體定義平臺(tái)版本、SDK版本、Product版本,我們可以將BUILD_NUMBER作為我們產(chǎn)品generic_x86的version信息,當(dāng)然,也可以自定義一個(gè)版本變量。
回到envsetup.mk,接著設(shè)置默認(rèn)目標(biāo)產(chǎn)品(generic),這里由于我們?cè)?/span>buildspec.mk里設(shè)置過TARGET_PRODUCT,事實(shí)上這個(gè)變量值為generic_x86。
然后讀取product的設(shè)置(41行),具體實(shí)現(xiàn)在build/core/product_config.mk中,進(jìn)而進(jìn)入product.mk,從build/target/product/AndroidProducts.mk中讀出PRODUCT_MAKEFILES,這些makefile各自獨(dú)立定義product,而我們的產(chǎn)品generic_x86也應(yīng)添加一個(gè)makefile文件generic_x86.mk。在generic_x86.mk中我們可以加入所需編譯的PRODUCT_PACKAGES。
下面為generic_x86.mk:
接著回到config.mk,(114行)這里會(huì)搜索所有的BoardConfig.mk,主要有以下幾個(gè)地方:
這里的TARGET_DEVICE就是generic_x86,就是說為了定義我們自己的產(chǎn)品generic_x86,我們要在build/target/board下添加一個(gè)自己的目錄generic_x86用來加載自己的board配置。
在BoardConfig.mk中會(huì)決定是否編譯bootloader、kernel等信息。
結(jié)束全局變量配置后,回到main.mk,對(duì)編譯工具及版本進(jìn)行檢查,錯(cuò)誤便中斷編譯。
line142,包含文件definitions.mk,這里面定義了許多變量和函數(shù)供main.mk使用。
line 446,這里會(huì)去讀取所有的Android.mk文件:
其中include $(ONE_SHOT_MAKEFILE)
這個(gè)ONE_SHOT_MAKEFILE是在前面提到的mm(envsetup.mk)函數(shù)中賦值的:
ONE_SHOT_MAKEFILE=$M make -C $T files $@
回到main.mk,最終將遍歷查找到的所有子目錄下的Android.mk的路徑保存到subdir_makefiles變量里(main.mk里的470行):
我們?cè)?/span>package/apps下每個(gè)模塊根目錄都能看到Android.mk,里面會(huì)去定義當(dāng)前本地模塊的Tag:LOCAL_MODULE_TAGS,Android會(huì)通過這個(gè)Tag來決定哪些本地模塊會(huì)編譯進(jìn)系統(tǒng),通過PRODUCT和LOCAL_MODULE_TAGS來決定哪些應(yīng)用包會(huì)編譯進(jìn)系統(tǒng)。(前面說過,你也能通過buildspec.mk來制定你要編譯進(jìn)系統(tǒng)的模塊)
這個(gè)過程在mian.mk的445行開始,最后需要編譯的模塊路徑打包到ALL_DEFAULT_INSTALLED_MODULES(602行):
關(guān)于Main.mk更多的話
user_PACKAGES := PRODUCT_PACKAGES PRODUCT_PACKAGES在core.mk, generic_no_telephony.mk和sdk.mk中定義,是APK名稱列表。
[user/eng/debug/tests]_MODULES += user_PACKAGES
modules_to_install是根據(jù)規(guī)則從[user/eng/debug/tests]_MODULES檢出,然后除去overriden_packages,然后除去target_gnu_MODULES,對(duì)于剩下的modules_to_install,不是檢查modules_to_install的存在性,而是檢查所有PRODUCT_PACKAGES的存在性。
envsetup.sh通過遍歷特定的目錄下的AndroidProduct.mk文件,這個(gè)文件中的會(huì)有如下語句:
<LOCAL_DIR>/msm7627a.mk,
envsetup.sh會(huì)去掉.mk用msm7627a作為平臺(tái)名稱,供配置選擇,而該平臺(tái)對(duì)應(yīng)的編譯文件就是msm7627a.mk,其中會(huì)根據(jù)情況包含一些其他的.mk文件,如../<VENDOR>/common.mk和../<VENDOR>/product_name.mk.
Prebuild的模塊可以直接拷貝到相關(guān)輸出目錄,也可以使用BUILD_PREBUILT或BUILD_MULTI_PREBUILT進(jìn)行拷貝,模塊可以是app,lib等。
Resources overlay可以使用PRODUCT_PACKAGE_OVERLAYS由編譯系統(tǒng)進(jìn)行目錄遍歷的歸并。
一些要需要編譯的模塊可以直接加到PRODUCT_PACKAGES中進(jìn)行編譯。
如果想用Vendor自定義的不同名Prebuild包替換掉原生的apk,可以直接將原生apk編譯模塊名從PRODUCT_PACKAGES中去掉,添加上自己的apk名。當(dāng)然最好是在定制包目錄下使用Android.mk的LOCAL_OVERRIDES_PACKAGES BUILT_PREBUILD更正規(guī)一些。
ALL_MODULES 是用來根據(jù)MODULE_TAG控制拷貝(安裝)。所以Prebuild的包可以根據(jù)其輸出方式?jīng)Q定是否加入到ALL_MODULES和PRODUCT_PACKAGES中。
ALL_MODULES.$(m).INSTALLED := $path/$package_name.apk
ALL_MODULES和PRODUCT_PACKAGES的關(guān)系?
ALL_MODULES在base_rules.mk中定義,是所有LOCAL_MODULE的集合;PRODUCT_PACKAGES在product.mk中定義,會(huì)以$PRODUCT.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES體現(xiàn)在main,mk中使用,在common.mk/sdk.mk中初始化賦值。
編譯系統(tǒng)會(huì)掃描源碼目錄中所有的Android.mk,形成subdir_makefiles,解析所有Android.mk,每個(gè)Android.mk會(huì)包含base_rules.mk中從而引入ALL_MODULES和其代碼,從而會(huì)將LOCAL_MODULE添加到ALL_MODULES中,LOCAL_MODULE的詳細(xì)信息會(huì)添加到ALL_MODULES.$(LOCAL_MODULE)的各信息字段中,如INSTALLED字段就包含完整的模塊安裝路徑名, dir/file_name.ext。這用于控制特定產(chǎn)品Product(user,debug,eng,tests)的模塊的安裝。
大致是PRODUCT_PACKAGES中的模塊會(huì)被編譯,而ALL_MODULES用來控制輸出安裝。
在main.mk中,編譯sdk時(shí)有如下代碼片段用于模塊檢查,
# Ensure every module listed in PRODUCT_PACKAGES gets something installed
$(foreach m, $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES), \
$(if $(strip $(ALL_MODULES.$(m).INSTALLED)),,\
$(error Module '$(m)' in PRODUCT_PACKAGES has nothing to install!)))
編譯時(shí)可能會(huì)報(bào)某些模塊無從安裝。
這主要是因?yàn)椴恢滥K如何輸出安裝。
說明模塊名在PRODUCT_PACKAGES中,但是ALL_MODULES中對(duì)應(yīng)模塊的INSTALLED目錄為空,或者ALL_MODULES中不存在該項(xiàng)。
這通常是自己在PRODUCT_PACKAGES中直接添加需要編譯的模塊,然后自己拷貝;
或者其INSTALLED因?yàn)闆]有默認(rèn)輸出目錄從而為空,或者沒有ALL_MODULES += $(LOCAL_MODULE)將其添加到ALL_MODULES中,或者根本就不從在對(duì)應(yīng)MODULE目標(biāo)的Android.mk。
這可以自己根據(jù)情況要么filter_out,要么添加ALL_MODULES.$(m)各子字段即可。
如下為編譯SDK時(shí),Filter out掉的包,因?yàn)檫@些源碼目錄已經(jīng)被刪掉(用Vendor Prebuild的VendorNamePackageName.apk模塊代替),從而Android.mk也不復(fù)存在,但是MOUDLE Name沒有PRODUCT_PACKAGES中去掉。
ifdef is_sdk_build
# same name packages in core.mk replaced by vendor prebuild.
CORE_PACKAGES_REPLACED_BY_PREBUILD := \
Contacts \
ContactsProvider \
Home \
TelephonyProvider \
libdrmframeworkcommon
# same name packages in sdk.mk replaced by vendor prebuild.
SDK_PACKAGES_REPLACED_BY_PREBUILD := \
Calculator \
Camera \
DeskClock \
Email \
Exchange \
Gallery \
Music \
Mms \
OpenWnn \
libWnnEngDic \
libWnnJpnDic \
libwnndict \
Phone \
PinyinIME \
Launcher2 \
SdkSetup \
LatinIME \
CalendarProvider \
Calendar
PACKAGES_REPLACED_BY_PREBUILD := \
$(CORE_PACKAGES_REPLACED_BY_PREBUILD) \
$(SDK_PACKAGES_REPLACED_BY_PREBUILD)
# filter out deleted packages, these modules will be copy to destination dirs directly.
PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES := \
$(filter-out $(PACKAGES_REPLACED_BY_PREBUILD),$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES))
endif
所有需要配置的準(zhǔn)備工作都已完成,下面該決定如何生成image輸出文件了,這一過程實(shí)際上在build/core/Makefile中處理的。
這里定義各種img的生成方式,包括ramdisk.img、userdata.img、system.img、update.zip、recover.img等。
當(dāng)Make include所有的文件,完成對(duì)所有make文件的解析以后就會(huì)尋找生成對(duì)應(yīng)目標(biāo)的規(guī)則,依次生成它的依賴,直到所有滿足的模塊被編譯好,然后使用相應(yīng)的工具打包成相應(yīng)的img。
具體make操作:
完整編譯
我們?cè)诟夸浵螺斎?/span>make命令即可開始完全編譯。這個(gè)命令實(shí)際編譯生成的默認(rèn)目標(biāo)是droid。
也就是說,大家敲入make實(shí)際上執(zhí)行的make droid。而接下來大家看看main.mk文件里最后面的部分,會(huì)有很多偽目標(biāo),如sdk、clean、clobber等,這些在默認(rèn)的make droid的命令下是不會(huì)執(zhí)行的。我們可以在make后加上這些標(biāo)簽來單獨(dú)實(shí)現(xiàn)一些操作。如:輸入make sdk將會(huì)生成該版本對(duì)應(yīng)的SDK,輸入make clean會(huì)清除上次編譯的輸出。
模塊編譯
有時(shí)候我們只修改了某一個(gè)模塊,希望能單獨(dú)編譯這個(gè)模塊而不是重新完整編譯一次,這時(shí)候我們要用到build/envsetup.sh中提供的幾個(gè)bash的幫助函數(shù)。
在源代碼根目錄下執(zhí)行:
. build/envsetup.sh(.后面有空格)
這樣大家相當(dāng)于多了幾個(gè)可用的命令。
這時(shí)可以用help命令查看幫助信息:
其中對(duì)模塊編譯有幫助的是tapas、m、mm、mmm這幾個(gè)命令。
1、tapas——以交互方式設(shè)置build環(huán)境變量。
輸入:tapas
第一步,選擇目標(biāo)設(shè)備:
第二步,選擇代碼格式:
第三步,選擇產(chǎn)品平臺(tái):
注意:這里,Google源代碼里默認(rèn)是generic,而我們針對(duì)自己的產(chǎn)品應(yīng)修改成generic_x86具體在build/envsetup.sh里的函數(shù)chooseproduct()中對(duì)相應(yīng)代碼進(jìn)行修改。
2、m、mm、mmm使用獨(dú)立模塊的make命令。
幾個(gè)命令的功能使用help命令查看。
舉個(gè)例子,我們修改了Camera模塊的代碼,現(xiàn)在需要重新單獨(dú)編譯這一塊,這時(shí)可以使用mmm命令,后面跟指定模塊的路徑(注意是模塊的根目錄)。
具體如下:
mmm packages/apps/Camera/
為了可以直接測(cè)試改動(dòng),編譯好后需要重新生成system.img可以執(zhí)行:make snod
單獨(dú)編譯image文件
一般我們完整編譯后,會(huì)生成三個(gè)重要的image文件:ramdisk.img、system.img和userdata.img。當(dāng)然我們可以分開單獨(dú)去編譯這三個(gè)目標(biāo):
make ramdisk —— ramdisk.img
make userdataimage —— userdata.img
make systemimage —— system.img
轉(zhuǎn)自 http://blog.chinaunix.net/u/8866/
本文詳細(xì)解析了編譯系統(tǒng)的mk腳本文件,特別用示例的方式描述了編譯的過程。
Android Make腳本的簡(jiǎn)記(1)
Build Layers描述的是產(chǎn)品的硬件配置情況,據(jù)此make時(shí)選擇不同的配置和模塊。按照從上到下的順序,Build Layer分成4層。
Layer sample Note
Arch arm, x86 處理器的種類
Board - 板子類型的代號(hào)
Device - device配置的類型代號(hào)
Product - 具體產(chǎn)品的代號(hào)
以calculator為例,app代碼可以放到packages/apps/目錄下邊,一個(gè)app對(duì)應(yīng)一個(gè)目錄,此例,pakcages/apps/Calculator/。創(chuàng)建Android.mk,已去除多余的注釋行。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := libarity
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := Calculator
include $(BUILD_PACKAGE)
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := libarity:arity-2.1.2.jar
include $(BUILD_MULTI_PREBUILT)
# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
至少有一個(gè)子目錄,src下放源碼。
Android.mk中需要賦值的幾個(gè)LOCAL_XXX變量,
LOCAL_PATH,調(diào)用my-dir(在defination.mk中定義),得到當(dāng)前路徑,即,<yourSrcPath>/ pakcages/apps/Calculator/。
LOCAL_MODULE_TAGS,取值范圍
debug eng tests optional samples shell_ash shell_mksh。注意不能取值user,如果要預(yù)裝,則應(yīng)定義core.mk。
LOCAL_SRC_FILES,app的所有源碼,可以調(diào)用all-java-files-under得到,如果是java源碼的話。
LOCAL_PACKAGE_NAME,package的名字,這個(gè)名字在腳本中將標(biāo)識(shí)這個(gè)app或package。
$(CLEAR_VARS)指的是clear_vars.mk,腳本會(huì)清空所有LOCAL_xxx的變量,不影響后面這些變量的使用。
$(BUILD_PACKAGE)指的是package.mk生成規(guī)則
最后一句all-makefiles-under將會(huì)包含當(dāng)前目錄下所有的mk腳本文件。
Include $(CLEAR_VARS)后,可以做為局部宏定義使用.
說明:
必須定義, 在app或package的Android.mk中必須給定值。
可選定義,在app或package的Android.mk中可以也可以不給定值。
不用定義,在app或package的Android.mk中不要給定值,腳本自動(dòng)指定值。
LOCAL_PATH, 當(dāng)前路徑,必須定義。
LOCAL_PACKAGE_NAME, 必須定義,package的名字,這個(gè)名字在腳本中將標(biāo)識(shí)app或package。
LOCAL_MODULE_SUFFIX, 不用定義,module的后綴,=.apk。
LOCAL_MODULE, 不用定義,=$(LOCAL_PACKAGE_NAME)。
LOCAL_JAVA_RESOURCE_DIRS, 不用定義。
LOCAL_JAVA_RESOURCE_FILES, 不用定義。
LOCAL_MODULE_CLASS, APPS/ETC(for firmware)/EXECUTABLES/STATIC_LIBRARYS/SHARED_LIBRARYS/JAVA_LIBRARYS
LOCAL_MODULE_TAGS, 可選定義。默認(rèn)optional。取值范圍user debug eng tests optional samples shell_ash shell_mksh。
LOCAL_ASSET_DIR, 可選定義,推薦不定義。默認(rèn)$(LOCAL_PATH)/assets
LOCAL_RESOURCE_DIR, 可選定義,推薦不定義。默認(rèn)product package和device package相應(yīng)的res路徑和$(LOCAL_PATH)/res。
LOCAL_EXPORT_PACKAGE_RESOURCES, 可選定義,默認(rèn)null。如果允許app的資源被其它模塊使用,則設(shè)置true。
LOCAL_PROGUARD_ENABLED, 可選定義,默認(rèn)為full,如果是user或userdebug。取值full, disabled, custom。
LOCAL_MANIFEST_FILE AndroidManifest.xml
full_android_manifest, 不用定義,=$(LOCAL_PATH)/AndroidManifest.xml。
LOCAL_CERTIFICATE, 可選定義,默認(rèn)為testkey。最終
private_key := $(LOCAL_CERTIFICATE).pk8
certificate := $(LOCAL_CERTIFICATE).x509.pem
以Calculator為例,
設(shè)置中間生成目錄路徑,中間路徑將放置R.stamp文件。
由LOCAL_PATH 導(dǎo)出LOCAL_ASSET_DIR all_assets,LOCAL_RESOURCE_DIR all_resources,由LOCAL_PACKAGE_NAME導(dǎo)出變量LOCAL_MODULE。
設(shè)置LOCAL_MODULE_CLASS=APPS,此值local-intermediates-dir會(huì)用到。
package_expected_intermediates_COMMON := $(call local-intermediates-dir,COMMON)
這里COMMON是null,而LOCAL_MODULE_CLASS=APPS,所以
package_expected_intermediates_COMMON=
out/target/common/obj/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates
即
package_expected_intermediates_COMMON=
out/target/common/obj/APPS/Calculator_intermediates
設(shè)置
LOCAL_BUILT_MODULE_STEM := package.apk
而
LOCAL_BUILT_MODULE :=$(built_module_path)/$(LOCAL_BUILT_MODULE_STEM) @base_rules.mk
built_module_path := $(intermediates) @base_rules.mk
intermediates := $(call local-intermediates-dir) @java.mk
最終
LOCAL_BUILT_MODULE=
out/target/product/<PRODUCT>/obj/$(LOCAL_MODULE_CLASS)/
$(LOCAL_MODULE)_intermediates/$(LOCAL_BUILT_MODULE_STEM)
即
LOCAL_BUILT_MODULE=
out/target/product/generic/obj/APPS/Calculator_intermediates/package.apk
由LOCAL_CERTIFICATE導(dǎo)出
private_key := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE).pk8
certificate :=$(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE).x509.pem
LOCAL_CERTIFICATE默認(rèn)為testkey。
PACKAGES.$(LOCAL_PACKAGE_NAME).PRIVATE_KEY := $(private_key)
PACKAGES.$(LOCAL_PACKAGE_NAME).CERTIFICATE := $(certificate)
PACKAGES.$(LOCAL_PACKAGE_NAME).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))
PACKAGES.$(LOCAL_PACKAGE_NAME).RESOURCE_FILES := $(all_resources)
PACKAGES := $(PACKAGES) $(LOCAL_PACKAGE_NAME)
全編譯時(shí),PACKAGES變量將會(huì)記錄遍歷到的packages。
Android Make腳本的簡(jiǎn)記(2)
選取APPS場(chǎng)景,以Calculator為例說明。
LOCAL_JAVA_LIBRARIES=true時(shí),Android.mk中不能定義LOCAL_SDK_VERSION。
當(dāng)LOCAL_SDK_VERSION=current,LOCAL_JAVA_LIBRARIES=android_stubs_current。
package.mk中定義LOCAL_BUILT_MODULE_STEM=package.apk。
兩個(gè)中間目錄的路徑,即對(duì)應(yīng)的obj目錄下APPS/<LOCAL_MODULE>_intermediates/。
intermediates=out/target/product/generic/obj/APPS/Calculator_intermediates
intermediates.COMMON=out/target/common/obj/APPS/Calculator_intermediates
LOCAL_INTERMEDIATE_TARGETS先前package.mk中已經(jīng)定義了R.stamp,
java.mk又增添了7個(gè)。
LOCAL_INTERMEDIATE_TARGETS += /
$(full_classes_jar) /
$(full_classes_compiled_jar) /
$(full_classes_emma_jar) /
$(full_classes_full_names_jar) /
$(full_classes_stubs_jar) /
$(full_classes_jarjar_jar) /
$(built_dex)
此例中,具體值是
LOCAL_INTERMEDIATE_TARGETS=
out/target/common/obj/APPS/Calculator_intermediates/src/R.stamp @ package.mk
out/target/common/obj/APPS/Calculator_intermediates/classes.jar @full_classes_jar
out/target/common/obj/APPS/Calculator_intermediates/classes-full-debug.jar @full_classes_compiled_jar
out/target/common/obj/APPS/Calculator_intermediates/emma_out/lib/classes-full-debug.jar @full_classes_emma_jar
out/target/common/obj/APPS/Calculator_intermediates/classes-full-names.jar @full_classes_full_names_jar
out/target/common/obj/APPS/Calculator_intermediates/stubs.jar @full_classes_stubs_jar
out/target/common/obj/APPS/Calculator_intermediates/classes-jarjar.jar @full_classes_jarjar_jar
out/target/common/obj/APPS/Calculator_intermediates/classes.dex @built_dex
java.mk隨后include base_rules.mk
后面處理了EMMA,PROGUARD在enable/disable情況下的動(dòng)作,最后定義的target, $(LOCAL_MODULE)-findbugs因?yàn)?/span>prebuilt/common下還沒有findbugs,目前不可用。
java.mk還定義了幾個(gè)特別的變量,
ALL_MODULES.$(LOCAL_MODULE).PROGUARD_ENABLED:=$(LOCAL_PROGUARD_ENABLED)
ALL_MODULES.$(LOCAL_MODULE).CHECKED := $(full_classes_compiled_jar)
ALL_MODULES.$(LOCAL_MODULE).STUBS := $(full_classes_stubs_jar)
續(xù)1的場(chǎng)景。
提取變量my_prefix:=TARGET_
LOCAL_MODULE_TAGS在Android.mk或package.mk中已經(jīng)設(shè)定,默認(rèn)是optional。
確認(rèn)LOCAL_MODULE_PATH,默認(rèn)$($(my_prefix)OUT$(use_data)_$(LOCAL_MODULE_CLASS)),此例中是out/target/product/generic/system/app
設(shè)定
module_id :=MODULE.$(TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE),此例MODULE.TARGET.APPS.Calculator。
設(shè)定中間目錄路徑intermediates,intermediates.COMMON,參見1.
設(shè)定LOCAL_MODULE_STEM=$(LOCAL_MODULE),此例,Calculator。LOCAL_INSTALLED_MODULE_STEM=Calculator.apk。
LOCAL_INTERMEDIATE_TARGETS追加上package.apk,參見1.
處理aidl,轉(zhuǎn)為java,放在intermediates.COMMON下的目錄中。
處理logtag,轉(zhuǎn)為java,放在intermediates.COMMON下的目錄中。
確定java_sources,這包括android.mk中包含的,aidl和logtag生成的。
處理java_resource_files
處理java lib相關(guān)
定義clean-$(LOCAL_MODULE) target, 可以刪除app/package的生成文件,包括$(PRIVATE_CLEAN_FILES),$(LOCAL_BUILT_MODULE),$(LOCAL_INSTALLED_MODULE),$(intermediates),$(intermediates.COMMON)
還定義了$(LOCAL_MODULE) target, 幾個(gè)變量的值
LOCAL_MODULE=Calculator
LOCAL_BUILT_MODULE=out/target/product/generic/obj/APPS/Calculator_intermediates/package.apk
LOCAL_INSTALLED_MODULE=out/target/product/generic/system/app/Calculator.apk
最后定義了幾個(gè)ALL_MODULES變量。
ALL_MODULES.$(LOCAL_MODULE).CLASS
ALL_MODULES.$(LOCAL_MODULE).PATH
ALL_MODULES.$(LOCAL_MODULE).TAGS
ALL_MODULES.$(LOCAL_MODULE).CHECKED
ALL_MODULES.$(LOCAL_MODULE).BUILT
ALL_MODULES.$(LOCAL_MODULE).INSTALLED
ALL_MODULES.$(LOCAL_MODULE).REQUIRED
ALL_MODULES.$(LOCAL_MODULE).EVENT_LOG_TAGS
續(xù)1的場(chǎng)景。
mulit_prebuilt.mk顧名思義就是多次調(diào)用prebuilt.mk,對(duì)幾種明確的prebuilt library完成需要的copy操作。
multi_prebuilt.mk定義了命令auto-prebuilt-boilerplate。入口有6個(gè)參數(shù)
# $(1): file list, "<modulename>:<filename>"
# $(2): IS_HOST_MODULE
# $(3): MODULE_CLASS
# $(4): OVERRIDE_BUILT_MODULE_PATH
# $(5): UNINSTALLABLE_MODULE
# $(6): BUILT_MODULE_STEM
根據(jù)這6個(gè)參數(shù),命令確定
LOCAL_IS_HOST_MODULE
LOCAL_MODULE_CLASS
OVERRIDE_BUILT_MODULE_PATH
LOCAL_UNINSTALLABLE_MODULE
LOCAL_MODULE
LOCAL_SRC_FILES
LOCAL_BUILT_MODULE_STEM
LOCAL_MODULE_SUFFIX
并調(diào)用prebuilt.mk
multi_prebuilt.mk中分別對(duì)下面5中lib調(diào)用了auto-prebuilt-boilerplate。
prebuilt_static_libs := $(filter %.a,$(LOCAL_PREBUILT_LIBS))
prebuilt_shared_libs := $(filter-out %.a,$(LOCAL_PREBUILT_LIBS))
prebuilt_executables := $(LOCAL_PREBUILT_EXECUTABLES)
prebuilt_java_libraries := $(LOCAL_PREBUILT_JAVA_LIBRARIES)
prebuilt_static_java_libraries := $(LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES)
續(xù)1的場(chǎng)景。
首先,include base_rules.mk
定義
PACKAGES.$(LOCAL_MODULE).OVERRIDES
第二步,如果是APPS類型,則zipalign,并拷貝到中間路徑$(intermediates)。不是APPS,則不做zipalign。
本例是JAVA_LIBRARY類型,目的路徑out/target/common/obj/JAVA_LIBRARIES/libarity_intermediates/javalib.jar,注意其中的libarity和javalib.jar。
最后檢查 signed情況。
Android Make腳本的簡(jiǎn)記(3)
main.mk中調(diào)用了findleaves.py,得到所有子目錄下Android.mk文件的路徑。
subdir_makefiles := /
$(shell build/tools/findleaves.py --prune=out --prune=.repo --prune=.git $(subdirs) Android.mk)
$(subdirs)一般編譯中取值$(TOP)。
使用方法,
Usage: %(progName)s [<options>] <dirlist> <filename>
Options:
--mindepth=<mindepth>
Both behave in the same way as their find(1) equivalents.
--prune=<dirname>
Avoids returning results from inside any directory called <dirname>
(e.g., "*/out/*"). May be used multiple times.
程序首先依次選取dirlist中的目錄,然后遍歷所有子目錄查找Android.mk文件,如果有,則加入到返回列表中。
pathmap.mk 中定義了一個(gè)列表pathmap_INCL,列表中每項(xiàng)是"短名:路徑"對(duì)。命令include-path-for使用這個(gè)pathmap_INCL列表,輸入短名,得到路徑。你可以在這個(gè)列表中添加自己的對(duì)。使用$(call include-path-for, <短名>)就可以得到路徑。
另外,定義了FRAMEWORKS_BASE_JAVA_SRC_DIRS,含有frameworks/base目錄下含java文件的所有目錄。
其次,定義了一些變量,例如通用的編譯參數(shù),package的后綴名等。
隨后包含buildspec.mk。
接著包含envsetup.mk。
然后包含$(board_config_mk)。$(board_config_mk)是位于build/target/board /$(TARGET_DEVICE)/,device/*/$(TARGET_DEVICE)/,或vendor/*/$(TARGET_DEVICE) /目錄下的BoardConfig.mk文件。
4. buildspec.mk的分析buildspec.mk是用戶應(yīng)當(dāng)配置的腳本文件,模板可以使用buildspec.mk.default,放到$(TOP)下。在 buildspec.mk中,用戶應(yīng)該配置好主要的參數(shù),例如 TARGET_PRODUCT, TARGET_BUILD_VARIANT, CUSTOM_MODULES, TARGET_SIMULATOR, TARGET_BUILD_TYPE, CUSTOM_LOCALES, 和BUILD_ENV_SEQUENCE_NUMBER等。如果不使用buildspec.mk配置參數(shù),也可以使用環(huán)境變量的形式。若不配置參數(shù),那么android會(huì)使用默認(rèn)的參數(shù)。
首先包含進(jìn)version_defaults.mk,定義好一些版本相關(guān)的變量。參見version_defaults.mk。
定義CORRECT_BUILD_ENV_SEQUENCE_NUMBER,這個(gè)數(shù)字用于buildspec.mk更新時(shí)的提醒,應(yīng)該同buildspec.mk中的或環(huán)境變量中的BUILD_ENV_SEQUENCE_NUMBER相等。一般不用關(guān)注。
隨后檢查TARGET_PRODUCT,若為空,則置generic。TARGET_PRODUCT應(yīng)當(dāng)在buildspec.mk或環(huán)境變量中已經(jīng)定義好。
再檢查TARGET_BUILD_VARIANT,若為空,則置eng。TARGET_BUILD_VARIANT應(yīng)當(dāng)在buildspec.mk或環(huán)境變量中已經(jīng)定義好。
然后包含進(jìn)product_config.mk。
接著,檢查$(TARGET_BUILD_VARIANT),取值范圍是eng user userdebug tests。
隨后判定HOST_OS(linux),HOST_ARCH(x86)
接著,確定TARGET_ARCH和TARGET_OS,若沒有定義,則取默認(rèn)值。
TARGET_ARCH := arm
TARGET_OS := linux
接著,確定TARGET_BUILD_TYPE,若沒有定義,則取默認(rèn)值。
TARGET_BUILD_TYPE := release
接著,確定OUT_DIR。OUT_DIR是存放中間文件和最終結(jié)果的地方。若沒有定義,則取默認(rèn)值。
OUT_DIR := $(TOPDIR)out
隨后,定義了一些列的路徑變量
DEBUG_OUT_DIR,TARGET_OUT_ROOT_release,TARGET_OUT_ROOT_debug,TARGET_OUT_ROOT,BUILD_OUT,PRODUCT_OUT,TARGET_COMMON_OUT_ROOT,等等。
version_defaults.mk是檢查一些跟版本相關(guān)的變量是否定義,如果未定義,則使用默認(rèn)值。這些變量包括
PLATFORM_VERSION,默認(rèn)AOSP
PLATFORM_SDK_VERSION,默認(rèn)8
PLATFORM_VERSION_CODENAME,默認(rèn)AOSP
DEFAULT_APP_TARGET_SDK,默認(rèn)AOSP
BUILD_ID,默認(rèn)UNKNOWN
BUILD_NUMBER,默認(rèn)eng.$(USER).$(shell date +%Y%m%d.%H%M%S)的形式。
version_defaults.mk首先包含進(jìn)build_id.mk。用戶應(yīng)當(dāng)配置build_id.mk,而不應(yīng)該改動(dòng)version_defaults.mk文件。
然后檢查上述變量,如未定義則賦值默認(rèn)值。
用戶可以在build_id.mk中定義這樣幾個(gè)參數(shù),
PLATFORM_VERSION
PLATFORM_SDK_VERSION
PLATFORM_VERSION_CODENAME
DEFAULT_APP_TARGET_SDK
BUILD_ID
BUILD_NUMBER
這些參數(shù)最終將出現(xiàn)build.prop中。
Froyo的build_id.mk中定義了2個(gè)變量,
BUILD_ID,通常用于說明分支branch的,默認(rèn)的是OPENMASTER,用戶應(yīng)該配置這個(gè)參數(shù)。
DISPLAY_BUILD_NUMBER,在TARGET_BUILD_VARIANT=user的版本中,build.prop中是ro.build.id是顯示成$(BUILD_ID).$(BUILD_NUMBER),還是顯示成$(BUILD_ID)形式。設(shè)成true,則顯示前者。
make PRODUCT-<prodname>-<goal> <other>
如果使用上述形式的make命令,那么將等同于
TARGET_PRODUCT:=<prodname>
TARGET_BUILD_VARIANT:=<goal>
goal_name:=PRODUCT-<prodname>-<goal>
MAKECMDGOALS:=droid <other>
.PHONY: $(goal_name)
$(goal_name): $(MAKECMDGOALS)
endif
注意,goal的取值范圍是user userdebug eng tests,如果不屬于上述范圍,則將算入MAKECMDGOALS中,此時(shí), TARGET_BUILD_VARIANT := eng。例如
make PRODUCT-dream-installclean
等同于
TARGET_PRODUCT=dream make installclean
使用make PRODUCT-<prodname>-<goal>這種形式,可以方便的指定TARGET_PRODUCT,和TARGET_BUILD_VARIANT。
make APP-<appname> <other>
如果使用上述形式的make命令,那么將等同于
TARGET_BUILD_APPS:=<appname>
unbundled_goals:=APP-<appname>
MAKECMDGOALS:=droid <other>
.PHONY: $(unbundled_goals)
$(unbundled_goals): $(MAKECMDGOALS)
使用make APP-<appname>這種形式,可以方便的指定TARGET_BUILD_APPS。
注意,PRODUCT-<prodname>-<goal>和APP-<appname>可以一塊使用。
處理完PRODUCT-<prodname>-<goal>和APP-<appname>,product_config.mk會(huì)包含下面3個(gè)文件
node_fns.mk
product.mk
device.mk
上面的3個(gè)mk文件定義了一些命令,用于搜尋product, device對(duì)應(yīng)的目錄,生成相應(yīng)的PRODUCT.XXX,和DEVICE.XXX變量。
接著,使用$(call import-products, $(get-all-product-makefiles))遍歷Prodcut相關(guān)的AndroidProducts.mk文件,讀入PRODCUTS.xxx變量??梢匀サ粑募邢旅鎯删湓挼淖⑨尫榭?。
#$(dump-products)
#$(error done)
隨后,使用PRODCUT.xxx和TARGET_PRODUCT,得到INTERNAL_PRODUCT信息,即指定product的路徑。
再由INTERNAL_PRODUCT得到TARGET_DEVICE, PRODUCT_LOCALES,PRODUCT_BRAND, PRODUCT_MODEL, PRODUCT_MANUFACTURER, PRODUCT_DEFAULT_WIFI_CHANNELS, PRODUCT_POLICY, PRODUCT_COPY_FILES, PRODUCT_PROPERTY_OVERRIDES, PRODUCT_PACKAGE_OVERLAYS, DEVICE_PACKAGE_OVERLAYS, PRODUCT_TAGS, PRODUCT_OTA_PUBLIC_KEYS。
由PRODUCT_LOCALES導(dǎo)出PRODUCT_AAPT_CONFIG。
ADDITIONAL_BUILD_PROPERTIES中追加PRODUCT_PROPERTY_OVERRIDES中的值。
上面所說的這些值,實(shí)際上都是在product的mk文件中定義。
定義了一些命令。這些命令在product.mk,device.mk,和product_config.mk中會(huì)使用。這里重點(diǎn)說明import-nodes。
import-nodes需要3個(gè)入口參數(shù):
$(1)是一個(gè)字串,是輸出變量的主干名。例如”PRODUCTS"和”DEVICES“。
$(2)是一個(gè)makefile文件列表,這些文件中應(yīng)該含有對(duì)$(3)中變量的定義。
$(3)是一個(gè)變量列表。
import- nodes會(huì)創(chuàng)建這樣形式的變量,以$(1)="PRODUCTS", $(2)中含有"build/target/product/core.mk", $(3)中含有"PRODUCT_NAME",而且core.mk中定義了PRODUCT_NAME:=core為例,
PRODUCT.build/target/product/core.mk.PRODUCT_NAME:=core
import- nodes中還考慮了inherit的問題,如果某個(gè)PRODUCTS.XXX變量的值中有‘@inherit:<mk文件>’標(biāo)識(shí)后面跟著 mk文件名的字串,則會(huì)把那個(gè)mk文件中相應(yīng)的變量的屬性添加到PRODUCTS.XXX中。'@inherit:<mk文件>'是 inherit-product命令添加的。參見product.mk。
在product_config.mk中會(huì)說明$(2)中的mk文件列表是AndroidProducts.mk中的PRODUCT_MAKEFILES定義的。
node_fns.mk的代碼真的很殺傷腦細(xì)胞...
product.mk構(gòu)造了一些命令,供product_config.mk中使用。
_find-android-products-files這個(gè)命令會(huì)得到device/和vendor/,包括子目錄,以及build/target/product/下的AndroidProducts.mk文件列表。
get-all-product-makefiles這個(gè)命令會(huì)得到所有$(_find-android-products-files)的AndroidProducts.mk文件中PRODUCT_MAKEFILES變量定義的mk文件。
_product_var_list對(duì)應(yīng)的是import-nodes命令的$(3),定義了會(huì)生成那些PRODUCT屬性名的變量。這些變量實(shí)際也是在product的mk文件中要考慮定義的。
_product_var_list := /
PRODUCT_NAME /
PRODUCT_MODEL /
PRODUCT_LOCALES /
PRODUCT_PACKAGES /
PRODUCT_DEVICE /
PRODUCT_MANUFACTURER /
PRODUCT_BRAND /
PRODUCT_PROPERTY_OVERRIDES /
PRODUCT_COPY_FILES /
PRODUCT_OTA_PUBLIC_KEYS /
PRODUCT_POLICY /
PRODUCT_PACKAGE_OVERLAYS /
DEVICE_PACKAGE_OVERLAYS /
PRODUCT_CONTRIBUTORS_FILE /
PRODUCT_TAGS /
PRODUCT_SDK_ADDON_NAME /
PRODUCT_SDK_ADDON_COPY_FILES /
PRODUCT_SDK_ADDON_COPY_MODULES /
PRODUCT_SDK_ADDON_DOC_MODULE /
PRODUCT_DEFAULT_WIFI_CHANNELS
import-products會(huì)調(diào)用import-nodes。product_config.mk中用到。
define import-products
$(call import-nodes,PRODUCTS,$(1),$(_product_var_list))
endef
inherit-product命令則將在所有的PRODUCT.xxx變量值中后綴上'@inherit:<mk文件>',當(dāng)import-nodes處理時(shí),會(huì)替換成繼承的屬性。
check-all-products命令借助$(PRODUCTS)諸變量,會(huì)對(duì)product進(jìn)行唯一性檢查和PRODUCT_NAME,PRODUCT_BRAND,PRODCUT_COPY_FILES的簡(jiǎn)單檢查。
resolve-short-product-name命令,給定Product的短名,返回對(duì)應(yīng)mk的路徑。
同product.mk類似,device.mk構(gòu)造了一些命令。有resolve-short-device-name,和import-devices。
Android Make腳本的簡(jiǎn)記(4)
首先,包含pathmap.mk,其次,定義了一些變量,例如通用的編譯參數(shù),package的后綴名等。
隨后包含buildspec.mk。
接著包含envsetup.mk。envsetup.mk中會(huì)遍歷所有product相關(guān)的路徑,載入所有支持的product的信息到變量集 PRODUCT.<productMkPath>.<attribute>中,一個(gè)product對(duì)應(yīng)一個(gè)<productMkPath>。最后根據(jù)TARGET_PRODUCT的值,定義各種跟product相關(guān)的變量,包括 TARGET_DEVICE變量。
然后包含$(board_config_mk)。$(board_config_mk)是位于 build/target/board/$(TARGET_DEVICE)/,device/*/$(TARGET_DEVICE)/,或vendor /*/$(TARGET_DEVICE)/目錄下的BoardConfig.mk文件。 $(TARGET_DEVICE)已經(jīng)在product_config.mk中定義了。在包含$(board_config_mk)之前,會(huì)做檢查,多個(gè)$(board_config_mk)存在則報(bào)錯(cuò)。
定義TARGET_DEVICE_DIR,TARGET_BOOTLOADER_BOARD_NAME,TARGET_CPU_ABI等跟board相關(guān)的變量。
接著,依次以HOST_和TARGET_條件包含select.mk。這里說明TARGET_的select.mk。先定義combo_os_arch,通常是linux-arm,然后定義各種跟編譯鏈接相關(guān)的一些變量,最后再包含進(jìn)build/core/combo/TARGET_linux- arm.mk。
再包含javac.mk,定義javac的命令和通用參數(shù)。
隨后,定義一些變量,指向通用工具,其中一些是os提供的,例如YACC;一些是froyo編譯生成,放在out/host/linux-x86/bin/下,一些是預(yù)定義的腳本和工具,例如MKTARBALL。
最后定義了一些編譯鏈接變量,這里專門列出,
HOST_GLOBAL_CFLAGS += $(COMMON_GLOBAL_CFLAGS)
HOST_RELEASE_CFLAGS += $(COMMON_RELEASE_CFLAGS)
HOST_GLOBAL_CPPFLAGS += $(COMMON_GLOBAL_CPPFLAGS)
HOST_RELEASE_CPPFLAGS += $(COMMON_RELEASE_CPPFLAGS)
TARGET_GLOBAL_CFLAGS += $(COMMON_GLOBAL_CFLAGS)
TARGET_RELEASE_CFLAGS += $(COMMON_RELEASE_CFLAGS)
TARGET_GLOBAL_CPPFLAGS += $(COMMON_GLOBAL_CPPFLAGS)
TARGET_RELEASE_CPPFLAGS += $(COMMON_RELEASE_CPPFLAGS)
HOST_GLOBAL_LD_DIRS += -L$(HOST_OUT_INTERMEDIATE_LIBRARIES)
TARGET_GLOBAL_LD_DIRS += -L$(TARGET_OUT_INTERMEDIATE_LIBRARIES)
HOST_PROJECT_INCLUDES:= $(SRC_HEADERS) $(SRC_HOST_HEADERS) $(HOST_OUT_HEADERS)
TARGET_PROJECT_INCLUDES:= $(SRC_HEADERS) $(TARGET_OUT_HEADERS)
ifneq ($(TARGET_SIMULATOR),true)
TARGET_GLOBAL_CFLAGS += $(TARGET_ERROR_FLAGS)
TARGET_GLOBAL_CPPFLAGS += $(TARGET_ERROR_FLAGS)
endif
HOST_GLOBAL_CFLAGS += $(HOST_RELEASE_CFLAGS)
HOST_GLOBAL_CPPFLAGS += $(HOST_RELEASE_CPPFLAGS)
TARGET_GLOBAL_CFLAGS += $(TARGET_RELEASE_CFLAGS)
TARGET_GLOBAL_CPPFLAGS += $(TARGET_RELEASE_CPPFLAGS)
其中的TARGET_PROJECT_INCLUDES包含了SRC_HEADERS,添加頭文件路徑的話,可以改動(dòng)SRC_HEADERS。
最后包含進(jìn)dumpvar.mk
javac.mk中會(huì)定義javac的編譯命令和通用參數(shù)。
CUSTOM_JAVA_COMPILER做為javac.mk的入口參數(shù),可以考慮openjdk,eclipse。不定義時(shí)則使用默認(rèn)的javac。另外定義為openjdk時(shí),因?yàn)?/span>prebuilt/對(duì)應(yīng)目錄下沒有相應(yīng)的工具,所以還不可用。
依次一般忽略定義CUSTOM_JAVA_COMPILER,只要直接配置自己編譯環(huán)境的path,指向使用的javac就可以了。
javac在linux平臺(tái)的定義是
javac -J-Xmx512M -target 1.5 -Xmaxerrs 9999999
-J-Xmx512M,傳遞給vm launcher參數(shù)-Xmx512M,告知起始空間設(shè)定為512M。
-target 1.5,編譯的結(jié)果適用1.5版本。
-Xmaxerrs 9999999,最大輸出的錯(cuò)誤數(shù)是9999999。
dumpvar.mk 支持兩種target: dumpvar-<varName>,和dumpvar-abs-<varName>。envsetup.sh中的 get_build_var和get_abs_build_var就使用了這些target。
使用方法:假設(shè)位于$(TOPDIR)路徑,
CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make -f build/core/config.mk dumpvar-<varName>
或
CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make -f build/core/config.mk dumpvar-abs-<varName>
第一種形式,返回varName的值。第二種形式,返回varName的值,前綴上路徑。考慮到android腳本中廣泛使用':=’的變量定義方法,因此,基本上只能顯示dumpvar.mk之前定義的變量值。LOCAL_xxxx的變量也不適用。
main.mk在包含了config.mk后,會(huì)包含進(jìn)cleanbuild.mk。
定義了add-clean-step命令。有一個(gè)入口參數(shù)
$(1),執(zhí)行刪除操作的具體shell命令。
一般add-clean-step應(yīng)當(dāng)在%/cleanspec.mk腳本中使用,命令會(huì)為$(1)定義一個(gè)變量保存,變量的名字是 INTERNAL_STEP.$(_acs_id),所有的$(_acs_id)保存在INTERNAL_STEPS中。$(_acs_id)的值分成3個(gè)部分構(gòu)造
第一部分是有cleanspec.mk的路徑轉(zhuǎn)化而來,用'_'替代'/','-'替代'.',后綴_acs。第二部分是$(INTERNAL_CLEAN_BUILD_VERSION),默認(rèn)是4,第三部分是有'@'組成,cleanspec.mk中的第幾個(gè)add- clean-step就用幾個(gè)@。
例如,packages/apps/Camera/cleanspec.mk中定義了兩個(gè)刪除動(dòng)作
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/Camera*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Camera*)
那么,對(duì)應(yīng)的有
INTERNAL_STEP.packages_apps_Camera_CleanSpec-mk_acs4@ := rm -rf $(PRODUCT_OUT)/obj/APPS/Camera*
INTERNAL_STEP.packages_apps_Camera_CleanSpec-mk_acs4@@ := rm -rf $(OUT_DIR)/target/common/obj/APPS/Camera*
接著,包擴(kuò)進(jìn)cleanspec.mk
包含進(jìn)$(PRODUCT_OUT)/clean_steps.mk,
接下來,檢查CURRENT_CLEAN_BUILD_VERSION是否與INTERNAL_CLEAN_BUILD_VERSION相同,默認(rèn)是4
如果相同,
執(zhí)行所有在INTERNAL_STEPS中登記的刪除操作。
否則,
刪除 $(OUT_DIR)
然后,重新生成$(PRODUCT_OUT)/clean_steps.mk,寫入"CURRENT_CLEAN_BUILD_VERSION := $(INTERNAL_CLEAN_BUILD_VERSION)"和"CURRENT_CLEAN_STEPS := $(INTERNAL_CLEAN_STEPS)"。
隨后,讀入$(PRODUCT_OUT)/previous_build_config.mk,看是否與當(dāng)前的編譯選項(xiàng)一致,不一致則標(biāo)明上次的中間文件不可用,則刪除相應(yīng)的中間目錄,或提示用戶。接著重新將當(dāng)前的信息寫入$(PRODUCT_OUT)/previous_build_config.mk,格式是,
current_build_config := /
$(TARGET_PRODUCT)-$(TARGET_BUILD_VARIANT)$(building_sdk)-{$(locale_list)}
echo "PREVIOUS_BUILD_CONFIG := $(current_build_config)" > /
$(previous_build_config_file)
最后,定義了兩個(gè)target, installclean和dataclean。
dataclean刪除的主要是./$(PRODUCT_OUT)/data/*,
installclean的刪除包括dataclean。installclean的本意是用于不同build_type編譯時(shí)刪除前次的中間文件。
總結(jié)cleanbuild.mk的內(nèi)容,就3件事,一是載入所有的CleanSpec.mk,二是檢查更新clean_steps.mk和 previous_build_config.mk,避免不同編譯間的互相干擾。最后是,定義installclean和dataclean。
首先定義
INTERNAL_CLEAN_BUILD_VERSION := 4
接著使用findleaves.py遍歷所有子目錄,找到CleanSpec.mk,并包含進(jìn)。用戶可以在CleanSpec.mk中定義自己需要的刪除操作。實(shí)際上還可以包含不僅僅是刪除的操作。
至此,INTERNAL_STEP.XXXX包含了所有CleanSpec.mk定義的clean動(dòng)作。
main.mk 在cleanbuild.mk后,會(huì)借助$(OUT_DIR)/version_checked.mk檢查版本,如果版本不一致,則重新檢查系統(tǒng)文件系統(tǒng)大小寫敏感問題,路徑上是否含有空格,java和javac的版本,沒有問題,則更新version_checked.mk。
version_checked.mk中就定義了
VERSIONS_CHECKED := $(VERSION_CHECK_SEQUENCE_NUMBER)
checkbuild貌似并未使用。
showcommands必須同其它target一同使用,showcommands會(huì)詳細(xì)打印出執(zhí)行的具體命令內(nèi)容。
definations.mk中定義了大量的命令,其它的mk文件將使用。這其中包括執(zhí)行編譯鏈接的命令,通常是transform-XXX-to-XXX的形式,例如,transform-cpp-to-o。
其中的inherit-package命令有待研究...
Android Make腳本的簡(jiǎn)記(5)
首先定義target,用于生成$(OUT_DOCS)/index.html
再定義target,用于生成$(TARGET_ROOT_OUT)/default.prop
再定義target,用于生成$(TARGET_OUT)/build.prop。build.prop文件記錄了一系列屬性值。它的內(nèi)容分成兩部分,第一部分是一些關(guān)于 product,device,build的一般性屬性值,第二部分的屬性值源自ADDITIONAL_BUILD_PROPERTIES。 product配置mk文件中定義的PRODUCT_PROPERTY_OVERRIDES會(huì)加入到 ADDITIONAL_BUILD_PROPERTIES,建議增加property時(shí),直接修改 PRODUCT_PROPERTY_OVERRIDES。
再定義target,用于生成$(PRODUCT_OUT)/sdk/sdk-build.prop
再定義target,package-stats,用于生成$(PRODUCT_OUT)/package-stats.txt,這個(gè)文件包含了.jar,.apk后綴文件的信息。
再定義target,apkcerts-list,用于生成$(name)-apkcerts-$(FILE_NAME_TAG),描述各module的certificate和private_key文件信息。
接著,如果定義了CREATE_MODULE_INFO_FILE,則生成$(PRODUCT_OUT)/module-info.txt,其中包含了描述所有module的信息。
再定義target,event-log-tags。
接著,處理ramdisk.img
再處理boot.img,如果TARGET_NO_KERNEL不是true,則將kernel和ramdisk.img組裝成boot.img。
接著,定影命令combine-notice-files,用于生成target,notice_files。notice_files會(huì)抽取生成相應(yīng)的聲明文件。
隨后,建立target,otacert,用于將.x509.pem后綴的認(rèn)證文件打包存放到$(TARGET_OUT_ETC)/security/otacerts.zip。
接著,建立target,recoveryimage,處理recovery img
還有下面的target,
systemimage-nodeps, snod
systemtarball-nodeps,stnod
boottarball-nodeps,btnod
userdataimage-nodeps
userdatatarball-nodeps
otatools
target-files-package
otapackage
installed-file-list
tests-zip-package
dalvikfiles
updatepackage
最后包含進(jìn) build/core/task/下的mk文件。
聯(lián)系客服