欢迎光临
专注android技术,聚焦行业精粹,我们一直在努力

Gradle源代码编译以及源代码分析(2)

一句话概括Gradle自身源代码编译流程-用gradle来编译Gradle

注:下面编译的过程中,gradle 会访问google,所以要先准备好电脑成功科学上网

下面我们正式开始分析:

因为我们拿到源代码后,首先接触的是gradlew.bat,也就是Gradle源代码自身编译的命令。所以,我们还是从这个脚本开始分析。

一. Eclipse打开源代码

为了方便修改代码,我选择用Eclipse来打开这个工程。步骤是:

File->New->Java Project->Use default location去掉勾选->Browse选择Gradle源代码目录->finish

二. gradlew.bat脚本

1. 还是从我们编译Gradle源代码的命令入手

gradlew.bat assemble

那首先来看下gradlw.bat :

执行gradlew.bat assemble时,首先来看看这个脚本里面的各个变量值:

CLASSPATH:gradle-3.1\\gradle\wrapper\gradle-wrapper.jar

表示的是gradle源代码里面gralde\wrapper\目录下gradle-wrapper.jar,这个jar也是待会要执行的编译操作要运行的jar。

DEFAULT_JVM_OPTS:-Xmx1024m -Dfile.encoding=UTF-8 表示的是Java虚拟机配置

JAVA_OPTS:空

GRADLE_OPTS:空

CMD_LINE_ARGS:assemble 表示要执行的gradle task名字

然后接下来,就会执行重要的一句,启动gradle-wrapper.jar里面的GradleWrapperMain.main函数。

那这里可能有个疑问,就是此时Gradle源代码还没有编译出来,哪来的gradle-wrapper.jar。这个问题就像鸡和蛋的问题,先有鸡还是先有蛋。

Gradle的做法是先有鸡后有蛋,那第一只鸡哪来的呢? Gradle是自己给它造了一只鸡。

请看gradle\wrapper\gradle-wrapper.jar

所以这里有个小的细节要提醒下大家,大家修改完GradleWrapperMain这个类之后,比如打印了日志,如果要验证它的结果,需要首先执行几个步骤

  1. gradlew.bat assemble
  2. 进行编译把编译出来的gradle-wrapper.jar覆盖到gradle\wrapper\目录下。
  3. 再执行一个gradlew.bat assemble就可以在命令行里面验证。

三. GradleWrapperMain

文件路径:

gradle-3.1\subprojects\wrapper\src\main\java\org\gradle\wrapper\GradleWrapperMain.java

GradleWrapperMain位置subprojects里面,Gradle源代码把各个工程拆分成各个模块,类似于插件的方式。

也就是说每个功能都拆分成一个插件,然后使用的时候进行配置,比如某个插件需要依赖于哪几个插件,那就直接配置上就可以。

配置的路径在每个插件的jar包里面,名称叫做xxx-classpath.properties,里面有个projects属性,配置了这个插件依赖的插件(也可以叫项目或者模块)。

这种设计思想可以让整个项目层次清晰,同时便于多个团队间合作开发。

看下GradleWrapperMain的main函数:

打印的log是:

这个日志已经很清楚的说明了各个变量的值。

需要说明的一点是gradleUserHome,这个是Gradle下载其他Jar包的存放地址,默认是c盘的user/xxx/.gradle/目录。

但是这个目录是可以配置的,配置GRADLE_USER_HOME环境变量即可。

这点从上面代码getUserHome可以清楚的看到。

另外,程序的最后面Gradle执行WrapperExecutor.execute(xxxx)方法,这个比较关键。

四. WrapperExecutor.execute

1. execute


 

可以看到execute里面没有什么东西,调用的是传入的install.createDist和bootstrapMainStarter.start方法,所以,需要分析下这两个方法。

2. Install.createDist

这是打印的日志:

这里有几个问题:

a. 下载zip包

createDist其实就是去下载distributionUrl描述的zip包。

其实这还是个鸡和蛋的问题,Gradle源代码是用Gradle来编译的,现在我们只有源代码,那怎么编译呢?

所以就只能先从服务器上把Gradle zip包下载下来。

b. distributionUrl定义位置

gradle源代码根目录/gradle/wrapper/gradle-wrapper.properties

也就是:

配置文件位置可以在WrapperExecutor的构造函数看出来:

c. 根据md5计算出zip文件的存放目录

distDir目录,也就是下载下来的zip文件存放目录有一串字符串,这是根据md5算出来的,保证唯一性,代码如下:

文件路径:

subprojects\wrapper\src\main\java\org\gradle\wrapper\PathAssembler.java


 

d. 执行时机

在第一次执行gradlew.bat assemble的时候会去下载,然后解压。

所以第一次执行gradlew.bat assemble会出现这样日志:

Downloading xxxx…….

Unzipping…..

3. bootstrapMainStarter.start

文件路径:

subprojects\wrapper\src\main\java\org\gradle\wrapper\BootstrapMainStarter.java


 

打印日志如下:


 

那么现在来解释下上面这段代码是在干什么:

a. 从gradle bin下载解压目录的lib文件夹找到gradle-launcher-.*\\.jar。

b. 然后执行launcher-xxx.jar包里面的org.gradle.launcher.GradleMain.main函数。

c. 同时,把我们输入的参数assemble传入进去。

那么接下去执行的就是我们下载的gradle里面的launcher-xxx.jar的函数了,不是我们源代码里面的,这点要特别区分清楚。

执行下载的gradle里面的代码来编译Gradle源代码的过程,就像gradle编译其他程序一样。

所以才说Gradle源代码的编译过程就是用gradle来编译Gradle.

这个地方就是之前我们说过的gradlew.bat和gradle.bat的区别。

d. gradlew.bat和gradle.bat的区别

gradlew.bat是Gradle源代码自身编译时候的bat脚本

加载的是当前目录下 gralde/wrapper/gradle-wrapper.jar包,执行的是GradleWrapperMain.main方法。

然后去下载gradle bin,再解压。然后执行gradle lib里面的gradle-launcher-xxx.jar里面的GradleMain.main函数。

gradle.bat是gradle编译其他程序的bat脚本

加载的是gradle lib里面gradle-launcher-xxx.jar里面的GradleMain.main函数。

e. 关于gradlew.bat命名的思考

我在思考为什么编译Gradle自身源代码的脚本要叫gradlew.bat呢?和编译其他程序的脚本gradle.bat只有一字之差?”w”代表的意思是什么呢?

gradlew.bat做的事情是编译Gradle源代码自身,那么叫叫gradle_compile_self.bat比较直观点?

也许,我们可以理解”w”是wrapper的缩写,因为两个脚本加载的Jar就是这样的区别;而且wapper做的事情真的就是包装的工作。比如它只是去下载gradle bin,然后就直接调用gradle bin的grale-launcher-xxx.jar了。

所以,也许这个就是Gradle团队对于”w”的理解吧。。

接下来的话,Gradle自身源代码的编译过程就和一般程序的编译过程一样了;我们再分析gradle编译应用程序过程。

 

赞(0) 打赏
未经允许不得转载:花花鞋 » Gradle源代码编译以及源代码分析(2)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

国内精品Android技术社区

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏