1. 编译命令
source build/envsetup.sh
lunch aosp_car_arm64-userdebug
make
2. 编译流程
source build/envsetup.sh
- 定义一些函数的环境变量,如 lunch
- validate_current_shell,确认 shell 环境
- set_global_paths,设置环境变量 ANDROID_GLOBAL_BUILD_PATHS
- source_vendorsetup,从 device vendor product 等目录遍历搜索 vendorsetup.sh(添加厂商自己定义的产品编译选项),并 source 进来
- addcompletions,为一些命令添加自动补全功能
lunch aosp_car_arm64-userdebug
- lunch,设置 TARGET_PRODUCT、TARGET_BUILD_VARIANT、PLATFORM_VERSION 等,示例:
- TARGET_PRODUCT=aosp_car_arm64
- TARGET_BUILD_VARIANT=userdebug
- 调到 build/soong/soong_ui.bash,走到 build/soong/cmd/soong_ui/main.go
soong_build_go soong_ui android/soong/cmd/soong_ui soong_build_go mk2rbc android/soong/mk2rbc/mk2rbc soong_build_go rbcrun rbcrun/rbcruncd ${TOP} exec "$(getoutdir)/soong_ui" "$@"
- 通过编译 android/soong/cmd/soong_ui/main.go 来编译生成 soong_ui。该工具是 AOSP 的主入口之一,负责调度整个 Soong 构建流程(包括 lunch 后执行的 make 实际就是调用它)
- 构建 mk2rbc 工具:Make to RBC 转换工具,作用是将 .mk 格式的旧 Makefile 语法转换为 Blueprint(或 Soong 的)中间格式(RBC:Rule-Based Config)
构建 rbcrun 工具,用于执行 mk2rbc 转换后生成的 .rbc 中间构建逻辑
- 执行 build_build_var_cache,调到 build/soong/soong_ui.bash,执行 --dumpvars-mode。
bash |-- build/soong/cmd/soong_ui/main.go dumpVars |-- build/soong/ui/build/dumpvars.go 最后调用到了ckati执行-f build/make/core/config.mk 从Makefile获取变量值 → 传给Soong使用
- config.mk等
make
- 执行 envsetup.sh 中的 make,调到 build/soong/soong_ui.bash,执行 --make-node。
- 最终会执行 exec out/soong_ui --make-mode 进行编译。
|-- build/soong/cmd/soong_ui/main.gorunMakelogAndSymlinkSetup()|-- build/soong/ui/build/finder.goFindSources # 创建out/.module_paths/AndroidProducts.mk.list# 将device、vendor和product路径下所有的AndroidProducts.mk文件路径收集起来build.Build()|-- build/soong/ui/build/build.gorunMakeProductConfig runSoongrunKatiBuildrunNinjaForBuild
runMakeProductConfig – build/soong/ui/build/dumpvars.go
- 主要配置编译参数
runSoong – build/soong/ui/build/soong.go
- 对工具进行编译,编译出 blueprint 等编译工具, 把 *.bp 编译成 out/soong/build.ninja
bootstrapBlueprint└─ bootstrap.RunBlueprint(...)├─ ctx.ListModulePaths → 获取Android.bp列表,列出需要解析的.bp文件路径├─ ctx.ParseFileList → 解析Android.bp文件├─ ctx.ResolveDependencies → 模块依赖关系建立,主要在.bp文件语法解析完之后、生成.ninja构建规则之前,进行模块依赖检查和构建图生成├─ ctx.PrepareBuildActions → 生成构建动作(构建图)└─ ctx.WriteBuildFile → 生成Ninja构建文件,bootstrap.ninjaninja("bootstrap", "bootstrap.ninja", targets...)|-- ninja -f out/soong/bootstrap.ninja [targets...]2025/06/19 14:28:59.631720 build/soong/ui/logger/logger.go:290: "soong bootstrap" executing "prebuilts/build-tools/linux-x86/bin/ninja" [prebuilts/build-tools/linux-x86/bin/ninja -d keepdepfile -d stats -o usesphonyoutputs=yes -o preremoveoutputs=yes -w dupbuild=err -w outputdir=warn -w missingoutfile=warn -j 22 --frontend_file out/.ninja_fifo -f out/soong/bootstrap.ninja out/soong/build.ninja]
-d keepdepfile
:不要删除由构建命令产生的依赖文件 depfile(build.ninja.d),depfile 是构建过程中生成的文件,通常用来描述构建目标依赖了哪些源文件。ninja 通过读取 depfile,能知道当某个依赖文件发生改变时,哪些目标需要重新构建。Android.bp (模块描述文件)↓ soong_build (调用Blueprint解析Android.bp)↓ Blueprint(解析并构建模块依赖图)↓ 生成Ninja构建文件(build.ninja)↓ ninja执行build.ninja完成编译链接等动作
runKatiBuild – build/soong/ui/build/kati.go
runKatiBuild|-- runKati2025/06/19 15:45:33.680642 build/soong/ui/logger/logger.go:290: "ckati" executing "prebuilts/build-tools/linux-x86/bin/ckati" [prebuilts/build-tools/linux-x86/bin/ckati --ninja --ninja_dir=out --ninja_suffix=-aosp_car_arm64 --no_ninja_prelude --use_ninja_phony_output --use_ninja_symlink_outputs --regen --ignore_optional_include=out/%.P --detect_android_echo --color_warnings --gen_all_targets --use_find_emulator --werror_find_emulator --no_builtin_rules --werror_suffix_rules --werror_real_to_phony --top_level_phony --werror_phony_looks_real --werror_writable --kati_stats --writable out/ --werror_implicit_rules -f build/make/core/main.mk ......]runKatiPackage|-- runKati2025/06/19 15:47:09.954615 build/soong/ui/logger/logger.go:290: "ckati" executing "prebuilts/build-tools/linux-x86/bin/ckati" [prebuilts/build-tools/linux-x86/bin/ckati --ninja --ninja_dir=out --ninja_suffix=-aosp_car_arm64-package --no_ninja_prelude --use_ninja_phony_output --use_ninja_symlink_outputs --regen --ignore_optional_include=out/%.P --detect_android_echo --color_warnings --gen_all_targets --use_find_emulator --werror_find_emulator --no_builtin_rules --werror_suffix_rules --werror_real_to_phony --top_level_phony --werror_phony_looks_real --werror_writable --kati_stats --writable out/dist/ --werror_implicit_rules --werror_overriding_commands -f build/make/packaging/main.mk ......]
- 运行 runKatiBuild() 和 runKatiPackage(),加载 build/make/core/main.mk和build/make/packaging/main.mk(从 main.mk 开始,将通过 include 命令将其所有需要的 .mk 文件包含进来),分别生成 out/build-aosp_car_arm64.ninja 和 out/build-aosp_car_arm64-package.ninja。
runNinjaForBuild – build/soong/ui/build/ninja.go
2025/06/19 15:47:09.959923 build/soong/ui/logger/logger.go:290: "ninja" executing "prebuilts/build-tools/linux-x86/bin/ninja" [prebuilts/build-tools/linux-x86/bin/ninja -d keepdepfile -d keeprsp -d stats --frontend_file out/.ninja_fifo nothing -j 22 -f out/combined-aosp_car_arm64.ninja -o usesphonyoutputs=yes -w dupbuild=err -w missingdepfile=err]
- out/combined-aosp_car_arm64.ninja 内容如下:
builddir = outpool highmem_pooldepth = 7subninja out/build-aosp_car_arm64.ninjasubninja out/build-aosp_car_arm64-package.ninjasubninja out/soong/build.ninjaAndroid.bp --> Blueprint --> Soong --> NinjaMakefile/Android.mk --> kati --> Ninja
3. systemimage 打包
- build/make/core/main.mk
# This is the default target. It must be the first declared target.
.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL): droid_targets.PHONY: droid_targets
droid_targets:......droid_targets: droidcore-unbundled.......PHONY: droidcore-unbundled
droidcore-unbundled: $(filter $(HOST_OUT_ROOT)/%,$(modules_to_install)) \$(INSTALLED_FILES_OUTSIDE_IMAGES) \$(INSTALLED_SYSTEMIMAGE_TARGET) \$(INSTALLED_RAMDISK_TARGET) \......$(INSTALLED_VENDORIMAGE_TARGET) \......
-
build/make/core/Makefile
# 这里就是out/target/product/<product_name>/system.img INSTALLED_SYSTEMIMAGE_TARGET := $(PRODUCT_OUT)/system.img......$(INSTALLED_SYSTEMIMAGE_TARGET): $(。)@echo "Install system fs image: $@"$(copy-file-to-target)$(hide) $(call assert-max-image-size,$@,$(BOARD_SYSTEMIMAGE_PARTITION_SIZE))......systemimage_intermediates := \$(call intermediates-dir-for,PACKAGING,systemimage) BUILT_SYSTEMIMAGE := $(systemimage_intermediates)/system.img # 这里就是out/target/product/<product_name>/obj/PACKAGING/systemimage_intermediates/system.img......# $(1): output file define build-systemimage-target@echo "Target system fs image: $(1)"@mkdir -p $(dir $(1)) $(systemimage_intermediates) && rm -rf $(systemimage_intermediates)/system_image_info.txt$(call generate-image-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt,system, \skip_fsck=true)PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$$PATH \$(BUILD_IMAGE) \$(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1) $(TARGET_OUT) \|| ( mkdir -p $${DIST_DIR}; \cp $(INSTALLED_FILES_FILE) $${DIST_DIR}/installed-files-rescued.txt; \exit 1 ) endef$(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE)$(call build-systemimage-target,$@)
- BUILD_IMAGE 根据 system_image_info.txt(部分内容如下)最终生成 system.img
system_fs_type=erofs system_disable_sparse=true system_selinux_fc=out/target/product/<product_name>/obj/ETC/file_contexts.bin_intermediates/file_contexts.bin building_system_image=true ext_mkuserimg=mkuserimg_mke2fs fs_type=ext4 extfs_sparse_flag=-s erofs_sparse_flag=-s squashfs_sparse_flag=-s f2fs_sparse_flag=-S erofs_default_compressor=lz4hc,9 ext4_share_dup_blocks=true avb_avbtool=avbtool avb_system_hashtree_enable=true ......
- BUILD_IMAGE 根据 system_image_info.txt(部分内容如下)最终生成 system.img
-
build/make/core/definitions.mk
define copy-file-to-target @mkdir -p $(dir $@) $(hide) rm -f $@ $(hide) cp "$<" "$@" endef
- $@:
out/target/product/<product_name>/system.img
- $<:第一个依赖文件,
out/target/product/<product_name>/obj/PACKAGING/systemimage_intermediates/system.img
- $@:
-
build/make/core/Makefile 中的
$(FULL_SYSTEMIMAGE_DEPS)
和$(INSTALLED_FILES_FILE)
INSTALLED_FILES_FILE := $(PRODUCT_OUT)/installed-files.txt INSTALLED_FILES_JSON := $(INSTALLED_FILES_FILE:.txt=.json) $(INSTALLED_FILES_FILE): .KATI_IMPLICIT_OUTPUTS := $(INSTALLED_FILES_JSON) $(INSTALLED_FILES_FILE): $(FULL_SYSTEMIMAGE_DEPS) $(FILESLIST) $(FILESLIST_UTIL)@echo Installed file list: $@mkdir -p $(dir $@)rm -f $@$(FILESLIST) $(TARGET_OUT) > $(@:.txt=.json)$(FILESLIST_UTIL) -c $(@:.txt=.json) > $@
-
这里的
TARGET_OUT := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_SYSTEM)
,即out/target/product/<product_name>/system
PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE) -- out/target/product/<product_name>
TARGET_DEVICE := $(PRODUCT_DEVICE) -- build/make/core/product_config.mk
PRODUCT_DEVICE := <product_name>
TARGET_PRODUCT_OUT_ROOT := $(TARGET_OUT_ROOT)/product -- out/target/product
TARGET_OUT_ROOT := $(OUT_DIR)/target -- out/target
OUT_DIR := out
TARGET_COPY_OUT_SYSTEM := system
-
$(FILESLIST)
是生成 JSON 清单的工具,输入是$(TARGET_OUT)
(打包目录),输出为out/target/product/<product_name>/installed-files.json
-
$(FILESLIST_UTIL)
是工具程序,-c 选项代表将 .json 压缩为 .txt 形式的清单# out/target/product/<product_name>/installed-files.txt351773687 /system/priv-app/CarSettings/CarSettings.apk74870784 /system/apex/com.android.vndk.current.apex48640000 /system/apex/com.android.i18n.apex46346240 /system/apex/com.android.car.framework.apex42966569 /system/framework/framework.jar39179408 /system/lib64/libflutter_engine.so......
# out/target/product/missi/installed-files.json [{"SHA256": "b120b4ed5d86a9e935eeda485ac92e1e8d9f63d6f5fb8e735fa0f0bac3d5da48","Name": "/system/priv-app/CarSettings/CarSettings.apk","Size": 351778736},{"SHA256": "792fe7a24c7f38721a0f87056f849e89d4ed4e1546ae0e001f228c75ae9bc9e0","Name": "/system/apex/com.android.vndk.current.apex","Size": 74830784},......
-
build/make/core/Makefile 中 $(FULL_SYSTEMIMAGE_DEPS)
FULL_SYSTEMIMAGE_DEPS := $(INTERNAL_SYSTEMIMAGE_FILES) $(INTERNAL_USERIMAGES_DEPS)INTERNAL_USERIMAGES_DEPS := \$(BUILD_IMAGE) \$(MKE2FS_CONF) \$(MKEXTUSERIMG)INTERNAL_USERIMAGES_DEPS += ......# 从$(ALL_DEFAULT_INSTALLED_MODULES)过滤只符合out/target/product/<product_name>/system分区的文件路径 INTERNAL_SYSTEMIMAGE_FILES := $(sort $(filter $(TARGET_OUT)/%, \$(ALL_DEFAULT_INSTALLED_MODULES)))# $(ALL_DEFAULT_INSTALLED_MODULES)所有模块最终的安装目标路径(包含system/vendor/product等)
$(INTERNAL_USERIMAGES_DEPS)
:列出了制作 system.img 所需要的工具BUILD_IMAGE := $(HOST_OUT_EXECUTABLES)/build_image$(HOST_EXECUTABLE_SUFFIX)
- 即:
out/host/linux-x86/bin/build_image -- build/make/tools/releasetools/build_image.py
- 即:
MKE2FS_CONF := system/extras/ext4_utils/mke2fs.conf
MKEXTUSERIMG := $(HOST_OUT_EXECUTABLES)/mkuserimg_mke2fs
- 即:
out/host/linux-x86/bin/mkuserimg_mke2fs
- 即:
- 等其它工具,不一一列出
$(INTERNAL_SYSTEMIMAGE_FILES)
$(ALL_DEFAULT_INSTALLED_MODULES)
所有模块最终的安装目标路径- build/make/core/main.mk
known_custom_modules := $(filter $(ALL_MODULES),$(CUSTOM_MODULES)) unknown_custom_modules := $(filter-out $(ALL_MODULES),$(CUSTOM_MODULES)) CUSTOM_MODULES := \$(call module-installed-files,$(known_custom_modules)) \$(unknown_custom_modules)modules_to_install := $(sort \$(ALL_DEFAULT_INSTALLED_MODULES) \$(product_target_FILES) \$(product_host_FILES) \$(CUSTOM_MODULES) \)ALL_DEFAULT_INSTALLED_MODULES := $(modules_to_install) ifeq ($(HOST_OS),linux)include $(BUILD_SYSTEM)/Makefile # BUILD_SYSTEM -- build/make/core endif modules_to_install := $(sort $(ALL_DEFAULT_INSTALLED_MODULES)) ALL_DEFAULT_INSTALLED_MODULES :=product_host_FILES := $(call host-installed-files,$(INTERNAL_PRODUCT))product_target_FILES := $(call product-installed-files, $(INTERNAL_PRODUCT))
- build/make/core/product_config.mk
product_paths := common_lunch_choices := products_using_starlark_config := $(foreach f,$(android_products_makefiles), \$(call _read-ap-file,$(f)) \$(eval product_paths += $(ap_product_paths)) \$(eval common_lunch_choices += $(ap_common_lunch_choices)) \$(eval products_using_starlark_config += $(ap_products_using_starlark_config)) \ )# Dedup, extract product names, etc. product_paths := $(sort $(product_paths)) all_named_products := $(sort $(call _first,$(product_paths),:)) current_product_makefile := $(call _second,$(filter $(TARGET_PRODUCT):%,$(product_paths)),:)
- build/make/core/main.mk
- 回到 build/make/core/main.mk:
product_host_FILES := $(call host-installed-files,$(INTERNAL_PRODUCT)) product_target_FILES := $(call product-installed-files, $(INTERNAL_PRODUCT))
- 根据这个
$(INTERNAL_PRODUCT)
,抽取它所有声明的包和拷贝文件安装路径,作为最终 system.img 所需的内容清单。 - product_host_FILES 部分内容如下:
out/host/linux-x86/framework/BugReport.jar out/host/linux-x86/bin/BugReport out/host/linux-x86/bin/adb out/host/linux-x86/fake_packages/art-tools-timestamp out/host/linux-x86/bin/atest-dev out/host/linux-x86/bin/bcc out/host/linux-x86/bin/bit out/host/linux-x86/bin/brillo_update_payload out/host/linux-x86/bin/dump.erofs out/host/linux-x86/bin/e2fsck out/host/linux-x86/bin/e2fsdroid out/host/linux-x86/bin/fastboot out/host/linux-x86/bin/flags_health_check out/host/linux-x86/bin/fsck.erofs out/host/linux-x86/bin/fsck.f2fs out/host/linux-x86/bin/resize.f2fs out/host/linux-x86/bin/defrag.f2fs out/host/linux-x86/bin/dump.f2fs out/host/linux-x86/com.android.i18n/etc/icu/icudt72l.dat out/host/linux-x86/com.android.tzdata/etc/icu/icu_tzdata.dat out/host/linux-x86/bin/idmap2 out/host/linux-x86/bin/incident_report out/host/linux-x86/bin/ld.mc out/host/linux-x86/bin/lpdump out/host/linux-x86/bin/make_f2fs out/host/linux-x86/bin/minigzip out/host/linux-x86/bin/mke2fs out/host/linux-x86/bin/mkfs.erofs out/host/linux-x86/bin/qiifa_py2 out/host/linux-x86/bin/resize2fs out/host/linux-x86/bin/sgdisk out/host/linux-x86/bin/sload_f2fs out/host/linux-x86/bin/sqlite3 out/host/linux-x86/bin/tinyplay ......
- product_target_FILES 部分内容如下:
...... out/target/product/missi/system/lib64/libservices.so out/target/product/missi/system/lib64/libservices.core-gnss.so out/target/product/missi/system/lib/libservices.core-gnss.so ......
- 根据这个
-