Android Build系列专题【篇四:编译相关语法】

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_MODULELOCAL_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

相关推荐
雨白5 小时前
优雅地处理协程:取消机制深度剖析
android·kotlin
leon_zeng06 小时前
更改 Android 应用 ID (ApplicationId) 后遭遇记
android·发布
2501_916007477 小时前
iOS 混淆工具链实战,多工具组合完成 IPA 混淆与加固(iOS混淆|IPA加固|无源码混淆|App 防反编译)
android·ios·小程序·https·uni-app·iphone·webview
Jeled9 小时前
Retrofit 与 OkHttp 全面解析与实战使用(含封装示例)
android·okhttp·android studio·retrofit
ii_best11 小时前
IOS/ 安卓开发工具按键精灵Sys.GetAppList 函数使用指南:轻松获取设备已安装 APP 列表
android·开发语言·ios·编辑器
2501_9159090611 小时前
iOS 26 文件管理实战,多工具组合下的 App 数据访问与系统日志调试方案
android·ios·小程序·https·uni-app·iphone·webview
limingade13 小时前
手机转SIP-手机做中继网关-落地线路对接软交换呼叫中心
android·智能手机·手机转sip·手机做sip中继网关·sip中继
RainbowC013 小时前
GapBuffer高效标记管理算法
android·算法
程序员码歌14 小时前
豆包Seedream4.0深度体验:p图美化与文生图创作
android·前端·后端