Gradle中buildscript块的目的是什么?

310

我是Gradle的新手,正在阅读文档,但是有些部分我不理解。其中一个部分与buildscript块有关。它的目的是什么?

如果您的构建脚本需要使用外部库,您可以在构建脚本本身中将它们添加到脚本的类路径中。您可以使用buildscript()方法来实现这一点,传递一个声明构建脚本类路径的闭包。

buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'
  }
}

好的,但这与以下内容有何不同:

repositories {
  mavenCentral()
}
dependencies {
  compile group: 'commons-codec', name: 'commons-codec', version: '1.2'
}

比如,为什么需要使用buildscript呢?


2
可能是Gradle buildscript dependencies的重复问题。 - fejese
9个回答

225

buildScript块决定了在剩余的构建脚本中可用的插件、任务类和其他类。如果没有buildScript块,您可以使用Gradle默认提供的一切内容。如果您还想在构建脚本中使用第三方插件、任务类或其他类,则必须在buildScript块中指定相应的依赖项。


2
我不明白Em是什么意思。我编写了一个任务类,_group为sample.infotask',name为'infotask',version为'1.0'并使用_uploadArchives_任务将其上传到本地存储库_../lib'_。 在另一个项目中,如果我使用我的任务,我必须编写以下代码: buildscript { repositories { maven {url 'file:../lib' } } dependencies { classpath group: 'sample.infotask', name: 'infotask', version: '1.0' } } 对吗? 为什么我们必须使用_buildScript_块?当我上传本地构件时,我已经有了jar文件在我的机器上。只需要告诉Gradle从哪里获取并将其放入我的类路径中,没有其他特殊之处。 - Xelian
51
你必须使用buildScript块,因为Gradle需要这些信息才能理解剩余的构建脚本。这就是为什么你必须在一个单独的通道(即buildScript块)中提供这些信息的原因。从技术上讲,Gradle需要这些信息来编译和评估剩余的构建脚本。在幕后发生的事情是,Gradle将构建脚本分成两个脚本(即buildScript块和其他所有内容),以便可以分开处理它们。 - Peter Niederwieser
3
如果你在阅读其他答案后阅读了这个答案,你就能理解Peter想要表达的意思(并且是相当正确的)。但是第二行 -“如果没有buildScript块,您可以使用Gradle随附的一切”- 是使答案含糊不清的原因。 - Dexter
只是一个简短的笔记让我理解了整个事情。当使用“buildscript”时,你是在说 buildscript { ... } 中的任何依赖项不会被 Java/Kotlin 代码/程序(或其他你正在使用的内容)所使用。而是,它们仅用于 gradle 脚本。因此,例如,如果需要使用一些默认未提供的插件,则将其添加到 buildscript {...} 中,然后你就能够仅在 gradle 脚本中使用它。希望这有所帮助。 - cesarmax

193
  • 全局级别的 dependenciesrepositories 部分列出了构建源代码和运行源代码所需的依赖项等。
  • buildscript 用于 build.gradle 文件本身。因此,它将包含例如创建 RPM、Dockerfile 和任何其他依赖关系的依赖项,以运行所有依赖的 build.gradle 中的任务。

7
Gradle自身的所有扩展都通过buildscript->dependencies找到,这些依赖项从buildscript->repositories部分下载。buildscript块在执行构建任务(例如源代码编译等)之前首先运行(构建系统准备阶段)。 - Raja Nagendra Kumar
7
buildscript仅是您构建脚本的依赖。 - slier
5
buildscript 在 Node.js 中相当于 devDependencies,而顶层依赖则是 dependencies。 - sfy

85

我很感谢Peter的回答……但对于强调了回答和文档中的“构建脚本的其余部分”(the rest of the build script)这一术语,我一开始并没有立即理解它的含义。

通常,引入依赖功能是为了在Java程序或其他程序中使用。比如说,引入Spring框架不是用在构建脚本中,而是在Java程序中使用。将其放在buildscript闭包中可以确保这些依赖项可用于gradle构建本身,而不是输出程序。


13

通过演示Android顶层gradle文件进行更详细的解释。

buildscript {
    // this is where we are going to find the libraries defined in "dependencies block" at below
    repositories {
        google()
        jcenter()
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
    }

    // everything listed in the dependencies is actually a plugin, which we'll do "apply plugin" in our module level gradle file.
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.2' // this is android gradle plugin
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // kotlin gradle plugin
    }
}

模块级别的Gradle文件

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

"插件"是什么?它们只是实现插件接口的Java类。在该接口下,有一个名为"apply"的方法,用于添加多个具有不同名称的任务对象。任务是我们可以实现工作流程的类。例如,构建任务包括构建应用程序的流程。

那么,buildscript是做什么的?它定义了插件的位置。插件是做什么的?它包含多个任务。任务是做什么的?它为我们提供了构建、安装、lint等功能。

我的理解可能有误,请务必指正我如果您发现有不准确的地方。


9

"buildscript" 配置部分是为 gradle 本身而设的(即更改 gradle 执行构建的方式)。因此,该部分通常会包括 Android Gradle 插件。


3

这有点高级,但希望能帮到你。

对我来说,一旦我开始理解什么是构建块、方法和任务,以及语法的外观、如何配置它们等,清晰的区分就开始形成了。因此,我建议你浏览所有这些内容。之后,你就可以开始理解这个语法。

然后非常重要的是要知道build.gradle对象(Project类的实例)的类型,以便知道build.gradle文件中可以包含什么。这将回答“buildScript”和其他问题的来源。为了扩展你的能力/功能(比如Android),看看插件如何帮助。

最后但同样重要的是,在这里有一个非常好的教程,讲述了闭包、委托等概念,这些是理解脚本的关键概念。


2
“buildscript”块用于构建脚本,而不是Gradle构建输出(例如,Android应用程序apk)。在以下代码示例中,编码代码用于构建脚本,而不是Gradle构建输出程序;因此,依赖项应添加到“buildscript”块中。

https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies

构建脚本的外部依赖 建议使用自带类路径的插件来应用,而不是直接操纵脚本的类路径。对于自定义构建逻辑,建议使用自定义插件。如果您的构建脚本需要使用外部库,则可以在构建脚本中将它们添加到脚本的类路径中。您可以使用buildscript()方法来实现这一点,传入一个块来声明构建脚本类路径。
传递给buildscript()方法的块配置了ScriptHandler实例。通过向类路径配置添加依赖项来声明构建脚本类路径。这与声明Java编译类路径的方式相同。除了项目依赖项之外,您可以使用任何依赖类型。
声明了构建脚本类路径后,您可以像使用类路径上的其他类一样使用构建脚本中的类。下面的示例在前一个示例的基础上添加了内容,并使用了构建脚本类路径中的类。
import org.apache.commons.codec.binary.Base64

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'
    }
}

tasks.register('encode') {
    doLast {
        def byte[] encodedString = new Base64().encode('hello world\n'.getBytes())
        println new String(encodedString)
    }
}

1

我相信在buildscript {}中声明的所有内容都将对当前构建脚本本身以及其所有子项目可用。

对于在文件本身外部声明的属性,它不会立即对给定项目本身的buildscript可用,但对于所有子项目都是可用的。

  • 因此,如果您想要声明某些内容并立即将其用于构建脚本本身(当前的buildscript而不仅仅是子项目的buildscript),请在当前项目的buildscript {}中声明它们,并且这也会让子项目稍后使用它们。

  • 如果您只想全局声明某些内容(对于子项目的buildscript),则可以直接在父项目中声明它们为ext {}。父项目将无法将其用于自己的buildscript,但所有子项目都可以在buildscript子句内或外使用它们。

例如,在父项目中:

ext {
    kotlin_version_XX = '1.7.10' 
}

buildscript {
    ext {
      kotlin_version = '1.7.10' 
    }
    // kotlin_version will be available here since declared in buildscript{}
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 

    // will NOT be available here -- error due to kotlin_version_XX declared in project 
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version_XX" 
}

如果您有一个子项目


dependencies {
   
    // both kotlin_version and kotlin_version_XX can be used here, since it was declared in parent project
    implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version_XX"
}

buildscript {
    
    // both kotlin_version and kotlin_version_XX can even be used here for subproject's script's use, since it was already declared in parent project
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version_XX"
}

0

你可以将buildScript块想象成Gradle核心的内容,就像plugins{}块一样已经内置到Gradle中。 因此,父级build.gradlebuildScript中的所有插件都将在所有嵌套的build.gradle模块中可用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接