第6章 Build Script Basics 构建脚本的基础识
最后更新于:2022-04-01 02:32:33
在 Gradle 中两个顶级概念:project(项目)和 task 任务)
所有 Gradle 都有一个或多个 project 构成。project 的展现取决于 Gradle 所做的工作。举例。 project 可以是一个 JAR 库 或者是 web 应用。它可以是由项目生产 JAR 组成发布的 ZIP。一个 project 不一定 代表一个东西要构建。它可能是一件要做的事,如将应用程序部署到工作台 或生产环境。如果这看起来有点模糊,现在不要担心。Gradle 基于约定的构建支持增加一个 更具体的定义的 project。
每个项目都是由一个或多个 task。一个 task 代表了一个构建生成的原子的作品。这可能是编写一些类,创建一个 JAR ,生成 Javadoc,或发布一些库。
现在,我们将看看在构建一个 project 时定义一些简单的 task 。后面的章节将介绍多个 project 和更多的 task 。
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#62-hello-world)6.2\. Hello world
运行 Gradle 是使用 gradle 命令行。命令行会寻找项目的根目录下 build.gradle 的文件(有关命令行,详见 [Appendix D. Gradle Command Line 命令行](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Appendix%20D.%20Gradle%20Command%20Line%20%E5%91%BD%E4%BB%A4%E8%A1%8C.md)),这个就是构建的脚本,或者严格说是构建的配置脚本。他定义了project(项目)和 task 任务)。
尝试输出,创建一个 `build.gradle` 命名的文件:
Example 6.1\. Your first build script
build.gradle
~~~
task hello {
doLast {
println 'Hello world!'
}
}
~~~
命令行切换到包含 build.gradle 文件的目录,执行 `gradle -q hello`
[![gradle601.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47fe533d70.jpg "gradle601.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47fe533d70.jpg)
Example 6.2\. Execution of a build script
输出为:
~~~
> gradle -q hello
Hello world!
~~~
[![gradle602.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47fecd4ae8.jpg "gradle602.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47fecd4ae8.jpg)
这个脚本定义了一个 名字是`hello` 的 task,并且添加了动作。当运行 `gradle hello` ,Gradle 执行这个 `hello` task,接着执行里面的动作。这里的动作只是简单的包含了一些可以执行的 Groovy 代码。
看上去很像 Ant ,不错,Gradle task 是相当于 Ant 的 target,但是你将看到,他们更强大。我们使用了跟 Ant 不同的术语,因为 task 比 target 更富表现力。
不幸的是,这一术语与 Ant 有冲突,Ant 调用它的命令行,如 javac 或copy 称之为 task 。所以当我们谈论的 task ,默认说的是 Gradle task ,这是相当 Ant 的 target。如果我们谈论的 Ant 的 task (Ant 命令),我们明确地说的 Ant task。
### [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#命令行加中--q-的作用)命令行加中 `-q` 的作用
q 是 quiet 的简写,意思是要安静、干净的输出。如果不加 `-q` 则会输出日志。详见[Chapter 18\. Logging 日志](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2018.%20Logging%20%E6%97%A5%E5%BF%97.md).下面是对比
[![gradle604.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47feecd975.jpg "gradle604.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47feecd975.jpg)
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#63-a-shortcut-task-definition-快捷-task-定义)6.3\. A shortcut task definition 快捷 task 定义
定义 task 可以使用快捷方式,这样更简明。
Example 6.3\. A task definition shortcut
build.gradle
~~~
task hello << {
println 'Hello world!'
}
~~~
再次执行,得到相同的输出。在下面的文章中,我们都会采用这种定义方式。
[![gradle605.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47fefc56d3.jpg "gradle605.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47fefc56d3.jpg)
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#64-build-scripts-are-code-构建的脚本都是代码)6.4\. Build scripts are code 构建的脚本都是代码
工具的构建脚本给你完整的 Groovy 的功能。作为开胃菜,看看这个:
Example 6.4\. Using Groovy in Gradle's tasks
build.gradle
~~~
task upper << {
String someString = 'mY_nAmE'
println "Original: " + someString
println "Upper case: " + someString.toUpperCase()
}
~~~
执行 `gradle -q upper` 输出
~~~
> gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME
~~~
[![gradle606.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff094c15.jpg "gradle606.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff094c15.jpg)
或者
Example 6.5\. Using Groovy in Gradle's tasks
build.gradle
~~~
task count << {
4.times { print "$it " }
}
~~~
执行 `gradle -q count` 输出
~~~
> gradle -q count
0 1 2 3
~~~
[![gradle607.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff27cc55.jpg "gradle607.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff27cc55.jpg)
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#65-task-dependencies-依赖)6.5\. Task dependencies 依赖
可以声明 task 与 其他 task 的依赖
Example 6.6\. Declaration of task that depends on other task
build.gradle
~~~
task hello << {
println 'Hello world!'
}
task intro(dependsOn: hello) << {
println "I'm Gradle"
}
~~~
执行 `gradle -q intro` 输出
~~~
> gradle -q intro
Hello world!
I'm Gradle
~~~
[![gradle608.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff345d81.jpg "gradle608.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff345d81.jpg)
添加一个依赖,相应的 task 不需要存在
Example 6.7\. Lazy dependsOn - the other task does not exist (yet)
build.gradle
~~~
task taskX(dependsOn: 'taskY') << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
~~~
执行 `gradle -q taskX`输出
~~~
> gradle -q taskX
taskY
taskX
~~~
[![gradle609.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff5c1ef6.jpg "gradle609.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff5c1ef6.jpg)
taskX 的依赖 taskY 是在 taskY 定义之前 声明的。这个在多 project 构建时很重要。关于 task 的依赖详见 [Chapter 15\. More about Tasks 更多关于任务](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2015.%20More%20about%20Tasks%20%E6%9B%B4%E5%A4%9A%E5%85%B3%E4%BA%8E%E4%BB%BB%E5%8A%A1.md)
请注意不要使用快捷符号,当引用的 task 还没有定义的情况下。
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#66-dynamic-tasks-动态-task)6.6\. Dynamic tasks 动态 task
Groovy 的能力不仅仅是定义一个 task。例如,你也可以用它来动态创建的 task。
Example 6.8\. Dynamic creation of a task
build.gradle
~~~
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
~~~
执行 `gradle -q task1` 输出
~~~
> gradle -q task1
I'm task number 1
~~~
[![gradle610.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff6ef423.jpg "gradle610.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff6ef423.jpg)
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#67-manipulating-existing-tasks-利用现有的任务)6.7\. Manipulating existing tasks 利用现有的任务
一旦 task 创建,他们可以通过一个 API 访问。例如,在运行时您可以使用此动态添加依赖到 task 。Ant 不允许这样的事情。
Example 6.9\. Accessing a task via API - adding a dependency
build.gradle
~~~
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
task0.dependsOn task2, task3
~~~
执行 `gradle -q task0` 输出
~~~
> gradle -q task0
I'm task number 2
I'm task number 3
I'm task number 0
~~~
或者 可以添加行为到一个已经存在 task 中
Example 6.10\. Accessing a task via API - adding behaviour
build.gradle
~~~
task hello << {
println 'Hello Earth'
}
hello.doFirst {
println 'Hello Venus'
}
hello.doLast {
println 'Hello Mars'
}
hello << {
println 'Hello Jupiter'
}
~~~
执行 `gradle -q hello` 输出
~~~
> gradle -q hello
Hello Venus
Hello Earth
Hello Mars
Hello Jupiter
~~~
[![gradle611.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff79d64b.jpg "gradle611.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff79d64b.jpg)
doFirst 和 doLast 可以多次执行调用。他们在开始或结束的 task 动作清单中添加动作。task 执行时,按动作列表的顺序执行的动作。操作符 `<<` 仅仅是 doLast 的别名。
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#68-shortcut-notations-快捷符号)6.8\. Shortcut notations 快捷符号
在前面的示例中已经注意到,有一个方便的符号访问现有的 task 。每个 task 可以作为构建脚本的一个属性:
Example 6.11\. Accessing task as a property of the build script
build.gradle
~~~
task hello << {
println 'Hello world!'
}
hello.doLast {
println "Greetings from the $hello.name task."
}
~~~
执行 `gradle -q hello`输出
~~~
> gradle -q hello
Hello world!
Greetings from the hello task.
~~~
[![gradle612.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff81fe62.jpg "gradle612.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff81fe62.jpg)
这使得代码可读性增强,尤其是当使用的插件提供的 task ,如 compile task
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#69-extra-task-properties-额外-task-属性)6.9\. Extra task properties 额外 task 属性
可以添加自己属性到 task ,添加 `myProperty`属性,设置 、`ext.myProperty` 初始值,从这一点上,该属性可以读取和设置就像一个预定义的任务属性。
Example 6.12\. Adding extra properties to a task
build.gradle
~~~
task myTask {
ext.myProperty = "myValue"
}
task printTaskProperties << {
println myTask.myProperty
}
~~~
执行 `gradle -q printTaskProperties`输出
~~~
> gradle -q printTaskProperties
myValue
~~~
[![gradle613.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff988ea1.jpg "gradle613.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ff988ea1.jpg)
task 不对额外属性做限制,更多详见[Chapter 13\. Writing Build Scripts 编写构建脚本](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2013.%20Writing%20Build%20Scripts%20%E7%BC%96%E5%86%99%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC.md) 中 13.4.2 节 “Extra properties”.
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#610-using-ant-tasks-使用-ant-task)6.10\. Using Ant Tasks 使用 Ant task
Ant task 是 Gradle 一等公民。 Gradle 给 Ant task 提供了不错的整合通过简单依靠于 Gradle 。Groovy 被奇异的 AntBuilder 装载。从 Gradle 使用 Ant task 比使用 build.xml 文件更方便和更强大。从下面的例子中,你可以学习如何执行 Ant task 和如何访问 Ant 属性:
Example 6.13\. Using AntBuilder to execute ant.loadfile target
build.gradle
~~~
task loadfile << {
def files = file('antLoadfileResources').listFiles().sort()
files.each { File file ->
if (file.isFile()) {
ant.loadfile(srcFile: file, property: file.name)
println " *** $file.name ***"
println "${ant.properties[file.name]}"
}
}
}
~~~
执行 `gradle -q loadfile`输出
~~~
> gradle -q loadfile
*** agile.manifesto.txt ***
Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan
*** gradle.manifesto.txt ***
Make the impossible possible, make the possible easy and make the easy elegant.
(inspired by Moshe Feldenkrais)
~~~
[![gradle614.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ffa4a8b4.jpg "gradle614.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ffa4a8b4.jpg)
更多关于 构建脚本中使用 Ant ,详见 [Chapter 17\. Using Ant from Gradle 从 Gradle 使用 Ant](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2017.%20Using%20Ant%20from%20Gradle%20%E4%BB%8E%20Gradle%20%E4%BD%BF%E7%94%A8%20Ant.md)
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#611-using-methods-使用方法)6.11\. Using methods 使用方法
Gradle 延伸取决你如何组织的建造逻辑。上面的例子中的第一级别的组织你的构建逻辑,是提取方法。
Example 6.14\. Using methods to organize your build logic
build.gradle
~~~
task checksum << {
fileList('../antLoadfileResources').each {File file ->
ant.checksum(file: file, property: "cs_$file.name")
println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
}
}
task loadfile << {
fileList('../antLoadfileResources').each {File file ->
ant.loadfile(srcFile: file, property: file.name)
println "I'm fond of $file.name"
}
}
File[] fileList(String dir) {
file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}
~~~
执行 `gradle -q loadfile`输出
~~~
> gradle -q loadfile
I'm fond of agile.manifesto.txt
I'm fond of gradle.manifesto.txt
~~~
[![gradle615.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ffb1346f.jpg "gradle615.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ffb1346f.jpg)
以后你会发现这样的方法可以在多 project 构建的子 project 之间共享。如果你建立逻辑变得越来越复杂,Gradle 为您提供其他工具很方便的方式来组织它。我们有专门一章[Chapter 60\. Organizing Build Logic](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2060.%20Organizing%20Build%20Logic%20%E7%BB%84%E7%BB%87%E6%9E%84%E5%BB%BA%E9%80%BB%E8%BE%91.md)
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#612-default-tasks-默认-task)6.12\. Default tasks 默认 task
Gradle 允许你定义一个或多个默认 task 给你的构建
Example 6.15\. Defining a default tasks
build.gradle
~~~
defaultTasks 'clean', 'run'
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
~~~
执行 `gradle -q` 输出
~~~
> gradle -q
Default Cleaning!
Default Running!
~~~
[![gradle617.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ffd34ced.jpg "gradle617.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ffd34ced.jpg)
这个等于执行了 `gradle clean run` ,在多 project 中构建所有的子 project 都可以有自己具体的默认 task 。如果 子 project 没有明确的默认 task,则执行父 project 的默认 task(如果定义的话)
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#613-configure-by-dag-通过-dag-配置)6.13\. Configure by DAG 通过 DAG 配置
以后会详细描述(见[Chapter 56\. The Build Lifecycle 构建生命周期](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2056.%20The%20Build%20Lifecycle%20%E6%9E%84%E5%BB%BA%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F.md) ),Gradle 有配置阶段和执行阶段。配置阶段后,Gradle 知道所有的 task 应该执行。Gradle 提供给你一个钩子来利用这些信息。这个用例将检查发布 的 task 是否是要执行的 task。基于此,你可以赋予不同的值到一些变量。
在下面的例子中,在不同 version 变量中的 distribution 和 release task 执行结果不同。
Example 6.16\. Different outcomes of build depending on chosen tasks
build.gradle
~~~
task distribution << {
println "We build the zip with version=$version"
}
task release(dependsOn: 'distribution') << {
println 'We release now'
}
gradle.taskGraph.whenReady {taskGraph ->
if (taskGraph.hasTask(release)) {
version = '1.0'
} else {
version = '1.0-SNAPSHOT'
}
}
~~~
执行 `gradle -q distribution` 输出
~~~
> gradle -q distribution
We build the zip with version=1.0-SNAPSHOT
~~~
执行 `gradle -q release` 输出
~~~
> gradle -q release
We build the zip with version=1.0
We release now
~~~
[![gradle618.jpg](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ffeaad04.jpg "gradle618.jpg")](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-19_55d47ffeaad04.jpg)
`whenReady`影响了 release task 在 release task 被执行之前。同样适用于 release task 不是 主 task 的情况(比如,task 被 gradle 命令通过了)
## [](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2006.%20Build%20Script%20Basics%20%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC%E7%9A%84%E5%9F%BA%E7%A1%80%E8%AF%86.md#614-where-to-next-下一步工作)6.14\. Where to next? 下一步工作
本章,我们大概浏览了下 task ,但这不是 task 的全部,可以详见[Chapter 15\. More about Tasks 更多关于任务](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2015.%20More%20about%20Tasks%20%E6%9B%B4%E5%A4%9A%E5%85%B3%E4%BA%8E%E4%BB%BB%E5%8A%A1.md)
另外,继续教程 [Chapter 7\. Java Quickstart 快速开始 Java](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2007.%20Java%20Quickstart%20%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B%20Java.md) 和 [Chapter 8\. Dependency Management Basics 依赖管理的基础知识.md](https://github.com/waylau/Gradle-2-User-Guide/blob/master/Chapter%2008.%20Dependency%20Management%20Basics%20%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86.md)