Android ninja编译启动过程分析
---make是如何转换到到ninja编译的
1.首先你的得对make的工作机制有个大概的了解:
运行的命令在要编译的目录下运行make,或者make target_name
a.分析处理保存阶段(没有实际编译动作):它首先对当前目录下的Makefile文件的做一次扫描,语法分析,还有处理,主要是变量的保存,目标依赖列表生成,目标下的action列表的生成,然后记住
b.然后按记住的目标执行action列表动作(有实际编译动作).
编译启动的入口方式还是运行make:
2开始make-jxxx方式进入.....(xxx是本机cpu的数量)
make开始做进行第一次扫描....
目前USE_NINJA还是没有定义,估计以后很久很久才能启用的了!
BUILDING_WITH_NINJA开始也是没定义的
看make扫描入口文件:
Makefile:
include build/core/main.mk
在build/core/main.mk:
在ninia之前都有include help.mk和config.mk
97include$(BUILD_SYSTEM)/help.mk
98
99#Set up various standard variables based on configuration
100#and host information.
101include$(BUILD_SYSTEM)/config.mk
说明make help//显示make帮助make config//当前显示配置
103relaunch_with_ninja:=
104ifneq($(USE_NINJA),false)
105ifndef BUILDING_WITH_NINJA<==第二次扫描不会到这里了
106relaunch_with_ninja:=true
107endif
108endif
116ifeq($(relaunch_with_ninja),true)<===第一次扫描入这里了
117#Mark this is a ninja build.
118$(shell mkdir-p$(OUT_DIR)&&touch$(OUT_DIR)/ninja_build)
119include build/core/ninja.mk//---进入ninja.mk
第一次扫描到此为止就结束掉了,因为在当前ifeq else endif后面没有代码了
120else#///!relaunch_with_ninja<===第二次扫描入这里了
121ifndef BUILDING_WITH_NINJA
122#Remove ninja build mark if it exists.
123$(shell rm-f$(OUT_DIR)/ninja_build)
124endif
......
endif////////!relaunch_with_ninja
这里是文件底了
接着上面的include build/core/ninja.mk
build/core/ninja.mk:
$(sort$(DEFAULT_GOAL)$(ANDROID_GOALS)):ninja_wrapper//使nijia_wrapper成为第一扫描后要做的action 的第一个跳入的标签
ninja_wrapper:$(COMBINED_BUILD_NINJA)$(MAKEPARALLEL)
@echo Starting build with ninja
+$(hide)export NINJA_STATUS="$(NINJA_STATUS)"&&source$(KATI_ENV_SH)&&$(NINJA_MAKEPARALLEL) $(NINJA)$(NINJA_GOALS)-C$(TOP)-f$(COMBINED_BUILD_NINJA)$(NINJA_ARGS)
这里被依赖$(COMBINED_BUILD_NINJA)要先被处理完后才能返回来继续这里的action了
ifeq($(USE_SOONG),true)
135$(COMBINED_BUILD_NINJA):$(KATI_BUILD_NINJA)$(SOONG_ANDROID_MK)
136$(hide)echo"builddir=$(OUT_DIR)">$(COMBINED_BUILD_NINJA)
137$(hide)echo"subninja$(SOONG_BUILD_NINJA)">>$(COMBINED_BUILD_NINJA)
138$(hide)echo"subninja$(KATI_BUILD_NINJA)">>$(COMBINED_BUILD_NINJA)
139else
140COMBINED_BUILD_NINJA:=$(KATI_BUILD_NINJA)
141endif
继续看:$(KATI_BUILD_NINJA)
162$(KATI_BUILD_NINJA):$(KATI)$(MAKEPARALLEL)$(DUMMY_OUT_MKS)$(SOONG_ANDROID_MK)FORCE 163@echo Running kati to generate build$(KATI_NINJA_SUFFIX).ninja...
164+$(hide)$(KATI_MAKEPARALLEL)$(KATI)--ninja--ninja_dir=$(OUT_DIR)
--ninja_suffix=$(KATI_NINJA_SUFFIX)--regen--ignore_dirty=$(OUT_DIR)/%
--no_ignore_dirty=$(SOONG_ANDROID_MK)--ignore_optional_include=$(OUT_DIR)/%.P--detect_android_echo $(KATI_FIND_EMULATOR)-f build/core/main.mk$(KATI_GOALS)--gen_all_targets BUILDING_WITH_NINJA=true SOONG_ANDROID_MK=$(SOONG_ANDROID_MK)
在这个位置触发了的第二次build/core/main.mk(由kati处理的)的扫描,看起来他和make功能一样,这里kati要处理一遍: build/core/main.mk,下面他处理的包括的过程:
文件开始
....117else
#!relaunch_with_ninja
118ifndef BUILDING_WITH_NINJA
119#Remove ninja build mark if it exists.
120$(shell rm-f$(OUT_DIR)/ninja_build)
121endif
.....
#endif
也就是说kati处理了从main.mk文件开始到末尾的全部,不包括include build/core/ninja.mk部分的全部了,包括他include makefiles了
@echo Running kati to generate build$(KATI_NINJA_SUFFIX).ninja...
/////////////在屏幕上可以看到是否kati开始了扫描生成.ninja file的过程
在这个过程中,kati要判断是否生成.ninja是否需要更新了,这个是在kati内部完成的!
./:172:fprintf(stderr,"%s was modified,regenerating...\n",s.c_str());
看来东西不少,然后他回到ninja_wrapper:下继续上一层的action执行
ninja_wrapper:$(COMBINED_BUILD_NINJA)$(MAKEPARALLEL)//重新贴了一遍上面的东西
@echo Starting build with ninja
+$(hide)export NINJA_STATUS="$(NINJA_STATUS)"&&source$(KATI_ENV_SH)&&$(NINJA_MAKEPARALLEL) $(NINJA)$(NINJA_GOALS)-C$(TOP)-f$(COMBINED_BUILD_NINJA)$(NINJA_ARGS)
这个执行就是启动ninja了,看:$(NINJA)$(NINJA_GOALS)
@echo Starting build with ninja
/////////////在屏幕上可以看到是否开是在ninja带领下编译开始了.....
//====到此,第一阶段准备工作部分分析完成了,下面进入具体的ninjia编译阶段了
3.总结
kati代替了make过去做的非常相同一样的工作(连输出打印都很一样,例如遇到$(error xxxx)会退出),parse makefile。
,只是他会输出.ninja file,而不是如过去make解析makefile记在心里,然后给他自己跳入做action,而现在是生成个文件给ninja跳入做action了.
在下载的Android源码下,测试通过make droid-j25最接续编译测试:
####make completed successfully(01:06(mm:ss))####
快的震惊啊!
测试用代码版本:
PLATFORM_VERSION:=7.1.2。