首页
chatGPT
关于
友链
其它
统计
更多
壁纸
留言
Search
1
cgroup--(4)cgroup v1和cgroup v2的详细介绍
6,410 阅读
2
修改Linux Kernel defconfig的标准方法
6,382 阅读
3
Android系统之VINTF(1)manifests&compatibility matrices
5,975 阅读
4
使用git生成patch和应用patch
3,454 阅读
5
c语言的__attribute__
3,168 阅读
默认分类
文章收集
学习总结
算法
环境配置
知识点
入门系列
vim
shell
Git
Make
Android
Linux
Linux命令
内存管理
Linux驱动
Language
C++
C
工具
软件工具
Bug
COMPANY
登录
Search
标签搜索
shell
Linux
c
uboot
Vim
vintf
Linux驱动
Android
device_tree
git
DEBUG
arm64
链表
数据结构
IDR
内核
ELF
gcc
ARM
网址
adtxl
累计撰写
367
篇文章
累计收到
14
条评论
首页
栏目
默认分类
文章收集
学习总结
算法
环境配置
知识点
入门系列
vim
shell
Git
Make
Android
Linux
Linux命令
内存管理
Linux驱动
Language
C++
C
工具
软件工具
Bug
COMPANY
页面
chatGPT
关于
友链
其它
统计
壁纸
留言
搜索到
133
篇与
的结果
2021-07-01
git origin的含义
转载自https://www.cnblogs.com/xuyaowen/p/git-origin.html
2021年07月01日
719 阅读
0 评论
0 点赞
2021-07-01
git将一段commit合并到另一个分支
部分转载自https://www.jianshu.com/p/4a8f4af4e803
2021年07月01日
1,733 阅读
0 评论
1 点赞
2021-07-01
ninja文件语法
https://note.qidong.name/2017/08/ninja-syntax/https://ninja-build.org/
2021年07月01日
803 阅读
0 评论
0 点赞
2021-06-30
[转载]Android overlay机制简介
转载自Android overlay简单总结版权声明:本文为CSDN博主「一只特立独行的Yang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/Dylan_Sen/article/details/78878641
2021年06月30日
2,039 阅读
0 评论
0 点赞
2021-06-30
[转载]Android编译生成文件夹out详解
Android编译生成文件夹out详解很老了
2021年06月30日
777 阅读
0 评论
0 点赞
2021-06-30
如何解压缩boot.img?
如何解压缩boot.img?mkbootimg github code
2021年06月30日
1,485 阅读
0 评论
0 点赞
2021-06-16
[转载]Android make中变量记录
转载自Android make 中变量记录
2021年06月16日
1,219 阅读
0 评论
0 点赞
2021-05-17
刀
暂无简介
2021年05月17日
1,328 阅读
2 评论
1 点赞
2021-04-29
好用的c/c++在线编译器
暂无简介
2021年04月29日
983 阅读
0 评论
0 点赞
2021-03-01
[转载]make编译过程-Android10.0编译系统(三)
版权声明:本文为CSDN博主「IngresGe」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/yiranfeng/article/details/1090840821. 概述上一节,我们理清了编译环境初始化的过程,环境变量已经加载,并配置了编译目标,接下来执行一个make命令我们就能够进行编译。make之后是怎么完成编译的,这个很有意思,我们一起往下探讨。2. Android系统的编译历程Android7.0 Google引入了soong构建系统,用来逐步替代GNU make的编译,因此在Android10.0 上,make执行后,我们走的是soong构建环境。Android系统的编译历程:3.Soong编译系统家族成员从下图可知,mk文件被编译成了 out/build-aosp\_arm.ninja和out/build-aosp\_arm-package.ninja,bp文件被编译成了out/soong/build.ninja,这三个ninja文件又被合并成out/combined-aosp\_arm.ninja,最终通过ninja工具来编译out/combined-aosp\_arm.ninja完成最终的编译。4. make的流程图soong构建的流程图如下图所示:5. make()执行完make命令后,会调用envsetup.sh的make()函数进行处理。function make() { _wrap_build $(get_make_command "$@") "$@" }从get_make_command()可以看出,make后,真正然后执行编译的入口是:build/soong/soong_ui.bashfunction get_make_command() { # If we're in the top of an Android tree, use soong_ui.bash instead of make if [ -f build/soong/soong_ui.bash ]; then # Always use the real make if -C is passed in for arg in "$@"; do if [[ $arg == -C* ]]; then echo command make return fi done echo build/soong/soong_ui.bash --make-mode else echo command make fi }6. soong_ui.bash6.1 soong_ui.bash调用栈soong_ui.bash执行过程:source microfactory.bash,得到一些函数命令, 例如:soong_build_go编译/build/soong/cmd/soong_ui/main.go,生成 out/soong_ui这个可执行程序执行命令:out/soong_ui --make-mode ,执行了make命令,会把"build/make/core/main.mk" 加到构建环境中,同时启动kati、blueprint-soong、ninja的编译。接下来根据调用栈的流程,来详细分析编译的过程。6.2 [build/soong/soong_ui.bash]soong_ui.bash 用来配置一些资源环境,得到一些函数命令,例如:soong_build_go,最终回退到根目录,执行out/soong_ui --make-mode进行真正的构建。# Save the current PWD for use in soong_ui export ORIGINAL_PWD=${PWD} export TOP=$(gettop) source ${TOP}/build/soong/scripts/microfactory.bash soong_build_go soong_ui android/soong/cmd/soong_ui cd ${TOP} exec "$(getoutdir)/soong_ui" "$@"6.2.1 [/soong/../microfactory.bash]得到build_go的函数命令,并提供 soong_build_go的函数执行方法[/build/soong/scripts/microfactory.bash] function soong_build_go { BUILDDIR=$(getoutdir) \ SRCDIR=${TOP} \ BLUEPRINTDIR=${TOP}/build/blueprint \ EXTRA_ARGS="-pkg-path android/soong=${TOP}/build/soong -pkg-path github.com/golang/protobuf=${TOP}/external/golang-protobuf" \ build_go $@ } source ${TOP}/build/blueprint/microfactory/microfactory.bash6.2.2 [/blueprint/../microfactory.bash]build_go主要目的就是用来构建生成 out/soong_ui这个可执行程序,用于参与最终的编译[/build/blueprint/microfactory/microfactory.bash ] function build_go { # Increment when microfactory changes enough that it cannot rebuild itself. # For example, if we use a new command line argument that doesn't work on older versions. local mf_version=3 local mf_src="${BLUEPRINTDIR}/microfactory" local mf_bin="${BUILDDIR}/microfactory_$(uname)" local mf_version_file="${BUILDDIR}/.microfactory_$(uname)_version" local built_bin="${BUILDDIR}/$1" local from_src=1 if [ -f "${mf_bin}" ] && [ -f "${mf_version_file}" ]; then if [ "${mf_version}" -eq "$(cat "${mf_version_file}")" ]; then from_src=0 fi fi local mf_cmd if [ $from_src -eq 1 ]; then # `go run` requires a single main package, so create one local gen_src_dir="${BUILDDIR}/.microfactory_$(uname)_intermediates/src" mkdir -p "${gen_src_dir}" sed "s/^package microfactory/package main/" "${mf_src}/microfactory.go" >"${gen_src_dir}/microfactory.go" mf_cmd="${GOROOT}/bin/go run ${gen_src_dir}/microfactory.go" else mf_cmd="${mf_bin}" fi # GOROOT must be absolute because `go run` changes the local directory GOROOT=$(cd $GOROOT; pwd) ${mf_cmd} -b "${mf_bin}" \ -pkg-path "github.com/google/blueprint=${BLUEPRINTDIR}" \ -trimpath "${SRCDIR}" \ ${EXTRA_ARGS} \ -o "${built_bin}" $2 if [ $? -eq 0 ] && [ $from_src -eq 1 ]; then echo "${mf_version}" >"${mf_version_file}" fi }soong_ui最终的编译命令展开为:$(cd /prebuilts/go/linux-x86/; pwd) /out/microfactory_Linux -b "/out/microfactory_Linux" \ -pkg-path "github.com/google/blueprint=/build/blueprint" \ -trimpath "./" \ -pkg-path android/soong=/build/soong -pkg-path github.com/golang/protobuf=/external/golang-protobuf} \ -o "out/soong_ui" android/soong/cmd/soong_ui从上面的流程可知,生成soong_ui经历几件事情:通过/build/blueprint/microfactory/microfactory.go 编译出/out/microfactory_Linux使用/out/microfactory_Linux来编译soong_uimicrofactory是一个增量编译go程序的工具。它类似于“go install”,但不需要GOPATH。包->路径映射可以指定为命令行选项:-pkg-path android/soong=build/soong -pkg-path github.com/google/blueprint=build/blueprint其实microfactory就是一个高级一点的go命令,它自己由go编出来,又代替了一部分go的部分功能,鸡生蛋,蛋生鸡的故事,这里得到了完美解释 ^\_^。microfactory编译示例:准备go的代码在/home/ingresge/AP/AOSP_Q中创建一个目录hello:创建hello.go---vim hello/hello.go在其中打印一个“Hello,Go!”package main import ( "log" "os" ) func main() { testlog := log.New(os.Stderr, "", log.Ltime) testlog.Println("Hello,Go!") }使用microfactory 编译hello.go/home/ingresge/AP/AOSP_Q/out/microfactory_Linux -pkg-path android/hello=/home/ingresge/AP/AOSP_Q/hello -trimpath /home/ingresge/AP/AOSP_Q/hello -o /home/ingresge/AP/AOSP_Q/out/hellogo android/hello/运行执行命令:./out/hellogo输出结果:17:18:44 Hello,Go!6.3 soong_uisoong_ui 是通过编译 build/soong/cmd/soong_ui/main.go得来,我们接下来分析一下main.go的一些流程6.3.1 main.go调用栈6.3.2 soong_ui启动编译的入口func main() { var stdio terminal.StdioInterface stdio = terminal.StdioImpl{} // dumpvar uses stdout, everything else should be in stderr if os.Args[1] == "--dumpvar-mode" || os.Args[1] == "--dumpvars-mode" { stdio = terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr) } writer := terminal.NewWriter(stdio) defer writer.Finish() log := logger.New(writer) defer log.Cleanup() if len(os.Args) < 2 || !(inList("--make-mode", os.Args) || os.Args[1] == "--dumpvars-mode" || os.Args[1] == "--dumpvar-mode") { log.Fatalln("The `soong` native UI is not yet available.") } ctx, cancel := context.WithCancel(context.Background()) defer cancel() trace := tracer.New(log) defer trace.Close() met := metrics.New() stat := &status.Status{} defer stat.Finish() stat.AddOutput(terminal.NewStatusOutput(writer, os.Getenv("NINJA_STATUS"), build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))) stat.AddOutput(trace.StatusTracer()) build.SetupSignals(log, cancel, func() { trace.Close() log.Cleanup() stat.Finish() }) buildCtx := build.Context{ContextImpl: &build.ContextImpl{ Context: ctx, Logger: log, Metrics: met, Tracer: trace, Writer: writer, Status: stat, }} var config build.Config if os.Args[1] == "--dumpvars-mode" || os.Args[1] == "--dumpvar-mode" { config = build.NewConfig(buildCtx) } else { config = build.NewConfig(buildCtx, os.Args[1:]...) } build.SetupOutDir(buildCtx, config) logsDir := config.OutDir() if config.Dist() { logsDir = filepath.Join(config.DistDir(), "logs") } os.MkdirAll(logsDir, 0777) log.SetOutput(filepath.Join(logsDir, "soong.log")) trace.SetOutput(filepath.Join(logsDir, "build.trace")) stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, "verbose.log"))) stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, "error.log"))) defer met.Dump(filepath.Join(logsDir, "build_metrics")) if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok { if !strings.HasSuffix(start, "N") { if start_time, err := strconv.ParseUint(start, 10, 64); err == nil { log.Verbosef("Took %dms to start up.", time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds()) buildCtx.CompleteTrace(metrics.RunSetupTool, "startup", start_time, uint64(time.Now().UnixNano())) } } if executable, err := os.Executable(); err == nil { trace.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace")) } } // Fix up the source tree due to a repo bug where it doesn't remove // linkfiles that have been removed fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.bp") fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.mk") f := build.NewSourceFinder(buildCtx, config) defer f.Shutdown() build.FindSources(buildCtx, config, f) if os.Args[1] == "--dumpvar-mode" { dumpVar(buildCtx, config, os.Args[2:]) } else if os.Args[1] == "--dumpvars-mode" { dumpVars(buildCtx, config, os.Args[2:]) } else { if config.IsVerbose() { writer.Print("! The argument `showcommands` is no longer supported.") writer.Print("! Instead, the verbose log is always written to a compressed file in the output dir:") writer.Print("!") writer.Print(fmt.Sprintf("! gzip -cd %s/verbose.log.gz | less -R", logsDir)) writer.Print("!") writer.Print("! Older versions are saved in verbose.log.#.gz files") writer.Print("") time.Sleep(5 * time.Second) } toBuild := build.BuildAll if config.Checkbuild() { toBuild |= build.RunBuildTests } build.Build(buildCtx, config, toBuild) } }主要执行soong/ui/build/build.go,从build.go就可以看到执行soong的大体流程。main.go中配置的toBuild为 BuildProductConfig | BuildSoong | BuildKati | BuildNinja,支持productconfig\soong\kati\ninja的构建。6.3.3 Build调用栈编译步骤如下:1) runMakeProductConfig 主要配置编译参数2) runSoong 对工具进行编译,编译出blueprint等编译工具, 把*.bp 编译成 out/soong/build.ninja/.minibootstrap/build.ninja - Run minibp to generate .bootstrap/build.ninja (Primary stage) - Run minibp to generate .minibootstrap/build.ninja.in /.bootstrap/build.ninja - Build any bootstrap_go_binary rules and dependencies -- usually the primary builder and any build or runtime dependencies. - Run the primary builder to generate build.ninja3) runKatiBuild, 加载 build/make/core/main.mk, 搜集所有的Android.mk文件生成ninja文件:out/build-aosp\_arm.ninja4) runKatiPackage, 加载build/make/packaging/main.mk, 编译生成out/build-aosp\_arm-package.ninja5) createCombinedBuildNinjaFile,将out/soong/build.ninja 、out/build-aosp_arm.ninja和out/build-aosp\_arm-package.ninja, 合成为out/combined-aosp\_arm.ninja6) runNinja,运行Ninja命令, 解析combined-aosp\_arm.ninja,执行编译过程out/combined-aosp_arm.ninja 内容展示如下:builddir = out pool local_pool depth = 42 build _kati_always_build_: phony subninja out/build-aosp_arm.ninja subninja out/build-aosp_arm-package.ninja subninja out/soong/build.ninja6.3.4 BuildBuild入口[/build/soong/ui/build/build.go] func Build(ctx Context, config Config, what int) { ctx.Verboseln("Starting build with args:", config.Arguments()) ctx.Verboseln("Environment:", config.Environment().Environ()) if config.SkipMake() { ctx.Verboseln("Skipping Make/Kati as requested") what = what & (BuildSoong | BuildNinja) } if inList("help", config.Arguments()) { help(ctx, config, what) return } else if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) { clean(ctx, config, what) return } // Make sure that no other Soong process is running with the same output directory buildLock := BecomeSingletonOrFail(ctx, config) defer buildLock.Unlock() checkProblematicFiles(ctx) SetupOutDir(ctx, config) checkCaseSensitivity(ctx, config) ensureEmptyDirectoriesExist(ctx, config.TempDir()) SetupPath(ctx, config) if config.StartGoma() { // Ensure start Goma compiler_proxy startGoma(ctx, config) } if what&BuildProductConfig != 0 { // Run make for product config runMakeProductConfig(ctx, config) } if inList("installclean", config.Arguments()) { installClean(ctx, config, what) ctx.Println("Deleted images and staging directories.") return } else if inList("dataclean", config.Arguments()) { dataClean(ctx, config, what) ctx.Println("Deleted data files.") return } if what&BuildSoong != 0 { // Run Soong runSoong(ctx, config) } if what&BuildKati != 0 { // Run ckati genKatiSuffix(ctx, config) runKatiCleanSpec(ctx, config) runKatiBuild(ctx, config) runKatiPackage(ctx, config) ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0777) } else { // Load last Kati Suffix if it exists if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil { ctx.Verboseln("Loaded previous kati config:", string(katiSuffix)) config.SetKatiSuffix(string(katiSuffix)) } } // Write combined ninja file createCombinedBuildNinjaFile(ctx, config) if what&RunBuildTests != 0 { testForDanglingRules(ctx, config) } if what&BuildNinja != 0 { if !config.SkipMake() { installCleanIfNecessary(ctx, config) } // Run ninja runNinja(ctx, config) } }6.4 main.mk文件分析执行runKatiBuild时,有个重要的步骤,就是加载build/make/core/main.mk,main.mk文件是Android Build系统的主控文件。从main.mk开始,将通过include命令将其所有需要的.mk文件包含进来,最终在内存中形成一个包括所有编译脚本的集合,这个相当于一个巨大Makefile文件。Makefile文件看上去很庞大,其实主要由三种内容构成: 变量定义、函数定义和目标依赖规则,此外mk文件之间的包含也很重要。main.mk主要做了以下几件事情: 1. 定义编译目标product 2. 加载config.mk来初始化相关变量,检测编译环境和目标环境 3. 清除规则,清除out目录中的dex文件 4. 加载build/croe/definitions.mk,定义了很多通用函数,供编译过程调用 5. 加载平台开发工具包 build/make/core/pdk_config.mk 6. 加载系统中所有的Android.mk,最终会被存放到out/.module_paths/Android.mk.list 7. Link 类型检查,校验Link 8. 要为此产品生成的模块的基本列表由相应的产品定义文件指定,这些定义在"product_config.mk"中 9. 运行时APEX库,并进行检查校验 10. 将所有要安装的模块都保存在变量ALL_DEFAULT_INSTALLED_MODULES中,并且将build/core/Makefie文件加载进来。build/core/Makefie文件会根据要安装的模块生成system.img、super.img、boot.img和recovery.img等镜像文件的生成规则 11. 定义编译的image目标 12. 构建文件,然后将其打包成rom格式6.4.1 定义编译目标product流程1:没有KATI命令时,走run_soong_ui执行,通过soong_ui.bash --make-mode 进行编译流程2:通过kati命令编译时在Android10.0中,使用的是soong构建,因此直接走流程2确定了最终的编译目标为droidifndef KATI host_prebuilts := linux-x86 ifeq ($(shell uname),Darwin) host_prebuilts := darwin-x86 endif #流程1:没有KATI命令时,走run_soong_ui执行,通过soong_ui.bash --make-mode 进行编译 .PHONY: run_soong_ui run_soong_ui: +@prebuilts/build-tools/$(host_prebuilts)/bin/makeparallel --ninja build/soong/soong_ui.bash --make-mode $(MAKECMDGOALS) .PHONY: $(MAKECMDGOALS) $(sort $(MAKECMDGOALS)) : run_soong_ui @#empty else # KATI #流程2:通过kati命令编译时,走该流程,Android10.0中走该流程 $(info [1/1] initializing build system ...) .... #1.定义编译目标product #这是默认目标。它必须是第一个声明的目标。 .PHONY: droid DEFAULT_GOAL := droid $(DEFAULT_GOAL): droid_targets .PHONY: droid_targets droid_targets: ... #endif #KATI6.4.2 加载config.mk加载config.mk来初始化相关变量,检测编译环境和目标环境,加载clang/config.mk,配置一些编译的环境。include build/make/core/config.mk ... #加载out/soong/make_vars-aosp_arm.mk include $(SOONG_MAKEVARS_MK) #加载clang编译的一些配置 include $(BUILD_SYSTEM)/clang/config.mk ...6.4.3 清楚规则清除规则,清除out目录中的dex文件。... .PHONY: clean-dex-files clean-dex-files: $(hide) find $(OUT_DIR) -name "*.dex" | xargs rm -f $(hide) for i in `find $(OUT_DIR) -name "*.jar" -o -name "*.apk"` ; do ((unzip -l $$i 2> /dev/null | \ grep -q "\.dex$$" && rm -f $$i) || continue ) ; done @echo "All dex files and archives containing dex files have been removed." ...6.4.5 加载pdk_config.mk加载 平台开发工具包... include build/make/core/pdk_config.mk #为userdebug、eng和non-REL生成启用动态链接器警告 ifneq ($(TARGET_BUILD_VARIANT),user) ADDITIONAL_BUILD_PROPERTIES += ro.bionic.ld.warning=1 else #只要user版本不是最终版本,就启用它。 ifneq ($(PLATFORM_VERSION_CODENAME),REL) ADDITIONAL_BUILD_PROPERTIES += ro.bionic.ld.warning=1 endif endif ...6.4.6 加载系统所有的Android.mk加载系统中所有的Android.mk,最终会被存放到out/.module_paths/Android.mk.list。如果环境变量ONE_SHOT_MAKEFILE的值不等于空,也就是我们执行的是mm或者mmm命令,那么就表示要编译的是特定的模块。这些指定要编译的模块的Android.mk文件路径就保存在环境变量ONE_SHOT_MAKEFILE中,因此直接将这些Android.mk文件加载进来就获得相应的编译规则。如果环境变量ONE_SHOT_MAKEFILE的值等于空,且dont_bother不为true,会通过out/soong/Android-aosp_arm.mk 来获得Android源代码工程下的所有Android.mk文件的路径列表,并存入到out/.module_paths/Android.mk.list 中。 ... ifneq ($(ONE_SHOT_MAKEFILE),) #我们可能已经被带有子目录makefile的“mm” shell函数调用了。 include $(SOONG_ANDROID_MK) $(wildcard $(ONE_SHOT_MAKEFILE)) # Change CUSTOM_MODULES to include only modules that were # defined by this makefile; this will install all of those # modules as a side-effect. Do this after including ONE_SHOT_MAKEFILE # so that the modules will be installed in the same place they # would have been with a normal make. CUSTOM_MODULES := $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS))) #帮助目标打印出安装路径 define register_module_install_path .PHONY: GET-MODULE-INSTALL-PATH-$(1) GET-MODULE-INSTALL-PATH-$(1): echo 'INSTALL-PATH: $(1) $(ALL_MODULES.$(1).INSTALLED)' endef SORTED_ALL_MODULES := $(sort $(ALL_MODULES)) UNIQUE_ALL_MODULES := $(foreach m,$(SORTED_ALL_MODULES),\ $(if $(call streq,$(m),$(lastword $(UNIQUE_ALL_MODULES))),,\ $(eval UNIQUE_ALL_MODULES += $(m)))) SORTED_ALL_MODULES := $(foreach mod,$(UNIQUE_ALL_MODULES),$(if $(ALL_MODULES.$(mod).INSTALLED),\ $(eval $(call register_module_install_path,$(mod)))\ $(foreach path,$(ALL_MODULES.$(mod).PATH),\ $(eval my_path_prefix := GET-INSTALL-PATH-IN)\ $(foreach component,$(subst /,$(space),$(path)),\ $(eval my_path_prefix := $$(my_path_prefix)-$$(component))\ $(eval .PHONY: $$(my_path_prefix))\ $(eval $$(my_path_prefix): GET-MODULE-INSTALL-PATH-$(mod)))))) UNIQUE_ALL_MODULES := else # ONE_SHOT_MAKEFILE ifneq ($(dont_bother),true) FULL_BUILD := true #包括系统中的所有makefile :out/.module_paths/Android.mk.list subdir_makefiles := $(SOONG_ANDROID_MK) $(file <$(OUT_DIR)/.module_paths/Android.mk.list) subdir_makefiles_total := $(words int $(subdir_makefiles) post finish) .KATI_READONLY := subdir_makefiles_total $(foreach mk,$(subdir_makefiles),$(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] including $(mk) ...)$(eval include $(mk))) ifneq (,$(PDK_FUSION_PLATFORM_ZIP)$(PDK_FUSION_PLATFORM_DIR)) # 加载pdk_fusion_modules.mk include $(BUILD_SYSTEM)/pdk_fusion_modules.mk endif # PDK_FUSION_PLATFORM_ZIP || PDK_FUSION_PLATFORM_DIR droid_targets : blueprint_tools endif # dont_bother endif # ONE_SHOT_MAKEFILE ...6.4.7 Link检查编译时的Link 类型检查,校验Link... #Link 类型检查 #“ALL_LINK_TYPES”包含所有链接类型前缀的列表(通常每个模块一个,但是apk可以“链接”到java和本机代码)。 #链接类型前缀由intermediates dir所需的所有信息组成: # # LINK_TYPE:TARGET:_:2ND:STATIC_LIBRARIES:libfoo # #所有未在“允许”或“警告”中列出的依赖关系链接类型都将成为错误 link_type_error := define link-type-prefix-base $(word 2,$(subst :,$(space),$(1))) endef define link-type-prefix $(if $(filter AUX-%,$(link-type-prefix-base)),$(patsubst AUX-%,AUX,$(link-type-prefix-base)),$(link-type-prefix-base)) endef define link-type-aux-variant $(if $(filter AUX-%,$(link-type-prefix-base)),$(patsubst AUX-%,%,$(link-type-prefix-base))) endef define link-type-common $(patsubst _,,$(word 3,$(subst :,$(space),$(1)))) endef define link-type-2ndarchprefix $(patsubst _,,$(word 4,$(subst :,$(space),$(1)))) endef define link-type-class $(word 5,$(subst :,$(space),$(1))) endef define link-type-name $(word 6,$(subst :,$(space),$(1))) endef define link-type-os $(strip $(eval _p := $(link-type-prefix))\ $(if $(filter HOST HOST_CROSS,$(_p)),\ $($(_p)_OS),\ $(if $(filter AUX,$(_p)),AUX,android))) endef define link-type-arch $($(link-type-prefix)_$(link-type-2ndarchprefix)ARCH) endef define link-type-name-variant $(link-type-name) ($(link-type-class) $(link-type-os)-$(link-type-arch)) endef ... # 验证$(1)是否可以链接到$(2) # $(1)和$(2)都是上面定义的链接类型前缀 define verify-link-type $(foreach t,$($(2).TYPE),\ $(if $(filter-out $($(1).ALLOWED),$(t)),\ $(if $(filter $(t),$($(1).WARN)),\ $(call link-type-warning,$(1),$(2),$(t)),\ $(call link-type-error,$(1),$(2),$(t))))) endef #验证所有分支/配置都有合理的警告/错误,并删除此重写 verify-link-type = $(eval $$(1).MISSING := true) ...6.4.8 加载product_config.mk要为此产品生成的模块的基本列表由相应的产品定义文件指定,这些定义在"product_config.mk"中... #列出特定产品安装的大多数文件,包括: # - PRODUCT_PACKAGES, and their LOCAL_REQUIRED_MODULES # - PRODUCT_COPY_FILES # 要为此产品生成的模块的基本列表由相应的产品定义文件指定,这些定义在"product_config.mk"中 define product-installed-files $(eval _mk := $(strip $(1))) \ $(eval _pif_modules := \ $(PRODUCTS.$(_mk).PRODUCT_PACKAGES) \ $(if $(filter eng,$(tags_to_install)),$(PRODUCTS.$(_mk).PRODUCT_PACKAGES_ENG)) \ $(if $(filter debug,$(tags_to_install)),$(PRODUCTS.$(_mk).PRODUCT_PACKAGES_DEBUG)) \ $(if $(filter tests,$(tags_to_install)),$(PRODUCTS.$(_mk).PRODUCT_PACKAGES_TESTS)) \ $(if $(filter asan,$(tags_to_install)),$(PRODUCTS.$(_mk).PRODUCT_PACKAGES_DEBUG_ASAN)) \ $(call auto-included-modules) \ ) \ $(eval ### Filter out the overridden packages and executables before doing expansion) \ $(eval _pif_overrides := $(call module-overrides,$(_pif_modules))) \ $(eval _pif_modules := $(filter-out $(_pif_overrides), $(_pif_modules))) \ $(eval ### Resolve the :32 :64 module name) \ $(eval _pif_modules_32 := $(patsubst %:32,%,$(filter %:32, $(_pif_modules)))) \ $(eval _pif_modules_64 := $(patsubst %:64,%,$(filter %:64, $(_pif_modules)))) \ $(eval _pif_modules_rest := $(filter-out %:32 %:64,$(_pif_modules))) \ $(eval ### Note for 32-bit product, 32 and 64 will be added as their original module names.) \ $(eval _pif_modules := $(call get-32-bit-modules-if-we-can, $(_pif_modules_32))) \ $(eval _pif_modules += $(_pif_modules_64)) \ $(eval ### For the rest we add both) \ $(eval _pif_modules += $(call get-32-bit-modules, $(_pif_modules_rest))) \ $(eval _pif_modules += $(_pif_modules_rest)) \ $(call expand-required-modules,_pif_modules,$(_pif_modules),$(_pif_overrides)) \ $(filter-out $(HOST_OUT_ROOT)/%,$(call module-installed-files, $(_pif_modules))) \ $(call resolve-product-relative-paths,\ $(foreach cf,$(PRODUCTS.$(_mk).PRODUCT_COPY_FILES),$(call word-colon,2,$(cf)))) endef ...6.4.9 运行APEX库运行时APEX库,并进行检查校验 ... APEX_MODULE_LIBS := \ libadbconnection.so \ libadbconnectiond.so \ libandroidicu.so \ libandroidio.so \ libart-compiler.so \ libart-dexlayout.so \ libart-disassembler.so \ libart.so \ libartbase.so \ libartbased.so \ libartd-compiler.so \ libartd-dexlayout.so \ libartd.so \ libartpalette.so \ libc.so \ libdexfile.so \ libdexfile_external.so \ libdexfiled.so \ libdexfiled_external.so \ libdl.so \ libdt_fd_forward.so \ libdt_socket.so \ libicui18n.so \ libicuuc.so \ libjavacore.so \ libjdwp.so \ libm.so \ libnativebridge.so \ libnativehelper.so \ libnativeloader.so \ libnpt.so \ libopenjdk.so \ libopenjdkjvm.so \ libopenjdkjvmd.so \ libopenjdkjvmti.so \ libopenjdkjvmtid.so \ libpac.so \ libprofile.so \ libprofiled.so \ libsigchain.so \ # Conscrypt APEX libraries APEX_MODULE_LIBS += \ libjavacrypto.so \ ... #如果下面的检查失败,那么某些库已经在system/lib或system/lib64中结束,而这些库只打算放入一些APEX包中。 #可能的原因是/system中的库或二进制文件已经增长了一个直接或间接拉入禁止的库的依赖关系。 #要解决此问题,请查找库所属的APEX包-在“APEX”构建模块中的“native_shared_lib”属性中搜索它(参见art/build/APEX/安卓.bp例如)。 #然后检查APEX包中是否有应该使用的导出库,即在其“native_shared_lib”属性中列出的库,对应的“cc_library”模块具有“stubs”子句(如art/libdexfile中的libdexfile_external)/安卓.bp). #如果您找不到适合您需要的APEX导出库,或者您认为/system中应该允许您依赖的库,那么请与包含该库的APEX包的所有者联系。 #如果在APEX中导出的库出现此错误,则APEX可能配置错误,或者生成系统中出现错误。 #请联系APEX包主和/或soong-team@,或android-building@googlegroups.com外部的。 define check-apex-libs-absence $(call maybe-print-list-and-error, \ $(filter $(foreach lib,$(APEX_MODULE_LIBS),%/$(lib)), \ $(filter-out $(foreach dir,$(APEX_LIBS_ABSENCE_CHECK_EXCLUDE), \ $(TARGET_OUT)/$(if $(findstring %,$(dir)),$(dir),$(dir)/%)), \ $(filter $(TARGET_OUT)/lib/% $(TARGET_OUT)/lib64/%,$(1)))), \ APEX libraries found in system image (see comment for check-apex-libs-absence in \ build/make/core/main.mk for details)) endef # TODO(b/129006418): The check above catches libraries through product # dependencies visible to make, but as long as they have install rules in # /system they may still be created there through other make targets. To catch # that we also do a check on disk just before the system image is built. define check-apex-libs-absence-on-disk $(hide) ( \ cd $(TARGET_OUT) && \ findres=$$(find lib* \ $(foreach dir,$(APEX_LIBS_ABSENCE_CHECK_EXCLUDE),-path "$(subst %,*,$(dir))" -prune -o) \ -type f \( -false $(foreach lib,$(APEX_MODULE_LIBS),-o -name $(lib)) \) \ -print) && \ if [ -n "$$findres" ]; then \ echo "APEX libraries found in system image (see comment for check-apex-libs-absence" 1>&2; \ echo "in build/make/core/main.mk for details):" 1>&2; \ echo "$$findres" | sort 1>&2; \ false; \ fi; \ ) endef endif ...6.4.10 保存所有模块将所有要安装的模块都保存在变量ALL_DEFAULT_INSTALLED_MODULES中,并且将build/core/Makefie文件加载进来。... #build/core/Makefie文件会根据要安装的模块生成system.img、super.img、boot.img和recovery.img等镜像文件的生成规则 # 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) \ $(call get-tagged-modules,$(tags_to_install)) \ $(CUSTOM_MODULES) \ ) ... #build/make/core/Makefile包含了我们不想污染这个顶级Makefile的额外内容。 #它希望“ALL_DEFAULT_INSTALLED_MODULES”包含当前make期间构建的所有模块,但它还进一步扩展了“ALL_DEFAULT_INSTALLED_MODULES”。 ALL_DEFAULT_INSTALLED_MODULES := $(modules_to_install) include $(BUILD_SYSTEM)/Makefile modules_to_install := $(sort $(ALL_DEFAULT_INSTALLED_MODULES)) ALL_DEFAULT_INSTALLED_MODULES := ... #这是用来获得正确的秩序,你也可以使用这些,但他们被认为是没有文件,所以不要抱怨,如果他们的行为改变。 #依赖于所有复制头的内部目标(请参见复制_标题.make). 需要首先复制头的其他目标可以依赖于此目标。 .PHONY: all_copied_headers all_copied_headers: ; $(ALL_C_CPP_ETC_OBJECTS): | all_copied_headers # All the droid stuff, in directories .PHONY: files files: $(modules_to_install) \ $(INSTALLED_ANDROID_INFO_TXT_TARGET) ...6.4.11 定义编译的image目标定义了我们编译过程中的所有image目标... .PHONY: ramdisk ramdisk: $(INSTALLED_RAMDISK_TARGET) .PHONY: ramdisk_debug ramdisk_debug: $(INSTALLED_DEBUG_RAMDISK_TARGET) .PHONY: systemtarball systemtarball: $(INSTALLED_SYSTEMTARBALL_TARGET) .PHONY: boottarball boottarball: $(INSTALLED_BOOTTARBALL_TARGET) .PHONY: userdataimage userdataimage: $(INSTALLED_USERDATAIMAGE_TARGET) ifneq (,$(filter userdataimage, $(MAKECMDGOALS))) $(call dist-for-goals, userdataimage, $(BUILT_USERDATAIMAGE_TARGET)) endif .PHONY: userdatatarball userdatatarball: $(INSTALLED_USERDATATARBALL_TARGET) .PHONY: cacheimage cacheimage: $(INSTALLED_CACHEIMAGE_TARGET) .PHONY: bptimage bptimage: $(INSTALLED_BPTIMAGE_TARGET) .PHONY: vendorimage vendorimage: $(INSTALLED_VENDORIMAGE_TARGET) .PHONY: productimage productimage: $(INSTALLED_PRODUCTIMAGE_TARGET) .PHONY: productservicesimage productservicesimage: $(INSTALLED_PRODUCT_SERVICESIMAGE_TARGET) .PHONY: odmimage odmimage: $(INSTALLED_ODMIMAGE_TARGET) .PHONY: systemotherimage systemotherimage: $(INSTALLED_SYSTEMOTHERIMAGE_TARGET) .PHONY: superimage_empty superimage_empty: $(INSTALLED_SUPERIMAGE_EMPTY_TARGET) .PHONY: bootimage bootimage: $(INSTALLED_BOOTIMAGE_TARGET) .PHONY: bootimage_debug bootimage_debug: $(INSTALLED_DEBUG_BOOTIMAGE_TARGET) .PHONY: vbmetaimage vbmetaimage: $(INSTALLED_VBMETAIMAGE_TARGET) .PHONY: auxiliary auxiliary: $(INSTALLED_AUX_TARGETS) ...6.4.12 构建系统,打包rom构建文件,然后将其打包成rom格式... .PHONY: droidcore droidcore: $(filter $(HOST_OUT_ROOT)/%,$(modules_to_install)) \ $(INSTALLED_SYSTEMIMAGE_TARGET) \ $(INSTALLED_RAMDISK_TARGET) \ $(INSTALLED_BOOTIMAGE_TARGET) \ $(INSTALLED_DEBUG_RAMDISK_TARGET) \ $(INSTALLED_DEBUG_BOOTIMAGE_TARGET) \ $(INSTALLED_RECOVERYIMAGE_TARGET) \ $(INSTALLED_VBMETAIMAGE_TARGET) \ $(INSTALLED_USERDATAIMAGE_TARGET) \ $(INSTALLED_CACHEIMAGE_TARGET) \ $(INSTALLED_BPTIMAGE_TARGET) \ $(INSTALLED_VENDORIMAGE_TARGET) \ $(INSTALLED_ODMIMAGE_TARGET) \ $(INSTALLED_SUPERIMAGE_EMPTY_TARGET) \ $(INSTALLED_PRODUCTIMAGE_TARGET) \ $(INSTALLED_SYSTEMOTHERIMAGE_TARGET) \ $(INSTALLED_FILES_FILE) \ $(INSTALLED_FILES_JSON) \ $(INSTALLED_FILES_FILE_VENDOR) \ $(INSTALLED_FILES_JSON_VENDOR) \ $(INSTALLED_FILES_FILE_ODM) \ $(INSTALLED_FILES_JSON_ODM) \ $(INSTALLED_FILES_FILE_PRODUCT) \ $(INSTALLED_FILES_JSON_PRODUCT) \ $(INSTALLED_FILES_FILE_PRODUCT_SERVICES) \ $(INSTALLED_FILES_JSON_PRODUCT_SERVICES) \ $(INSTALLED_FILES_FILE_SYSTEMOTHER) \ $(INSTALLED_FILES_JSON_SYSTEMOTHER) \ $(INSTALLED_FILES_FILE_RAMDISK) \ $(INSTALLED_FILES_JSON_RAMDISK) \ $(INSTALLED_FILES_FILE_DEBUG_RAMDISK) \ $(INSTALLED_FILES_JSON_DEBUG_RAMDISK) \ $(INSTALLED_FILES_FILE_ROOT) \ $(INSTALLED_FILES_JSON_ROOT) \ $(INSTALLED_FILES_FILE_RECOVERY) \ $(INSTALLED_FILES_JSON_RECOVERY) \ $(INSTALLED_ANDROID_INFO_TXT_TARGET) \ auxiliary \ soong_docs ... #构建一个完整的系统——默认情况下是构建droidcore droid_targets: droidcore dist_files ...7. 总结至此,make的流程我们基本理清了,后面还有ninja是如何把build.ninja编译出来的,image如何打包的,我们后面继续分析。
2021年03月01日
1,665 阅读
0 评论
0 点赞
1
...
10
11
12
...
14