Android系统编译【转】

摘要:
使用Android。工作中的mk只是一个复制和修改。项目的编译控件是基于Android编译系统//blog的sh脚本。csdn。NET/yili_Xie/archive/2009/11/30/4906865.aspx本文档主要描述envsetup.sh和Android.mk_XX以及BUILD_XX变量使用的LOCAL。

本文转载自;http://blog.csdn.net/zirconsdu/article/details/8005415

Android编译系统分析

概要

由于android编译系统的复杂和使用了不熟悉的Python,所以对其一直望而却步;工作中使用Android.mk也仅仅是拷贝修改。最近由于工作需要解决一个编译方面的问题1,浏览了一下编译系统;另外,项目上的编译控制是使用在Android编译系统基础之上的一个sh脚本,由于脚本维护滞后和Android源码目录增加删除修改的原因,该sh已经不能用来编译SDK。在解决 问题1之后,一股冲动,要编译出SDK供调试程序使用,就学习研究了一下Android编译系统,根据product makefile修改sdk.mk,终于编译出了SDK。

下面是学习研究过程中,参考的一些资料汇总。针对工作的使用,加了体会和注释。

编译脚本及系统变量

转自 http://blog.csdn.NET/yili_xie/archive/2009/11/30/4906865.aspx

本文档主要描述envsetup.sh和Android.mk使用的LOCAL_XX和BUILD_XX变量。
build/envsetup.sh脚本分析
在编译源代码之前通常需要在android源代码顶层目录执行 . ./build/envsetup.sh目的是为了使用脚本 envsetup.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
}
会依次进行如下选择:
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
默认选择以后会出现:
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()函数分析: 
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
经过:
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,但功能是一样的,即搜索平台名称,列表,供选择,赋值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}


怎样添加一个模块
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)

#使用静态库
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)

Note:

CLEAR_VARS用来将这些Shell变量的值清空,达到LOCAL的目的。

系统变量解析
LOCAL_MODULE -编译的目标对象
LOCAL_SRC_FILES -编译的源文件
LOCAL_C_INCLUDES -需要包含的头文件目录
LOCAL_SHARED_LIBRARIES - 链接时需要的共享库

LOCAL_PREBUILT_LIBS - 预编译好的静态库或动态库,可用于集成第三方库

LOCAL_LDLIBS - 链接时需要的外部库
LOCAL_PRELINK_MODULE - 是否需要prelink处理

LOCAL_JAVA_LIBRARIES - 编译Java程序时需要的jar包

LOCAL_PACKAGE_NAME-编译Java APK放入目标PACKAGE名字

可以看出这些变量就是Make系统的参数,完全就是编译器和链接器和其他二进制工具的控制参数。

BUILD_STATIC_LIBRARY-编译成静态库的控制脚本

BUILD_SHARED_LIBRARY -编译成动态库的控制脚本
BUILD_EXECUTABLE -编译成可执行文件的控制脚本
BUILD_PACKAGE -指明编译成java APK包

另外的,

LOCAL_MODULE_TAGS - 是控制编译出的该模块加入到特定编译Varient(user/ud/eng)中。

下面是函数或变量的详细内容。
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_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_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


使用时,只需要在Android.mk中include $(BUILD_XXXX_YYYY_ZZZZ)即可。
作用从名称可以看出,包括HOST和TARGET的可执行程序或库或二进制工具链。

============
LOCAL_PRELINK_MODULE

Prelink利用事先链接代替运行时链接的方法来加速共享库的加载,它不仅可以加快起动速度,还可以减少部分内存开销,是各种linux架构上用于减少程序加载时间、缩短系统启动时间和加快应用程序启动的很受欢迎的一个工具。程序运行时的动态链接尤其是重定位(relocation)的开销对于大型系统来说是很大的。

动态链接和加载的过程开销很大,并且在大多数的系统上,函数库并不会常常被更动,每次程序被执行时所进行的链接动作都是完全相同的,对于嵌入式系统来说尤其如此。因此,这一过程可以改在运行时之前就可以预先处理好,即花一些时间利用Prelink工具对动态共享库和可执行文件进行处理,修改这些二进制文件并加入相应的重定位等信息,节约了本来在程序启动时的比较耗时的查询函数地址等工作,这样可以减少程序启动的时间,同时也减少了内存的耗用。

Prelink的这种做法当然也有代价:每次更新动态共享库时,相关的可执行文件都需要重新执行一遍Prelink才能保证有效,因为新的共享库中的符号信息、地址等很可能与原来的已经不同了,这就是为什么 android framework代码一改动,这时候就会导致相关的应用程序重新被编译。

这种代价对于嵌入式系统的开发者来说可能稍微带来一些复杂度,不过好在对用户来说几乎是可以忽略的。
--------------------
变量设置为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: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。
参考文档:
动态库优化——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_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

本小段是工作中用到的点的记录.

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 的编译系统

转自:http://www.360doc.com/content/11/0609/14/474846_122680003.shtml

本文主要从编译全局控制的角度描述。

一、Makefile的主要流程


以下主要流程都在build/core/main.mk里安排。

    初始化相关的参数设置(buildspec.mk、envsetup.mk、config.mk)
    检测编译环境和目标环境
    读取product的配置信息及目标平台信息
    清除输出目录
    检查版本号
    读取Board的配置
    读取所有Module的配置
    根据配置产生必要的规则(build/core/Makefile)
    生成image

主要配置和实现文件:   

   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目录主要是设计到硬件芯片的配置,比如是否提供硬件的某些功能,比如说GPU等等,或者芯片支持浮点运算等等。

product目录是指针对当前的芯片配置定义你将要生产产品的个性配置,主要是指APK方面的配置,哪些APK会包含在哪个product中,哪些APK在当前product中是不提供的。
config.mk是一个总括性的东西,它里面定义了各种module编译所需要使用的HOST工具以及如何来编译各种模块,比如说 BUILT_PREBUILT就定义了如何来编译预编译模块。envsetup.mk主要会读取由envsetup.sh写入环境变量中的一些变量来配置编译过程中的输出目录,combo里面主要定义了各种Host和Target结合的编译器和编译选项。

配置部分主要完成以下几个工作:
a) 基于Android 产品的配置(product config):选择构建安装的运行程序(user package)
b) 设置 target 等相关变量TARGET_ARCH, TARGET_OS,TARGET_BUILD_TYPE,
TARGET_PREBUILT_TAG
c) 根据编译环境设置 host等相关变量HOST_OS, HOST_ARCH,HOST_BUILD_TYPE,
HOST_PREBUILT_TAG
d) 编译 target上运行程序所需的工具链及编译参数设置,如linux-arm-cc,cflag,include目录等。
e) 编译 host上运行程序所需的工具链及编译参数设置。
下图简要介绍了Android build system的配置部分的主要构成及相互关系。

二、初始化参数设置

在main.mk里,简单设置几个主要编译路径的变量后,来到config.mk:

——————————————config.mk——————————————

其中设置了源文件的一系列路径,包括头文件、库文件、服务、API已经编译工具的路径(前36行)。


从40行开始,定义一些编译模块的生成规则:

除了CLEAR_VARS是清楚本地变量之外,其他所有的都对应了一种模块的生成规则,每一个本地模块最后都会include其中的一种来生成目标模块。

回到config.mk,接着会尝试读取buildspec.mk的设置:

如同注释所说,会尝试查找buildspec.mk,如果文件不存在会自动使用环境变量的设置,如果仍然未定义,会按arm默认的设置去build。

这里的buildspec.mk可以自己创建,也可以将原先build/下的buildspec.mk.default直接命名为buildspec.mk并移到根目录。

实际上,buildspec.mk配置都被屏蔽了,我们可以根据需要直接打开和修改一些变量。在这里我们可以加入自己的目标产品信息:

ifndef TARGET_PRODUCT
TARGET_PRODUCT:=generic_x86
endif

以及输出目录设置:
OUT_DIR:=$(TOPDIR)generic_x86

三、读取Product的设定


回到config.mk,接着进行全局变量设置,进入envsetup.mk:

——————————————envsetup.mk——————————————

里面的大部分函数都在build/envsetup.sh中定义。

首先,设置版本信息,(11行)在build/core/version_defaults.mk中具体定义平台版本、SDK版本、Product版本,我们可以将BUILD_NUMBER作为我们产品generic_x86的version信息,当然,也可以自定义一个版本变量。

回到envsetup.mk,接着设置默认目标产品(generic),这里由于我们在buildspec.mk里设置过TARGET_PRODUCT,事实上这个变量值为generic_x86。

然后读取product的设置(41行),具体实现在build/core/product_config.mk中,进而进入product.mk,从build/target/product/AndroidProducts.mk中读出PRODUCT_MAKEFILES,这些makefile各自独立定义product,而我们的产品generic_x86也应添加一个makefile文件generic_x86.mk。在generic_x86.mk中我们可以加入所需编译的PRODUCT_PACKAGES。

下面为generic_x86.mk:

四、读取BoardConfig


接着回到config.mk,(114行)这里会搜索所有的BoardConfig.mk,主要有以下几个地方:

这里的TARGET_DEVICE就是generic_x86,就是说为了定义我们自己的产品generic_x86,我们要在build/target/board下添加一个自己的目录generic_x86用来加载自己的board配置。

在BoardConfig.mk中会决定是否编译bootloader、kernel等信息。

五、读取所有Module


结束全局变量配置后,回到main.mk,对编译工具及版本进行检查,错误便中断编译。
line142,包含文件definitions.mk,这里面定义了许多变量和函数供main.mk使用。
line 446,这里会去读取所有的Android.mk文件:

其中include $(ONE_SHOT_MAKEFILE)
这个ONE_SHOT_MAKEFILE是在前面提到的mm(envsetup.mk)函数中赋值的:
ONE_SHOT_MAKEFILE=$M make -C $T files $@

回到main.mk,最终将遍历查找到的所有子目录下的Android.mk的路径保存到subdir_makefiles变量里(main.mk里的470行):

我们在package/apps下每个模块根目录都能看到Android.mk,里面会去定义当前本地模块的Tag:LOCAL_MODULE_TAGS,Android会通过这个Tag来决定哪些本地模块会编译进系统,通过PRODUCT和LOCAL_MODULE_TAGS来决定哪些应用包会编译进系统。(前面说过,你也能通过buildspec.mk来制定你要编译进系统的模块)

这个过程在mian.mk的445行开始,最后需要编译的模块路径打包到ALL_DEFAULT_INSTALLED_MODULES(602行):

关于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是根据规则从[user/eng/debug/tests]_MODULES检出,然后除去overriden_packages,然后除去target_gnu_MODULES,对于剩下的modules_to_install,不是检查modules_to_install的存在性,而是检查所有PRODUCT_PACKAGES的存在性。

envsetup.sh通过遍历特定的目录下的AndroidProduct.mk文件,这个文件中的会有如下语句:

<LOCAL_DIR>/msm7627a.mk,

envsetup.sh会去掉.mk用msm7627a作为平台名称,供配置选择,而该平台对应的编译文件就是msm7627a.mk,其中会根据情况包含一些其他的.mk文件,如../<VENDOR>/common.mk和../<VENDOR>/product_name.mk.

Prebuild的模块可以直接拷贝到相关输出目录,也可以使用BUILD_PREBUILT或BUILD_MULTI_PREBUILT进行拷贝,模块可以是app,lib等。

Resources overlay可以使用PRODUCT_PACKAGE_OVERLAYS由编译系统进行目录遍历的归并。

一些要需要编译的模块可以直接加到PRODUCT_PACKAGES中进行编译。

如果想用Vendor自定义的不同名Prebuild包替换掉原生的apk,可以直接将原生apk编译模块名从PRODUCT_PACKAGES中去掉,添加上自己的apk名。当然最好是在定制包目录下使用Android.mk的LOCAL_OVERRIDES_PACKAGES BUILT_PREBUILD更正规一些。

ALL_MODULES 是用来根据MODULE_TAG控制拷贝(安装)。所以Prebuild的包可以根据其输出方式决定是否加入到ALL_MODULES和PRODUCT_PACKAGES中。

ALL_MODULES.$(m).INSTALLED := $path/$package_name.apk

ALL_MODULES和PRODUCT_PACKAGES的关系?

ALL_MODULES在base_rules.mk中定义,是所有LOCAL_MODULE的集合;PRODUCT_PACKAGES在product.mk中定义,会以$PRODUCT.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES体现在main,mk中使用,在common.mk/sdk.mk中初始化赋值。

编译系统会扫描源码目录中所有的Android.mk,形成subdir_makefiles,解析所有Android.mk,每个Android.mk会包含base_rules.mk中从而引入ALL_MODULES和其代码,从而会将LOCAL_MODULE添加到ALL_MODULES中,LOCAL_MODULE的详细信息会添加到ALL_MODULES.$(LOCAL_MODULE)的各信息字段中,如INSTALLED字段就包含完整的模块安装路径名, dir/file_name.ext。这用于控制特定产品Product(user,debug,eng,tests)的模块的安装。

大致是PRODUCT_PACKAGES中的模块会被编译,而ALL_MODULES用来控制输出安装。

在main.mk中,编译sdk时有如下代码片段用于模块检查,

# 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!)))

编译时可能会报某些模块无从安装。

这主要是因为不知道模块如何输出安装。

说明模块名在PRODUCT_PACKAGES中,但是ALL_MODULES中对应模块的INSTALLED目录为空,或者ALL_MODULES中不存在该项。

这通常是自己在PRODUCT_PACKAGES中直接添加需要编译的模块,然后自己拷贝;

或者其INSTALLED因为没有默认输出目录从而为空,或者没有ALL_MODULES += $(LOCAL_MODULE)将其添加到ALL_MODULES中,或者根本就不从在对应MODULE目标的Android.mk。

这可以自己根据情况要么filter_out,要么添加ALL_MODULES.$(m)各子字段即可。

如下为编译SDK时,Filter out掉的包,因为这些源码目录已经被删掉(用Vendor Prebuild的VendorNamePackageName.apk模块代替),从而Android.mk也不复存在,但是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

六、产生相应的Rules,生成image


所有需要配置的准备工作都已完成,下面该决定如何生成image输出文件了,这一过程实际上在build/core/Makefile中处理的。

这里定义各种img的生成方式,包括ramdisk.img、userdata.img、system.img、update.zip、recover.img等。

当Make include所有的文件,完成对所有make文件的解析以后就会寻找生成对应目标的规则,依次生成它的依赖,直到所有满足的模块被编译好,然后使用相应的工具打包成相应的img。

具体make操作:

    完整编译

我们在根目录下输入make命令即可开始完全编译。这个命令实际编译生成的默认目标是droid。

也就是说,大家敲入make实际上执行的make droid。而接下来大家看看main.mk文件里最后面的部分,会有很多伪目标,如sdk、clean、clobber等,这些在默认的make droid的命令下是不会执行的。我们可以在make后加上这些标签来单独实现一些操作。如:输入make sdk将会生成该版本对应的SDK,输入make clean会清除上次编译的输出。

    模块编译

有时候我们只修改了某一个模块,希望能单独编译这个模块而不是重新完整编译一次,这时候我们要用到build/envsetup.sh中提供的几个bash的帮助函数。

在源代码根目录下执行:

. build/envsetup.sh(.后面有空格)

这样大家相当于多了几个可用的命令。
这时可以用help命令查看帮助信息:
其中对模块编译有帮助的是tapas、m、mm、mmm这几个命令。

1、tapas——以交互方式设置build环境变量。
   输入:tapas
第一步,选择目标设备:
第二步,选择代码格式:
第三步,选择产品平台:

 注意:这里,Google源代码里默认是generic,而我们针对自己的产品应修改成generic_x86具体在build/envsetup.sh里的函数chooseproduct()中对相应代码进行修改。

2、m、mm、mmm使用独立模块的make命令。

几个命令的功能使用help命令查看。
举个例子,我们修改了Camera模块的代码,现在需要重新单独编译这一块,这时可以使用mmm命令,后面跟指定模块的路径(注意是模块的根目录)。

具体如下:
mmm packages/apps/Camera/

为了可以直接测试改动,编译好后需要重新生成system.img可以执行:make snod

    单独编译image文件

一般我们完整编译后,会生成三个重要的image文件:ramdisk.img、system.img和userdata.img。当然我们可以分开单独去编译这三个目标:

make ramdisk —— ramdisk.img
make userdataimage —— userdata.img
make systemimage  —— system.img

Android Make脚本的简记(1-5)

转自 http://blog.chinaunix.net/u/8866/

本文详细解析了编译系统的mk脚本文件,特别用示例的方式描述了编译的过程。

Android Make脚本的简记(1)

1.    Build Layers

Build Layers描述的是产品的硬件配置情况,据此make时选择不同的配置和模块。按照从上到下的顺序,Build Layer分成4层。
Layer    sample    Note
Arch    arm, x86    处理器的种类
Board    -    板子类型的代号
Device    -    device配置的类型代号
Product    -    具体产品的代号

2.    Android.mk中使用的LOCAL_VARS

2.1 Calculator as Sample

以calculator为例,app代码可以放到packages/apps/目录下边,一个app对应一个目录,此例,pakcages/apps/Calculator/。创建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))

至少有一个子目录,src下放源码。

Android.mk中需要赋值的几个LOCAL_XXX变量,
LOCAL_PATH,调用my-dir(在defination.mk中定义),得到当前路径,即,<yourSrcPath>/ pakcages/apps/Calculator/。
LOCAL_MODULE_TAGS,取值范围

debug eng tests optional samples shell_ash shell_mksh。注意不能取值user,如果要预装,则应定义core.mk。
LOCAL_SRC_FILES,app的所有源码,可以调用all-java-files-under得到,如果是java源码的话。
LOCAL_PACKAGE_NAME,package的名字,这个名字在脚本中将标识这个app或package。
$(CLEAR_VARS)指的是clear_vars.mk,脚本会清空所有LOCAL_xxx的变量,不影响后面这些变量的使用。
$(BUILD_PACKAGE)指的是package.mk生成规则
最后一句all-makefiles-under将会包含当前目录下所有的mk脚本文件。

2.2 LOCAL_XXX的列表

Include $(CLEAR_VARS)后,可以做为局部宏定义使用.

说明:
    必须定义, 在app或package的Android.mk中必须给定值。
    可选定义,在app或package的Android.mk中可以也可以不给定值。
    不用定义,在app或package的Android.mk中不要给定值,脚本自动指定值。

LOCAL_PATH,            当前路径,必须定义。
LOCAL_PACKAGE_NAME,    必须定义,package的名字,这个名字在脚本中将标识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,        可选定义。默认optional。取值范围user debug eng tests optional samples shell_ash shell_mksh。
LOCAL_ASSET_DIR,    可选定义,推荐不定义。默认$(LOCAL_PATH)/assets
LOCAL_RESOURCE_DIR,    可选定义,推荐不定义。默认product package和device package相应的res路径和$(LOCAL_PATH)/res。

LOCAL_EXPORT_PACKAGE_RESOURCES,    可选定义,默认null。如果允许app的资源被其它模块使用,则设置true。
LOCAL_PROGUARD_ENABLED,    可选定义,默认为full,如果是user或userdebug。取值full, disabled, custom。

LOCAL_MANIFEST_FILE    AndroidManifest.xml
full_android_manifest,        不用定义,=$(LOCAL_PATH)/AndroidManifest.xml。

LOCAL_CERTIFICATE,    可选定义,默认为testkey。最终
        private_key := $(LOCAL_CERTIFICATE).pk8
        certificate := $(LOCAL_CERTIFICATE).x509.pem

2.3 mm创建apk时的package.mk中变量分析

以Calculator为例,
设置中间生成目录路径,中间路径将放置R.stamp文件。
由LOCAL_PATH 导出LOCAL_ASSET_DIR all_assets,LOCAL_RESOURCE_DIR all_resources,由LOCAL_PACKAGE_NAME导出变量LOCAL_MODULE。
设置LOCAL_MODULE_CLASS=APPS,此值local-intermediates-dir会用到。
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

设置
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导出
private_key := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE).pk8
certificate :=$(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE).x509.pem
LOCAL_CERTIFICATE默认为testkey。

2.4 package.mk中定义的几个PACKAGE.xxx变量

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)
全编译时,PACKAGES变量将会记录遍历到的packages。

Android Make脚本的简记(2)

1.    java.mk分析


选取APPS场景,以Calculator为例说明。
LOCAL_JAVA_LIBRARIES=true时,Android.mk中不能定义LOCAL_SDK_VERSION。
当LOCAL_SDK_VERSION=current,LOCAL_JAVA_LIBRARIES=android_stubs_current。

package.mk中定义LOCAL_BUILT_MODULE_STEM=package.apk。
两个中间目录的路径,即对应的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中已经定义了R.stamp,

java.mk又增添了7个。
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情况下的动作,最后定义的target, $(LOCAL_MODULE)-findbugs因为prebuilt/common下还没有findbugs,目前不可用。

java.mk还定义了几个特别的变量,
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)

2. base_rules.mk的分析

续1的场景。
提取变量my_prefix:=TARGET_
LOCAL_MODULE_TAGS在Android.mk或package.mk中已经设定,默认是optional。
确认LOCAL_MODULE_PATH,默认$($(my_prefix)OUT$(use_data)_$(LOCAL_MODULE_CLASS)),此例中是out/target/product/generic/system/app
设定

module_id :=MODULE.$(TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE),此例MODULE.TARGET.APPS.Calculator。
设定中间目录路径intermediates,intermediates.COMMON,参见1.

设定LOCAL_MODULE_STEM=$(LOCAL_MODULE),此例,Calculator。LOCAL_INSTALLED_MODULE_STEM=Calculator.apk。
LOCAL_INTERMEDIATE_TARGETS追加上package.apk,参见1.
处理aidl,转为java,放在intermediates.COMMON下的目录中。
处理logtag,转为java,放在intermediates.COMMON下的目录中。
确定java_sources,这包括android.mk中包含的,aidl和logtag生成的。
处理java_resource_files
处理java lib相关

定义clean-$(LOCAL_MODULE) target, 可以删除app/package的生成文件,包括$(PRIVATE_CLEAN_FILES),$(LOCAL_BUILT_MODULE),$(LOCAL_INSTALLED_MODULE),$(intermediates),$(intermediates.COMMON)

还定义了$(LOCAL_MODULE) target, 几个变量的值
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

最后定义了几个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

3. multi_prebuilt.mk的分析

续1的场景。
mulit_prebuilt.mk顾名思义就是多次调用prebuilt.mk,对几种明确的prebuilt library完成需要的copy操作。

multi_prebuilt.mk定义了命令auto-prebuilt-boilerplate。入口有6个参数
# $(1): file list, "<modulename>:<filename>"
# $(2): IS_HOST_MODULE
# $(3): MODULE_CLASS
# $(4): OVERRIDE_BUILT_MODULE_PATH
# $(5): UNINSTALLABLE_MODULE
# $(6): BUILT_MODULE_STEM
根据这6个参数,命令确定
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
并调用prebuilt.mk

multi_prebuilt.mk中分别对下面5中lib调用了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)

4. prebuilt.mk的分析

续1的场景。

首先,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脚本的简记(3)

1.findleaves.py的分析

main.mk中调用了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文件,如果有,则加入到返回列表中。

2. pathmap.mk的分析

pathmap.mk 中定义了一个列表pathmap_INCL,列表中每项是"短名:路径"对。命令include-path-for使用这个pathmap_INCL列表,输入短名,得到路径。你可以在这个列表中添加自己的对。使用$(call include-path-for, <短名>)就可以得到路径。
另外,定义了FRAMEWORKS_BASE_JAVA_SRC_DIRS,含有frameworks/base目录下含java文件的所有目录。

3. config.mk的分析 首先,包含pathmap.mk,

其次,定义了一些变量,例如通用的编译参数,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是用户应当配置的脚本文件,模板可以使用buildspec.mk.default,放到$(TOP)下。
在 buildspec.mk中,用户应该配置好主要的参数,例如 TARGET_PRODUCT, TARGET_BUILD_VARIANT, CUSTOM_MODULES,  TARGET_SIMULATOR, TARGET_BUILD_TYPE, CUSTOM_LOCALES, 和BUILD_ENV_SEQUENCE_NUMBER等。
如果不使用buildspec.mk配置参数,也可以使用环境变量的形式。若不配置参数,那么android会使用默认的参数。
5. envsetup.mk的分析


首先包含进version_defaults.mk,定义好一些版本相关的变量。参见version_defaults.mk。


定义CORRECT_BUILD_ENV_SEQUENCE_NUMBER,这个数字用于buildspec.mk更新时的提醒,应该同buildspec.mk中的或环境变量中的BUILD_ENV_SEQUENCE_NUMBER相等。一般不用关注。

随后检查TARGET_PRODUCT,若为空,则置generic。TARGET_PRODUCT应当在buildspec.mk或环境变量中已经定义好。

再检查TARGET_BUILD_VARIANT,若为空,则置eng。TARGET_BUILD_VARIANT应当在buildspec.mk或环境变量中已经定义好。

然后包含进product_config.mk。

接着,检查$(TARGET_BUILD_VARIANT),取值范围是eng user userdebug tests。

随后判定HOST_OS(linux),HOST_ARCH(x86)

接着,确定TARGET_ARCH和TARGET_OS,若没有定义,则取默认值。
TARGET_ARCH := arm
TARGET_OS := linux

接着,确定TARGET_BUILD_TYPE,若没有定义,则取默认值。
TARGET_BUILD_TYPE := release

接着,确定OUT_DIR。OUT_DIR是存放中间文件和最终结果的地方。若没有定义,则取默认值。
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,等等。

6. version_defaults.mk的分析


version_defaults.mk是检查一些跟版本相关的变量是否定义,如果未定义,则使用默认值。这些变量包括
PLATFORM_VERSION,默认AOSP
PLATFORM_SDK_VERSION,默认8
PLATFORM_VERSION_CODENAME,默认AOSP
DEFAULT_APP_TARGET_SDK,默认AOSP
BUILD_ID,默认UNKNOWN
BUILD_NUMBER,默认eng.$(USER).$(shell date +%Y%m%d.%H%M%S)的形式。

version_defaults.mk首先包含进build_id.mk。用户应当配置build_id.mk,而不应该改动version_defaults.mk文件。
然后检查上述变量,如未定义则赋值默认值。

7. build_id.mk的分析


用户可以在build_id.mk中定义这样几个参数,
PLATFORM_VERSION
PLATFORM_SDK_VERSION
PLATFORM_VERSION_CODENAME
DEFAULT_APP_TARGET_SDK
BUILD_ID
BUILD_NUMBER
这些参数最终将出现build.prop中。

Froyo的build_id.mk中定义了2个变量,
BUILD_ID,通常用于说明分支branch的,默认的是OPENMASTER,用户应该配置这个参数。
DISPLAY_BUILD_NUMBER,在TARGET_BUILD_VARIANT=user的版本中,build.prop中是ro.build.id是显示成$(BUILD_ID).$(BUILD_NUMBER),还是显示成$(BUILD_ID)形式。设成true,则显示前者。

8. product_config.mk的分析


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中,此时, 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会包含下面3个文件
node_fns.mk
product.mk
device.mk

上面的3个mk文件定义了一些命令,用于搜寻product, device对应的目录,生成相应的PRODUCT.XXX,和DEVICE.XXX变量。

接着,使用$(call import-products, $(get-all-product-makefiles))遍历Prodcut相关的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导出PRODUCT_AAPT_CONFIG。
ADDITIONAL_BUILD_PROPERTIES中追加PRODUCT_PROPERTY_OVERRIDES中的值。
上面所说的这些值,实际上都是在product的mk文件中定义。

9. node_fns.mk的分析


定义了一些命令。这些命令在product.mk,device.mk,和product_config.mk中会使用。这里重点说明import-nodes。

import-nodes需要3个入口参数:
$(1)是一个字串,是输出变量的主干名。例如”PRODUCTS"和”DEVICES“。
$(2)是一个makefile文件列表,这些文件中应该含有对$(3)中变量的定义。
$(3)是一个变量列表。

import- nodes会创建这样形式的变量,以$(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的问题,如果某个PRODUCTS.XXX变量的值中有‘@inherit:<mk文件>’标识后面跟着 mk文件名的字串,则会把那个mk文件中相应的变量的属性添加到PRODUCTS.XXX中。'@inherit:<mk文件>'是inherit-product命令添加的。参见product.mk。

在product_config.mk中会说明$(2)中的mk文件列表是AndroidProducts.mk中的PRODUCT_MAKEFILES定义的。

node_fns.mk的代码真的很杀伤脑细胞...

10. product.mk的分析


product.mk构造了一些命令,供product_config.mk中使用。

_find-android-products-files这个命令会得到device/和vendor/,包括子目录,以及build/target/product/下的AndroidProducts.mk文件列表。

get-all-product-makefiles这个命令会得到所有$(_find-android-products-files)的AndroidProducts.mk文件中PRODUCT_MAKEFILES变量定义的mk文件。

_product_var_list对应的是import-nodes命令的$(3),定义了会生成那些PRODUCT属性名的变量。这些变量实际也是在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会调用import-nodes。product_config.mk中用到。
define import-products
$(call import-nodes,PRODUCTS,$(1),$(_product_var_list))
endef

inherit-product命令则将在所有的PRODUCT.xxx变量值中后缀上'@inherit:<mk文件>',当import-nodes处理时,会替换成继承的属性。

check-all-products命令借助$(PRODUCTS)诸变量,会对product进行唯一性检查和PRODUCT_NAME,PRODUCT_BRAND,PRODCUT_COPY_FILES的简单检查。

resolve-short-product-name命令,给定Product的短名,返回对应mk的路径。

11. device.mk的分析


同product.mk类似,device.mk构造了一些命令。有resolve-short-device-name,和import-devices。

Android Make脚本的简记(4)

1. config.mk的分析


首先,包含pathmap.mk,其次,定义了一些变量,例如通用的编译参数,package的后缀名等。

随后包含buildspec.mk。

接着包含envsetup.mk。envsetup.mk中会遍历所有product相关的路径,载入所有支持的product的信息到变量集PRODUCT.<productMkPath>.<attribute>中,一个product对应一个<productMkPath>。最后根据TARGET_PRODUCT的值,定义各种跟product相关的变量,包括 TARGET_DEVICE变量。

然后包含$(board_config_mk)。$(board_config_mk)是位于 build/target/board/$(TARGET_DEVICE)/,device/*/$(TARGET_DEVICE)/,或vendor /*/$(TARGET_DEVICE)/目录下的BoardConfig.mk文件。$(TARGET_DEVICE)已经在product_config.mk中定义了。在包含$(board_config_mk)之前,会做检查,多个$(board_config_mk)存在则报错。

定义TARGET_DEVICE_DIR,TARGET_BOOTLOADER_BOARD_NAME,TARGET_CPU_ABI等跟board相关的变量。

接着,依次以HOST_和TARGET_条件包含select.mk。这里说明TARGET_的select.mk。先定义combo_os_arch,通常是linux-arm,然后定义各种跟编译链接相关的一些变量,最后再包含进build/core/combo/TARGET_linux- arm.mk。

再包含javac.mk,定义javac的命令和通用参数。

随后,定义一些变量,指向通用工具,其中一些是os提供的,例如YACC;一些是froyo编译生成,放在out/host/linux-x86/bin/下,一些是预定义的脚本和工具,例如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,添加头文件路径的话,可以改动SRC_HEADERS。

最后包含进dumpvar.mk

2. javac.mk的分析


javac.mk中会定义javac的编译命令和通用参数。
CUSTOM_JAVA_COMPILER做为javac.mk的入口参数,可以考虑openjdk,eclipse。不定义时则使用默认的javac。另外定义为openjdk时,因为prebuilt/对应目录下没有相应的工具,所以还不可用。
依次一般忽略定义CUSTOM_JAVA_COMPILER,只要直接配置自己编译环境的path,指向使用的javac就可以了。

javac在linux平台的定义是
javac -J-Xmx512M -target 1.5 -Xmaxerrs 9999999

-J-Xmx512M,传递给vm launcher参数-Xmx512M,告知起始空间设定为512M。
-target 1.5,编译的结果适用1.5版本。
-Xmaxerrs 9999999,最大输出的错误数是9999999。

3. dumpvar.mk的分析


dumpvar.mk 支持两种target: dumpvar-<varName>,和dumpvar-abs-<varName>。envsetup.sh中的 get_build_var和get_abs_build_var就使用了这些target。

使用方法:假设位于$(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的变量也不适用。

4. cleanbuild.mk的分析


main.mk在包含了config.mk后,会包含进cleanbuild.mk。

定义了add-clean-step命令。有一个入口参数
$(1),执行删除操作的具体shell命令。
一般add-clean-step应当在%/cleanspec.mk脚本中使用,命令会为$(1)定义一个变量保存,变量的名字是INTERNAL_STEP.$(_acs_id),所有的$(_acs_id)保存在INTERNAL_STEPS中。$(_acs_id)的值分成3个部分构造
第一部分是有cleanspec.mk的路径转化而来,用'_'替代'/','-'替代'.',后缀_acs。第二部分是$(INTERNAL_CLEAN_BUILD_VERSION),默认是4,第三部分是有'@'组成,cleanspec.mk中的第几个add- clean-step就用几个@。
例如,packages/apps/Camera/cleanspec.mk中定义了两个删除动作
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/APPS/Camera*)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Camera*)
那么,对应的有
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*

接着,包扩进cleanspec.mk

包含进$(PRODUCT_OUT)/clean_steps.mk,

接下来,检查CURRENT_CLEAN_BUILD_VERSION是否与INTERNAL_CLEAN_BUILD_VERSION相同,默认是4
    如果相同,
        执行所有在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,看是否与当前的编译选项一致,不一致则标明上次的中间文件不可用,则删除相应的中间目录,或提示用户。接着重新将当前的信息写入$(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)

最后,定义了两个target, installclean和dataclean。
dataclean删除的主要是./$(PRODUCT_OUT)/data/*,
installclean的删除包括dataclean。installclean的本意是用于不同build_type编译时删除前次的中间文件。

总结cleanbuild.mk的内容,就3件事,一是载入所有的CleanSpec.mk,二是检查更新clean_steps.mk和previous_build_config.mk,避免不同编译间的互相干扰。最后是,定义installclean和dataclean。

5. cleanspec.mk的分析


首先定义
INTERNAL_CLEAN_BUILD_VERSION := 4

接着使用findleaves.py遍历所有子目录,找到CleanSpec.mk,并包含进。用户可以在CleanSpec.mk中定义自己需要的删除操作。实际上还可以包含不仅仅是删除的操作。

至此,INTERNAL_STEP.XXXX包含了所有CleanSpec.mk定义的clean动作。

6. version_checked.mk的分析


main.mk 在cleanbuild.mk后,会借助$(OUT_DIR)/version_checked.mk检查版本,如果版本不一致,则重新检查系统文件系统大小写敏感问题,路径上是否含有空格,java和javac的版本,没有问题,则更新version_checked.mk。

version_checked.mk中就定义了
VERSIONS_CHECKED := $(VERSION_CHECK_SEQUENCE_NUMBER)

7. showcommands和checkbuild的说明


checkbuild貌似并未使用。

showcommands必须同其它target一同使用,showcommands会详细打印出执行的具体命令内容。

8. definations.mk的说明


definations.mk中定义了大量的命令,其它的mk文件将使用。这其中包括执行编译链接的命令,通常是transform-XXX-to-XXX的形式,例如,transform-cpp-to-o。

其中的inherit-package命令有待研究...

Android Make脚本的简记(5)

1. Makefile的分析


首先定义target,用于生成$(OUT_DOCS)/index.html

再定义target,用于生成$(TARGET_ROOT_OUT)/default.prop

再定义target,用于生成$(TARGET_OUT)/build.prop。build.prop文件记录了一系列属性值。它的内容分成两部分,第一部分是一些关于 product,device,build的一般性属性值,第二部分的属性值源自ADDITIONAL_BUILD_PROPERTIES。 product配置mk文件中定义的PRODUCT_PROPERTY_OVERRIDES会加入到 ADDITIONAL_BUILD_PROPERTIES,建议增加property时,直接修改PRODUCT_PROPERTY_OVERRIDES。

再定义target,用于生成$(PRODUCT_OUT)/sdk/sdk-build.prop

再定义target,package-stats,用于生成$(PRODUCT_OUT)/package-stats.txt,这个文件包含了.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会抽取生成相应的声明文件。

随后,建立target,otacert,用于将.x509.pem后缀的认证文件打包存放到$(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

最后包含进 build/core/task/下的mk文件。

免责声明:文章转载自《Android系统编译【转】》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇区块链学习(4)交易(二)Linux C语言中gotoxy函数下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Oracle 通过触发器 来创建 同步临时表 及处理 通过 自治事务 来解决 查询 基表的问题

// 触发器 create or replace trigger tr_sync_BD_MARBASCLASS after INSERT or UPDATE on BD_MARBASCLASS for each row declare v_cnt integer; PRAGMA AUTONOMOUS_TRANSACTION; -- 自治事务...

FI常用BAPI(转)

总帐会计:  (比较简单全部测试通过,关帐时使用)      Line item of document for ledger with summary table GL   F: BAPI_GLX_GETDOCITEMS        Closing balance of G/L account for chosen year   F: BAPI_GL_...

阅读glibc源码

GNU C - Using GNU GCC __attribute__ mechanism 01  近来阅读glibc源码的时候遇到很多关于__attribute__的问题,索性就查找了相关的资料,学习了一下. 要是不解决了这个问题,有的时候还真的是比较难下手.就拿glibc来说,使用xcscope搜索POSIX pthread 函数: pthread...

Facebook Api 使用(PHP版)

如果想通过Facebook登录到你的网站,Facebook站外API可以实现你想要的,如下介绍实际使用. (我目前没在网上找到中文的更详细的介绍了,呵呵.) (提示:Facebook不支持取得朋友的邮件地址,如果需求是这个,别在浪费功夫了) 注册Facebook Key http://www.facebook.com/developers/apps.php...

关于stm32 HardFault_Handler 异常的处理 死机

在系统开发的时候,出现了HardFault_Handler硬件异常,也就是死机,尤其是对于调用了os的一系统,程序量大,检测堆栈溢出,以及数组溢出等,找了半天发现什么都没有的情况下,估计想死的心都有了。如果有些程序开始的时候一切没有问题,但是运行几个小时候,会发现死机了,搞个几天下来估计蛋都碎了一地吧。。。一般来说运行操作系统  是以下几个问题 1.开始的...

通知栏Notification的整理

一、介绍          通知栏适用于交互事件的通知,是位于顶层可以展开的通知列表。 二、功能作用   1.显示接收到短消息,及时消息等信息(如QQ、微信、新浪、短信)       2.显示客户端的推送消息(如有新版本发布,广告。推荐新闻等)   3.显示正在进行的事物(例如:后台运行的程序)(如音乐播放器、版本更新时候的下载进度等) 三、Notific...