Android——编译(二):android.mk的相关知识

简介: Android——编译(二):android.mk的相关知识

上一篇学习了make的相关东西,这里结合android.mk这个makefile文件讲讲安卓是怎么通过android.mk编译的(不用多想,android.mk就是个makefile)。

本文还是转载的前辈的文章,学习。

1. android系统源码的编译流程

来回顾一下常见的编译步骤:

source build/envsetup.sh
lunch xxx
make -j8 2>&1 | tee build.log

这三步究竟做了什么呢?我们来逐步分析一下。

1.1 source build/envsetup.sh

build/envsetup.sh这个文件中定义了一些变量和函数,执行source build/envsetup.sh之后,envsetup.sh中的变量成了全局变量,而其中的函数也可以直接在当前终端命令行中使用了。

这些函数可以帮助我们切换目录查找文件,可以使我们在编译源码时更方便。这些函数可通过hmm函数来查看,下面列出了一些常用的函数

lunch: lunch <product_name>-<build_variant> (选择要编译的目标产品和版本)
tapas: tapas [<App1> <App2> ...] [arm|x86|mips|armv5] [eng|userdebug|user]
croot: Changes directory to the top of the tree.(切换到源码的顶层目录)
m: Makes from the top of the tree.(从顶层目录build整个系统)
mm: Builds all of the modules in the current directory, but not their dependencies.(构建当前目录下所有的模块,但不包括它们的依赖)
mmm: Builds all of the modules in the supplied directories, but not their dependencies.(构建指定目录下所有的模块,但不包括它们的依赖)
mma: Builds all of the modules in the current directory, and their dependencies.(构建当前目录下所有的模块以及它们所依赖的模块)
mmma: Builds all of the modules in the supplied directories, and their dependencies.(构建指定目录下所有的模块以及它们所依赖的模块)
provision: Flash device with all required partitions. Options will be passed on to fastboot.(将设备所有需要的分区刷入,选项将传递给fastboot)
cgrep: Greps on all local C/C++ files.(在C,C++文件中搜索指定关键字)
ggrep: Greps on all local Gradle files.(在gradle文件中搜索指定关键字)
jgrep: Greps on all local Java files.(在java文件中搜索指定关键字)
resgrep: Greps on all local res/*.xml files.(在资源xml文件中搜索指定关键字)
mangrep: Greps on all local AndroidManifest.xml files.(在AndroidManifest.xml文件中搜索指定关键字)
mgrep: Greps on all local Makefiles files.(在Makefiles和android.mk文件中搜索指定关键字)
sepgrep: Greps on all local sepolicy files.(在sepolicy文件中搜索指定关键字)
sgrep: Greps on all local source files.(在所有本地文件中搜索指定关键字)
godir: Go to the directory containing a file.(切换到包含某个文件的目录下)

除了hmm提示的这些,还有一些方法,具体可以直接查看build/envsetup.sh文件(话说用来这么久,我竟然没有打开看过,真是羞愧):

cproj: 向上切换到最近包含Android.mk的目录下
findmakefile: 打印当前目录所在工程的Android.mk的文件路径
getsdcardpath: 获取Sd卡路径
getscreenshotpath: 获取屏幕截图的路径
getlastscreenshot: 获取最后一张截图,导出到当前目录下
getbugreports: 将bug报告从设备上导出到本地,bug报告存放于目录/sdcard/bugreports
gettop: 获取Android源码根目录
pid: pid processname 查看某个可执行程序对应的进程id
key_back: 模拟按返回键
key_home: 模拟按Home键
key_menu: 模拟按菜单键

envsetup.sh中还定义了add_lunch_combo函数,并且多次执行了add_lunch_combo函数,将自身定义的所有product添加到LUNCH_MENU_CHOICES中:

# Clear this variable.  It will be built up again when the vendorsetup.sh
# files are included at the end of this file.
unset LUNCH_MENU_CHOICES
function add_lunch_combo()
{
    local new_combo=$1
    local c
    for c in ${LUNCH_MENU_CHOICES[@]} ; do
        if [ "$new_combo" = "$c" ] ; then
            return
        fi
    done
    LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
}
# add the default one here
add_lunch_combo aosp_arm-eng
add_lunch_combo aosp_arm64-eng
add_lunch_combo aosp_mips-eng
add_lunch_combo aosp_mips64-eng
add_lunch_combo aosp_x86-eng
add_lunch_combo aosp_x86_64-eng

最后,envsetup.sh中还遍历并执行vendordevice目录下的所有vendorsetup.sh文件

# Execute the contents of any vendorsetup.sh files we can find.
for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
         `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
         `test -d product && find -L product -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort`
do
    echo "including $f"
    . $f
done
unset f

这些vendorsetup.sh中也定义了的一些product,执行这些vendorsetup.sh后,也会将它们当中定义的product添加到LUNCH_MENU_CHOICES中:

add_lunch_combo full_k63v2_64_bsp-eng
add_lunch_combo full_k63v2_64_bsp-user
add_lunch_combo full_k63v2_64_bsp-userdebug

在此之后,我们就可以在命令行用lunch函数从LUNCH_MENU_CHOICES中选择需要编译的product。

1.2 lunch

执行lunch函数时,如果用户指定了product,获取指定的product。

如果用户未指定product,调用print_lunch_menu函数输出上一步生成的lunch menu choices让用户选择。

如用户指定了product或者提示后选择了product,会获取用户指定的product,并提取p r o d u c t 和 product和productvariant。

然后检查是否支持product,如不支持,提示不支持并退出。如支持,接着会调用set_stuff_for_environment函数设置一系列环境变量,还会调用printconfig输出相关变量和配置信息。

function lunch()
{
    local answer
    if [ "$1" ] ; then
        answer=$1
    else
        print_lunch_menu
        echo -n "Which would you like? [aosp_arm-eng] "
        read answer
    fi
    local selection=
    if [ -z "$answer" ]
    then
        selection=aosp_arm-eng
    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
    then
        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
        then
            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
        fi
    else
        selection=$answer
    fi
    export TARGET_BUILD_APPS=
    local product variant_and_version variant version
    product=${selection%%-*} # Trim everything after first dash
    variant_and_version=${selection#*-} # Trim everything up to first dash
    if [ "$variant_and_version" != "$selection" ]; then
        variant=${variant_and_version%%-*}
        if [ "$variant" != "$variant_and_version" ]; then
            version=${variant_and_version#*-}
        fi
    fi
    if [ -z "$product" ]
    then
        echo
        echo "Invalid lunch combo: $selection"
        return 1
    fi
    TARGET_PRODUCT=$product \
    TARGET_BUILD_VARIANT=$variant \
    TARGET_PLATFORM_VERSION=$version \
    build_build_var_cache
    if [ $? -ne 0 ]
    then
        return 1
    fi
    export TARGET_PRODUCT=$(get_build_var TARGET_PRODUCT)
    export TARGET_BUILD_VARIANT=$(get_build_var TARGET_BUILD_VARIANT)
    if [ -n "$version" ]; then
      export TARGET_PLATFORM_VERSION=$(get_build_var TARGET_PLATFORM_VERSION)
    else
      unset TARGET_PLATFORM_VERSION
    fi
    export TARGET_BUILD_TYPE=release
    echo
    set_stuff_for_environment
    printconfig
    destroy_build_var_cache
}

1.3 make -j8 2>&1 | tee build.log

  • -j8是用于指定编译的cpu核心,如果编译服务器配置好,可以略为改大一些。
  • 2>&1 | tee build.log则是同时输出编译的提示、异常信息到终端和build.log文件中。
  • 具体可以看一下:
每个程序在运行后,都会至少打开三个文件描述符,分别是0:标准输入;1:标准输出;2:标准错误。
1、程序运行后会打开三个文件描述符,分别是标准输入,标准输出和标准错误输出。
2、在调用脚本时,可使用2>&1来将标准错误输出重定向。
3、只需要查看脚本的错误时,可将标准输出重定向到文件,而标准错误会打印在控制台,便于查看。
4、>>log.txt会将重定向内容追加到log.txt文件末尾。
5、通过查看/proc/进程id/fd下的内容,可了解进程打开的文件描述符信息。
  • make则是执行make命令,寻找源码根目录下的Makefile,解析Makefile并开始整个源码的编译。

接下来我们就从源码根目录下的Makefile开始逐步解析。

2. android的Makefile和android.mk

执行make之后,从源码根目录下的Makefile开始逐步解析。该Makefile的内容很少,只是导入了build/make/core/main.mk。

Makefile:

### DO NOT EDIT THIS FILE ###
include build/make/core/main.mk
### DO NOT EDIT THIS FILE ###

main.mk中有两个最重要的部分,一个是导入build/make/core/config.mk和build/make/core/definitions.mk

main.mk:

......
BUILD_SYSTEM := $(TOPDIR)build/make/core
......
# Set up various standard variables based on configuration
# and host information.
include $(BUILD_SYSTEM)/config.mk
......
# Bring in standard build system definitions.
include $(BUILD_SYSTEM)/definitions.mk
......

config.mk中定义了一系列编译需要用到的变量,比如常用的CLEAR_VARSBUILD_PACKAGE。这些变量实际上是每一个变量导入另一个.mk文件

每一个被导入的.mk完成一个基本功能,比如,CLEAR_VARS对应的build/make/core/clear_vars.mk清除编译的临时变量,BUILD_PACKAGE对应的build/make/core/package.mk是编译APK。

config.mk:

# Set up efficient math functions which are used in make.
# Here since this file is included by envsetup as well as during build.
include $(BUILD_SYSTEM)/math.mk
# Various mappings to avoid hard-coding paths all over the place
include $(BUILD_SYSTEM)/pathmap.mk
# Allow projects to define their own globally-available variables
include $(BUILD_SYSTEM)/project_definitions.mk
# ###############################################################
# Build system internal files
# ###############################################################
BUILD_COMBOS:= $(BUILD_SYSTEM)/combo
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.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_HEADER_LIBRARY:= $(BUILD_SYSTEM)/header_library.mk
BUILD_AUX_STATIC_LIBRARY:= $(BUILD_SYSTEM)/aux_static_library.mk
BUILD_AUX_EXECUTABLE:= $(BUILD_SYSTEM)/aux_executable.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/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_RRO_PACKAGE:= $(BUILD_SYSTEM)/build_rro_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_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
BUILD_APIDIFF:= $(BUILD_SYSTEM)/apidiff.mk
BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
BUILD_NATIVE_TEST := $(BUILD_SYSTEM)/native_test.mk
BUILD_NATIVE_BENCHMARK := $(BUILD_SYSTEM)/native_benchmark.mk
BUILD_HOST_NATIVE_TEST := $(BUILD_SYSTEM)/host_native_test.mk
BUILD_FUZZ_TEST := $(BUILD_SYSTEM)/fuzz_test.mk
BUILD_HOST_FUZZ_TEST := $(BUILD_SYSTEM)/host_fuzz_test.mk
BUILD_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/shared_test_lib.mk
BUILD_HOST_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/host_shared_test_lib.mk
BUILD_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/static_test_lib.mk
BUILD_HOST_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/host_static_test_lib.mk
BUILD_NOTICE_FILE := $(BUILD_SYSTEM)/notice_files.mk
BUILD_HOST_DALVIK_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_java_library.mk
BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_static_java_library.mk
BUILD_HOST_TEST_CONFIG := $(BUILD_SYSTEM)/host_test_config.mk
BUILD_TARGET_TEST_CONFIG := $(BUILD_SYSTEM)/target_test_config.mk

definitions.mk中用define也定义了一系列变量,比如常用的my-dir、all-subdir-makefiles、all-subdir-java-files等等。

这些编译主要用于处理目录相关的功能,比如my-dir是获取当前目录路径,all-subdir-makefiles 调用所有子目录的android.mk

definitions.mk中有很多变量,列举如下:

definitions.mk:

define print-vars
define true-or-empty
define gcno-touch-rule
define my-dir
define all-makefiles-under
define first-makefiles-under
define all-subdir-makefiles
define all-named-subdir-makefiles
define all-named-dirs-under
define all-subdir-named-dirs
define all-named-files-under
define all-subdir-named-files
define all-java-files-under
define all-subdir-java-files
define all-c-files-under
define all-subdir-c-files
define all-cpp-files-under
define all-subdir-cpp-files
define all-Iaidl-files-under
define all-subdir-Iaidl-files
define all-vts-files-under
define all-subdir-vts-files
define all-logtags-files-under
define all-proto-files-under
define all-renderscript-files-under
define all-S-files-under
define all-html-files-under
define all-subdir-html-files
define find-subdir-files
define find-subdir-subdir-files
define find-subdir-assets
define find-other-java-files
define find-other-html-files
define find-files-in-subdirs
define find-parent-file
define find-test-data-in-subdirs
define add-dependency
define reverse-list
define def-host-aux-target
define find-idf-prefix
define intermediates-dir-for
define local-intermediates-dir
define generated-sources-dir-for
define local-generated-sources-dir
define module-built-files
define module-installed-files
define module-stubs-files
define doc-timestamp-for
define java-lib-files
define java-lib-header-files
define java-lib-header-files
define java-lib-deps
define app-lib-files
define app-lib-header-files
define app-lib-header-files
define streq
define normalize-path-list
define normalize-comma-list
define word-colon
define collapse-pairs
define uniq-pairs-by-first-component
define modules-for-tag-list
define module-names-for-tag-list
define get-tagged-modules
define append-path
define echo-warning
define echo-error
define pretty-warning
define pretty-error
define _get-package-overrides
define get-package-overrides
define pretty
define pretty
define include-depfile
define include-depfiles-for-objs
define track-src-file-obj
define _track-src-file-obj
define track-src-file-gen
define _track-src-file-gen
define track-gen-file-obj
define transform-l-to-c-or-cpp
define transform-y-to-c-or-cpp
define _merge-renderscript-d
define transform-renderscripts-to-java-and-bc
define transform-bc-to-so
define transform-renderscripts-to-cpp-and-bc
define transform-aidl-to-java
define transform-aidl-to-cpp
define define-aidl-java-rule
define define-aidl-java-rule
define-aidl-java-rule-src
define define-aidl-cpp-rule
define define-aidl-cpp-rule
define-aidl-cpp-rule-src
define transform-vts-to-cpp
define define-vts-cpp-rule
define define-vts-cpp-rule
define-vts-cpp-rule-src
define transform-logtags-to-java
define transform-proto-to-java
define transform-proto-to-cc
define c-includes
define transform-cpp-to-o-compiler-args
define clang-tidy-cpp
define transform-cpp-to-o
define transform-cpp-to-o
define transform-c-or-s-to-o-compiler-args
define transform-c-to-o-compiler-args
define clang-tidy-c
define transform-c-to-o
define transform-c-to-o
define transform-s-to-o
define transform-asm-to-o
define transform-m-to-o
define transform-host-cpp-to-o-compiler-args
define clang-tidy-host-cpp
define transform-host-cpp-to-o
define transform-host-cpp-to-o
define transform-host-c-or-s-to-o-common-args
define transform-host-c-or-s-to-o
define transform-host-c-to-o-compiler-args
define clang-tidy-host-c
define transform-host-c-to-o
define transform-host-c-to-o
define transform-host-s-to-o
define transform-host-m-to-o
define transform-host-mm-to-o
define compile-dotdot-cpp-file
define compile-dotdot-c-file
define compile-dotdot-s-file
define compile-dotdot-s-file-no-deps
define _concat-if-arg2-not-empty
define split-long-arguments
define _extract-and-include-single-target-whole-static-lib
define extract-and-include-whole-static-libs-first
define extract-and-include-target-whole-static-libs
define transform-o-to-static-lib
define _extract-and-include-single-aux-whole-static-lib
define extract-and-include-aux-whole-static-libs
define transform-o-to-aux-static-lib
define transform-o-to-aux-executable-inner
define transform-o-to-aux-executable
define transform-o-to-aux-static-executable-inner
define transform-o-to-aux-static-executable
define _extract-and-include-single-host-whole-static-lib
define extract-and-include-host-whole-static-libs
define create-dummy.o-if-no-objs
define get-dummy.o-if-no-objs
define delete-dummy.o-if-no-objs
define transform-host-o-to-static-lib
define transform-host-o-to-shared-lib-inner
define transform-host-o-to-shared-lib
define transform-host-o-to-package
define transform-o-to-shared-lib-inner
define transform-o-to-shared-lib
define transform-to-stripped
define transform-to-stripped-keep-mini-debug-info
define transform-to-stripped-keep-symbols
define pack-elf-relocations
define transform-o-to-executable-inner
define transform-o-to-executable
define transform-o-to-static-executable-inner
define transform-o-to-static-executable
define transform-host-o-to-executable-inner
define transform-host-o-to-executable
define create-resource-java-files
define find-generated-R.java
define aapt2-compile-one-resource-file
define aapt2-compile-resource-dirs
define aapt2-compile-resource-zips
define aapt2-compile-one-resource-file-rule
define aapt2-compiled-resource-out-file
define aapt2-link
define emit-line
define dump-words-to-file
define unzip-jar-files
define jar-args-sorted-files-in-directory
define fetch-additional-java-source
define write-java-source-list
define compile-java
define transform-java-to-header.jar
define commit-change-for-toc
define _transform-dex-to-toc
define define-dex-to-toc-rule
define define-dex-to-toc-rule
define define-dex-to-toc-rule
define define-dex-to-toc-rule
define codename-or-sdk-to-sdk
define desugar-classes-jar
define transform-classes.jar-to-dex
define transform-classes-d8.jar-to-dex
define create-empty-package-at
define create-empty-package
define initialize-package-file
define add-assets-to-package
define _add-jni-shared-libs-to-package-per-abi
define add-jni-shared-libs-to-package
define add-dex-to-package
define add-dex-to-package-arg
define add-java-resources-to
define add-jar-resources-to-package
define sign-package
define sign-package-arg
define align-package
define compress-package
define remove-timestamps-from-package
define uncompress-dexs
define uncompress-shared-libs
define transform-host-java-to-package
define transform-host-java-to-dalvik-package
define copy-one-header
define copy-one-file
define copy-and-uncompress-dexs
define copy-many-files
define copy-xml-file-checked
define copy-file-to-target
define copy-file-to-target-with-cp
define copy-file-to-target-strip-comments
define copy-file-to-new-target
define copy-file-to-new-target-with-cp
define transform-prebuilt-to-target
define transform-prebuilt-to-target-strip-comments
define copy-files-with-structure
define symlink-file
define _symlink-file
define dexpreopt-copy-jar
define dexpreopt-remove-classes.dex
define hiddenapi-copy-dex-files
define hiddenapi-copy-soong-jar
define transform-jar-to-proguard
define transform-jar-to-proguard
define transform-jar-to-dex-r8
define transform-generated-source
define assert-max-image-size
define add-radio-file
define add-radio-file-internal
define add-radio-file-checked
define add-radio-file-checked-internal
define inherit-package
define inherit-package-internal
define set-inherited-package-variables
define keep-or-override
define set-inherited-package-variables-internal
define check-api
define if-build-from-source
define if-build-from-source
define include-if-build-from-source
define get-prebuilt-src-arch
define record-module-type
define compatibility_suite_dirs
define create-suite-dependencies
define _clean-path-strip-dotdot
define _clean-path-strip-root-dotdots
define _clean-path-expanded
define clean-path
define my_test
define try-validate-path-is-subdir
define validate-path-is-subdir
define try-validate-paths-are-subdirs
define validate-paths-are-subdirs
define test-validate-paths-are-subdirs
define jacoco-class-filter-to-file-args
define jacoco-validate-file-args
define append_enforce_rro_sources
define generate_all_enforce_rro_packages
define has-system-sdk-version
define get-numeric-sdk-version

main.mk中另一个重要的部分就是定义了一系列的规则,这些规则的目标就是编译要生成的目标文件:

# This is the default target.  It must be the first declared target.
.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL): droid_targets
......
.PHONY: ramdisk
ramdisk: $(INSTALLED_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: systemotherimage
systemotherimage: $(INSTALLED_SYSTEMOTHERIMAGE_TARGET)
.PHONY: bootimage
bootimage: $(MTK_BOOTIMAGE_TARGET)

而编译的默认目标,也就是终极目标droid,逐级依赖,依赖到各个image文件,也就是各个分区imge文件:

# Building a full system-- the default is to build droidcore
droid_targets: droidcore dist_files
......
# Build files and then package it into the rom formats
.PHONY: droidcore
droidcore: files \
    systemimage \
    $(INSTALLED_BOOTIMAGE_TARGET) \
    $(MTK_BOOTIMAGE_TARGET) \
    $(INSTALLED_RECOVERYIMAGE_TARGET) \
    $(INSTALLED_VBMETAIMAGE_TARGET) \
    $(INSTALLED_USERDATAIMAGE_TARGET) \
    $(INSTALLED_CACHEIMAGE_TARGET) \
    $(INSTALLED_BPTIMAGE_TARGET) \
    $(INSTALLED_VENDORIMAGE_TARGET) \
    $(INSTALLED_PRODUCTIMAGE_TARGET) \
    $(INSTALLED_SYSTEMOTHERIMAGE_TARGET) \
    $(INSTALLED_FILES_FILE) \
    $(INSTALLED_FILES_FILE_VENDOR) \
    $(INSTALLED_FILES_FILE_PRODUCT) \
    $(INSTALLED_FILES_FILE_SYSTEMOTHER) \
    soong_docs

根据make的编译原理,编译时,先编译终极目标的各个依赖文件,如image文件、bin文件等等,而image文件又依赖许多的库文件、APK文件、资源文件等等,也就会递归触发库文件、APK文件、资源文件等模块的编译。

递归编译完依赖文件,最后完成终极目标,这样就完成了整个android源码的构建。

当然,main.mk中为了完成整个android的编译,还导入了一系列的mk等等,这里就不一一介绍了,有兴趣的可以自行查看源码。

同样,根据make的编译原理,我们也可以通过make指定的目标单独编译某个模块,这样可以加快编译速度。例如: make systemimage。

当然,为了进一步加快编译速度,我们还可以**利用envsetup.sh中的mm或者mmm函数,在仅需要编译模块自身,**不需要编译模块的依赖的情况下,用mm或者mmm编译更快

我们可以看到,实际上android.mk和Makefile没有明显差别。

android.mk实际上只是多了一些方便编译android源码的内置变量内置函数

android.mk完全遵循Makefile的语法规则,并且它的内置变量和内置函数也是按照Makefile语法进行导入的。

最关键的,构建android系统时也是从一个Makefile开始的。

所以,我们可以认为android.mk实际上是一种扩展的Makefile,就像GNU make扩展了原始make一样。

接下来我们介绍android.mk的使用实例。

3. android.mk的使用实例

3.1 编译APK

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# 源文件,可包含java、aidl文件
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES += src/com/sprd/gallery3d/aidl/IFloatWindowController.aidl
# resource资源文件
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
# AndroidManifest.xml文件
LOCAL_MANIFEST_FILE := $(LOCAL_PATH)/AndroidManifest.xml
# 是否启用AAPT2
LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := optional
# 目标APK文件名称
LOCAL_PACKAGE_NAME := DreamCamera2
# 需要override的名称
LOCAL_OVERRIDES_PACKAGES := Camera2
# APK的签名
LOCAL_CERTIFICATE := platform
# 是否启用odex优化
LOCAL_DEX_PREOPT := false
# SDK版本
LOCAL_SDK_VERSION := current
# 混淆配置文件
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
# 依赖的java共享库
LOCAL_JAVA_LIBRARIES := android.test.runner
# 依赖的java静态库
LOCAL_STATIC_JAVA_LIBRARIES := zxing
# 依赖的共享库
LOCAL_SHARED_LIBRARIES := libjpeg
# 依赖的静态库
LOCAL_STATIC_LIBRARIES := libjpeg_static_ndk
# 版本号
LOCAL_AAPT_FLAGS := \
        --auto-add-overlay \
        --version-name "$(version_name_package)" \
        --version-code $(version_code_package) \
# 构建APK
include $(BUILD_PACKAGE)

3.2 编译java静态库

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 源文件,可包含java、aidl文件
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# 依赖的java静态库
LOCAL_STATIC_JAVA_LIBRARIES := zxing
# 依赖的java动态库
LOCAL_JAVA_LIBRARIES := android.test.runner
# 目标java静态库的名称
LOCAL_MODULE := scan
# 构建java静态库
include $(BUILD_STATIC_JAVA_LIBRARY)

3.3 编译java共享库

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 源文件,可包含java、aidl文件
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# 依赖的java共享库
LOCAL_JAVA_LIBRARIES := bouncycastle core-libart ext services.core
LOCAL_MODULE_TAGS := optional
LOCAL_JACK_ENABLED := disabled
# 目标java共享库的名称
LOCAL_MODULE:= security
# 构建java共享库
include $(BUILD_JAVA_LIBRARY)

3.4 编译C/C++静态库

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# 目标静态库的名称
LOCAL_MODULE := libgif-ex
# C/C++源文件
LOCAL_SRC_FILES := \
    dgif_lib.c     \
    egif_lib.c     \
    gifalloc.c     \
    gif_err.c      \
    gif_hash.c     \
    openbsd-reallocarray.c    \
    quantize.c
LOCAL_CFLAGS += -Wno-format -Wno-sign-compare -Wno-unused-parameter -DHAVE_CONFIG_H
LOCAL_SDK_VERSION := 8
LOCAL_NDK_STL_VARIANT := c++_static
# 构建C/C++静态库
include $(BUILD_STATIC_LIBRARY)

3.5 编译C/C++共享库

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# C/C++头文件
LOCAL_C_INCLUDES := \
        $(LOCAL_PATH)/include \
        $(TOPDIR)system/core/include
# C FLAG
LOCAL_CFLAGS := -O3 -DNDEBUG
# LDFLAG
LOCAL_LDFLAGS := -llog
# 依赖的共享库
LOCAL_SHARED_LIBRARIES := \
                          libutils \
                          myutils 
# 依赖的静态库
LOCAL_STATIC_LIBRARIES := libjpeg_static_ndk
# C/C++源文件
LOCAL_SRC_FILES := \
                   main.cpp \
                   utils.cpp 
# 目标共享库的名称
LOCAL_MODULE    := mylib
LOCAL_MODULE_TAGS := optional
# 构建共享库
include $(BUILD_SHARED_LIBRARY)

4. 用于预置的android.mk

4.1 预置jar

方法一:

LOCAL_PATH:= $(call my-dir)
# 预置
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := zxing:libs/core.jar \
                                        gson:libs/gson-2.8.0.jar \
                                        android-support-v7:libs/android-support-v7-recyclerview.jar 
include $(BUILD_MULTI_PREBUILT)
# 引用
include $(CLEAR_VARS)
......
LOCAL_STATIC_JAVA_LIBRARIES += zxing
LOCAL_STATIC_JAVA_LIBRARIES += gson
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7
......
include $(BUILD_PACKAGE)

方法二:

LOCAL_PATH := $(call my-dir)
# 预置
include $(CLEAR_VARS)
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE := commons-io
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := ../../../../../../../../prebuilts/tools/common/m2/repository/commons-io/commons-io/2.4/commons-io-2.4.jar
LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_PREBUILT)
# 引用
include $(CLEAR_VARS)
......
LOCAL_STATIC_JAVA_LIBRARIES += commons-io
......
include $(BUILD_PACKAGE)

4.2 预置so

方法一:

LOCAL_PATH:= $(call my-dir)
# 预置
include $(CLEAR_VARS)
LOCAL_MODULE := mylib2
LOCAL_SRC_FILES_32 := lib/armeabi-v7a/mylib2.so
LOCAL_SRC_FILES_64 := lib/arm64-v8a/mylib2.so
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := .so
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MULTILIB := both
include $(BUILD_PREBUILT)
......
# 引用
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES += mylib2
include $(BUILD_PACKAGE)
......

方法二:

LOCAL_PATH:= $(call my-dir)
# 预置
include $(CLEAR_VARS)
......
ifeq ($(strip $(TARGET_ARCH)), arm64)
    LOCAL_PREBUILT_JNI_LIBS := libs/arm64-v8a/mylib3.so
else ifeq ($(strip $(TARGET_ARCH)), x86_64)
    LOCAL_PREBUILT_JNI_LIBS := libs/x86_64/mylib3.so
else ifeq ($(strip $(TARGET_ARCH)),arm)
    LOCAL_PREBUILT_JNI_LIBS := libs/armeabi-v7a/mylib3.so
else
    LOCAL_PREBUILT_JNI_LIBS := libs/x86/mylib3.so
endif
......
include $(BUILD_PACKAGE)

4.3 预置APK

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 模块名称
LOCAL_MODULE := NewGallery2
# 要覆盖掉的模块名称
LOCAL_OVERRIDES_PACKAGES := Gallery Gallery3D GalleryNew3D Gallery2 DreamGallery2
# 模块类型为APPS
LOCAL_MODULE_CLASS := APPS
# 允许使用系统隐藏接口
LOCAL_PRIVATE_PLATFORM_APIS := true
# 签名,如无需重签名,则直接设置为PRESIGNED使用已有签名;需要重签,则设置为对应签名的值。
LOCAL_CERTIFICATE := platform
# 目标编译后的输出目录
LOCAL_MODULE_PATH := $(TARGET_OUT)/priv-app
# APK文件
LOCAL_SRC_FILES := apk/NewGallery2.apk
# APK预置的so
ifeq ($(strip $(TARGET_ARCH)), arm64)
    LOCAL_PREBUILT_JNI_LIBS := libs/arm64-v8a/libjni_jpeg.so
else ifeq ($(strip $(TARGET_ARCH)), x86_64)
    LOCAL_PREBUILT_JNI_LIBS := libs/x86_64/libjni_jpeg.so
else ifeq ($(strip $(TARGET_ARCH)),arm)
    LOCAL_PREBUILT_JNI_LIBS := libs/armeabi-v7a/libjni_jpeg.so
else
    LOCAL_PREBUILT_JNI_LIBS := libs/x86/libjni_jpeg.so
endif
include $(BUILD_PREBUILT)

5、结语

在掌握了Makefile基础知识以及结合源码理清楚了android.mk之后,就不会觉得.mk文件那么陌生了。

尤其是在理解了android.mk的内置变量和内置函数之后,我们在编写.mk文件就基本可以得心应手了。

由于make在编译android系统源码时表现出效率不够高的问题,google后来在7.0及以上版本引进了速度更快的Soong,Soong对应的配置文件是android.bp。

但google即便引进了Soong,源码中还是保留了部分android.mk

并且android.mk也可以通过kati工具转换成ninja构建清单文件,也就是说android.mk还可以继续使用。

所以,make仍然是android开发者的必备技能

目录
相关文章
|
3月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
241 1
|
5月前
|
Java API 开发工具
如何将python应用编译到android运行
【6月更文挑战第27天】本文介绍在Ubuntu 20上搭建Android开发环境,包括安装JRE/JDK,设置环境变量,添加i386架构,安装依赖和编译工具。并通过`p4a`命令行工具进行apk构建和清理。
87 6
如何将python应用编译到android运行
|
1月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
82 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
1月前
|
编译器 Android开发
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
|
1月前
|
Ubuntu Shell API
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
|
5月前
|
Android开发 iOS开发
android自动化编译
android自动化编译
|
3月前
|
Android开发 Docker 容器
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
616 1
|
3月前
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
132 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
3月前
|
API 开发工具 Android开发
Android Studio:解决AOSP自编译framework.jar引用不到的问题
在Android Studio中解决AOSP自编译framework.jar引用问题的几种方法,包括使用相对路径、绝对路径和通过`${project.rootDir}`动态获取路径的方法,以避免硬编码路径带来的配置问题。
234 0
Android Studio:解决AOSP自编译framework.jar引用不到的问题
|
3月前
|
搜索推荐 Android开发
学习AOSP安卓系统源代码,需要什么样的电脑?不同配置的电脑,其编译时间有多大差距?
本文分享了不同价位电脑配置对于编译AOSP安卓系统源代码的影响,提供了从6000元到更高价位的电脑配置实例,并比较了它们的编译时间,以供学习AOSP源代码时电脑配置选择的参考。
236 0
学习AOSP安卓系统源代码,需要什么样的电脑?不同配置的电脑,其编译时间有多大差距?