Android make 命令探索

53 篇文章 2 订阅
15 篇文章 1 订阅

前言

编译 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 [<product>-<variant>] # Choose the device to target.
m -j [<goals>]              # 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 中有对应的说明,

<p>
If you build one flavor and then want to build another, you should run
"<code>make installclean</code>" between the two makes to guarantee that
you don't pick up files installed by the previous flavor.  "<code>make
clean</code>" will also suffice, but it takes a lot longer.
</p>

搜索后找到 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/ 目录。

<li><b>clean</b> - <code>make clean</code> deletes all of the output and
intermediate files for this configuration.  This is the same as <code>rm -rf
out/&lt;configuration&gt;/</code></li>
<li><b>clobber</b> - <code>make clobber</code> deletes all of the output
and intermediate files for all configurations.  This is the same as
<code>rm -rf out/</code>.</li>
<li><b>dataclean</b> - <code>make dataclean</code> 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.</li>

对应 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 中有对应的说明,编译某个模块,单编某个模块,代码需要全编译过。

<li><b>LOCAL_MODULE</b> - Anything you specify as a <code>LOCAL_MODULE</code>
in an Android.mk is made into a pseudotarget.  For example, <code>make
runtime</code> might be shorthand for <code>make
out/linux-x86-debug/system/bin/runtime</code> (which would work), and
<code>make libkjs</code> might be shorthand for <code>make
out/linux-x86-debug/system/lib/libkjs.so</code> (which would also work).</li>
<li><b>targets</b> - <code>make targets</code> will print a list of all of
the LOCAL_MODULE names you can make.</li>
</ul>

make clean-$(LOCAL_MODULE)

build/make/core/build-system.html 中有对应的说明,清理某一个模块。

<li><b>clean-$(LOCAL_MODULE)</b> and <b>clean-$(LOCAL_PACKAGE_NAME)</b> - 
Let you selectively clean one target.  For example, you can type
<code>make clean-libutils</code> and it will delete libutils.so and all of the
intermediate files, or you can type <code>make clean-Home</code> and it will
clean just the Home app.</li>

make dataclean

build/make/core/build-system.html 中有对应的说明,清理 data 目录。

<li><b>dataclean</b> - <code>make dataclean</code> 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.</li>

对应 build/soong/ui/build/cleanbuild.go

func dataClean(ctx Context, config Config, what int) {
	removeGlobs(ctx, filepath.Join(config.ProductOut(), "data", "*"))
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
android make 介绍 Make 文件说明 整个 Build 系统的入口文件是源码树根目录下名称为“Makefile”的文件,当在源代码根目录上调用 make 命令 时,make 命令首先将读取该文件。 Makefile 文件的内容只有一行:“include build/core/main.mk”。该行代码的作用很明显:包含 build/core/main.mk 文 件。在 main.mk 文件中又会包含其他的文件,其他文件中又会包含更多的文件,这样就引入了整个 Build 系统。 这些 Make 文件间的包含关系是相当复杂的,图 3 描述了这种关系,该图中黄色标记的文件(且除了 $开头的文件) 都位于 build/core/ 目录下。 Android 源码中包含了许多的模块,模块的类型有很多种,例如:Java 库,C/C++ 库,APK 应用,以及可执行文件 等 。并且,Java 或者 C/C++ 库还可以分为静态的或者动态的,库或可执行文件既可能是针对设备(本文的“设备”指 的是 Android 系统将被安装的设备,例如某个型号的手机或平板)的也可能是针对主机(本文的“主机”指的是开发 Android 系统的机器,例如装有 Ubuntu 操作系统的 PC 机或装有 MacOS 的 iMac 或 Macbook)的。不同类型的模块 的编译步骤和方法是不一样,为了能够一致且方便的执行各种类型模块的编译,在 config.mk 中定义了许多的常量, 这其中的每个常量描述了一种类型模块的编译方式,这些常量有: BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk BUILD_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_package.mk BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk BUILD_HOST_

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值