Android.mk编译流程分析--android的build系统
关于Android.mk,可以很容易到关于它怎么编写的资料,不过最近在移植⼀个开源的linux项⽬,抛弃源⼯程的configure+make机制放⼊android源码⾥⾯⽤ mm命令来来编译,总是各种坑,在android源码⾥⾯编译要求很⾼⽐如 ⼀个int 函数没有return,也会报错,编译的模块需要依赖⼀个⾃⼰私⾃开发的so库时候,⽤参数 LOCAL_LDFLAGS来指定,也是种种问题,这些问题⽐如最终发现多了⼀个空格等等,甚⾄于解决了也是不知其然,被迫⽆奈,来探究⼀下mm这个命令到底是⼲了啥:
具体的分析细节不赘述,直接上理论成果吧(请忽略上下⽂,直接看4.0):制作android软件流程
1.0 编译⾸要的⼯作都是⼀个 source build/envsetup.sh 和 lunch,这个source 命令当然是linux的shell所⽀持的,他的作⽤就是把后⾯的 build/envsetup.sh 脚本⽂件中定义的变量和函数 导出来,可以直接在当前shell上调⽤。 这其中的函数就有                            m mm mmm 和lunch等等,然后我们就可以直接在终端⾥⾯敲这些函数。详细分析 参考:
2.0 那么mm函数做了什么? ⼀句shell命令⽽已: make -C /home/XXX  -f build/core/main.mk all_modules ,就是在前⾯先定义了⼏个变量,然后执⾏make ,所以后续所有的⼯作,就是makefile的⼯作,那么实际上还是linux的 make,只是这个makefile,可是相当庞⼤,可以当做⼀个project去分析了,完整的具备了变量,函数,条件判断+系统命令。看这个⼯程需要⾜够的makefile知识,后续单独总
结⼀篇吧。
3.0 makefile中基本就三种东西:依赖关系、命令规则、变量和函数,它的执⾏顺序,多线程的,可不是像shell脚本⼀样顺序执⾏,⽽是直接根据⽬标⽂件,查依赖关系,然后执⾏命令规则⽣成⽂件,⾥⾯唯⼀可以执⾏的,就是命令规则,在这⾥⾯可以⽤shell脚本的命令,可以调⽤shell⾥⾯的语法,⾄于 makefile中的变量和函数,也只有在这个命令规则中使⽤的时候才会调⽤,函数其实和变量⽤法⼀样,所以就不要想着突然在Android.mk⽂件中echo 了,这不是shell,除⾮echo放在命令规则⾥⾯,⽽且该命令规则会被执⾏
4.0 终极问题:拿⼀个 hello_world.c⽂件编译成⼀个 test_hello库来看,编写Android.mk⽂件,最终怎么 ⽤什么路径的gcc把这个.c⽂件怎么个编译连接成⼀个 so库并且放到什么⽬录下⾯了?注:个⼈的android源码 ⼯程 为7.0
使⽤Android.mk⽂件:
...
LOCAL_SRC_FILES:= hello.c
LOCAL_MODULE:= libhello_test23
include $(BUILD_SHARED_LIBRARY)
...#呵呵,就是不完整
在shared_library_internal.mk⽂件中,有这么⼀条规则
(到这个地⽅可是花费了不少时间,开始当然是从源头⽽下,结果在makefile众多的变量嵌套⾥⾯⼀下⼦就跟丢了线索,就开始另谋出路,在build⽬录下grep“:”,企图逐⼀查看所有的命令规则,结果太多太多,想到Android.mk中的句法
include $(BUILD_SHARED_LIBRARY),通过$(warning "BUILD_SHARED_LIBRARY $(BUILD_SHARED_LIBRARY)") 查看了下build/core/shared_library.mk 这个⽂件,没有什么线索,同样的还有两个句法LOCAL_LDFLAGS和LOCAL_CFLAGS,果然,顺着这两个变量的调⽤到了想要的结果) 两个echo是我加上去跟踪信息的(notepad++⾥⾯设置把所有的符号都显⽰出来,⽐如看到上⾯的空格和tab,最后⼀个没有续航符号,下⼀⾏就是以tab开头,这就是⼀个典型的 make的命令规
则)
这个transform-o-to-shared-lib, 是⼀个预定义的函数,看名字也能知道它的作⽤了,在definitions.mk⽂件中还有很多这样的定义
⽐如把.c⽂件编译成.o⽂件的函数,如上图。要查看这些函数具体做了什么,直接在⾥⾯echo ⽐如刚刚$(transform-o-to-shared-lib) 这个函数:
define transform-o-to-shared-lib
@echo "target SharedLib: $(PRIVATE_MODULE) ($@)"
@mkdir -p $(dir $@)
$(transform-o-to-shared-lib-inner)
endef
==>define transform-o-to-shared-lib-inner
echo "wang PRIVATE_CXX:$(PRIVATE_CXX)"  #当然这个⼜是我加进去的
$(hide) $(PRIVATE_CXX) \
-nostdlib -Wl,-soname,$(notdir $@) \
-Wl,--gc-sections \
$(if $(filter true,$(PRIVATE_CLANG)),-shared,-Wl$(comma)-shared) \
$(PRIVATE_TARGET_GLOBAL_LD_DIRS) \
$(PRIVATE_TARGET_CRTBEGIN_SO_O) \
$(PRIVATE_ALL_OBJECTS) \
-
Wl,--whole-archive \
$(call normalize-target-libraries,$(PRIVATE_ALL_WHOLE_STATIC_LIBRARIES)) \    -Wl,--no-whole-archive \
$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--start-group) \
$(call normalize-target-libraries,$(PRIVATE_ALL_STATIC_LIBRARIES)) \
$(if $(PRIVATE_GROUP_STATIC_LIBRARIES),-Wl$(comma)--end-group) \
$(if $(filter true,$(NATIVE_COVERAGE)),$(PRIVATE_TARGET_COVERAGE_LIB)) \    $(PRIVATE_TARGET_LIBATOMIC) \
$(PRIVATE_TARGET_LIBGCC) \
$(call normalize-target-libraries,$(PRIVATE_ALL_SHARED_LIBRARIES)) \
-o $@ \
$(PRIVATE_TARGET_GLOBAL_LDFLAGS) \
$(PRIVATE_LDFLAGS) \
$(PRIVATE_TARGET_CRTEND_SO_O) \
$(PRIVATE_LDLIBS)
endef
上⾯这⼀⼤坨,可以直接⽤echo "XXXX" ,复制到xxx可以输出看到完整的实际展开的命令参数输出了下,⼤概是这样⼦的。。。
嗯,很可怕,没敢贴完整。。这只是编译⼀个64位库的输出,还有⼀份同样的32bit的库的编译,所有其他的各种⽂件各种变量,⽆⾮就是根据具体情况来确定⽤什么编译器,⽂件的路径,连接什么库,需要什么参数。所以说整个编译架构,是⼀份完备的proj,⽤makefile写的proj,直接在linux终端上通过 grep来查看这些变量的定义和调⽤如:
在build⽬录下:grep "(transform" * -rn 查看这些函数的调⽤
分析这整个⼯程还需要其他更多的关于makefile的知识

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。