马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、引言
先看下面几条指令,相信编译过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,比如上述的下令lunch,make,在文件肯定能找到
- 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/initzygotemake app_processmmm frameworks/base/cmds/app_processsystem_servermake servicesmmm frameworks/base/servicesjava frameworkmake frameworkmmm frameworks/baseframework资源make framework-resmmm frameworks/base/core/resjni frameworkmake libandroid_runtimemmm frameworks/base/core/jnibindermake 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关键字所在文件的具体位置,指令
再如,搜刮全部Java代码中包罗zygote所在文件
又如,搜刮全部system_app的selinux权限信息
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可选的productprintconfig查询各项编译变量值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下令
- make -jX
X表示数字,这个下令将编译Android系统并天生镜像,XX表示可以使用到的CPU核数,这在设置好的电脑上特别有用,公司的16核ubuntu服务器执行make -j16只要不到20分钟,而双核PC上必要4个小时!
- make snod
这条下令将重新天生镜像,消耗的时间很少,雷同WinCE的makeimg过程,如果你修改了一些数据文件(如音乐、视频)等文件时比力有用。
- make cts
这条下令将编译CTS套机,编译出的结果放在out目录对应版的data/app目录下面。CTS测试时有用
- make installclean
这条下令扫除out目录下对应板文件夹中的内容,也就是相当于make clean,通常如果改变了一些数据文件(如去掉)、最好执行以下make installclean,否则残留在out目录下的还会被打包进去。
- mm/mm -B
开发调试中最喜欢这条下令了,在修改了的目录下执行这条下令,就能智能地举行编译,输出的文件在通过adb推送到目标机,可以很方便地调试。
1 .make sdk
这条下令可以天生可发布的SDK,目前还没试过,听说必要JDK1.5
- make Setting
可以单独编译setting这个模块,目前还没试,料想是不是可以单独编译Email、Music这些模块
- make bootimage
用这条下令可以天生boot.img,这个镜像文件中包罗Linux Kernel,Ram disk,天生的boot.img只能通过fastboot举行烧写,这在只修改了Linux内核的时候有用
- make systemimage
同上,不外是天生system.img用的。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |