转载请注明出处:http://blog.csdn.net/droyon/article/details/8639773
最近在读android内核剖析,将一些心得记录下来,方便自己查阅。
在android源代码文件夹下存在build文件夹,,他下面的文件构成了编译系统,该目录下的make脚本和shell脚本共同组成了Androd的编译环境。
在我们编译系统时,我们一般先执行:
. build/envsetup.sh makemake后面可以跟上参数,参数包括:产品名,模块名,sdk。
make 后面无论跟的是产品名还是模块名,那么首先编译系统要认识。产品和模块名如何要让android系统认识,是在android编译系统定义的,以及输出路径out(out下有两个目录,target是最终的输出目标,host是在编译sdk,或者cts时,生成的供pc使用的一些工具)目录的指定。android编译系统实现在build文件夹下,那里存放了一系列的*.mk文件。每个子项目目录下都有Android.mk,在文件中定义了子项目要生成的目标文件,是apk还是jar包。
1、关于Android.mk的语法:
LOCAL_PATH:指定了子项目的绝对路径,一般通过编译系统中定义的call-dir获取。
LOCAL_PATH:= $(call my-dir)LOCAL_MOKULE_TAGS:指定子项目的标签,标签包括:user、eng、userdebug、optional。
LOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES:指定子项目所包含的所有源文件。可以通过函数获得,如下所示。
LOCAL_SRC_FILES := $(call all-java-files-under, src) \ src/com/android/music/IMediaPlaybackService.aidlLOCAL_PACKAGE_NAME:指定项目名称,这个名称就是子项目名。对于c++项目使用LOCAL_MODULE。
LOCAL_PACKAGE_NAME := Music
LOCAL_MODULE:= reference-rilBUILE_PACKAGE:代表编译生成apk,还有BUILE_HOST_EXECUTABLE,BUILE_HOST_STATIC_LIBRARY
2、build编译系统文件加载顺序
执行make命令,会加载根目录中的Makefile,在这个文件中,会加载buile/core/main.mk,在这个文件中定义了,make命令不跟参数,所执行的情况。
.PHONY: droid DEFAULT_GOAL := droid $(DEFAULT_GOAL):在执行main.mk过程中,会包含build/core/config.mk,在这个文件中,定义了一系列路径变量:
SRC_HEADERS := \ $(TOPDIR)system/core/include \ $(TOPDIR)hardware/libhardware/include \ $(TOPDIR)hardware/libhardware_legacy/include \ $(TOPDIR)hardware/ril/include \ $(TOPDIR)dalvik/libnativehelper/include \ $(TOPDIR)frameworks/base/include \ $(TOPDIR)frameworks/base/opengl/include \ $(TOPDIR)frameworks/base/native/include \ $(TOPDIR)external/skia/include SRC_HOST_HEADERS:=$(TOPDIR)tools/include SRC_LIBRARIES:= $(TOPDIR)libs SRC_SERVERS:= $(TOPDIR)servers SRC_TARGET_DIR := $(TOPDIR)build/target SRC_API_DIR := $(TOPDIR)frameworks/base/api在config.mk文件中会包含pathmap.mk文件,在这个文件中也会定义一系列的framework层常量,很重要,在后面会引用
FRAMEWORKS_BASE_SUBDIRS := \ $(addsuffix /java, \ core \ graphics \ location \ media \ drm \ opengl \ sax \ telephony \ wifi \ keystore \ icu4j \ voip \ )
FRAMEWORKS_BASE_JAVA_SRC_DIRS := \ $(addprefix frameworks/base/,$(FRAMEWORKS_BASE_SUBDIRS))等,这个常量定义了编译到framework.jar的源文件目录,如果你修改了android framework层的代码,新建了目录,如果目录不再第一段代码中,那么可能编译不到framework.jar中。
然后继续config.mk的执行。然后config.mk会定义一系列的编译宏,在Android.mk中最后使用的那个命令include $(BUILD_PACKAGE)
BUILD_COMBOS:= $(BUILD_SYSTEM)/combo CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.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_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_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_PACKAGE,代表编译源文件成为apk。
再往下config.mk文件包含buildspec.mk在这个文件中会定义我们要编译的产品的名字。(如有错误请指正)文件路径为:根目录/buildspec.mk
再往下cofig.mk文件会包含envsetup.mk,主要是环境的配置,例如apk安装路径常量,设置目标输出路径。
OUT_DIR := $(TOPDIR)out
TARGET_SYSLOADER_SYSTEM_OUT := $(TARGET_SYSLOADER_OUT)/root/system TARGET_INSTALLER_OUT := $(PRODUCT_OUT)/installer TARGET_INSTALLER_DATA_OUT := $(TARGET_INSTALLER_OUT)/data
其中会包含product_config.mk文件,在这个文件中,它会包含product.mk文件,在product.mk文件中,会检测device 、verndor、build/target/product目录下所有的AndroidProduct.mk文件。
define _find-android-products-files $(shell test -d device && find device -maxdepth 6 -name AndroidProducts.mk) \ $(shell test -d vendor && find vendor -maxdepth 6 -name AndroidProducts.mk) \ $(SRC_TARGET_DIR)/product/AndroidProducts.mk endef文件目录深度为6级。
然后在product_config.mk文件中,调用自身函数将product加入进来。
ifneq ($(strip $(TARGET_BUILD_APPS)),) # An unbundled app build needs only the core product makefiles. $(call import-products,$(call get-product-makefiles,\ $(SRC_TARGET_DIR)/product/AndroidProducts.mk)) else # Read in all of the product definitions specified by the AndroidProducts.mk # files in the tree. # #TODO: when we start allowing direct pointers to product files, # guarantee that they're in this list. $(call import-products, $(get-all-product-makefiles)) endif # TARGET_BUILD_APPS到这里product_config.mk结束,继续config.mk文件的执行,也就是上面所的设置环境变量,设置OUT_DIR := $(TOPDIR)out,等。
这样envsetup.mk文件就执行结束了。继续执行config.mk文件,再往下config.mk文件会加载每一个product下的BoardConfig.mk文件。
board_config_mk := \ $(strip $(wildcard \ $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \ device/*/$(TARGET_DEVICE)/BoardConfig.mk \ vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \ )) ifeq ($(board_config_mk),) $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE)) endif ifneq ($(words $(board_config_mk)),1) $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk)) endif include $(board_config_mkBoardCOnfig.mk会加载一些属性,这些属性会加入到系统属性中。
最后config.mk文件会设置工具命令宏。
AAPT := $(HOST_OUT_EXECUTABLES)/aapt$(HOST_EXECUTABLE_SUFFIX)config.mk文件就执行结束了。
继续main.mk文件的执行。接下来检查编译系统,是linux还是window以及苹果 Darwin等,以及检查openJDK的版本等。
在然后,加载definations.mk加载各种函数,包括我们在Android.mk中使用的my-dir。
define my-dir