Android 系统编译
一、流程
根目录下的Makefile--->build/core/main.mk---->build/core/Makefile
1.1 根目录下的Makefile
1 2 3 | ### DO NOT EDIT THIS FILE ### include build/core/main.mk ### DO NOT EDIT THIS FILE ### |
1.2 main.mk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | .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 include $(BUILD_SYSTEM)/Makefile BUILD_SYSTEM := $(TOPDIR)build/core |
可以看出,该编译目标为 android的核心编译目标。kernelimage即编译出的目标zImage,systemimage即编译出的system.img。
$(TOPDIR)即为Android源码的根目录。所以就把build/core/Makefile包含进去了。
1.3 build/core/Makefile
这个文件里定义了上文所有的目标
1.3.1 接下来分析目标 kernelimage ⇒ {kernel, dtb}
定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | .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 参数,指定编译的源码路径编译。
1.3.2 kernelmodules
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | .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 |
1.3.3 目标 $(INSTALLED_BOOTIMAGE_TARGET) ==> boot.img
==> {kernel, dtb, ramdisk}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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 |
1.3.4 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。
1 2 3 4 5 6 7 8 9 10 11 12 | 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) |
1.3.5 目标 bootloader
即uboot的生成规则。
bootloader的生成规则相对比较简单,配置好交叉编译器,通过make **defconfig 配置源码,然后 make 就可以,接下来看Makefile:
build/core/main.mk的默认目标droidcore中包含了 bootloader目标,bootloader目标在build/core/Makefile中有定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | .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 |
二、编译运用
2.1 单独编译
我们要单独编译的时候,就可以在build 目录下搜索:grep -r "PHONY:" -n
这样就可以列出所有目标的定义。比如:.PHONY: recoveryimage
我就可以通过 make recoveryimage 来编译recovery.img,同时也可以查看recovery.img 在生成时要依赖哪些?编译过程是什么等?
2.2 lk的编译
我们通过上面的方式,找不到lk的定义,但是我们又可以通过make lk 来进行编译lk.bin呢?
因为,lk 这种不属于AOSP 的范畴了,所有它的定义是在:vendor/mediatek/proprietary/bootable/bootloader/lk/Android.mk
1 2 | 44 .PHONY: lk check-lk-config check-mtk-config include $(LOCAL_PATH)/build_lk.mk |
需要在不同的平台下去找,Android 编译的时候会扫描mk文件,从而将lk 的目标添加到系统,这样我们就可以通过make lk的方式来编译lk 了。
参考连接:https://blog.csdn.net/qq_29897125/article/details/108880883
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
2023-04-28 Python模块之struct
2023-04-28 为程序添加日志