本章着眼于编写构建脚本的一些细节.

The Gradle build language

Gradle provides a 特定领域的语言, or DSL, for describing builds. This build language is available in Groovy and Kotlin.

Groovy构建脚本可以包含任何Groovy语言元素. [ 1 ] Kotlin构建脚本可以包含任何Kotlin语言元素. Gradle假定每个构建脚本都是使用UTF-8编码的.

The Project API

构建脚本通过配置项目来描述您的构建. 项目是一个抽象的概念,但是通常您将Gradle项目映射到需要构建的软件组件,例如库或应用程序. 您拥有的每个构建脚本都与Project类型的对象相关联,并且在执行构建脚本时,它将配置此Project .

实际上,构建脚本中的几乎所有顶级属性和块都是Project API的一部分. 为了演示,请看以下示例构建脚本,该脚本显示其项目名称,可通过Project.name属性访问该名称:

例子1.访问Project对象的属性
build.gradle
println name
println project.name
build.gradle.kts
println(name)
println(project.name)
gradle -q check输出
> gradle -q check
projectApi
projectApi

这两个println语句都打印出相同的属性. 第一个使用对Project对象的name属性的顶级引用. 另一条语句使用任何构建脚本可用的project属性,该脚本返回关联的Project对象. 只有定义了与Project对象的成员名称相同的属性或方法,才需要使用project属性.

Standard project properties

Project对象提供了一些标准属性,这些属性在您的构建脚本中可用. 下表列出了一些常用的.

表1.项目属性
Name Type 默认值

project

Project

The Project instance

name

String

项目目录的名称.

path

String

项目的绝对路径.

description

String

项目说明.

projectDir

File

包含构建脚本的目录.

buildDir

File

projectDir/build

group

Object

unspecified

version

Object

unspecified

ant

AntBuilder

An AntBuilder instance

❗️
与其他目标脚本

此处描述的构建脚本Project对象为目标. 还有分别针对设置Gradle对象的设置脚本初始化脚本 .

The script API

当Gradle执行Groovy构建脚本( .gradle )时,它会将脚本编译为实现Script的类. 这意味着Script接口中声明的所有属性和方法在Script都可用.

当Gradle执行Kotlin构建脚本( .gradle.kts )时,它会将脚本编译为KotlinBuildScript的子类. 这意味着在脚本中可以使用KotlinBuildScript类型声明的所有可见属性和函数. 另请分别参阅KotlinSettingsScriptKotlinInitScript类型以获取设置脚本和初始化脚本.

Declaring variables

可以在构建脚本中声明两种变量:局部变量和额外属性.

Local variables

局部变量用def关键字声明. 它们仅在声明它们的范围内可见. 局部变量是基础Groovy语言的功能.

局部变量用val关键字声明. 它们仅在声明它们的范围内可见. 局部变量是基础Kotlin语言的功能.

例子2.使用局部变量
build.gradle
def dest = "dest"

task copy(type: Copy) {
    from "source"
    into dest
}
build.gradle.kts
val dest = "dest"

tasks.register<Copy>("copy") {
    from("source")
    into(dest)
}

Extra properties

Gradle的域模型中的所有增强对象都可以容纳额外的用户定义属性. 这包括但不限于项目,任务和源集.

可以通过拥有对象的ext属性添加,读取和设置其他属性. 或者,可以使用ext块一次添加多个属性.

可以通过拥有对象的Extra属性添加,读取和设置extra属性. 或者,可以通过使用by extra来通过Kotlin委托的属性来解决它们.

例子3.使用额外的属性
build.gradle
plugins {
    id 'java'
}

ext {
    springVersion = "3.1.0.RELEASE"
    emailNotification = "build@master.org"
}

sourceSets.all { ext.purpose = null }

sourceSets {
    main {
        purpose = "production"
    }
    test {
        purpose = "test"
    }
    plugin {
        purpose = "production"
    }
}

task printProperties {
    doLast {
        println springVersion
        println emailNotification
        sourceSets.matching { it.purpose == "production" }.each { println it.name }
    }
}
build.gradle.kts
plugins {
    java
}

val springVersion by extra("3.1.0.RELEASE")
val emailNotification by extra { "build@master.org" }

sourceSets.all { extra["purpose"] = null }

sourceSets {
    main {
        extra["purpose"] = "production"
    }
    test {
        extra["purpose"] = "test"
    }
    create("plugin") {
        extra["purpose"] = "production"
    }
}

tasks.register("printProperties") {
    doLast {
        println(springVersion)
        println(emailNotification)
        sourceSets.matching { it.extra["purpose"] == "production" }.forEach { println(it.name) }
    }
}
gradle -q printProperties输出
> gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin

在此示例中, ext块向project对象添加了两个额外的属性. 另外,通过将ext.purpose设置为null (将null为允许值),将名为purpose的属性添加到每个源集. 添加属性后,就可以像预定义属性一样读取和设置它们.

在此示例中,使用by extra来将两个额外的属性添加到project对象. 此外,通过将extra["purpose"]null ,可以将名为purpose的属性添加到每个源集( null是允许的值). 一旦添加了属性,就可以读取它们并将其设置为extra .

通过要求特殊语法来添加属性,当尝试设置(预定义或额外的)属性但该属性拼写错误或不存在时,Gradle可能会快速失败. 可以从可以访问其所属对象的任何位置访问其他属性,从而使它们的范围比局部变量大. 从子项目中可以看到项目的其他属性.

有关其他属性及其API的更多详细信息,请参阅API文档中的ExtraPropertiesExtension类.

Configuring arbitrary objects

您可以通过以下易读的方式配置任意对象.

例子4.配置任意对象
build.gradle
import java.text.FieldPosition

task configure {
    doLast {
        def pos = configure(new FieldPosition(10)) {
            beginIndex = 1
            endIndex = 5
        }
        println pos.beginIndex
        println pos.endIndex
    }
}
build.gradle.kts
import java.text.FieldPosition

tasks.register("configure") {
    doLast {
        val pos = FieldPosition(10).apply {
            beginIndex = 1
            endIndex = 5
        }
        println(pos.beginIndex)
        println(pos.endIndex)
    }
}
gradle -q configure输出
> gradle -q configure
1
5

Configuring arbitrary objects using an external script

您还可以使用外部脚本配置任意对象.

仅由Groovy脚本支持

Kotlin DSL尚不支持使用外部脚本配置任意对象. 有关更多信息,请参见gradle / kotlin-dsl#659 .

例子5.使用脚本配置任意对象
build.gradle
task configure {
    doLast {
        def pos = new java.text.FieldPosition(10)
        // Apply the script
        apply from: 'other.gradle', to: pos
        println pos.beginIndex
        println pos.endIndex
    }
}
other.gradle
// Set properties.
beginIndex = 1
endIndex = 5
gradle -q configure输出
> gradle -q configure
1
5

Some Groovy basics

💡
在寻找Kotlin的一些基础知识时, Kotlin参考文档Kotlin Koans应该对您有用.

Groovy语言提供了许多用于创建DSL的功能,而Gradle构建语言则利用了这些功能. 了解构建语言的工作方式将在您编写构建脚本时,特别是在开始编写自定义插件和任务时,对您有所帮助.

Groovy JDK

Groovy向标准Java类添加了许多有用的方法. 例如, Iterable获取each方法,该方法遍历Iterable的元素:

例子6. Groovy JDK方法
build.gradle
// Iterable gets an each() method
configurations.runtimeClasspath.each { File f -> println f }

有关更多详细信息, 访问https://groovy-lang.org/gdk.html .

Property accessors

Groovy自动将属性引用转换为对适当的getter或setter方法的调用.

例子7.属性访问器
build.gradle
// Using a getter method
println project.buildDir
println getProject().getBuildDir()

// Using a setter method
project.buildDir = 'target'
getProject().setBuildDir('target')

Optional parentheses on method calls

括号对于方法调用是可选的.

例子8.没有括号的方法调用
build.gradle
test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')

List and map literals

Groovy提供了一些用于定义ListMap实例的快捷方式. 两种文字都很简单,但是map文字有一些有趣的变化.

例如," apply "方法(通常在其中应用插件)实际上带有一个map参数. 但是,当您有一行诸如" apply plugin:'java' "的行时,您实际上并没有使用地图文字,而是使用了"命名参数",其语法与地图文字几乎完全相同(没有包装支架). 调用该方法时,已命名的参数列表将转换为映射,但它并非以映射开头.

例子9.列出和映射文字
build.gradle
// List literal
test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']

List<String> list = new ArrayList<String>()
list.add('org/gradle/api/**')
list.add('org/gradle/internal/**')
test.includes = list

// Map literal.
Map<String, String> map = [key1:'value1', key2: 'value2']

// Groovy will coerce named arguments
// into a single map argument
apply plugin: 'java'

Closures as the last parameter in a method

Gradle DSL在许多地方使用闭包. 您可以在此处找到有关闭包的更多信息. 当方法的最后一个参数是闭包时,可以将闭包放在方法调用之后:

例子10.闭包作为方法参数
build.gradle
repositories {
    println "in a closure"
}
repositories() { println "in a closure" }
repositories({ println "in a closure" })

Closure delegate

每个闭包都有一个delegate对象,Groovy使用该对象来查找不是闭包的局部变量或参数的变量和方法引用. Gradle将此用于配置闭包 ,其中将delegate对象设置为要配置的对象.

例子11.闭包委托
build.gradle
dependencies {
    assert delegate == project.dependencies
    testImplementation('junit:junit:4.12')
    delegate.testImplementation('junit:junit:4.12')
}

Default imports

为了使构建脚本更简洁,Gradle自动向Gradle脚本添加了一组导入语句. 这意味着,除了使用throw new org.gradle.api.tasks.StopExecutionException()您还可以键入throw new StopExecutionException() .

下面列出了添加到每个脚本的导入:

Gradle默认导入
import org.gradle.*
import org.gradle.api.*
import org.gradle.api.artifacts.*
import org.gradle.api.artifacts.component.*
import org.gradle.api.artifacts.dsl.*
import org.gradle.api.artifacts.ivy.*
import org.gradle.api.artifacts.maven.*
import org.gradle.api.artifacts.query.*
import org.gradle.api.artifacts.repositories.*
import org.gradle.api.artifacts.result.*
import org.gradle.api.artifacts.transform.*
import org.gradle.api.artifacts.type.*
import org.gradle.api.attributes.*
import org.gradle.api.attributes.java.*
import org.gradle.api.capabilities.*
import org.gradle.api.component.*
import org.gradle.api.credentials.*
import org.gradle.api.distribution.*
import org.gradle.api.distribution.plugins.*
import org.gradle.api.execution.*
import org.gradle.api.file.*
import org.gradle.api.initialization.*
import org.gradle.api.initialization.definition.*
import org.gradle.api.initialization.dsl.*
import org.gradle.api.invocation.*
import org.gradle.api.java.archives.*
import org.gradle.api.logging.*
import org.gradle.api.logging.configuration.*
import org.gradle.api.model.*
import org.gradle.api.plugins.*
import org.gradle.api.plugins.antlr.*
import org.gradle.api.plugins.quality.*
import org.gradle.api.plugins.scala.*
import org.gradle.api.provider.*
import org.gradle.api.publish.*
import org.gradle.api.publish.ivy.*
import org.gradle.api.publish.ivy.plugins.*
import org.gradle.api.publish.ivy.tasks.*
import org.gradle.api.publish.maven.*
import org.gradle.api.publish.maven.plugins.*
import org.gradle.api.publish.maven.tasks.*
import org.gradle.api.publish.plugins.*
import org.gradle.api.publish.tasks.*
import org.gradle.api.reflect.*
import org.gradle.api.reporting.*
import org.gradle.api.reporting.components.*
import org.gradle.api.reporting.dependencies.*
import org.gradle.api.reporting.dependents.*
import org.gradle.api.reporting.model.*
import org.gradle.api.reporting.plugins.*
import org.gradle.api.resources.*
import org.gradle.api.specs.*
import org.gradle.api.tasks.*
import org.gradle.api.tasks.ant.*
import org.gradle.api.tasks.application.*
import org.gradle.api.tasks.bundling.*
import org.gradle.api.tasks.compile.*
import org.gradle.api.tasks.diagnostics.*
import org.gradle.api.tasks.incremental.*
import org.gradle.api.tasks.javadoc.*
import org.gradle.api.tasks.options.*
import org.gradle.api.tasks.scala.*
import org.gradle.api.tasks.testing.*
import org.gradle.api.tasks.testing.junit.*
import org.gradle.api.tasks.testing.junitplatform.*
import org.gradle.api.tasks.testing.testng.*
import org.gradle.api.tasks.util.*
import org.gradle.api.tasks.wrapper.*
import org.gradle.authentication.*
import org.gradle.authentication.aws.*
import org.gradle.authentication.http.*
import org.gradle.buildinit.plugins.*
import org.gradle.buildinit.tasks.*
import org.gradle.caching.*
import org.gradle.caching.configuration.*
import org.gradle.caching.http.*
import org.gradle.caching.local.*
import org.gradle.concurrent.*
import org.gradle.external.javadoc.*
import org.gradle.ide.visualstudio.*
import org.gradle.ide.visualstudio.plugins.*
import org.gradle.ide.visualstudio.tasks.*
import org.gradle.ide.xcode.*
import org.gradle.ide.xcode.plugins.*
import org.gradle.ide.xcode.tasks.*
import org.gradle.ivy.*
import org.gradle.jvm.*
import org.gradle.jvm.application.scripts.*
import org.gradle.jvm.application.tasks.*
import org.gradle.jvm.platform.*
import org.gradle.jvm.plugins.*
import org.gradle.jvm.tasks.*
import org.gradle.jvm.tasks.api.*
import org.gradle.jvm.test.*
import org.gradle.jvm.toolchain.*
import org.gradle.language.*
import org.gradle.language.assembler.*
import org.gradle.language.assembler.plugins.*
import org.gradle.language.assembler.tasks.*
import org.gradle.language.base.*
import org.gradle.language.base.artifact.*
import org.gradle.language.base.compile.*
import org.gradle.language.base.plugins.*
import org.gradle.language.base.sources.*
import org.gradle.language.c.*
import org.gradle.language.c.plugins.*
import org.gradle.language.c.tasks.*
import org.gradle.language.coffeescript.*
import org.gradle.language.cpp.*
import org.gradle.language.cpp.plugins.*
import org.gradle.language.cpp.tasks.*
import org.gradle.language.java.*
import org.gradle.language.java.artifact.*
import org.gradle.language.java.plugins.*
import org.gradle.language.java.tasks.*
import org.gradle.language.javascript.*
import org.gradle.language.jvm.*
import org.gradle.language.jvm.plugins.*
import org.gradle.language.jvm.tasks.*
import org.gradle.language.nativeplatform.*
import org.gradle.language.nativeplatform.tasks.*
import org.gradle.language.objectivec.*
import org.gradle.language.objectivec.plugins.*
import org.gradle.language.objectivec.tasks.*
import org.gradle.language.objectivecpp.*
import org.gradle.language.objectivecpp.plugins.*
import org.gradle.language.objectivecpp.tasks.*
import org.gradle.language.plugins.*
import org.gradle.language.rc.*
import org.gradle.language.rc.plugins.*
import org.gradle.language.rc.tasks.*
import org.gradle.language.routes.*
import org.gradle.language.scala.*
import org.gradle.language.scala.plugins.*
import org.gradle.language.scala.tasks.*
import org.gradle.language.scala.toolchain.*
import org.gradle.language.swift.*
import org.gradle.language.swift.plugins.*
import org.gradle.language.swift.tasks.*
import org.gradle.language.twirl.*
import org.gradle.maven.*
import org.gradle.model.*
import org.gradle.nativeplatform.*
import org.gradle.nativeplatform.platform.*
import org.gradle.nativeplatform.plugins.*
import org.gradle.nativeplatform.tasks.*
import org.gradle.nativeplatform.test.*
import org.gradle.nativeplatform.test.cpp.*
import org.gradle.nativeplatform.test.cpp.plugins.*
import org.gradle.nativeplatform.test.cunit.*
import org.gradle.nativeplatform.test.cunit.plugins.*
import org.gradle.nativeplatform.test.cunit.tasks.*
import org.gradle.nativeplatform.test.googletest.*
import org.gradle.nativeplatform.test.googletest.plugins.*
import org.gradle.nativeplatform.test.plugins.*
import org.gradle.nativeplatform.test.tasks.*
import org.gradle.nativeplatform.test.xctest.*
import org.gradle.nativeplatform.test.xctest.plugins.*
import org.gradle.nativeplatform.test.xctest.tasks.*
import org.gradle.nativeplatform.toolchain.*
import org.gradle.nativeplatform.toolchain.plugins.*
import org.gradle.normalization.*
import org.gradle.platform.base.*
import org.gradle.platform.base.binary.*
import org.gradle.platform.base.component.*
import org.gradle.platform.base.plugins.*
import org.gradle.play.*
import org.gradle.play.distribution.*
import org.gradle.play.platform.*
import org.gradle.play.plugins.*
import org.gradle.play.plugins.ide.*
import org.gradle.play.tasks.*
import org.gradle.play.toolchain.*
import org.gradle.plugin.devel.*
import org.gradle.plugin.devel.plugins.*
import org.gradle.plugin.devel.tasks.*
import org.gradle.plugin.management.*
import org.gradle.plugin.use.*
import org.gradle.plugins.ear.*
import org.gradle.plugins.ear.descriptor.*
import org.gradle.plugins.ide.*
import org.gradle.plugins.ide.api.*
import org.gradle.plugins.ide.eclipse.*
import org.gradle.plugins.ide.idea.*
import org.gradle.plugins.javascript.base.*
import org.gradle.plugins.javascript.coffeescript.*
import org.gradle.plugins.javascript.envjs.*
import org.gradle.plugins.javascript.envjs.browser.*
import org.gradle.plugins.javascript.envjs.http.*
import org.gradle.plugins.javascript.envjs.http.simple.*
import org.gradle.plugins.javascript.jshint.*
import org.gradle.plugins.javascript.rhino.*
import org.gradle.plugins.signing.*
import org.gradle.plugins.signing.signatory.*
import org.gradle.plugins.signing.signatory.pgp.*
import org.gradle.plugins.signing.type.*
import org.gradle.plugins.signing.type.pgp.*
import org.gradle.process.*
import org.gradle.swiftpm.*
import org.gradle.swiftpm.plugins.*
import org.gradle.swiftpm.tasks.*
import org.gradle.testing.base.*
import org.gradle.testing.base.plugins.*
import org.gradle.testing.jacoco.plugins.*
import org.gradle.testing.jacoco.tasks.*
import org.gradle.testing.jacoco.tasks.rules.*
import org.gradle.testkit.runner.*
import org.gradle.vcs.*
import org.gradle.vcs.git.*
import org.gradle.work.*
import org.gradle.workers.*

1 . 除语句标签外的任何语言元素.