Android 编译

1、Android 内核编译

/项目/ap/

source build/envsetup.sh 
lunch msm8953-userdebug     
make update-api
make / make -j32 2>&1 |tee xxx.log

1、将envsetup.sh里的所有用到的命令加载到环境变量里
2、envsetup.sh里有很多命令,其主要作用如下:
   - 加载了编译时使用到的函数命令,如:help,lunch,m,mm,mmm等
   - 添加了两个编译选项:generic-eng和simulator,这两个选项是系统默认选项
   - 查找vendor/<-厂商目录>/和vendor/<厂商目录>/build/目录下的vendorsetup.sh,如果存在的话,加载执行它,添加厂商自己定义产品的编译选项
3、lunch命令是envsetup.sh里定义的一个命令,用来让用户选择编译项,来定义Product和编译过程中用到的全局变量
4、更新api,上层更新后会更新
5、编译整个内核或者某部分镜像 32线程 错误输出重定向到标准输出 输出 到xxx.log

envsetup.sh里到底是什么

2、Android app编译

/项目/ap/vendor/

1、新建目录,里面放入测试的源文件和一个Android.mk文件
2、到目录下使用 `mm` 命令(之前需source、lunch)

Android.mk里到底是什么

3、Android 编译流程

以boot.img为例
make bootimage这个命令其实是由两部分组成,make这个指令是编译器定义的指令,bootimage的target定义在build/core/main.mk中,main.mk中还包含了Makefile和其他重要的mk文件:

BUILD_SYSTEM := $(TOPDIR)build/core
...
include $(BUILD_SYSTEM)/Makefile
...
.PHONY: bootimage
bootimage: $(INSTALLED_BOOTIMAGE_TARGET)
...

INSTALLED_BOOTIMAGE_TARGET和它的依赖项就定义在Makefile中:

INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
...
$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES) $(BOOT_SIGNER)
	$(call pretty,"Target1 boot image: $@")
	$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
	$(BOOT_SIGNER) /boot $@ $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).pk8 \
$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).x509.pem $@
	$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))

$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
是关键的编译语句,使用$(MKBOOTIMG)工具,针对INTERNAL_BOOTIMAGE_ARGS来生成 bootimage。
INTERNAL_BOOTIMAGE_ARGS这个编译的参数也是定义在Makefile中:

# the boot image, which is a collection of other images.
INTERNAL_BOOTIMAGE_ARGS := \
	$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
	--kernel $(INSTALLED_KERNEL_TARGET)
ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
INTERNAL_BOOTIMAGE_ARGS += --ramdisk $(INSTALLED_RAMDISK_TARGET)
endif
INTERNAL_BOOTIMAGE_FILES := $(filter-out --%,$(INTERNAL_BOOTIMAGE_ARGS))
ifdef BOARD_KERNEL_BASE
  INTERNAL_BOOTIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)
endif
ifdef BOARD_KERNEL_PAGESIZE
  INTERNAL_BOOTIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)
endif
ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),true)
ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
VERITY_KEYID := veritykeyid=id:`openssl x509 -in $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).x509.pem -text \
                | grep keyid | sed 's/://g' | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/keyid//g'`
endif
endif
INTERNAL_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE) buildvariant=$(TARGET_BUILD_VARIANT) $(VERITY_KEYID))
ifdef INTERNAL_KERNEL_CMDLINE
INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(INTERNAL_KERNEL_CMDLINE)"
endif

可以看到我们编译的bootimage包含了几个image:kernel、ramdisk、cmdline、pagesize。我们看其中的kernel的target为INSTALLED_KERNEL_TARGET,也定义在本文件中:

INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel

要编译INSTALLED_KERNEL_TARGET目标就要有依赖关系,此处寻找依赖关系有些复杂,首先找到相关文件,main.mk文件会搜索并include所有子目录下的Android.mk文件,因此 build/target/board/Android.mk也已经被main.mk所引用

-include $(TARGET_DEVICE_DIR)/AndroidBoard.mk //include时遇到错误也不会中断

其中TARGET_DEVICE_DIR定义在build\core\envsetup.mk

TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
...
# Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
# or under vendor/*/$(TARGET_DEVICE).  Search in both places, but
# make sure only one exists.
# Real boards should always be associated with an OEM vendor.
board_config_mk := \
	$(strip $(sort $(wildcard \
		$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
		$(shell test -d device && find -L device -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \
		$(shell test -d vendor && find -L vendor -maxdepth 4 -path '*/$(TARGET_DEVICE)/BoardConfig.mk') \
	)))

上边这一段脚本会在device,vendor文件夹下寻找在当前项目名文件夹下包含的BoardConfig.mk。
而我们需要的INSTALLED_KERNEL_TARGET的依赖关系也就定义在这里

$(INSTALLED_KERNEL_TARGET): $(TARGET_PREBUILT_KERNEL) | $(ACP)
	$(transform-prebuilt-to-target)

本文件中包含kernel/ANdroidKernel.mk

ifeq ($(TARGET_KERNEL_SOURCE),)
     TARGET_KERNEL_SOURCE := kernel
endif
include $(TARGET_KERNEL_SOURCE)/AndroidKernel.mk

TARGET_PREBUILT_KERNE的依赖关系在之中:

TARGET_PREBUILT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)
ifeq ($(TARGET_USES_UNCOMPRESSED_KERNEL),true)
$(info Using uncompressed kernel)
TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/Image
else
ifeq ($(KERNEL_ARCH),arm64)
TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/Image.gz
else
TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/zImage
endif

AndroidKernel.mk中执行make编译命令就会调用到kernel目录下的Makefile文件

$(KERNEL_OUT):
	mkdir -p $(KERNEL_OUT)
$(KERNEL_CONFIG): $(KERNEL_OUT)
	$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG)
	$(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \
			echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \
			echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \
			$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi

原文链接

posted @ 2021-12-23 14:57  月的光景  阅读(441)  评论(0)    收藏  举报