搜索
 找回密码
 立即注册

简单一步 , 微信登陆

Android源代码编译命令m/mm/mmm/make分析(3)

作者:liuwei | 时间:2016-9-28 13:18:27 | 阅读:3568| 只看该作者

      文件build/core/binary.mk的加载逻辑如下所示:

        1. 获得当前编译的模块所依赖的动态链接库,也就是我们在Android.mk文件中通过LOCAL_SHARED_LIBRARIES变量引用的动态链接库。注意,如果定义了变量LOCAL_SDK_VERSION,那么就表示是在SDK环境下编译,这时候是不可以使用一些隐藏的系统动态链接库。这些隐藏的系统动态链接库由变量LOCAL_SYSTEM_SHARED_LIBRARIES描述。最终获得的依赖动态链接库保存在变量LOCAL_REQUIRED_MODULES中。前面我们在分析build/core/main.mk的加载过程时提到,Android编译系统会为当前编译的模块所依赖的每一个模块都生成一个依赖规则,用来保证编译出来的当前模块是最新的。

        2. 加载另外一个脚本文件build/core/base_rules.mk,用来计算一些基本变量的值,以及创建一些基本的依赖规则。

        3. 根据LOCAL_SRC_FILES和LOCAL_CPP_EXTENSION定义的C++文件制定对应的C++目标文件的依赖规则,并且通过函数transform-$(PRIVATE_HOST)cpp-to-o执行这些规则,实际上就是调用gcc来编译相应的C++源文件。注意,当我们是为目标机器编译模块时,变量PRIVATE_HOST的值为空,因此,这时候实际上是调用transform-cpp-to-o来将.cpp源文件编译成.o目标文件。

       4.  同样被制定依赖规则的还包括在LOCAL_SRC_FILES中引用的C文件、汇编文件、YACC文件和LEX文件等等。最终得到的所有目标文件都保存在变量all_objects中。

       5.  获得LOCAL_SHARED_LIBRARIES定义的各个动态依赖库的文件路径,并且保存在变量built_shared_libraries中。

       6.  获得LOCAL_STATIC_LIBRARIES定义的各个静态依赖库的文件路径,并且保存在变量built_static_libraries中。

       7.  获得LOCAL_WHOLE_STATIC_LIBRARIES定义的各个要完全静态链入当前编译模块的依赖库的文件路径,并且保存在变量built_whole_libraries中。

       8.  将所有获得的静态和动态依赖库文件路径保存在变量all_libraries中。

       至此,变量all_objects和all_libraries就描述了当前模块依赖的所有目标文件和库文件。前面在分析build/core/shared_library.mk的加载过程时提到一个依赖规则,也就是变量linked_module定义的文件依赖于变量all_objects和all_libraries的文件。也就是说,在文件build/core/binary.mk文件加载完成之后,我们就可以获得由变量linked_module所定义的文件。在我们这个情景中,变量linked_module定义的文件就是out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so。

       在我们这个情景中,前面提到的out/target/product/generic/obj/lib/libdis.so和out/target/product/generic/system/lib/libdis.so文件的生过过程我们依然还没有搞清楚,这就需要进一步分析build/core/base_rules.mk文件。

       文件build/core/base_rules.mk的相关内容如下所示:


[plain] view plain copy


  • ......  
  •   
  • LOCAL_MODULE_PATH := $(strip $(LOCAL_MODULE_PATH))  
  • ifeq ($(LOCAL_MODULE_PATH),)  
  •   LOCAL_MODULE_PATH := $($(my_prefix)OUT$(partition_tag)_$(LOCAL_MODULE_CLASS))  
  •   ifeq ($(strip $(LOCAL_MODULE_PATH)),)  
  •     $(error $(LOCAL_PATH): unhandled LOCAL_MODULE_CLASS "$(LOCAL_MODULE_CLASS)")  
  •   endif  
  • endif  
  • ......  
  •   
  • LOCAL_INSTALLED_MODULE_STEM := $(LOCAL_MODULE_STEM)$(LOCAL_MODULE_SUFFIX)  
  • ......  
  •   
  • intermediates := $(call local-intermediates-dir)  
  • ......  
  •   
  • # OVERRIDE_BUILT_MODULE_PATH is only allowed to be used by the  
  • # internal SHARED_LIBRARIES build files.  
  • OVERRIDE_BUILT_MODULE_PATH := $(strip $(OVERRIDE_BUILT_MODULE_PATH))  
  • ifdef OVERRIDE_BUILT_MODULE_PATH  
  •   ifneq ($(LOCAL_MODULE_CLASS),SHARED_LIBRARIES)  
  •     $(error $(LOCAL_PATH): Illegal use of OVERRIDE_BUILT_MODULE_PATH)  
  •   endif  
  •   built_module_path := $(OVERRIDE_BUILT_MODULE_PATH)  
  • else  
  •   built_module_path := $(intermediates)  
  • endif  
  • LOCAL_BUILT_MODULE := $(built_module_path)/$(LOCAL_BUILT_MODULE_STEM)  
  • ......  
  •   
  • ifneq (true,$(LOCAL_UNINSTALLABLE_MODULE))  
  •   LOCAL_INSTALLED_MODULE := $(LOCAL_MODULE_PATH)/$(LOCAL_INSTALLED_MODULE_STEM)  
  • endif  
  • ......  
  •   
  • # Provide a short-hand for building this module.  
  • # We name both BUILT and INSTALLED in case  
  • # LOCAL_UNINSTALLABLE_MODULE is set.  
  • .PHONY: $(LOCAL_MODULE)  
  • $(LOCAL_MODULE): $(LOCAL_BUILT_MODULE) $(LOCAL_INSTALLED_MODULE)  
  • ......  
  •   
  • ifndef LOCAL_UNINSTALLABLE_MODULE  
  •   # Define a copy rule to install the module.  
  •   # acp and libraries that it uses can't use acp for  
  •   # installation;  hence, LOCAL_ACP_UNAVAILABLE.  
  • ifneq ($(LOCAL_ACP_UNAVAILABLE),true)  
  • $(LOCAL_INSTALLED_MODULE): $(LOCAL_BUILT_MODULE) | $(ACP)  
  •     @echo "Install: $@"  
  •     $(copy-file-to-new-target)  
  • else  
  • $(LOCAL_INSTALLED_MODULE): $(LOCAL_BUILT_MODULE)  
  •     @echo "Install: $@"  
  •     $(copy-file-to-target-with-cp)  
  • endif  
  • ......  
  •   
  • ALL_MODULES += $(LOCAL_MODULE)  
  • ......  

       文件build/core/base_rules.mk的加载过程如下所示:

       1. 如果我们没有在Android.mk文件中定义LOCAL_MODULE_PATH,那么LOCAL_MODULE_PATH的值就设置为$($(my_prefix)OUT$(partition_tag)_$(LOCAL_MODULE_CLASS))。它的具体值与执行lunch命令时选择的目标产品和当前要编译的模块类型有关,例如,当我们编译的是动态链接库,并且目标机器是模拟器时,它的值就等于out/target/product/generic/system/lib。

        2. 前面在加载文件build/core/dynamic_binary.mk时提到,LOCAL_MODULE_STEM的值默认等于LOCAL_MODULE的值,而LOCAL_MODULE_SUFFIX的值等于.so,因此,这里得到的LOCAL_INSTALLED_MODULE_STEM的值就等于当前要编译的模块名称再加上其对应的后缀名。

        3. 函数local-intermediates-dir的返回值执行lunch命令时选择的目标产品和当前要编译的模块类型有关。例如,当我们编译的是动态链接库,并且目标机器是模拟器时,它的值就等于out/target/product/generic/obj/lib,也就是intermediates的值等于out/target/product/generic/obj/lib。

        4. 如果我们没有在Android.mk文件中定义OVERRIDE_BUILT_MODULE_PATH的值,那么就表示要将生成的不带符号的模块文件保存在intermediates指定的目录中。

        5. 经过上面的准备工作之后,我们就得到LOCAL_BUILT_MODULE的值等于$(built_module_path)/$(LOCAL_BUILT_MODULE_STEM)。也就是它描述的是当前模块在编译的过程中产生的不带符号模块文件路径。在我们这个情景中,实际上就是out/target/product/generic/obj/lib/libdis.so。

        6. 如果我们没有在Android.mk文件中将LOCAL_UNINSTALLABLE_MODULE的值设置为true,那么就表示我们需要将最终的不带符号的模块文件拷贝到变量LOCAL_MODULE_PATH所描述的目录中,并且文件名为LOCAL_INSTALLED_MODULE_STEM。在我们这个情景中,实际上拷贝得到的文件就是out/target/product/generic/system/lib/libdis.so,并且通过变量LOCAL_INSTALLED_MODULE来描述。

        7. 制定伪目标LOCAEL_MODULE的依赖规则,即它依赖于变量LOCAL_BUILT_MODULE和LOCAL_INSTALLED_MODULE定义的文件。在我们这个情景中,实际上就是定义了一个伪目标libdis,它依赖于out/target/product/generic/obj/lib/libdis.so和out/target/product/generic/system/lib/libdis.so文件。

        8. 前面提到,如果我们没有在Android.mk文件中定义LOCAL_UNINSTALLABLE_MODULE,那么就表示要将最终的不带符号的模块文件拷贝到变量LOCAL_MODULE_PATH所描述的目录中,即将LOCAL_BUILT_MODULE描述的文件拷贝为LOCAL_INSTALLED_MODULE描述的文件。这时候我们还需要制定一个LOCAL_INSTALLED_MODULE依赖LOCAL_BUILT_MODULE的规则。

        9. 将表示当前模块名称的LOCAL_MODULE值附加到ALL_MODULES后面去。

        通过第5步我们确定了LOCAL_BUILT_MODULE的值。前面对build/core/dynamic_binary.mk文件的加载过程分析中提到,LOCAL_BUILT_MODULE描述的文件依赖于out/target/product/generic/symbols/system/lib/libdis.so文件。也就是说,out/target/product/generic/obj/lib/libdis.so文件依赖于out/target/product/generic/symbols/system/lib/libdis.so文件。同样,通过第6步我们确定了out/target/product/generic/system/lib/libdis.so依赖于out/target/product/generic/obj/lib/libdis.so文件。

       至此,我们就搞清楚了前面提到的四个文件out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so、out/target/product/generic/symbols/system/lib/libdis.so、out/target/product/generic/obj/lib/libdis.so和out/target/product/generic/system/lib/libdis.so之间从右到左的依赖关系以及生成过程。

       然而,我们前面又提到,在执行mmm命令时,默认的make目标为all_modules,并且该目标依赖于变量ALL_MODULES所描述的伪目标,而变量ALL_MODULES所描述的伪目标又等于当前要编译的模块名称,即LOCAL_MODULE。最后,LOCAL_MODULE也是一个伪目标,它依赖于LOCAL_BUILT_MODULE和LOCAL_INSTALLED_MODULE所定义的文件,也就是out/target/product/generic/obj/lib/libdis.so和out/target/product/generic/system/lib/libdis.so文件。

       这样,我们就可以得到在我们所分析的情景中,上述各个make目标或者文件的之间的链式依赖关系:

       1. all_modules依赖于ALL_MODULES;

       2. ALL_MODULES依赖于LOCAL_MODULE;

       3. LOCAL_MODULE依赖于out/target/product/generic/obj/lib/libdis.so和out/target/product/generic/system/lib/libdis.so;

       4. out/target/product/generic/system/lib/libdis.so依赖于out/target/product/generic/obj/lib/libdis.so;

       5. out/target/product/generic/obj/lib/libdis.so依赖于out/target/product/generic/symbols/system/lib/libdis.so;

       6. out/target/product/generic/symbols/system/lib/libdis.so依赖于out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so;

       7. out/target/product/generic/obj/SHARED_LIBRARIES/libdis_intermediates/LINKED/libdis.so依赖于all_objects和all_libraries;

       8. all_objects依赖于在Android.mk文件中通过LOCAL_SRC_FILES定义的文件dispatcher.cpp和common.cpp文件;

       9. all_libraries依赖于在Android.mk文件中通过LOCAL_SHARED_LIBRARIES定义的文件libdl.so和liblog.so文件。

       通过调用gcc等编译工具,就可以从最后一步开始,一步步向上编译出各个模块文件,并且保存在合适的位置中。

       至此,我们就分析完成了使用mmm命令来编译一个动态链接库的过程。使用mmm命令来编译其它类型的模块,例如APK文件、EXE文件和JAVA库,过程也是差不多的,无非都是建立各个文件之间的依赖关系,以及调用相应的编译工具来进行编译。弄懂了mmm命令的编译过程之后, 另外的三个编译命令m、mm和make也可以一目了然了。

       当在Android源码中定义的各个模块都编译好之后,我们还需要将编译得到的文件打包成相应的镜像文件,例如system.img、boot.img和recorvery.img等,这样我们才可以将这些镜像烧录到目标设备去运行。


收藏
收藏0
分享
分享
点赞
点赞0
反对
反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册
手机版