Android(安卓)编译之android.mk
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
- (选择要编译的目标产品和版本) - tapas: tapas [ ...] [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_CHOICESfunction 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 hereadd_lunch_combo aosp_arm-engadd_lunch_combo aosp_arm64-engadd_lunch_combo aosp_mips-engadd_lunch_combo aosp_mips64-engadd_lunch_combo aosp_x86-engadd_lunch_combo aosp_x86_64-eng
最后,envsetup.sh中还遍历并执行vendor和device目录下的所有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" . $fdoneunset f
这些vendorsetup.sh中也定义了的一些product,执行这些vendorsetup.sh后,也会将它们当中定义的product添加到LUNCH_MENU_CHOICES中:
add_lunch_combo full_k63v2_64_bsp-engadd_lunch_combo full_k63v2_64_bsp-useradd_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,并提取$product和$variant。然后检查是否支持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文件中。
- 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_VARS、BUILD_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 placeinclude $(BUILD_SYSTEM)/pathmap.mk# Allow projects to define their own globally-available variablesinclude $(BUILD_SYSTEM)/project_definitions.mk# ################################################################ Build system internal files# ###############################################################BUILD_COMBOS:= $(BUILD_SYSTEM)/comboCLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mkBUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mkBUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mkBUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mkBUILD_HEADER_LIBRARY:= $(BUILD_SYSTEM)/header_library.mkBUILD_AUX_STATIC_LIBRARY:= $(BUILD_SYSTEM)/aux_static_library.mkBUILD_AUX_EXECUTABLE:= $(BUILD_SYSTEM)/aux_executable.mkBUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mkBUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mkBUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mkBUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mkBUILD_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_package.mkBUILD_RRO_PACKAGE:= $(BUILD_SYSTEM)/build_rro_package.mkBUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mkBUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mkBUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mkBUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mkBUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mkBUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mkBUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mkBUILD_APIDIFF:= $(BUILD_SYSTEM)/apidiff.mkBUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mkBUILD_NATIVE_TEST := $(BUILD_SYSTEM)/native_test.mkBUILD_NATIVE_BENCHMARK := $(BUILD_SYSTEM)/native_benchmark.mkBUILD_HOST_NATIVE_TEST := $(BUILD_SYSTEM)/host_native_test.mkBUILD_FUZZ_TEST := $(BUILD_SYSTEM)/fuzz_test.mkBUILD_HOST_FUZZ_TEST := $(BUILD_SYSTEM)/host_fuzz_test.mkBUILD_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/shared_test_lib.mkBUILD_HOST_SHARED_TEST_LIBRARY := $(BUILD_SYSTEM)/host_shared_test_lib.mkBUILD_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/static_test_lib.mkBUILD_HOST_STATIC_TEST_LIBRARY := $(BUILD_SYSTEM)/host_static_test_lib.mkBUILD_NOTICE_FILE := $(BUILD_SYSTEM)/notice_files.mkBUILD_HOST_DALVIK_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_java_library.mkBUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY := $(BUILD_SYSTEM)/host_dalvik_static_java_library.mkBUILD_HOST_TEST_CONFIG := $(BUILD_SYSTEM)/host_test_config.mkBUILD_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-varsdefine true-or-emptydefine gcno-touch-ruledefine my-dirdefine all-makefiles-underdefine first-makefiles-underdefine all-subdir-makefilesdefine all-named-subdir-makefilesdefine all-named-dirs-underdefine all-subdir-named-dirsdefine all-named-files-underdefine all-subdir-named-filesdefine all-java-files-underdefine all-subdir-java-filesdefine all-c-files-underdefine all-subdir-c-filesdefine all-cpp-files-underdefine all-subdir-cpp-filesdefine all-Iaidl-files-underdefine all-subdir-Iaidl-filesdefine all-vts-files-underdefine all-subdir-vts-filesdefine all-logtags-files-underdefine all-proto-files-underdefine all-renderscript-files-underdefine all-S-files-underdefine all-html-files-underdefine all-subdir-html-filesdefine find-subdir-filesdefine find-subdir-subdir-filesdefine find-subdir-assetsdefine find-other-java-filesdefine find-other-html-filesdefine find-files-in-subdirsdefine find-parent-filedefine find-test-data-in-subdirsdefine add-dependencydefine reverse-listdefine def-host-aux-targetdefine find-idf-prefixdefine intermediates-dir-fordefine local-intermediates-dirdefine generated-sources-dir-fordefine local-generated-sources-dirdefine module-built-filesdefine module-installed-filesdefine module-stubs-filesdefine doc-timestamp-fordefine java-lib-filesdefine java-lib-header-filesdefine java-lib-header-filesdefine java-lib-depsdefine app-lib-filesdefine app-lib-header-filesdefine app-lib-header-filesdefine streqdefine normalize-path-listdefine normalize-comma-listdefine word-colondefine collapse-pairsdefine uniq-pairs-by-first-componentdefine modules-for-tag-listdefine module-names-for-tag-listdefine get-tagged-modulesdefine append-pathdefine echo-warningdefine echo-errordefine pretty-warningdefine pretty-errordefine _get-package-overridesdefine get-package-overridesdefine prettydefine prettydefine include-depfiledefine include-depfiles-for-objsdefine track-src-file-objdefine _track-src-file-objdefine track-src-file-gendefine _track-src-file-gendefine track-gen-file-objdefine transform-l-to-c-or-cppdefine transform-y-to-c-or-cppdefine _merge-renderscript-ddefine transform-renderscripts-to-java-and-bcdefine transform-bc-to-sodefine transform-renderscripts-to-cpp-and-bcdefine transform-aidl-to-javadefine transform-aidl-to-cppdefine define-aidl-java-ruledefine define-aidl-java-ruledefine-aidl-java-rule-srcdefine define-aidl-cpp-ruledefine define-aidl-cpp-ruledefine-aidl-cpp-rule-srcdefine transform-vts-to-cppdefine define-vts-cpp-ruledefine define-vts-cpp-ruledefine-vts-cpp-rule-srcdefine transform-logtags-to-javadefine transform-proto-to-javadefine transform-proto-to-ccdefine c-includesdefine transform-cpp-to-o-compiler-argsdefine clang-tidy-cppdefine transform-cpp-to-odefine transform-cpp-to-odefine transform-c-or-s-to-o-compiler-argsdefine transform-c-to-o-compiler-argsdefine clang-tidy-cdefine transform-c-to-odefine transform-c-to-odefine transform-s-to-odefine transform-asm-to-odefine transform-m-to-odefine transform-host-cpp-to-o-compiler-argsdefine clang-tidy-host-cppdefine transform-host-cpp-to-odefine transform-host-cpp-to-odefine transform-host-c-or-s-to-o-common-argsdefine transform-host-c-or-s-to-odefine transform-host-c-to-o-compiler-argsdefine clang-tidy-host-cdefine transform-host-c-to-odefine transform-host-c-to-odefine transform-host-s-to-odefine transform-host-m-to-odefine transform-host-mm-to-odefine compile-dotdot-cpp-filedefine compile-dotdot-c-filedefine compile-dotdot-s-filedefine compile-dotdot-s-file-no-depsdefine _concat-if-arg2-not-emptydefine split-long-argumentsdefine _extract-and-include-single-target-whole-static-libdefine extract-and-include-whole-static-libs-firstdefine extract-and-include-target-whole-static-libsdefine transform-o-to-static-libdefine _extract-and-include-single-aux-whole-static-libdefine extract-and-include-aux-whole-static-libsdefine transform-o-to-aux-static-libdefine transform-o-to-aux-executable-innerdefine transform-o-to-aux-executabledefine transform-o-to-aux-static-executable-innerdefine transform-o-to-aux-static-executabledefine _extract-and-include-single-host-whole-static-libdefine extract-and-include-host-whole-static-libsdefine create-dummy.o-if-no-objsdefine get-dummy.o-if-no-objsdefine delete-dummy.o-if-no-objsdefine transform-host-o-to-static-libdefine transform-host-o-to-shared-lib-innerdefine transform-host-o-to-shared-libdefine transform-host-o-to-packagedefine transform-o-to-shared-lib-innerdefine transform-o-to-shared-libdefine transform-to-strippeddefine transform-to-stripped-keep-mini-debug-infodefine transform-to-stripped-keep-symbolsdefine pack-elf-relocationsdefine transform-o-to-executable-innerdefine transform-o-to-executabledefine transform-o-to-static-executable-innerdefine transform-o-to-static-executabledefine transform-host-o-to-executable-innerdefine transform-host-o-to-executabledefine create-resource-java-filesdefine find-generated-R.javadefine aapt2-compile-one-resource-filedefine aapt2-compile-resource-dirsdefine aapt2-compile-resource-zipsdefine aapt2-compile-one-resource-file-ruledefine aapt2-compiled-resource-out-filedefine aapt2-linkdefine emit-linedefine dump-words-to-filedefine unzip-jar-filesdefine jar-args-sorted-files-in-directorydefine fetch-additional-java-sourcedefine write-java-source-listdefine compile-javadefine transform-java-to-header.jardefine commit-change-for-tocdefine _transform-dex-to-tocdefine define-dex-to-toc-ruledefine define-dex-to-toc-ruledefine define-dex-to-toc-ruledefine define-dex-to-toc-ruledefine codename-or-sdk-to-sdkdefine desugar-classes-jardefine transform-classes.jar-to-dexdefine transform-classes-d8.jar-to-dexdefine create-empty-package-atdefine create-empty-packagedefine initialize-package-filedefine add-assets-to-packagedefine _add-jni-shared-libs-to-package-per-abidefine add-jni-shared-libs-to-packagedefine add-dex-to-packagedefine add-dex-to-package-argdefine add-java-resources-todefine add-jar-resources-to-packagedefine sign-packagedefine sign-package-argdefine align-packagedefine compress-packagedefine remove-timestamps-from-packagedefine uncompress-dexsdefine uncompress-shared-libsdefine transform-host-java-to-packagedefine transform-host-java-to-dalvik-packagedefine copy-one-headerdefine copy-one-filedefine copy-and-uncompress-dexsdefine copy-many-filesdefine copy-xml-file-checkeddefine copy-file-to-targetdefine copy-file-to-target-with-cpdefine copy-file-to-target-strip-commentsdefine copy-file-to-new-targetdefine copy-file-to-new-target-with-cpdefine transform-prebuilt-to-targetdefine transform-prebuilt-to-target-strip-commentsdefine copy-files-with-structuredefine symlink-filedefine _symlink-filedefine dexpreopt-copy-jardefine dexpreopt-remove-classes.dexdefine hiddenapi-copy-dex-filesdefine hiddenapi-copy-soong-jardefine transform-jar-to-proguarddefine transform-jar-to-proguarddefine transform-jar-to-dex-r8define transform-generated-sourcedefine assert-max-image-sizedefine add-radio-filedefine add-radio-file-internaldefine add-radio-file-checkeddefine add-radio-file-checked-internaldefine inherit-packagedefine inherit-package-internaldefine set-inherited-package-variablesdefine keep-or-overridedefine set-inherited-package-variables-internaldefine check-apidefine if-build-from-sourcedefine if-build-from-sourcedefine include-if-build-from-sourcedefine get-prebuilt-src-archdefine record-module-typedefine compatibility_suite_dirsdefine create-suite-dependenciesdefine _clean-path-strip-dotdotdefine _clean-path-strip-root-dotdotsdefine _clean-path-expandeddefine clean-pathdefine my_testdefine try-validate-path-is-subdirdefine validate-path-is-subdirdefine try-validate-paths-are-subdirsdefine validate-paths-are-subdirsdefine test-validate-paths-are-subdirsdefine jacoco-class-filter-to-file-argsdefine jacoco-validate-file-argsdefine append_enforce_rro_sourcesdefine generate_all_enforce_rro_packagesdefine has-system-sdk-versiondefine get-numeric-sdk-version
main.mk中另一个重要的部分就是定义了一系列的规则,这些规则的目标就是编译要生成的目标文件:
# This is the default target. It must be the first declared target..PHONY: droidDEFAULT_GOAL := droid$(DEFAULT_GOAL): droid_targets.......PHONY: ramdiskramdisk: $(INSTALLED_RAMDISK_TARGET).PHONY: systemtarballsystemtarball: $(INSTALLED_SYSTEMTARBALL_TARGET).PHONY: boottarballboottarball: $(INSTALLED_BOOTTARBALL_TARGET).PHONY: userdataimageuserdataimage: $(INSTALLED_USERDATAIMAGE_TARGET)ifneq (,$(filter userdataimage, $(MAKECMDGOALS)))$(call dist-for-goals, userdataimage, $(BUILT_USERDATAIMAGE_TARGET))endif.PHONY: userdatatarballuserdatatarball: $(INSTALLED_USERDATATARBALL_TARGET).PHONY: cacheimagecacheimage: $(INSTALLED_CACHEIMAGE_TARGET).PHONY: bptimagebptimage: $(INSTALLED_BPTIMAGE_TARGET).PHONY: vendorimagevendorimage: $(INSTALLED_VENDORIMAGE_TARGET).PHONY: productimageproductimage: $(INSTALLED_PRODUCTIMAGE_TARGET).PHONY: systemotherimagesystemotherimage: $(INSTALLED_SYSTEMOTHERIMAGE_TARGET).PHONY: bootimagebootimage: $(MTK_BOOTIMAGE_TARGET)
而编译的默认目标,也就是终极目标droid,逐级依赖,依赖到各个image文件,也就是各个分区imge文件:
# Building a full system-- the default is to build droidcoredroid_targets: droidcore dist_files......# Build files and then package it into the rom formats.PHONY: droidcoredroidcore: 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# 是否启用AAPT2LOCAL_USE_AAPT2 := trueLOCAL_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) \# 构建APKinclude $(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.coreLOCAL_MODULE_TAGS := optionalLOCAL_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.cLOCAL_CFLAGS += -Wno-format -Wno-sign-compare -Wno-unused-parameter -DHAVE_CONFIG_HLOCAL_SDK_VERSION := 8LOCAL_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 FLAGLOCAL_CFLAGS := -O3 -DNDEBUG# LDFLAGLOCAL_LDFLAGS := -llog# 依赖的共享库LOCAL_SHARED_LIBRARIES := \ libutils \ myutils # 依赖的静态库LOCAL_STATIC_LIBRARIES := libjpeg_static_ndk# C/C++源文件LOCAL_SRC_FILES := \ main.cpp \ utils.cpp # 目标共享库的名称LOCAL_MODULE := mylibLOCAL_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 += zxingLOCAL_STATIC_JAVA_LIBRARIES += gsonLOCAL_STATIC_JAVA_LIBRARIES += android-support-v7......include $(BUILD_PACKAGE)
方法二:
LOCAL_PATH := $(call my-dir)# 预置include $(CLEAR_VARS)LOCAL_MODULE_CLASS := JAVA_LIBRARIESLOCAL_MODULE := commons-ioLOCAL_SDK_VERSION := currentLOCAL_SRC_FILES := ../../../../../../../../prebuilts/tools/common/m2/repository/commons-io/commons-io/2.4/commons-io-2.4.jarLOCAL_UNINSTALLABLE_MODULE := trueinclude $(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 := mylib2LOCAL_SRC_FILES_32 := lib/armeabi-v7a/mylib2.soLOCAL_SRC_FILES_64 := lib/arm64-v8a/mylib2.soLOCAL_MODULE_TAGS := optionalLOCAL_MODULE_CLASS := SHARED_LIBRARIESLOCAL_MODULE_SUFFIX := .soLOCAL_PROPRIETARY_MODULE := trueLOCAL_MULTILIB := bothinclude $(BUILD_PREBUILT)......# 引用include $(CLEAR_VARS)LOCAL_SHARED_LIBRARIES += mylib2include $(BUILD_PACKAGE)......
方法二:
LOCAL_PATH:= $(call my-dir)# 预置include $(CLEAR_VARS)......ifeq ($(strip $(TARGET_ARCH)), arm64) LOCAL_PREBUILT_JNI_LIBS := libs/arm64-v8a/mylib3.soelse ifeq ($(strip $(TARGET_ARCH)), x86_64) LOCAL_PREBUILT_JNI_LIBS := libs/x86_64/mylib3.soelse ifeq ($(strip $(TARGET_ARCH)),arm) LOCAL_PREBUILT_JNI_LIBS := libs/armeabi-v7a/mylib3.soelse LOCAL_PREBUILT_JNI_LIBS := libs/x86/mylib3.soendif......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# 模块类型为APPSLOCAL_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预置的soifeq ($(strip $(TARGET_ARCH)), arm64) LOCAL_PREBUILT_JNI_LIBS := libs/arm64-v8a/libjni_jpeg.soelse ifeq ($(strip $(TARGET_ARCH)), x86_64) LOCAL_PREBUILT_JNI_LIBS := libs/x86_64/libjni_jpeg.soelse ifeq ($(strip $(TARGET_ARCH)),arm) LOCAL_PREBUILT_JNI_LIBS := libs/armeabi-v7a/libjni_jpeg.soelse LOCAL_PREBUILT_JNI_LIBS := libs/x86/libjni_jpeg.soendifinclude $(BUILD_PREBUILT)
5. 结语
在掌握了Makefile基础知识以及结合源码理清楚了android.mk之后,就不会觉得.mk文件那么陌生了。尤其是在理解了android.mk的内置变量和内置函数之后,我们在编写.mk文件就基本可以得心应手了。
由于make在编译android系统源码时表现出效率不够高的问题,google后来在7.0及以上版本引进了速度更快的ninja,中文意思是忍者,ninja对应的配置文件是android.bp。但google即便引进了ninja,源码中还是保留了部分android.mk。并且android.mk也可以通过kati工具转换成ninja,也就是说android.mk还可以继续使用。所以,make仍然是android开发者的必备技能。
更多相关文章
- Android(安卓)Studio(十二):打包多个发布渠道的apk文件
- android -> 修改自动转为大写 的textAllCaps 属性
- android XML文件序列化
- Android(安卓)jni调用,实现自己的JNI_OnLoad函数
- Android(安卓)Studio导入Android平台源码
- android 编译模块
- android 扫描SD卡与系统文件
- Android(安卓)LCD和键盘 背光亮度设置
- NPM 和webpack 的基础使用