编译 Android aosp 源码的步骤一般为
source build/envsetup.sh
lunch //选择对应的device
make -j12
如果切换了 device 或者代码有改动,一般会执行 make installclean ;make -j12
,
如果编译报错,排除语法问题,则需要 make clean ; make -j12
。
这些 make 命令具体做了什么,探索记录下。
基于 Android 11 ,make 命令可直接用 m 。
涉及的文件:
build/soong/ui/build/build.go
build/make/help.sh
build/make/core/build-system.html
build/soong/ui/build/cleanbuild.go
make 后面的不同参数,是在 build/soong/ui/build/build.go
中区分的,
// Build the tree. The 'what' argument can be used to chose which components of
// the build to run.
func Build(ctx Context, config Config, what int) {
ctx.Verboseln("Starting build with args:", config.Arguments())
ctx.Verboseln("Environment:", config.Environment().Environ())
if totalRAM := config.TotalRAM(); totalRAM != 0 {
ram := float32(totalRAM) / (1024 * 1024 * 1024)
ctx.Verbosef("Total RAM: %.3vGB", ram)
if ram <= 16 {
ctx.Println("************************************************************")
ctx.Printf("You are building on a machine with %.3vGB of RAM\n", ram)
ctx.Println("")
ctx.Println("The minimum required amount of free memory is around 16GB,")
ctx.Println("and even with that, some configurations may not work.")
ctx.Println("")
ctx.Println("If you run into segfaults or other errors, try reducing your")
ctx.Println("-j value.")
ctx.Println("************************************************************")
} else if ram <= float32(config.Parallel()) {
ctx.Printf("Warning: high -j%d count compared to %.3vGB of RAM", config.Parallel(), ram)
ctx.Println("If you run into segfaults or other errors, try a lower -j value")
}
}
ctx.BeginTrace(metrics.Total, "total")
defer ctx.EndTrace()
if config.SkipMake() {
ctx.Verboseln("Skipping Make/Kati as requested")
what = what & (BuildSoong | BuildNinja)
}
if inList("help", config.Arguments()) { //注释1
help(ctx, config, what)
return
} else if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) { //注释2
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 config.StartRBE() {
// Ensure RBE proxy is started
startRBE(ctx, config)
}
if what&BuildProductConfig != 0 {
// Run make for product config
runMakeProductConfig(ctx, config)
}
if inList("installclean", config.Arguments()) ||
inList("install-clean", config.Arguments()) { //注释3
installClean(ctx, config, what)
ctx.Println("Deleted images and staging directories.")
return
} else if inList("dataclean", config.Arguments()) ||
inList("data-clean", config.Arguments()) { //注释4
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)
}
}
注释1 :对应 make help
注释2 :对应 make clean
注释3 :对应 make installclean
注释4 :对应 make dataclean
在 build/soong/ui/build/build.go
中定义如下,实际是索引到 build/make/help.sh
,
func help(ctx Context, config Config, what int) {
cmd := Command(ctx, config, "help.sh", "build/make/help.sh")
cmd.Sandbox = dumpvarsSandbox
cmd.RunAndPrintOrFatal()
}
运行结果,
source build/envsetup.sh # Add "lunch" (and other utilities and variables)
# to the shell environment.
lunch [-] # Choose the device to target.
m -j [] # Execute the configured build.
Usage of "m" imitates usage of the program "make".
See /ANDROIDR/build/make/Usage.txt for more info about build usage and concepts.
Common goals are:
clean (aka clobber) equivalent to rm -rf out/
checkbuild Build every module defined in the source tree
droid Default target
nothing Do not build anything, just parse and validate the build structure
java Build all the java code in the source tree
native Build all the native code in the source tree
host Build all the host code (not to be run on a device) in the source tree
target Build all the target code (to be run on the device) in the source tree
(java|native)-(host|target)
(host|target)-(java|native)
Build the intersection of the two given arguments
snod Quickly rebuild the system image from built packages
Stands for "System, NO Dependencies"
vnod Quickly rebuild the vendor image from built packages
Stands for "Vendor, NO Dependencies"
pnod Quickly rebuild the product image from built packages
Stands for "Product, NO Dependencies"
senod Quickly rebuild the system_ext image from built packages
Stands for "SystemExt, NO Dependencies"
onod Quickly rebuild the odm image from built packages
Stands for "ODM, NO Dependencies"
So, for example, you could run:
cd /ANDROIDR
source build/envsetup.sh
lunch aosp_arm-userdebug
m -j java
to build all of the java code for the userdebug variant of the aosp_arm device.
清除上一次编译的产物,具体清除什么呢?
在 build/make/core/build-system.html
中有对应的说明,
If you build one flavor and then want to build another, you should run
"make installclean
" between the two makes to guarantee that
you don't pick up files installed by the previous flavor. "make
clean
" will also suffice, but it takes a lot longer.
搜索后找到 build/soong/ui/build/cleanbuild.go
,
// installClean deletes all of the installed files -- the intent is to remove
// files that may no longer be installed, either because the user previously
// installed them, or they were previously installed by default but no longer
// are.
//
// This is faster than a full clean, since we're not deleting the
// intermediates. Instead of recompiling, we can just copy the results.
func installClean(ctx Context, config Config, what int) {
dataClean(ctx, config, what)
if hostCrossOutPath := config.hostCrossOut(); hostCrossOutPath != "" {
hostCrossOut := func(path string) string {
return filepath.Join(hostCrossOutPath, path)
}
removeGlobs(ctx,
hostCrossOut("bin"),
hostCrossOut("coverage"),
hostCrossOut("lib*"),
hostCrossOut("nativetest*"))
}
hostOutPath := config.HostOut()
hostOut := func(path string) string {
return filepath.Join(hostOutPath, path)
}
productOutPath := config.ProductOut()
productOut := func(path string) string {
return filepath.Join(productOutPath, path)
}
ctx.Printf("[TEST] in installClean , productOutPath :%q", productOutPath) // 注释 1
// Host bin, frameworks, and lib* are intentionally omitted, since
// otherwise we'd have to rebuild any generated files created with
// those tools.
removeGlobs(ctx,
hostOut("apex"),
hostOut("obj/NOTICE_FILES"),
hostOut("obj/PACKAGING"),
hostOut("coverage"),
hostOut("cts"),
hostOut("nativetest*"),
hostOut("sdk"),
hostOut("sdk_addon"),
hostOut("testcases"),
hostOut("vts"),
hostOut("vts10"),
hostOut("vts-core"),
productOut("*.img"),
productOut("*.zip"),
productOut("android-info.txt"),
productOut("apex"),
productOut("kernel"),
productOut("data"),
productOut("skin"),
productOut("obj/APPS"),//注释2
productOut("obj/NOTICE_FILES"),
productOut("obj/PACKAGING"),
productOut("ramdisk"),
productOut("debug_ramdisk"),
productOut("vendor-ramdisk"),
productOut("vendor-ramdisk-debug.cpio.gz"),
productOut("vendor_debug_ramdisk"),
productOut("test_harness_ramdisk"),
productOut("recovery"),
productOut("root"),
productOut("system"),
productOut("system_other"),
productOut("vendor"),
productOut("product"),
productOut("system_ext"),
productOut("oem"),
productOut("obj/FAKE"),
productOut("breakpad"),
productOut("cache"),
productOut("coverage"),
productOut("installer"),
productOut("odm"),
productOut("sysloader"),
productOut("testcases"))
}
注释1 处 :打印出来就是 out/target/product/xxx , xxx 就是 lunch 时选择的 device 。
注释2 处 :自己加的,把这个目录也清除了。这个目录是编译应用生成的中间产物,如 Bluetooth_intermediates
、QuickSearchBox_intermediates
。
运行 log 如下,
11:11:17 [TEST] in removeGlobs , remove "out/host/windows-x86/lib"
11:11:17 [TEST] in removeGlobs , remove "out/host/windows-x86/lib64"
11:11:17 [TEST] in installClean , productOutPath :"out/target/product/xxx"
11:11:17 [TEST] in removeGlobs , remove "out/host/linux-x86/obj/NOTICE_FILES"
11:11:17 [TEST] in removeGlobs , remove "out/target/product/xxx/boot-debug.img"
11:11:17 [TEST] in removeGlobs , remove "out/target/product/xxx/boot.img"
11:11:17 [TEST] in removeGlobs , remove "out/target/product/xxx/cache.img"
11:11:17 [TEST] in removeGlobs , remove "out/target/product/xxx/dtb.img"
11:11:17 [TEST] in removeGlobs , remove "out/target/product/xxx/ramdisk-debug.img"
11:11:17 [TEST] in removeGlobs , remove "out/target/product/xxx/ramdisk-recovery.img"
11:11:17 [TEST] in removeGlobs , remove "out/target/product/xxx/ramdisk.img"
11:11:17 [TEST] in removeGlobs , remove "out/target/product/xxx/recovery.img"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/super.img"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/system.img"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/tvconfig.img"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/userdata.img"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/vendor.img"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/android-info.txt"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/apex"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/kernel"
11:11:18 [TEST] in removeGlobs , remove "out/target/product/xxx/data"
11:11:19 [TEST] in removeGlobs , remove "out/target/product/xxx/obj/NOTICE_FILES"
11:11:20 [TEST] in removeGlobs , remove "out/target/product/xxx/obj/PACKAGING"
11:11:20 [TEST] in removeGlobs , remove "out/target/product/xxx/ramdisk"
11:11:20 [TEST] in removeGlobs , remove "out/target/product/xxx/debug_ramdisk"
11:11:20 [TEST] in removeGlobs , remove "out/target/product/xxx/recovery"
11:11:20 [TEST] in removeGlobs , remove "out/target/product/xxx/root"
11:11:27 [TEST] in removeGlobs , remove "out/target/product/xxx/system"
11:11:27 [TEST] in removeGlobs , remove "out/target/product/xxx/vendor"
11:11:28 [TEST] in removeGlobs , remove "out/target/product/xxx/obj/FAKE"
11:11:28 [TEST] in removeGlobs , remove "out/target/product/xxx/cache"
在 build/make/core/build-system.html
中有对应的说明,等同于删除 out/
目录。
clean - make clean
deletes all of the output and
intermediate files for this configuration. This is the same as rm -rf
out/<configuration>/
clobber - make clobber
deletes all of the output
and intermediate files for all configurations. This is the same as
rm -rf out/
.
dataclean - make dataclean
deletes contents of the data
directory inside the current combo directory. This is especially useful on the
simulator and emulator, where the persistent data remains present between
builds.
对应 build/soong/ui/build/cleanbuild.go
// Remove everything under the out directory. Don't remove the out directory
// itself in case it's a symlink.
func clean(ctx Context, config Config, what int) {
removeGlobs(ctx, filepath.Join(config.OutDir(), "*"))
ctx.Println("Entire build directory removed.")
}
在 build/make/core/build-system.html
中有对应的说明,编译某个模块,单编某个模块,代码需要全编译过。
LOCAL_MODULE - Anything you specify as a LOCAL_MODULE
in an Android.mk is made into a pseudotarget. For example, make
runtime
might be shorthand for make
out/linux-x86-debug/system/bin/runtime
(which would work), and
make libkjs
might be shorthand for make
out/linux-x86-debug/system/lib/libkjs.so
(which would also work).
targets - make targets
will print a list of all of
the LOCAL_MODULE names you can make.
在 build/make/core/build-system.html
中有对应的说明,清理某一个模块。
clean-$(LOCAL_MODULE) and clean-$(LOCAL_PACKAGE_NAME) -
Let you selectively clean one target. For example, you can type
make clean-libutils
and it will delete libutils.so and all of the
intermediate files, or you can type make clean-Home
and it will
clean just the Home app.
在 build/make/core/build-system.html
中有对应的说明,清理 data 目录。
dataclean - make dataclean
deletes contents of the data
directory inside the current combo directory. This is especially useful on the
simulator and emulator, where the persistent data remains present between
builds.
对应 build/soong/ui/build/cleanbuild.go
,
func dataClean(ctx Context, config Config, what int) {
removeGlobs(ctx, filepath.Join(config.ProductOut(), "data", "*"))
}