背景: android 6.0 nxp imx6duallite
一、根目录下 Makefile 如下:
### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###
include 语言跟c语言一样,包含build/core/main.mk
二、接下来简要分析 build/core/main.mk
打开main.mk,G到最后一行,往上分析。可以看到很多编译目标,类似 .PHONY: modules
…
.PHONY: clean
…
其中在878行:
.PHONY: droidcore
droidcore: kernelimage \
kernelmodules \
bootloader \
files \
systemimage \
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_RECOVERY_TARGET) \
$(INSTALLED_USRTDATAIAGE_TARGET) \
$(INSTALLED_CACHEIMAGE_TARGET) \
$(INSTALLED_VERDORIMAGE_TARGET) \
$(INSTALLED_FILES_FILE) \
ubiimagesgenerate
可以看出,该编译目标为 android的核心编译目标。kernelimage即编译出的目标zImage,systemimage即编译出的system.img, $(INSTALLED_BOOTIMAGE_TARGET)为boot.img。搜索main.mk,查找不到目标的定义。那该定义就是在其他文件中。在main.mk的784行有一句:
include $(BUILD_SYSTEM)/Makefile
BUILD_SYSTEM的值为:
BUILD_SYSTEM := $(TOPDIR)build/core
$(TOPDIR)即为Android源码的根目录。所以从main.mk的784行那一句include 就把build/core/Makefile包含进去了。
- 接下来分析目标 kernelimage ⇒ {kernel, dtb}
打开build/core/Makefile,搜索kernelimage 的定义,如下:
.PHONY: kernelimage
ifneq ($(strip $(TARGET_NO_KERNEL)), true)
KERNEL_CROSS_TOOLCHAIN := `pwd`/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-
KERNEL_CFLAGS := KCFLAGS=-mno-android
KERNEL_ENV := ARCH=arm CROSS_COMPILE=$(KERNEL_CROSS_TOOLCHAIN) LOADADDR=$(LOAD_KERNEL_ENTRY) $(KERNEL_CFLAGS)
HOST_PROCESSOR := $(shell cat /proc/cpuinfo | grep processor | wc -l)
INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)kernel
TARGET_PREBUILT_KERNEL := $(PRODUCT_OUT)kernel
KERNEL_CONFIGURE := kernel_imx/.config
TARGET_KERNEL_CONFIGURE := $(PRODUCT_OUT)/.config
KERNEL_ZMAGE := kernel_imx/arch/arm/boot/zImage
KERNEL_OUT :=$(TARGET_OUT_INTERMEDIATES/KERNEL_OBJ
.PHONY: $(TARGET_PREBUILT_KERNEL)
kernel.image: $(TARGET_PREBUILT_KERNEL)
# 默认的内核配置文件
$(KERNEL_CONFIGURE): kernel_imx/arch/arm/configs/$(TARGET_KERNEL_DEFCONF)
# 配置内核
$(TARGET_KERNEL_CONFIGURE): kernel_imx/arch/arm/configs/$(TARGET_KERNEL_DEFCONF) $(KERNEL_CONFIGURE)
$(MAKE) -C kernel_imx $(TARGET_KERNEL_DEFCONF) $(KERNEL_ENV)
install -D $(KERNEL_CONFIGURE) $(TARGET_KERNEL_CONFIGURE)
# 编译uImage 和 dtb,并安装到指定的目录
$(TARGET_PREBUILT_KERNEL): $(TARGET_KERNEL_CONFIGURE)
$(MAKE) -C kernel_imx -j$(HOST_PROCESSOR) uImage $(KERNEL_ENV)
$(MAKE) -C kernel_imx dtbs $(KERNEL_ENV)
install -D $(KERNEL_ZIMAGE) $(PRODUCT_OUT)/kernel
for dtsplat in $(TARGET_BOARD_DTS_CONFIG); do \
DTS_PLATFORM=`echo $$dtsplat | cut -d':' -f1`; \
DTS_BOARD=`echo $$dtsplat | cut -d':' -f2`; \
install -D kernel_imx/arch/arm/boot/dts/$$DTS_BOARD $(PRODUCT_OUT)/$$DTS_BOARD; \
done
else
kernelimage:
endif
*整体过程就是配置交叉编译链,默认的配置文件,内核和设备树的输出目录和其他参数。这里用到了make 的 -C 参数,指定编译的源码路径编译。
2.接下来是 kernelmodules
.PHONY: kernelmodules
kernel_modules_src_list :=
kernel_modules_dist_list :=
$(foreach cf, $(TARGET_KERNEL_MODULES), \
$(eval _src := $(call word-colon,1,$(cf))) \
$(eval _dest := $(call word-colon,2,$(cf))) \
$(eval kernel_modules_src_list += $(_src)) \
$(eval kernel_modules_dest_list += $(call append-path, $(PRODUCT_OUT), $(_dest))))
ifneq ($(strip $(kernel_modules_src_list)),)
# 编译模块,并拷贝到指定的目录
kernelmodules: $(TARGET_PREBUILT_KERNEL) | $(ACP)
$(MAKE) -C kernel_imx modules $(KERNEL_ENV)
$(hide) $(foreach cf, $(TARGET_KERNEL_MODULES), \
$(eval _src := $(call word-colon,1,$(cf))) \
$(eval _dest := $(call word-colon,2,$(cf))) \
$(eval _full_dest := $(call append-path, $(PRODUCT_OUT), $(_dest))) \
$(eval _dest_dir := $(call dir, $(_full_dest)))
mkdir -p $(_dest_dir) \
$(ACP) $(_src) $(_full_dest); \
)
@echo "install kernel modules: $(kernel_modules_src_list)"
else
kernelmodules:
endif
3.目标 $(INSTALLED_BOOTIMAGE_TARGET) ==> boot.img
==> {kernel, dtb, ramdisk}
ifneq ($(strip $(TARGET_NO_KERNEL)), true)
# 编译boot.img的参数
INTERNAL_BOOTIMAGE_ARGS := \
$(addprefix --second , $(INSTALLED_2NDBOOTLOADER_TARGET)) \
--kernel $(INSTALLED_KERNEL_TARGET)
# ramdisk 参数
ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE), true)
INTERNAL_BOOTIMAGE_ARGS += --ramdisk $(INSTALLED_RAMDISK_TARGET)
endif
INTERNAL_BOOTIMAGE_FILLES := $(filter-out --%, $(INTERNAL_BOOTIMAGE_ARGS))
# cmdline 参数
BOARD_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE))
ifdef BOARD_KERNEL_CMDLINE
INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"
endif
# base ?
BOARD_KERNEL_BASE := $(strip $(BOARD_KERNEL_BASE))
ifdef BOARD_KERNEL_BASE
INTERNAL_BOOTIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)
endif
# 页大小的参数
BOARD_KERNEL_PAGESIZE := $(strip $(BOARD_KERNEL_PAGESIZE))
ifdef BOARD_KERNEL_PAGESIZE
INTERNAL_BOOTIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)
endif
# 生成目标的完整路径文件名
INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)
$(error TARGET_BOOTIMAGE_USE_EXT2 is not supports anymore)
else ifeq (true, $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_BOOT_SIGNER))
# 此处省略部分源码 本平台没用到
.....
else ifeq (true, $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT))
# 此处省略部分源码 本平台没用到
.....
else
$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES)
$(call pretty, "Target boot image: $@")
for dtsplat in $(TARGET_BOARD_DTS_CONFIG); do \
DTS_PLATFORM=`echo $$dtsplat | cut =d':' -f1`; \
DTS_BOARD=`echo $$dtsplat | cut =d':' -f2`; \
BOOT_IMAGE_BOATD=$(patsubst %.img,%-$$DTS_PLATFORM.img,$@); \
$(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) --second $(PRODUCT_OUT)/$$DTS_BOARD $(BOARD_MKBOOTIMG_ARGS) --output $@; \
cp -f $@ $$BOOT_IMGAE_BOARD; \
done
.PHONY: bootimage-nodeps
bootimage-nodeps: $(MKBOOTIMG)
@echo "make $@: ignoring dependencies"
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
$(hide) $(call assert-max-image-size, $(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
endif
- ramdisk 是如何生成的? 跟踪 $(INSTALLED_BOOTIMAGE_TARGET)的依赖 $(INTERNAL_BOOTIMAGE_FILES)
$(INTERNAL_BOOTIMAGE_FILES) := $(filter-out --%, $(INTERNAL_BOOTIMAGE_ARGS))
然后有一句:
$(INTERNAL_BOOTIMAGE_ARGS) += --ramdisk $(INSTALLED_RAMDISK_TARGET)
所以 $(INSTALLED_RAMDISK_TARGET)会生成ramdisk。
INTERNAL_RAMDISK_FILES := $(filter $(TARGET_ROOT_OUT)/%, \
$(ALL_PREBUILT) \
$(ALL_COPIED_HEADERS) \
$(ALL_GENERATED_SOURCES) \
$(ALL_DEFAULT_INSTALLED_MODULES))
BUILT_RAMDISK_TARGET := $(PRODUCT_OUT)/ramdisk.img
INSTALLED_RAMDISK_TARGET := $(BUILT_RAMDISK_TARGET)
$(INSTALLED_RAMDISK_TARGET): $(MKBOOTFS) $(INTERNAL_RAMDISK_FILES) | $(MINIGZIP)
$(call pretty, "Target ram disk: $@")
$(hide) $(MKBOOTFS) -d $(TARGET_OUT) $(TARGET_ROOT_OUT) | $(MINIGZIP) > $(INSTALLED_RAMDISK_TARGET)
5.目标 bootloader, 即uboot的生成规则。
bootloader的生成规则相对比较简单,配置好交叉编译器,通过make **defconfig 配置源码,然后 make 就可以,接下来看Makefile:
build/core/main.mk的默认目标droidcore中包含了 bootloader目标,bootloader目标在build/core/Makefile中有定义:
.PHONY: bootloader
ifneq ($(strip $(TARGET_BOOTLOADER_CONFIG)),)
BOOTLOADER_CROSS_TOOLCHAIN := `pwd`/prebuilts/gcc/linux-x86/arm/arm-linux-androideaib-4.9/bin/arm-linux
BOOTLOADER_ENV := ARCH=arm CROSS_COMPILE=$(BOOTLOADER_CROSS_TOOLCHAIN)
HOST_PROCESSOR := $(shell cat /proc/cpuinfo | grep processor | wc -l)
TARGET_BOOTLODAER_IMAGE := $(PRODUCT_OUT)/u-boot.imx
BOOTLOADER_PATH := bootable/bootloader/uboot/
bootloader: $(TARGET_BOOTLOADER_IMAGE)
.PHONY $(TARGET_BOOTLOADER_IMAGE)
$(TARGET_BOOTLOADER_IMAGE):
for ubootplat in $(TARGET_BOOTLOADER_CONFIG); do \
UBOOT_PLATFORM=`echo $$ubootplat | cut -d':' -f1`; \
UBOOT_CONFIG=`echo $$ubootplat | cut -d':' -f2`; \
$(MAKE) -C $(BOOTLOADER_PATH) distclean $(BOOTLOADER_ENV); \
$(MAKE) -C $(BOOTLOADER_PATH) $$UBOOT_CONFIG $(BOOTLOADER_ENV); \
$(MAKE) -C $(BOOTLOADER_PATH) $(BOOTLOADER_ENV); \
install -D $(BOOTLOADER_PATH)/u-boot.imx $(PRODUCT_OUT)/u-boot-$$UBOOT_PLATFORM.imx; \
install -D $(BOOTLOADER_PATH)/u-boot.imx $@; \
done
else
bootloader:
endif