Android源码编译命令详解

news2025/3/10 16:37:33

一、引言

先看下面几条指令,相信编译过Android源码的人都再熟悉不过的。

source setenv.sh
lunch
make -j8

记得最初刚接触Android时,同事告诉我用上面的指令就可以编译Android源码,指令虽短但过几天就记不全或者忘记顺序,每次编译时还需要看看自己的云笔记,冰冷的指令总是难以让我记忆。后来我决定认真研究下这个指令的含义。知其然还需知其所以然,这样能更深层次的理解并记忆,才能与自身的知识体系建立强连接,或许还有意外收获,果然如此,接下来跟大家分享一下在研究上述几条指令含义的过程中,深入了解到的Android Build(编译)系统。

二、编译命令

准备好编译环境后,编译Android源码的第一步是 source build/envsetup.sh,其中source命令就是用于运行shell脚本命令,功能等价于”.”,因此该命令也等价于 . build/envsetup.sh 。在文件 envsetup.sh 声明了当前会话终端可用的命令,这里需要注意的是当前会话终端,也就意味着每次新打开一个终端都必须再一次执行这些指令。起初并不理解为什么新开的终端不能直接执行make指令,到这里总算明白了。

接下来,解释一下本文开头的引用的命令:

source setenv.sh  //初始化编译环境,包括后面的lunch和make指令
lunch  //指定此次编译的目标设备以及编译类型
make  -j8 //开始编译,默认为编译整个系统,其中-j8代表的是编译的job数量为8。

所有的编译命令都在envsetup.sh文件能找到相对应的function,比如上述的命令lunchmake,在文件一定能找到

function lunch(){
    ...
}

function make(){
    ...
}

source envsetup.sh,需要cd到setenv.sh文件所在路径执行,路径可能在build/envsetup.sh,或者integrate/envsetup.sh,再或者不排除有些厂商会封装自己的.sh脚本,但核心思路是一致的。

具体实现这里就不展开说明,下面精炼地总结了一下各个指令用法和功效。

2.1 代码编译

编译指令解释
m在源码树的根目录执行编译
mm编译当前路径下所有模块,但不包含依赖
mmm [module_path]编译指定路径下所有模块,但不包含依赖
mma编译当前路径下所有模块,且包含依赖
mmma [module_path]编译指定路径下所有模块,且包含依赖
make [module_name]无参数,则表示编译整个Android代码

下面列举部分模块的编译指令:

模块make命令mmm命令
initmake initmmm system/core/init
zygotemake app_processmmm frameworks/base/cmds/app_process
system_servermake servicesmmm frameworks/base/services
java frameworkmake frameworkmmm frameworks/base
framework资源make framework-resmmm frameworks/base/core/res
jni frameworkmake libandroid_runtimemmm frameworks/base/core/jni
bindermake libbindermmm frameworks/native/libs/binder

上述mmm命令同样适用于mm/mma/mmma,编译系统采用的是增量编译,只会编译发生变化的目标文件。当需要重新编译所有的相关模块,则需要编译命令后增加参数 -B,比如make -B [module_name],或者 mm -B [module_path]。

Tips:
  • 对于m、mm、mmm、mma、mmma这些命令的实现都是通过make方式来完成的。
  • mmm/mm编译的效率很高,而make/mma/mmma编译较缓慢;
  • make/mma/mmma编译时会把所有的依赖模块一同编译,但mmm/mm不会;
  • 建议:首次编译时采用make/mma/mmma编译;当依赖模块已经编译过的情况,则使用mmm/mm编译。

2.2 代码搜索

搜索指令解释
cgrep所有 C/C++ 文件执行搜索操作
jgrep所有Java文件执行搜索操作
ggrep所有Gradle文件执行搜索操作
mangrep [keyword]所有AndroidManifest.xml文件执行搜索操作
mgrep [keyword]所有Android.mk文件执行搜索操作
sepgrep [keyword]所有sepolicy文件执行搜索操作
resgrep [keyword]所有本地res/*.xml文件执行搜索操作
sgrep [keyword]所有资源文件执行搜索操作

上述指令用法最终实现方式都是基于grep指令,各个指令用法格式:

xgrep [keyword]  //x代表的是上表的搜索指令

例如,搜索所有AndroidManifest.xml文件中的launcher关键字所在文件的具体位置,指令

mangrep launcher

再如,搜索所有Java代码中包含zygote所在文件

jgrep zygote

又如,搜索所有system_app的selinux权限信息

sepgrep system_app
Tips: Android源码非常庞大,直接采用grep来搜索代码,不仅方法笨拙、浪费时间,而且搜索出很多无意义的混淆结果。根据具体需求,来选择合适的代码搜索指令,能节省代码搜索时间,提高搜索结果的精准度,方便定位目标代码。

2.3 导航指令

导航指令解释
croot切换至Android根目录
cproj切换至工程的根目录
godir [filename]跳转到包含某个文件的目录
Tips: 当每次修改完某个文件后需要编译时,执行cproj后会跳转到当前模块的根目录,也就是Android.mk文件所在目录,然后再执行mm指令,即可编译目标模块;当进入源码层级很深后,需要返回到根目录,使用croot一条指令完成;另外cd - 指令可用于快速切换至上次目录。

2.4 信息查询

查询指令解释
hmm查询所有的指令help信息
findmakefile查询当前目录所在工程的Android.mk文件路径
print_lunch_menu查询lunch可选的product
printconfig查询各项编译变量值
gettop查询Android源码的根目录
gettargetarch获取TARGET_ARCH值

2.5 其他指令

上述只是列举比较常用的指令,还有其他指令,而且不同的build编译系统,支持的指令可能会存在一些差异,当忘记这些编译指令,可以通过执行hmm,查询指令的帮助信息。

最后再列举两个比较常用的指令:

make clean:执行清理操作,等价于rm -rf out/
make update-api:更新API,在framework API改动后需执行该指令,Api记录在目录frameworks/base/api

三、编译系统

Android 编译系统是Android源码的一部分,用于编译Android系统,Android SDK以及相关文档。该编译系统是由Make文件、Shell以及Python脚本共同组成,其中最为重要的便是Make文件。

3.1 Makefile分类

整个Build系统的Make文件分为三大类:

  • 系统核心的Make文件:定义了Build系统的框架,文件全部位于路径/build/core,其他Make文件都是基于该框架编写的;
  • 针对产品的Make文件:定义了具体某个型号手机的Make文件,文件路径位于 /device ,该目录下往往又以公司名和产品名划分两个子级目录,比如 /device/qcom/msm8916
  • 针对模块的Make文件:整个系统分为各个独立的模块,每个模块都一个专门的Make文件,名称统一为”Android.mk”,该文件定义了当前模块的编译方式。Build系统会扫描整个源码树中名为”Android.mk”的问题,并执行相应模块的编译工作。

3.2 编译产物

经过make编译后的产物,都位于 /out目录 ,该目录下主要关注下面几个目录:

  • /out/host:Android开发工具的产物,包含SDK各种工具,比如adb,dex2oat,aapt等。
  • /out/target/common:通用的一些编译产物,包含Java应用代码和Java库;
  • /out/target/product/[product_name]:针对特定设备的编译产物以及平台相关C/C++代码和二进制文件;

在/out/target/product/[product_name]目录下,有几个重量级的镜像文件:

  • system.img:挂载为根分区,主要包含Android OS的系统文件;
  • ramdisk.img:主要包含init.rc文件和配置文件等;
  • userdata.img:被挂载在/data,主要包含用户以及应用程序相关的数据;

当然还有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_SRC_FILES:当前模块包含的所有源码文件;
  • LOCAL_MODULE:当前模块的名称(具有唯一性);
  • LOCAL_PACKAGE_NAME:当前APK应用的名称(具有唯一性);
  • LOCAL_C_INCLUDES:C/C++所需的头文件路径;
  • LOCAL_STATIC_LIBRARIES:当前模块在静态链接时需要的库名;
  • LOCAL_SHARED_LIBRARIES:当前模块在运行时依赖的动态库名;
  • LOCAL_STATIC_JAVA_LIBRARIES:当前模块依赖的Java静态库;
  • LOCAL_JAVA_LIBRARIES:当前模块依赖的Java共享库;
  • LOCAL_CERTIFICATE:签署当前应用的证书名称,比如platform。
  • LOCAL_MODULE_TAGS:当前模块所包含的标签,可以包含多标签,可能值为debgu,eng,user,development或optional(默认值)

针对这些环境变量,编译系统还定义了一些便捷函数,如下:

  • $(call my-dir):获取当前文件夹路径;
  • $(call all-java-files-under, ):获取指定目录下的所有Java文件;
  • $(call all-c-files-under, ):获取指定目录下的所有C文件;
  • $(call all-Iaidl-files-under, ) :获取指定目录下的所有AIDL文件;
  • $(call all-makefiles-under, ):获取指定目录下的所有Make文件;

示例:

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)

四、附录:常用make命令

  1. make -jX
    X表示数字,这个命令将编译Android系统并生成镜像,XX表示可以使用到的CPU核数,这在配置好的电脑上特别有用,公司的16核ubuntu服务器执行make -j16只要不到20分钟,而双核PC上需要4个小时!
  2. make snod
    这条命令将重新生成镜像,消耗的时间很少,类似WinCE的makeimg过程,如果你修改了一些数据文件(如音乐、视频)等文件时比较有用。
  3. make cts
    这条命令将编译CTS套机,编译出的结果放在out目录对应版的data/app目录下面。CTS测试时有用
  4. make installclean
    这条命令清除out目录下对应板文件夹中的内容,也就是相当于make clean,通常如果改变了一些数据文件(如去掉)、最好执行以下make installclean,否则残留在out目录下的还会被打包进去。
  5. mm/mm -B
    开发调试中最喜欢这条命令了,在修改了的目录下执行这条命令,就能智能地进行编译,输出的文件在通过adb推送到目标机,可以很方便地调试。
    1 .make sdk
    这条命令可以生成可发布的SDK,目前还没试过,据说需要JDK1.5
  6. make Setting
    可以单独编译setting这个模块,目前还没试,猜想是不是可以单独编译Email、Music这些模块
  7. make bootimage
    用这条命令可以生成boot.img,这个镜像文件中包含Linux Kernel,Ram disk,生成的boot.img只能通过fastboot进行烧写,这在只修改了Linux内核的时候有用
  8. make systemimage
    同上,不过是生成system.img用的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2312792.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

任务11:路由器配置与静态路由配置

目录 一、概念 二、路由器配置 三、配置静态路由CSDN 原创主页:不羁https://blog.csdn.net/2303_76492156?typeblog 一、概念 1、路由器的作用:通过路由表进行数据的转发。 2、交换机的作用:通过学习和识别 MAC 地址,依据 M…

Python实例:PyMuPDF实现PDF翻译,英文翻译为中文,并按段落创建中文PDF

基于PyMuPDF与百度翻译的PDF翻译处理系统开发:中文乱码解决方案与自动化排版实践 一 、功能预览:将英文翻译为中文后创建的PDF 二、完整代码 from reportlab.lib.pagesizes import letter from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle

LeeCode题库第四十六题

46.全排列 项目场景: 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例 2&am…

LangChain4j开发RAG入门示例

本文将详细介绍如何基于Java语言,使用Langchain4j开源框架、Milvus向量数据、阿里Qwen大模型,开发一个RAG入门级简单示例。本示例虽然简单,但涉及到多个知识点,包括:Milvus初始化、Embedding模型、文档切片、Springboo…

快速从C过度C++(一):namespace,C++的输入和输出,缺省参数,函数重载

📝前言: 本文章适合有一定C语言编程基础的读者浏览,主要介绍从C语言到C过度,我们首先要掌握的一些基础知识,以便于我们快速进入C的学习,为后面的学习打下基础。 这篇文章的主要内容有: 1&#x…

课程《Deep Learning Specialization》

在coursera上,Deep Learning Specialization 课程内容如下图所示:

微服务与消息队列RabbitMQ

简介 同步模式 异步模式 内容 解决方案RabbitMQ 同步调用的优缺点 同步调用的优势是什么? 时效性强,等待到结果后才返回。 同步调用的问题是什么? 拓展性差性能下降级联失败问题

苹果 M3 Ultra 芯片深度解析:AI 时代的性能革命

2025 年 3 月 5 日,苹果正式发布了其史上最强 PC 芯片 ——M3 Ultra。这款基于 UltraFusion 封装技术的旗舰级 SoC,不仅延续了苹果芯片在能效比上的传统优势,更通过架构创新与硬件升级,将 AI 计算能力推向了新高度。本文将从性能突…

通义千问:Qwen2.5-0.5B模型架构解释

通义千问:Qwen2.5-0.5B模型架构解释 1. 模型权重文件 .mdl、.msc:存储模型核心参数,是模型训练后学习到的知识载体,包含神经网络各层权重,加载后模型才能执行推理、生成等任务。 .mdl文件:通常是模型的核心权重数据文件,存储神经网络各层的权重参数、张量等关键数据,是…

【Linux】冯诺依曼体系与操作系统理解

🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:Linux 目录 前言 一、冯诺依曼体系结构 二、操作系统 1. 操作系统的概念 2. 操作系统存在的意义 3. 操作系统的管理方式 4. 补充:理解系统调用…

玩转ChatGPT:GPT 深入研究功能

一、写在前面 民间总结: 理科看Claude 3.7 Sonnet 文科看DeepSeek-R1 那么,ChatGPT呢? 看Deep Research(深入研究)功能。 对于科研狗来说,在这个文章爆炸的时代,如何利用AI准确、高效地收…

虚函数和虚表的原理是什么?

虚函数是一个使用virtual关键字声明的成员函数,在基类中声明虚函数,在子类中可以使用override重写该函数。虚函数根据指针或引用指向的实际对象调用,实现运行时的多态。 虚函数表(虚表)是一个用于存储虚函数地址的数组…

laravel es 相关代码 ElasticSearch

来源&#xff1a; github <?phpnamespace App\Http\Controllers;use Elastic\Elasticsearch\ClientBuilder; use Illuminate\Support\Facades\DB;class ElasticSearch extends Controller {public $client null;public function __construct(){$this->client ClientB…

字节跳动C++客户端开发实习生内推-抖音基础技术

智能手机爱好者和使用者&#xff0c;追求良好的用户体验&#xff1b; 具有良好的编程习惯&#xff0c;代码结构清晰&#xff0c;命名规范&#xff1b; 熟练掌握数据结构与算法、计算机网络、操作系统、编译原理等课程&#xff1b; 熟练掌握C/C/OC/Swift一种或多种语言&#xff…

C语言_数据结构总结6:链式栈

纯c语言代码&#xff0c;不涉及C 顺序栈的实现&#xff0c;欢迎查看这篇文章&#xff1a;C语言_数据结构总结5&#xff1a;顺序栈-CSDN博客 0. 结构单元 #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef struct Linknode { ElemType…

基于DeepSeek的智慧医药系统(源码+部署教程)

运行环境 智慧医药系统运行环境如下&#xff1a; 前端&#xff1a; HTMLCSS后端&#xff1a;Java AIGCDeepseekIDE工具&#xff1a;IDEA技术栈&#xff1a;Springboot HTMLCSS MySQL 主要角色 智慧医药系统主要分为两个角色。 游客 尚未进行注册和登录。具备登录注册、…

信奥赛CSP-J复赛集训(模拟算法专题)(6):P6352 [COCI 2007/2008 #3] CETIRI

信奥赛CSP-J复赛集训&#xff08;模拟算法专题&#xff09;&#xff08;6&#xff09;&#xff1a;P6352 [COCI 2007/2008 #3] CETIRI 题目描述 你原本有 4 4 4 个数&#xff0c;它们从小到大排序后构成了等差数列。 但是现在丢失了一个数&#xff0c;并且其余的三个数的顺序…

2025-03-09 学习记录--C/C++-PTA 习题11-1 输出月份英文名

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 裁判测试程序样例&#xff1a; #include <stdio.h>char *getmonth( int n );int main() {int n;char …

linux环保监测4G边缘网关:环境数据的可靠传输者

环保监测工控机&#xff0c;常被称为“环境数据采集器”或“环保数据终端”&#xff0c;是一种专门用于环境监测领域的工业计算机。它具备强大的数据处理能力、稳定的运行性能和多种接口&#xff0c;能够实时采集、处理和传输环境监测数据。这些数据包括空气质量、水质、噪声、…

【哇! C++】类和对象(五) - 赋值运算符重载

目录 ​编辑 一、运算符重载 1.1 运算符重载概念 1.2 全局运算符重载 1.3 运算符重载为成员函数 二、赋值运算符重载的特性 2.1 赋值运算符重载需要注意的点 2.2 赋值运算符重载格式 2.2.1 传值返回 2.2.2 传引用返回 2.2.3 检查自己给自己赋值 三、赋值运算符重载的…