Android Build系统主要由:makefile文件、mk文件、bp文件、sh文件、python文件等组成。由于build系统太过庞大,本篇只是针对常用的一些语法进行介绍和总结。
一、makefile
Makefile是GNU Make工具的标准配置文件,采用通用语法定义编译规则、依赖关系和命令,适用于大多数C/C++项目。
Makefile直接控制编译流程,支持复杂条件判断和自定义规则,适用于通用Linux/Unix环境。是Linux/Unix环境下的通用工具,主要功能就是用来编译,因此相关基础语法可以参考如下https://blog.csdn.net/weixin_61678229/article/details/145117435
二、mk
mk文件 是Android NDK专用的构建脚本,属于Makefile的变种,语法经过Android编译系统封装,简化了模块定义(如LOCAL_MODULE
、LOCAL_SRC_FILES
等变量)。它需通过ndk-build
命令解析,最终转换为标准Makefile格式。
mk文件官方介绍:https://developer.android.com/ndk/guides/android_mk
mk文件其实是makefile的变种,是专门针对android的编译构建开发的一种工具或者语法,因此在android源码中,存在大量的mk文件和makefile文件混用,但是无论如何最终都转换成了标准的makefile格式。下面针对mk中的一些常用语法和函数进行介绍。
1、Android.mk是否自动参与构建?
android.mk文件参与编译需要满足如下几种场景:
- 执行mm命令仅编译当前目录或指定目录下的android.mk文件;注意mm命令并不会执行当前目录的makefile文件
- 通过include $(LOCAL_PATH)/subdir/Android.mk命令指定执行某个子目录下的android.mk文件
- 通过相关函数递归执行指定目录下所有的android.mk文件
bash
#定义LOCAL_PATH变量,指定当前模块的源文件路径。$(call my-dir)是编译系统提供的宏函数,用于返回当前Android.mk文件所在的目录路径
LOCAL_PATH:= $(call my-dir)
#动态包含当前目录及其子目录下的所有Android.mk文件。first-makefiles-under宏会递归查找指定路径(此处为LOCAL_PATH)下的.mk文件,但不包含当前目录自身的文件
include $(call first-makefiles-under,$(LOCAL_PATH))
因此做如下总结:
android.mk文件不会自动参与构建,但我们观察android编译日志会发现,各个目录下的android.mk依次参与构建,并没有没有找到相关引用的地方,怀疑此种方式是通过了类似first-makefiles-under方案:如下为asop system编译的时候依次编译qcom各个子目录的Android.mk

2、mk基本语法
- 使用
#
表示注释,使用$()
表示取值,使用:=
表示赋值,使用+=
表示附加等等
bash
# 注释内容使用 "#" 号
# call 是调用一个系统提供的宏函数,此处是 my-dir
# $() 是取值
# := 是赋值
LOCAL_PATH := $(call my-dir)
# 我们也可以使用 ifeq 和 ifneq 进行条件判断
ifeq ($(HOST_OS, linux)
...(省略)
else
...(省略)
endif
# 使用 := 是赋值,当某一行很长时,可以使用反斜杠 \ 换行
LOCAL_SRC_FILES := adb.c \
utils.c
# 使用 += 是附加
LOCAL_SRC_FILES += $(USB_SRCS)
- 我们可以通过export 设置某个变量
被export修饰的变量的生命周期从执行export语句开始直到shell终端终止都生效,因此我们可以在export中预设编译宏控,来实现相关特性的控制,如下:

在envsetup.sh四部曲中进行配置之后,编译开始之后JOURNEY_BUILD_SCRIPT变量被设置为yes,那么后续可以在任何地方使用这个编译宏控,如下:

- 内置变量

3、mk常用函数
A include (call first-makefiles-under,(LOCAL_PATH))
- 功能 :动态包含当前目录及其子目录下的所有
Android.mk
文件。first-makefiles-under
宏会递归查找指定路径(此处为LOCAL_PATH
)下的.mk
文件,但不包含当前目录自身的文件14 - 作用 :实现模块化构建,允许将不同子模块的编译规则分散到子目录的
Android.mk
中,最终统一集成到主构建流程 - 注意事项 :若需包含当前目录的
.mk
文件,需显式使用include $(LOCAL_PATH)/xxx.mk
B include $(call all-subdir-makefiles)
- 递归包含机制 :
all-subdir-makefiles
是Android构建系统提供的宏函数,会自动扫描当前LOCAL_PATH
目录下的所有子目录,查找并包含其中符合命名规范的Android.mk
文件56。例如在jni目录执行时,会加载jni/armeabi、jni/x86等子目录的构建脚本1。 - 模块化构建 :通过该指令,父目录的Makefile可以聚合子模块的编译定义,实现多模块联合编译。每个子目录的
Android.mk
可独立定义LOCAL_MODULE
,最终由系统统一处理依赖关系 - 变量污染风险 :由于所有子Makefile在同一个GNU Make上下文中执行,需避免变量命名冲突。建议使用
include $(CLEAR_VARS)
及时清理局部变量
4、mk常用宏定义
A PRODUCT_COPY_FILES
- PRODUCT_COPY_FILES功能:拷贝源码中的文件到android设备out目录指定位置,用法如下:
PRODUCT_COPY_FILES += CODE源码路径 : OUT输出路径
#其中LOCAL_PATH指定当前mk所在的目录;TARGET_XXX_OUT指定设备输出的根目录
PRODUCT_COPY_FILES += (LOCAL_PATH)/apps/BootLogo/image/gms_800x1340.img:(TARGET_COPY_OUT_VENDOR)/etc/res/images/default/bootlogo/bootlogo_601.img
- PRODUCT_COPY_FILES实现:遍历此宏参数,然后先check是否违背一些规则,然后执行copy命令进行文件拷贝


三、案例
1、案例之编译阶段创建目录
问题背景:在设备输出目录中创建某个目录,例如创建/system/app/目录下面创建china和global两个目录
解决方案:通常有多少方式能够创建,这里介绍两种方式
- 方案1:通过init.rc去创建目录,此方式属于运行阶段去创建

方案2:通过PRODUCT_COPY_FILES去创建目录,如下如果bootlogo目录不存在者在cp的时候自动创建

2、案例之替换源码动态库
在高通的一个项目里面,高通因为无法提供diff patch,因此直接提供了一堆media so库过来,让我们进行替换编译,其中部分so库是闭源的,即我们的基线没有源代码,此类情况直接替换对应的so文件就行了,但是另外还存在4个so库是非闭源的,即我们的基线存在源代码,此类so是通过源代码编译生成,如下:

此时的需求是不采用上面的源代码构建生成libqc2colorconvertfilter.so,而直接使用高通释放的so替换,可以采用Android mk 引用 jar 包、so 库、aar 包介绍的方式进行替换:

通过上面方式来修改如上的Android.mk文件,但始终报如下类似错误:

后可能原因为SRC的路径可能不对,之后参考高通基线案例:

作如下修改:
bash
+$(warning "------------------SHEN: start build lib64/libqcodec2_utils.so")
+
include $(CLEAR_VARS)
LOCAL_MODULE := libqcodec2_v4l2codec
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
@@ -7622,6 +7637,25 @@ LOCAL_PROPRIETARY_MODULE := true
include $(BUILD_PREBUILT)
endif
+ifeq ($(wildcard vendor/qcom/proprietary/media),)
+
+$(warning "------------------SHEN: start build lib64/libqc2colorconvertfilter.so")
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libqc2colorconvertfilter
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libqcodec2_base libqcodec2_utils libqcodec2_basecodec libcodec2_vndk
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_STRIP_MODULE := false
+LOCAL_MULTILIB := 64
+LOCAL_MODULE_OWNER := qcom
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := ../../.././target/product/lahaina/vendor/lib64/libqc2colorconvertfilter.so
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_VENDOR)/lib64
+LOCAL_PROPRIETARY_MODULE := true
+include $(BUILD_PREBUILT)
+endif
+
+$(warning "------------------SHEN: start build lib/libqcodec2_v4l2codec.so")
+
include $(CLEAR_VARS)
LOCAL_MODULE := libqcodec2_v4l2codec
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
@@ -11246,6 +11294,27 @@ LOCAL_PROPRIETARY_MODULE := true
include $(BUILD_PREBUILT)
endif
+
+ifeq ($(wildcard vendor/qcom/proprietary/media),)
+
+$(warning "------------------SHEN: start build lib/libqc2colorconvertfilter.so")
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libqc2colorconvertfilter
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libqcodec2_base libqcodec2_utils libqcodec2_basecodec libcodec2_vndk
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_STRIP_MODULE := false
+LOCAL_MULTILIB := 32
+LOCAL_MODULE_OWNER := qcom
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := ../../.././target/product/lahaina/vendor/lib/libqc2colorconvertfilter.so
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_VENDOR)/lib
+LOCAL_PROPRIETARY_MODULE := true
+include $(BUILD_PREBUILT)
+endif
+
+
include $(CLEAR_VARS)
LOCAL_MODULE := libqcrildatactl
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
@@ -13896,3 +13965,5 @@ $(shell mkdir -p $(PRODUCT_OUT)/vendor/lib/egl && pushd $(PRODUCT_OUT)/vendor/li
$(shell mkdir -p $(PRODUCT_OUT)/vendor/lib/egl && pushd $(PRODUCT_OUT)/vendor/lib > /dev/null && ln -s egl/libq3dtools_adreno.so libq3dtools_adreno.so && popd > /dev/null)
$(shell mkdir -p $(PRODUCT_OUT)/vendor/lib/egl && pushd $(PRODUCT_OUT)/vendor/lib > /dev/null && ln -s egl/libEGL_adreno.so libEGL_adreno.so && popd > /dev/null)
+
+$(warning "------------------SHEN:os/la.um/vendor/qcom/proprietary/prebuilt_HY11/target/product/lahaina/Android.mk end")
然后删掉libqc2colorconvertfilter对应的Android.mk之后实现此方案,编译OK