工欲善其事,必先利其器。 想要深入学习Android源码,首先必须掌握Android编译命令。
一、简介
关于AndroidBuild系统,这个话题准备了很久,但是很久没有写出来,所以决定跟大家分享一下。 先看下面的指令,相信编译过Android源码的人都比较熟悉。
source /opt/android1204_17.conf
source setenv.sh
lunch
make -j12
记得刚接触Android的时候,朋友告诉我,用前面的命令就可以编译Android源码。 虽然命令很短,但是我记不住或者忘记了命令。 每次编译的时候都需要看一下我的云笔记。 是冷的。 我总是记不住指示。 后来我决定仔细研究一下这个命令的含义。 你需要知道为什么,这样你才能更深层次地理解和记忆,并能够与自己的知识体系进行完善和联系。 事实上,你可以获得意想不到的收获。 果然,我在学习的时候就跟大家分享一下上述指令的含义。 在学习AndroidBuild(编译)系统的过程中。
2. 编译命令
准备好编译环境后,编译Android源码的第一步是sourcebuild/envsetup.sh,其中source命令用于运行shell脚本命令,其作用相当于“.”,所以这个命令也是相当于 .build/envsetup .sh。 在文件 envsetup.sh 中,声明了当前会话终端可用的命令。 这里需要注意的是当前会话终端Android源码增量编译,这意味着每次打开新终端时都必须再次执行该命令。 本来不明白为什么新打开的终端不能直接执行make命令,到这里终于明白了。
拿出来解释一下本文开头引用的命令:
source /opt/android1204_17.conf //初始化jdk环境变量(这个不是必需的,因厂商而异)
source setenv.sh //初始化编译环境,包括后面的lunch和make指令
lunch //指定此次编译的目标设备以及编译类型
make -j12 //开始编译,默认为编译整个系统,其中-j12代表的是编译的job数量为12。
所有的编译命令都可以在envsetup.sh文件中找到对应的函数,比如上面提到的命令lunch和make,必须在该文件中找到
function lunch(){
...
}
function make(){
...
}
具体实现这里不再赘述,下面总结一下各指令的用法和作用。
2.1 代码编译及编译指令解释
在源代码树的根目录下编译
毫米
编译当前路径下的所有模块,但不包含依赖项
嗯[模块路径]
编译指定路径下的所有模块,但不包含依赖
MMA
编译当前路径下的所有模块,包括依赖
mmma[模块路径]
编译指定路径下的所有模块,并包含依赖
使[模块名称]
不带参数,表示编译整个Android代码
部分模块的编译说明如下:
模块 make 命令 mmm 命令
在里面
初始化
mmm系统/核心/init
受精卵
makeapp_process
mmmframeworks/base/cmds/app_process
系统服务器
制造服务
mmmframeworks/基础/服务
java框架
制作框架
mmm框架/基础
框架资源
makeframework-res
mmmframeworks/基础/核心/res
jni框架
makelibandroid_运行时
mmmframeworks/基础/核心/jni
活页夹
makelibbinder
mmmframeworks/native/libs/binder
上述mmm命令也适用于mm/mma/mmma。 编译系统采用增量编译,只有发生变化的目标文件才会被编译。 当需要重新编译所有相关模块时,需要在编译命令后添加参数-B,如make -B[module_name],或者mm -B[module_path]。
尖端:
2.2 代码搜索搜索命令解释
正则表达式
对所有 C/C++ 文件执行搜索操作
jgrep
对所有 Java 文件执行搜索操作
格列普
所有 Gradle 文件都执行搜索操作
mangrep[关键字]
所有AndroidManifest.xml文件都执行搜索操作
sepgrep [关键字]
对所有 sepolicy 文件执行搜索操作
resgrep [关键字]
对所有本地 res/*.xml 文件执行搜索操作
sgrep [关键字]
对所有资源文件执行搜索操作
上述指令用法的最终实现方法是基于grep指令,各指令的用法格式如下:
xgrep [keyword] //x代表的是上表的搜索指令
例如,要搜索所有AndroidManifest.xml文件中launcher关键字所在文件的具体位置,指令
mangrep launcher
再比如,搜索所有system_app selinux权限信息
sepgrep system_app
Tips:Android的源代码非常庞大。 直接使用grep来搜索代码很笨拙、耗时,而且会发现很多无意义的混乱结果。 根据具体需要选择合适的代码搜索命令,可以节省代码搜索时间,提高搜索结果的准确性,方便定位目标代码。
2.3 导航指令 导航指令说明
克鲁特
切换到Android根目录
项目组
切换到项目根目录
godir [文件名]
跳转到包含文件的目录
Tips:当一个文件每次修改后都需要编译时,执行cproj后会跳转到当前模块的根目录,也就是Android.mk文件所在的目录,然后执行mm命令进行编译目标模块; 当深入源码级别后,需要返回到根目录,使用croot命令来完成; 另外,cd-命令可用于快速切换到下一个目录。
2.4 信息查询查询指令说明
唔
查询所有命令帮助信息
查找makefile
查询当前目录所在项目的Android.mk文件路径
打印午餐菜单
查询午餐可用产品
打印配置
查询各种编译变量的值
盖顶
查询Android源码根目录
获取目标架构
获取TARGET_ARCH值
Tips:当你忘记以上所有命令时Android源码增量编译,可以执行一个hmm来输出该命令的帮助信息。
其他说明:
3、编译系统
Android编译系统是Android源码的一部分,用于编译Android系统、AndroidSDK以及相关文档。 编译系统由Make文件、Shell和Python脚本组成,其中最重要的是Make文件。 关于编译系统,请参考了解AndroidBuild系统。
3.1 Makefile分类
整个Build系统的Make文件分为三类:
3.2 编译产品
make编译出来的产品都位于/out目录下。 在该目录中,主要关注以下目录:
在/out/target/product/[product_name]目录下,有几个重量级的镜像文件:
其实还有boot.img、reocovery.img等镜像文件,这里就不介绍了。
3.3 Android.mk分析
源码树中每个模块的所有文件一般都有自己的文件夹,在模块的根目录下有一个名为“Android.mk”的文件。
文档。 编译系统以模块为单位进行编译。 每个模块都有一个唯一的模块名称。 一个模块可以依赖于多个其他模块。 模块之间的依赖关系通过模块名称来引用。 也就是说,当模块需要依赖jar包或apk时,必须先将jar包或apk定义为模块,然后再依赖相应的模块。
对于Android.mk文件,一般有以下两行
LOCAL_PATH := $(call my-dir) //设置当编译路径为当前文件夹所在路径
include $(CLEAR_VARS) //清空编译环境的变量(由其他模块设置过的变量)
为了模块编译的方便,编译系统设置了很多编译环境变量,如下:
对于这些环境变量,编译系统还定义了一些方便的函数,如下:
例子:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# 获取所有子目录中的Java文件
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# 当前模块依赖的动态Java库名称
LOCAL_JAVA_LIBRARIES := com.gityuan.lib
# 当前模块的名称
LOCAL_MODULE := demo
# 将当前模块编译成一个静态的Java库
include $(BUILD_STATIC_JAVA_LIBRARY)