Android编译脚本(.mk文件)解析

摘要:本文将简单介绍Android编译系统并举例说明如何编写不同类型的mk文件以达到不同的目的。虽然.mk文件即将被.bp文件替代,但是在Android9之前的版本中.mk文件的使用频率依旧很高,同时理解.mk文件也有助于理解Android编译系统和其替代者.bp文件。

一、Android编译系统

1.从基础make脚本到Android编译系统

首先我们来看一个make脚本的基本格式:

目标(target): 条件:(prerequest)
	命令

比如:

hello: hello.c
	gcc hello.c -o hello.bin

在以上编译脚本中,hello为编译目标,hello.c为编译条件,即只要hello.c有变化,那么调用make hello时就会执行gcc hello.c -o hello.bin命令

Android通过mk文件和shell脚本实现对基础make脚本的封装,从而便于编译多个项目,但是无论Android编译系统如何封装,这些mk文件被make程序解析时,所产生的脚本文件的结构依然是个基础的make脚本模型

那么Android编译系统如何实mk文件向基础make脚本的转换呢?

2.协同合作实现转换

我们已经知道:Android的编译系统是通过各种mk文件和各种shell脚本共同定义了一个编译框架,这个框架是基于基本的make概念的,从mk文件向基础make脚本的转换过程是比较复杂的,在此我们只概括性的总结一下:
整个过程主要依赖于Android编译系统的三个部分:

  • 子项目:每一个子项目都必须包含一个Android.mk文件,该文件中将描述该项目包含哪些源文件,并且指出该项目的输出目标是何种类型,如APK、so库或Jar包等。可以说众多子项目编译产物的合理组合构成了整个Android系统
  • 编译中枢:是Android编译系统的核心,其主要完成两件事:
    1)定义一些变量(下文会有介绍),子项目只需要对这些变量赋值即可描述编译所需要的信息,相比make自身的语法,这种赋值方法更简单
    2)从Android根目录下寻找所有子目录中的Android.mk文件,根据mk文件提供的信息生成所有target,从而当用户调用make xxx命令时,中枢能够知道应该执行什么命令以产生指定的target
  • 输出路径:顾名思义就是规定了编译过程中产生的各种临时文件和最终输出目标的输出路径,默认为out目录,该目录下主要包含两个子目录:host对应PC上所需的各种工具;target就是最终输出目标。其实输出路径本身也是在编译中枢中定义的。

通过以上三个部分以及众多shell脚本的协同合作,即可完成Android系统的编译。什么?还有点晕?嗨,其实我们在项目开发的过程中也不需要知道这里面具体是怎么实现的,我们只需要看懂mk文件,能写出自己需要的mk文件就行了,为了达到这个目的,我们需要知道编译中枢都定义了哪些用来描述子项目的变量以及mk文件是如何使用这些变量的。

3.mk文件解析

以下代码来自子项目:packages/services/Car/service中的Android.mk文件:

# Build the Car service.

#disble build in PDK, missing aidl import breaks build
ifneq ($(TARGET_BUILD_PDK),true)

//LOCAL_PATH是编译中枢定义的变量,用于指定该子项目的绝对路径
//my-dir是编译中枢定义的函数,可以调用这个函数直接获得当前路径
LOCAL_PATH:= $(call my-dir)

//定义一个变量:car_service_sources,后面调用编译中枢定义的all-java-files-under函数,这个函数的作用是找到指定目录下的Java文件
//这句话的解释为:将car_service_sources赋值,其表示src目录下的所有Java文件
car_service_sources := $(call all-java-files-under, src)

//用于清理、重置环境,每次开始编译一个子项目时都要调用,调用几次就说明此mk文件有几个子项目
include $(CLEAR_VARS)

//指定该项目所包含的所有源文件
LOCAL_SRC_FILES := $(car_service_sources)

//aapt 是Android Asset Packaging Tool的缩写,默认使用
LOCAL_USE_AAPT2 := true

//指定该项目的名称,如果是C/C++文件项目,则使用变量:LOCAL_MODULE
LOCAL_PACKAGE_NAME := CarService
//设置是否使用sdk中已经hide的api来编译
LOCAL_PRIVATE_PLATFORM_APIS := true

# Each update should be signed by OEMs
//指定用的是什么签名
LOCAL_CERTIFICATE := platform
//这个变量决定了其编译后的在ROM中的安装位置
//如果设置为true,则安装在system/priv-app目录下,如果不设置或者设置为false,则安装在system/app下面,当然对应的权限也会有变化
LOCAL_PRIVILEGED_MODULE := true

//混淆规则配置文件
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
//混淆配置,默认为full obfuscation,全代码混淆,disabled为不开启
LOCAL_PROGUARD_ENABLED := disabled

//指定依赖的动态共享java类库,动态的意思是这个只是编译时依赖,最终不会打包到apk
//关于动态/静态库,这里就是只在out目录下生成的jar包,比如android.car.jar
LOCAL_JAVA_LIBRARIES += \
        android.car \
        DFAPI \
        bluetoothkit \

//指定依赖的静态java类库,静态的意识是最终会打包到apk里面
LOCAL_STATIC_JAVA_LIBRARIES += \
        android.hidl.base-V1.0-java \
        android.hardware.automotive.audiocontrol-V1.0-java \
        android.hardware
  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值