Bootstrap

Android构建系统 - 03 编译执行流程

执行编译

Linux内核编译

不同产品的硬件配置,生产商,型号都可能不一样。这就涉及到了内核驱动的移植。

其他地方讨论的编译流程都只针对Android系统本身。

但是,Linux内核和Android的编译都是独立的

对于设备开发商来说,还要 下载,修改,编译 内核版本。

make编译系统

Android 编译命令 - 狼太白 - 博客园 (cnblogs.com)

Android 编译系统是Android源码的一部分,用于编译Android系统,Android SDK以及相关文档。该编译系统是由Make文件、Shell以及Python脚本共同组成,其中最为重要的便是Make文件。关于编译系统可参考 理解 Android Build 系统

选择编译命令 make m …

source build/envsetup.sh命令执行成功后,我们会得到了一些有用的命令,比如

make、m、mm、mmm

对于m、mm、mmm、mma、mmma这些命令的实现都是通过make方式来完成的。

  • make/mma/mmma编译时会把所有的依赖模块一同编译,但mmm/mm不会;

    • mmm/mm编译的效率很高,而make/mma/mmma编译较缓慢;
    • 建议:首次编译时采用make/mma/mmma编译;当依赖模块已经编译过的情况,则使用mmm/mm编译。
  • m: Makes from the top of the tree.

  • mm: Builds all of the modules in the current directory.

  • mmm: Builds all of the modules in the supplied directories.

make

make指令——开始编译整个系统

该指令通过-j参数来设置参与编译的线程数量,以提高编译速度。

  • -j参数 取决于开发机器的CPU数,每颗CPU的核心数,每个核心的线程数。
  • 通常根据cup的核心来确定:core*2,即当前cpu的核心的2倍。
# 查看相关cpu信息
cat /proc/cpuinfo
# 双核四线程的,根据公式。最快速的编译可以make -j8.
make -j8
m mm mma …

除了通过make命令编译可以整个android源码外,

Google也为我们提供了相应的命令来支持单独模块的编译.

编译指令解释
m在源码树的根目录执行make编译
mmmake编译当前路径下所有模块,但不包含依赖
mmm [module_path]make编译指定路径下所有模块,但不包含依赖
mmamake编译当前路径下所有模块,且包含依赖
mmma [module_path]make编译指定路径下所有模块,且包含依赖
make [module_name]无参数,则表示编译整个Android代码

下面列举部分模块的编译指令:

模块make命令mmm命令
initmake initmmm system/core/init
zygotemake app_processmmm frameworks/base/cmds/app_process
system_servermake servicesmmm frameworks/base/services
java frameworkmake frameworkmmm frameworks/base
framework资源make framework-resmmm frameworks/base/core/res
jni frameworkmake libandroid_runtimemmm frameworks/base/core/jni
bindermake libbindermmm frameworks/native/libs/binder
其他命令
代码搜索
搜索指令解释
croot回到树的根位置,AOSP工程的根目录
cgrep所有C/C++文件执行搜索操作
jgrep所有Java文件执行搜索操作
ggrep所有Gradle文件执行搜索操作
mangrep [keyword]所有AndroidManifest.xml文件执行搜索操作
mgrep [keyword]所有Android.mk文件执行搜索操作
sepgrep [keyword]所有sepolicy文件执行搜索操作
resgrep [keyword]所有本地res/*.xml文件执行搜索操作
sgrep [keyword]所有资源文件执行搜索操作
godir转到包含指定文件的目录下
导航指令
导航指令解释
croot切换至Android根目录
cproj切换至工程的根目录
godir [filename]跳转到包含某个文件的目录

Tips:

当每次修改完某个文件后需要编译时,

  • 修改文件
  • 执行cproj后会跳转到当前模块的根目录,也就是Android.mk文件所在目录,
  • 执行mm指令,即可编译目标模块;

当进入源码层级很深后,需要返回到根目录,

  • 使用croot一条指令完成;
make clean/update-api

再列举两个比较常用的指令:

  • make clean:执行清理操作,等价于 rm -rf out/
  • make update-api:更新API,在framework API改动后需执行该指令,Api记录在目录frameworks/base/api

Makefile分类

整个Build系统的Make文件分为三大类:

系统核心的Make文件:

  • 文件全部位于路径/build/core
  • 定义了Build系统的框架,
  • 其他Make文件都是基于该框架编写的;

针对产品的Make文件:

  • 文件路径位于/device

  • 定义了具体某个型号手机的Make文件,

  • 该目录下往往又以公司名和产品名划分两个子级目录,

    比如/device/qcom/msm8916

针对模块的Make文件:模块编译

  • 用于编译某个模块的标准。

  • 整个系统分为各个独立的模块

    整个产品由很多Android.mk生产出的“零件”组合而成。

  • 每个模块都一个专门的Make文件,名称统一为”Android.mk”,该文件定义了当前模块的编译方式。

  • Build系统会扫描整个源码树中名为”Android.mk”的问题,并执行相应模块的编译工作。

解析过程

典型的解析过程:

  1. 变量赋值,环境检测等初始化操作
  2. 按照规则生成所有依赖树
  3. 根据被用户选择的依赖树,从叶到根逐步生成目标文件
树根节点 droid
/Makefile

make命令对依赖树的根节点是:droid

编译系统中往往不止一颗依赖树存在。

  • 显示指定编译目标——make sdk
    • 指定部分编译目标后,对ONE_SHOT_MAKEFILE进行赋值(否则为空)
  • 没有显示指定——不带任何参数的make
    • 第一个符合要求的目标,会被Make作为默认的依赖树根节点
    • 在Makefile中,一定要注意各Target的排放顺序
make	# make命令 执行根目录下的Makefile文件
# 默认的找名为`GNUmakefile`、`makefile`、`Makefile`的文件
./Makefile
### DO NOT EDIT THIS FILE ###
include build/make/core/main.mk
### DO NOT EDIT THIS FILE ###
main.mk

/sm8350_r_13300_dev_i7/build/core/main.mk

# This is the default target.  It must be the first declared target.
.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL): droid_targets
droid
  • 这里的droid是一个空的 “规则”,相当于预先占个地方

  • 真正的定义在main.mk的其他地方,

  • 根据TARGET_BUILD_APPS值的不同,出现了两个分支

      # Some modules produce only host installed files when building with TARGET_BUILD_APPS
      ifeq ($(TARGET_BUILD_APPS),)
    
    • 编译整个系统
      • 依赖 droidcore——后续介绍
      • 依赖 dist_files——在out目录下产生专门的dist文件夹,存储多种分发包
    # Building a full system-- the default is to build droidcore
    droid_targets: droidcore dist_files
    
    • 只依赖apps_only
    apps_only: $(unbundled_build_modules)
    
    droid_targets: apps_only
    
droidcore节点

在编译整个Android系统的情况下,droid依赖于droidcore,dist_files。

  • droidcore负责生成系统的所有可运行程序包

    包括以下 img 文件

# Build files and then package it into the rom formats
.PHONY: droidcore
droidcore: $(filter $(HOST_OUT_ROOT)/%,$(modules_to_install)) \
    $(INSTALLED_SYSTEMIMAGE_TARGET) \
    $(INSTALLED_RAMDISK_TARGET) \
    $(INSTALLED_BOOTIMAGE_TARGET) \
    $(INSTALLED_RADIOIMAGE_TARGET) \
    $(INSTALLED_DEBUG_RAMDISK_TARGET) \
    $(INSTALLED_DEBUG_BOOTIMAGE_TARGET) \
    $(INSTALLED_RECOVERYIMAGE_TARGET) \
    # ...
.img

$(INSTALLED_SYSTEMIMAGE_TARGET) 生成 system.img

$(INSTALLED_BOOTIMAGE_TARGET) 生成 boot.img

$(INSTALLED_RECOVERYIMAGE_TARGET) 生成 recovery.img

$(INSTALLED_USERDATAIMAGE_TARGET) 生成 userdata.img

$(INSTALLED_CACHEIMAGE_TARGET) 生成 cache.img

$(INSTALLED_VENDORIMAGE_TARGET) 生成 vendor.imb

$(INSTALLED_FILES_FILE) 生成 installed-files.txt,记录当前系统中预装的程序、库等

files

描述了系统需要安装的模块

# All the droid stuff, in directories
.PHONY: files
files: $(modules_to_install) \
       $(INSTALLED_ANDROID_INFO_TXT_TARGET)
modules_to_install

描述了系统需要安装的模块

# TODO: Remove the 3 places in the tree that use ALL_DEFAULT_INSTALLED_MODULES
# and get rid of it from this list.
modules_to_install := $(sort \
    $(ALL_DEFAULT_INSTALLED_MODULES) \
    $(product_target_FILES) \
    $(product_host_FILES) \
    $(CUSTOM_MODULES) \
  )
INSTALLED_ANDROID_INFO_TXT_TARGET

vendor编译

product.mk

之前内容请看 Android编译–>定制产品

板级特性 AndroidProducts.mk中,通过PRODUCT_MAKEFILES来指定商品的属性的makefile

envsetup.sh::source_vendorsetup # 执行扫描到的 vendorsetup.sh 们
	build/soong/ui/build/finder.go # 找到 AndroidProducts.mk
        # 添加到选单, 为lunch命令添加一条加载项
        AndroidProducts.mk::COMMON_LUNCH_CHOICES
        # 引入产品makefile
        AndroidProducts.mk::PRODUCT_MAKEFILES
            lahaina.mk
            pineapple.mk
                pixelworks_iris.mk

AndroidProducts.mk::PRODUCT_MAKEFILES 添加 lahaina.mk

在 lahaina.mk 中,pixelworks_iris.mk被引入编译。

pixelworks_iris.mk设置了BOARD_HAS_PXLW_IRIS

# device/qcom/lahaina/lahaina.mk
-include vendor/pixelworks/libirisservice/config/pixelworks_iris.mk
# vendor/pixelworks/libirisservice/config/pixelworks_iris.mk
BOARD_HAS_PXLW_IRIS := true

具体内容看下一大章。

pixelworks_iris.mk

在这里从pixelworks_iris.mk 开始说起。

vendor/pixelworks/libirisservice/config/
	pixelworks_iris.mk

同目录下还有很多其他 xxx_pixelworks_iris_xxx.mk。它们都是类似的

vendor/pixelworks/libirisservice/
	config/

这里的宏会在其他仓库中被使用。

BOARD_HAS_PXLW_IRIS
# Comment this line to disable pixelworks iris
BOARD_HAS_PXLW_IRIS := true

表明:当前平台,是否装配了 IRIS 芯片。

以此来判别,当前平台是否具有IRIS能力。

PXLW
PXLW_IRIS_CHIP_TYPE
# This is compile option for Static Compatibility. Should be: iris5, iris7
PXLW_IRIS_CHIP_TYPE := iris7

静态兼容,使用该宏确定 IRIS版本

PXLW_HDK_ONLY
# PWLOG is debug feature for PW HDK, no need porting to customer side
# Copy Qualcomm QDCM files for PW HDK, no need porting to customer side
PXLW_HDK_ONLY := true

用于区分代码是否需要porting给客户的宏。

PXLW_AIDL_SUPPORT
# Enable IIris AIDL and IIrisFeature AIDL
PXLW_AIDL_SUPPORT := false

IIrisIIrisFeature,使用AIDL还是HIDL

PXLW_IRIS_SERVICE_PASSTHROUGH
PXLW_IRIS_SERVICE_PASSTHROUGH := 1
IRIS_BSP_PLATFORM
IRIS_BSP_PLATFORM := QCOM_DRM

IRIS_BSP_PLATFORM := MTK_DRM

当前平台,体现在IrisIoctlWrapper.cpp中,

Soong namespace

PRODUCT_SOONG_NAMESPACES

添加两个Soong命名空间

PRODUCT_SOONG_NAMESPACES += vendor/pixelworks/libirisservice
PRODUCT_SOONG_NAMESPACES += vendor/pixelworks/libpwirishalwrapper

意味着,分析,有两个入口。

接下来就是 Android.bp 的世界了。

PRODUCT_PACKAGES

vendor partition

# vendor partition
PRODUCT_PACKAGES += [email protected]
PRODUCT_PACKAGES += libpwirisfeature
ifeq ($(PXLW_AIDL_SUPPORT), true)
PRODUCT_PACKAGES += vendor.pixelworks.hardware.display-V1-ndk
PRODUCT_PACKAGES += vendor.pixelworks.hardware.feature-V1-ndk
endif

vendor/odm partition

# vendor/odm partition
ifeq ($(PXLW_AIDL_SUPPORT), true)
PRODUCT_PACKAGES += vendor.pixelworks.hardware.display-impl-i7
else
PRODUCT_PACKAGES += [email protected]
endif
PRODUCT_PACKAGES += irisConfig irisdbgd irisdbgc
PRODUCT_PACKAGES += libpwirispq \
        libpwirisPCS
文件copy

略过一些隐私信息。

Soong
Soong Namespcae
# Soong Namespace
SOONG_CONFIG_NAMESPACES += pxlw_iris
Soong Keys
# Soong Keys
SOONG_CONFIG_pxlw_iris := enable_iris enable_iris_dual enable_hidl enable_aidl

声明。

Soong Values
# Soong Values
SOONG_CONFIG_pxlw_iris_enable_iris := true
SOONG_CONFIG_pxlw_iris_enable_iris_dual := true
ifeq ($(PXLW_AIDL_SUPPORT), true)
SOONG_CONFIG_pxlw_iris_enable_aidl := true
SOONG_CONFIG_pxlw_iris_enable_hidl := false
else
SOONG_CONFIG_pxlw_iris_enable_aidl := false
SOONG_CONFIG_pxlw_iris_enable_hidl := true
endif

BoardConfig.mk

用于填写目标架构,硬件设备属性,编译器的条件标志,分布布局,boot地址,ramdisk等一系列参数。

  • 硬件特性,底层变量
  • 板级特性 CPU,WIFI,Bootloader etc
device/qcom/lahaina/BoardConfig.mk

很多变量以TARGET_BOARD_开头。

# config.mk
#
# Product-specific compile-time definitions.
#
# TODO(b/124534788): Temporarily allow eng and debug LOCAL_MODULE_TAGS

BOARD_SYSTEMSDK_VERSIONS := 30

TARGET_BOARD_PLATFORM := lahaina
TARGET_BOOTLOADER_BOARD_NAME := lahaina

TARGET_ARCH := arm64
TARGET_ARCH_VARIANT := armv8-a
TARGET_CPU_ABI := arm64-v8a
TARGET_CPU_ABI2 :=
TARGET_CPU_VARIANT := kryo300

DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE

base.mk
device/qcom/vendor-common/base.mk
DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE := vendor/qcom/opensource/core-utils/vendor_framework_compatibility_matrix.xml
#if defined(PXLW_IRIS)
ifeq ($(BOARD_HAS_PXLW_IRIS), true)
DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE += vendor/pixelworks/interfaces/vendor_framework_compatibility_matrix.xml
endif
#endif /* defined(PXLW_IRIS) */
qssi.mk
device\qcom\qssi\qssi.mk
#if defined(PXLW_IRIS)
-include vendor/pixelworks/libirisservice/config/pixelworks_iris.mk
ifeq ($(BOARD_HAS_PXLW_IRIS), true)
DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE += vendor/pixelworks/interfaces/vendor_framework_compatibility_matrix.xml
endif
#endif /* defined(PXLW_IRIS) */

;