Android make 命令探索

编译 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 参数追踪

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

make help

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.

make installclean

清除上一次编译的产物,具体清除什么呢?

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_intermediatesQuickSearchBox_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"

make clean && make clobber

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.")
    }
    

    make LOCAL_MODULE

    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.
  • make clean-$(LOCAL_MODULE)

    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.
  • make dataclean

    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", "*"))
    }
    

    你可能感兴趣的:(Android,编译,aosp,android,build)