LoginSignup
18
17

動機

つい1週間くらい前にはじめてbuild.gradle触ってみて「はにゃ?」てなったので、どこかのbuild.gradleを読んでざっくり理解できるようになれたらいいな、のスタンスです

Gradle

GradleはGroovyを使ってスクリプトを記述するビルドツール

入門するなら

ありがたい先人の知恵(ほんとにありがたい......)

そもそもbuild.gradleとは

  • build.gradleは、Gradleというビルドツールの設定ファイルのこと(入門したらほぼ確実に触るやつ)
  • build.gradleを使ってプロジェクトのビルド方法や依存関係などを指定できる
    • 具体的には、プロジェクトの構造や使用する外部ライブラリ、ビルド時のオプションなどの設定が可能
    • これにより、Gradleが自動的に必要なファイルや依存関係をダウンロードし、プロジェクトをビルドする際に必要なタスクが実行可能になる
    • 例えばプロジェクトがJavaで開発されている場合、build.gradleにはコンパイル対象のソースコードや依存するライブラリの指定を含むことができ、また、ビルド時に実行したいテストやデプロイなどのタスクも定義できる
  • 要するに、build.gradleはプロジェクトのビルドに関する設定を記述するファイルであり、Gradleがこれを読み込んでビルド作業を進める役割を果たしている

ビルドスクリプト内のセクションやブロックについて

基本的(だと思っている)なものを載せています

※ サンプルコードはそれぞれ独立しているし中身もちゃんとしてないので、書いても機能しません

import

正確にはセクションやブロックではないけども

build.gradle
/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.5/samples
 * This project uses @Incubating APIs which are subject to change.
 */
// 上記はgradle initコマンドで勝手に生成される

/*
 * 先頭に追加されるimport文はGradleプラグインが提供する機能によって自動的に追加される。
 * たとえばJavaプラグインを適用する場合、import文が自動的に生成されてJava関連のクラスやタスクをビルドスクリプト内で利用できるようになる、など。
 */
import org.gradle.api.tasks... // Gradleのタスク関連のクラスを使用する場合など
import org.gradle.api... // Gradleの基本的な機能やAPIを使用する場合など
import org.gradle.api.artifacts... // Gradleの依存関係管理に関連するクラスなど
import org.gradle.api.plugins... // Gradleのプラグイン関連のクラスを使用する場合など

buildscript

ビルドスクリプト自体の設定やクラスパスの管理

build.gradle
/*
 * Gradleビルドスクリプト内で「ビルドスクリプト自体」の設定や
 * 依存関係を管理するために使用されるブロック。
 * 主に、ビルドスクリプト内で使用する外部プラグインや依存関係を指定するために使用。
 */
buildscript {
    repositories {
        // 必要なリポジトリをここに指定
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.1' // Gradleプラグインの依存関係の指定
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.10' // Kotlinプラグインの依存関係の指定
    }
}

buildscriptブロックは通常、ビルドスクリプトの先頭に配置される。

  • buildscriptブロックの主な要素とその目的:
    • repositories
      • ビルドスクリプトが使用するリポジトリ(依存関係の解決に使用されるライブラリやプラグインが存在する場所)を定義する
      • Maven Central RepositoryJCenter Repository などのリポジトリを指定することが多い
    • dependencies
      • ビルドスクリプト自体が依存する外部のライブラリやプラグインを指定する
      • ビルドスクリプト自体が利用する機能やタスクに必要な依存関係を追加する

参考:

plugins

プラグインの適用や構成

build.gradle
/*
 * Gradleビルドスクリプトでプラグインを宣言し、
 * プロジェクトに適用するために使用されるブロック
 */

// Gradle 2.1以降で導入された新しい書き方
plugins {
  id 'java'
  id 'com.github.johnrengelman.shadow' version '7.1.0'
}

// 古いバージョンから使用されている書き方
apply plugin: 'application'
apply plugin: 'com.google.cloud.tools.jib' version: '3.2.0'

pluginの設定で、ビルドプロセスに追加の機能やタスクを追加することができる(めっちゃ便利)

pluginをいれるとざっくり以下のようなことができるようになる

  • 追加のタスクの実行:
    • プラグインによって提供されるタスクをビルドプロセスに追加することができる
    • これにより、目的に応じて自動化された作業を簡単に行えるようになる
  • 依存関係の管理:
    • プラグインを使用することで、依存関係の管理を楽にすることができる
    • 例えば、JavaプロジェクトにMavenプラグインを設定すればMavenリポジトリから依存するライブラリを自動的にダウンロードしてビルドに組み込める、など
  • ビルド環境のカスタマイズ:
    • プラグインを使用することで、ビルドプロセスや環境のカスタマイズができる
    • 例えば、AndroidプロジェクトにAndroidプラグインを設定すればアプリケーションのビルドタイプや署名設定、リソースの最適化などの定義もできるようになる
  • 拡張機能の利用:
    • プラグインは、Gradleの機能やタスクを拡張するためのものも存在している
    • 例えば、静的解析ツールやコード品質の改善、デプロイの自動化など、プラグインを使用して開発プロセスを向上させることができる

参考:

プラグインの設定

pluginの補足:設定例

build.gradle
// SonarQubeとJaCoCoのプラグインをビルドスクリプトに追加
plugins {
    id 'org.sonarqube' version '3.1.1' // SonarQubeプラグイン
    id 'jacoco' version '0.8.7' // JaCoCoプラグイン
}

sonarqube {
    properties {
        property 'sonar.host.url', 'https://sonarqube.example.com' // SonarQubeサーバのURL
        property 'sonar.login', 'your-sonarqube-token' // SonarQubeサーバへのアクセスに使用する認証トークン
    }
}

jacoco {
    toolVersion = '0.8.7' // JaCoCoのバージョン
    reportsDir = file("$buildDir/reports/jacoco") // JaCoCoレポートの出力ディレクトリ
}

上記のように設定を組んで、明示的にタスクを呼び出せば走ってくれる

  • 補足:CI/CDパイプライン内でよく使われてそうなpluginたち
    • Lint:コードの品質やスタイルに関する静的解析
    • SonarQube:静的解析およびバグ検出
    • Jacoco:コードのカバレッジ情報の提供
    • SpotBugs / FindBugs:バグ検出
    • Checkstyle:コードスタイルチェッカー

参考:

java

サンプルはjavaですが、他のプログラミング言語のブロックも定義可能

  • Kotlin
  • Groovy
  • Scala
  • Android

など...

build.gradle
/*
 * Javaプラグインが提供する機能を設定するために使用される
 * このブロック内で、プロジェクトのJavaソースコードに関連する設定や依存関係を定義できる
 */
java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}
  • javaブロックはプロジェクト自体に対する設定(Javaのコンパイル設定やソースセットの管理、依存関係など)を定義する
  • sourceCompatibilitytargetCompatibilityについて
    • sourceCompatibility
      • プロジェクトのソースコード(Javaファイル)が指定したバージョンのJavaと互換性があることを示す
      • コード内で使用される言語機能やAPIのバージョンに合わせて設定する
    • targetCompatibility
      • プロジェクトのターゲットとするJavaバージョンのコンパイル互換性を指定する
      • ソースコードはこのバージョンに従ってコンパイルされ、バイトコードやクラスファイルが生成される
      • 実行またはデプロイ時に、ターゲットJavaバージョンと互換性があることが保証される
  • javaブロック内にsourceSetsブロックやdependenciesブロックをまとめてしまう書き方もできる

参考:

こういうのもあるみたいね

IDE

※ サンプルとしてeclipseを定義

build.gradle
/*
 * IntelliJ IDEAやVisual Studio Codeの定義もできるみたい
 */
eclipse {
    // Java Development Tools(JDT)の設定
    jdt {
        sourceCompatibility = 1.8 // javaブロックに設定があればこっちで設定しなくてもOK
        targetCompatibility = 1.8 // javaブロックに設定があればこっちで設定しなくてもOK
        
        // ソースファイルのエンコーディングを設定する例
        encoding = 'UTF-8'

        // コンパイラオプションを設定する例
        compilerOptions = [
            'compliance': '1.8',
            'source': '1.8',
            'target': '1.8',
            'unchecked': 'true',
            'deprecation': 'true'
        ]

        // コードフォーマッタの設定を設定する例
        formatter {
            lineSplit = 100
            // その他のフォーマッタ設定...
        }
    }
    
    // Web Tools Platform(WTP)の設定
    wtp {
        component {
            contextPath = 'yourApplicationName'
        }
    }
    
    // プロジェクトにカスタムファセットを追加するための設定
    facet {
        myFacet {
            facetName = 'myFacet'
            facetVersion = '1.0'
        }
    }
    // こういう書き方もできる
    facet(name: 'myFacet2', version: '2.0')
    facet(name: 'myFacet3', version: '3.0')
    
    // ビルドパスの設定
    classpath {
        file {
            def node = it.asNode().appendNode('classpathentry', [ kind: 'src', path: 'src/main/com/example' ])
            node.appendNode('attributes').appendNode('attribute', [name: 'optional', value: 'true'])
        }
    }
}
  • eclipseブロック:
    • GradleプロジェクトをEclipse IDEで使用するための定義
  • jdtブロック:
    • Eclipseプラグインを使用して生成されるEclipseプロジェクトのJDT(Java Development Tools)の設定をカスタマイズする
    • 例えば以下のような設定が可能
      • encoding
      • compilerArgs
      • compilerOptions
      • formatter
  • wtpブロック:
    • Eclipseプラグインを使用して生成されるEclipseプロジェクトのWTP(Web Tools Platform)の設定をカスタマイズする
      • componentブロック内では、アプリケーションのコンテキストパス(WebアプリケーションがWebコンテナにデプロイされた際のアクセスURLの一部)を指定する
      • デプロイ時にアプリケーションがWebコンテナに展開される際のパス
      • 例えばサンプルの場合、WebアプリケーションへのアクセスURLは以下のようになる
        • http://localhost:8080/yourApplicationName
  • facetブロック:
    • カスタムファセットとは、Eclipseプロジェクトに追加できる特定の機能や設定のセット
      • サンプルでは、myFacetという名前のファセットを定義し、バージョンは1.0に設定されている
      • サンプルのように2通りの書き方があるみたい
  • classpathブロック:
    • ビルドパスの設定を詳細に行うために使用される
    • このブロック内でfileブロックを使用して、ビルドに必要なクラスパスの設定を行う
      • サンプルでは、src/main/com/exampleディレクトリをビルドパスに追加し、それをオプションのソースディレクトリとしてマークしている
      • これにより、src/main/com/exampleディレクトリが存在しなくてもビルドが成功するように設定される

参考:

configurations / configurations.all

依存関係のグループやスコープを管理

build.gradle
/*
 * プロジェクトの依存関係を管理するための設定を行うブロック
 * Gradleでは、ビルド時に使用する外部ライブラリやモジュールを依存関係として宣言する
 * -> この依存関係はconfigurationsと呼ばれる「グループ」に分類される
 * 例えば以下はJavaプロジェクトでよくある設定例
 */
configurations {
    compileOnly // コンパイル時にのみ必要な依存関係
    implementation // コンパイルから実行までの全体のプロセスで必要な依存関係
    testImplementation // 実行時に必要な依存関係
    runtimeOnly // コンパイル時には必要ないが、実行時にのみ必要な依存関係
}

「configurations と dependencies はどちらも依存関係を管理してるな?」と、けっこう理解に苦しんだのですが、以下のような感じです。

  • configurationsブロック:
    • プロジェクト内の依存関係を「グループに分類するため」に使用される
    • ブロック内で定義したグループは、依存関係のスコープやカテゴリに基づいて命名される
    • これにより、ビルド時に必要な依存関係を特定のスコープに紐づけることができる
  • dependenciesブロック:
    • 実際の依存関係をconfiguration(グループ)に対して「依存関係を追加する」ために使用される
    • 依存関係は、外部のライブラリやモジュールの指定、プロジェクト内の他のモジュールとの依存関係、またはオプションの条件(例:テスト実行時のみの依存関係)として指定可能

つまり、configurationsは依存関係のグループ(またはスコープ)を作成し、dependenciesはそのグループに対して実際の依存関係を指定するために使用されるという違いがある

例えば以下のサンプルのように定義されていた場合、

build.gradle
configurations {
    compileOnly
    implementation
    testImplementation
}

dependencies {
    compileOnly 'com.example:library:1.0'
    implementation 'com.example:library:2.0'
    testImplementation 'com.example:library:3.0'
}
  • configurations:設定した依存関係が適用されるビルドプロセスの「グループを定義」している
  • dependencies:指定したライブラリなどが、上記ビルドプロセスの「どこで依存関係を発生させるか」を定義している

つまりサンプルのスクリプトで説明すると、

  • com.example:library:1.0 はコンパイル時のみ依存関係が指定され、それ以外のプロセスでは指定なし
  • com.example:library:2.0 はビルドプロセス全体で依存関係が指定されている
  • com.example:library:3.0 はテストのビルドプロセス全体で依存関係が指定される

ざっくり言ってしまえば、configurationsブロックでビルドプロセスの段階をグループとして宣言しておいて、dependenciesブロックでライブラリなどを宣言したグループにあてはめることで依存関係を設定している、といった感じかなと。


ちなみに cofigurations.all は、というと

build.gradle
/*
 * build.gradle内のすべてのconfigurationsに共通の設定を適用するために使用される
 * configurationsブロック内で個別に設定を行う代わりに、
 * すべてのconfigurationsに一括で設定を適用する場合に便利
 * たとえば、以下のようにconfigurations.allブロックを使用して、
 * すべてのconfigurationsに対して依存関係解決戦略を適用することができる
 */
configurations.all {
    resolutionStrategy {
        // 依存関係の解決戦略を設定
    }
}
  • configurations.allブロック内で依存関係の解決戦略や他の設定を指定することにより、プロジェクト全体に適用されるグローバルな設定ができる
    • たとえば以下
      • 依存関係の変更通知を有効にする
      • 必要な依存関係を一括で除外する
      • 特定の依存関係をすべてのconfigurationsに適用させる
  • ただし、configurations.allを使用するとすべてのconfigurationsに対して一括で設定が適用されるため、予期しない影響が発生する場合があるので注意が必要!

repositories

ビルドプロセスで使用される外部リポジトリの設定

build.gradle
/*
 * Gradleビルドスクリプト内でプロジェクトの依存関係を解決するための
 * リポジトリなどの設定を行うために使用される
 */
repositories {
    // Maven Centralリポジトリ
    mavenCentral()

    // JCenterリポジトリ
    jcenter()

    // カスタムのMavenリポジトリ
    maven {
        url "https://example.repo.com/maven-repo"
    }
}
  • repositoriesブロックをbuildscriptブロック内に指定する場合:
    • リポジトリは、Gradle「ビルドスクリプト自体」を実行するために必要なライブラリやプラグインの解決にのみ使用される。
  • repositoriesブロックをbuildscriptブロックの外で指定する場合:
    • リポジトリは、プロジェクトの通常の依存関係の解決およびビルドスクリプトの実行に使用される。

参考:

dependencies

ビルドプロセスでプロジェクトが依存する外部ライブラリやプラグインの定義

build.gradle
/*
 * Gradleのビルドスクリプト内で依存関係の管理を行う
 * プロジェクトに必要な外部ライブラリやモジュールの依存関係を宣言できる
 */
dependencies {
    // 通常の依存関係の宣言
    implementation 'com.example:library:1.0.0' 

    // group、name、versionの各プロパティを明示的に指定することもできる
    implementation group: 'com.example', name: 'library', version: '1.0.0' 

    // APIとして公開される依存関係を宣言するとき
    api 'com.example:api:2.0.0' 

    // コンパイル時のみに依存する依存関係を宣言するとき
    compileOnly 'com.example:compileOnly:1.0.0' 

    // 実行時のみに依存する依存関係を宣言するとき
    runtimeOnly 'com.example:runtimeOnly:1.5.0' 

    // 依存ライブラリを除外するとき
    implementation ('com.example:exclude:1.0.0') {
        exclude group: 'org.unwanted', module: 'unwanted-lib'
    }
    
    // 外部リポジトリからの依存関係の追加するとき必要
    // build.gradleファイル内のどこかで既にrepositoriesブロックが定義されている場合は不要
    repositories {
        mavenCentral()
        jcenter()
    }
}

Gradleは、あなたのプロジェクトをビルドしたり実行したりするのに必要なファイルが何かを判定し、それらを見つけてこなければなりません。これらの入力ファイルを、プロジェクトの依存関係と呼びます。
(引用:Gradle公式ドキュメント > 第8章 依存関係管理の基本

参考:

推移的依存について:

sourceSets

ソースセットやリソースのディレクトリ構造を定義

build.gradle
/*
 * Gradleビルドスクリプト内でソースセットの構成を定義するために使用される。
 * デフォルトではmainとtestという2つのソースセットが提供されるが、
 * それ以外のソースセットを追加したり既存のソースセットの構成を変更したりする場合は
 * sourceSetsブロックを使用する必要がある。
 * ただしデフォルトのディレクトリ構造に従っている場合、
 * 特にカスタムのソースセットを追加しない場合は、
 * sourceSetsブロックを明示的に定義する必要はない。
 */
sourceSets {
    main {
        java.srcDirs = ['src/main/java']
        resources.srcDirs = ['src/main/resources']
    }
    test {
        java.srcDirs = ['src/test/java']
        resources.srcDirs = ['src/test/resources']
    }
    integrationTest {
        java.srcDirs = ['src/integrationTest/java'] // 統合テストコードのディレクトリを指定する
        resources.srcDirs = ['src/integrationTest/resources'] // 統合テストリソースのディレクトリを指定する
    }
}

ちなみに補足

  • ソースセット:
    • 全体的なプロジェクトのソースコードのセットを表し、通常は「main」と「test」などのサブセットを持っている
  • リソースのディレクトリ構造:
    • リソースのディレクトリ構造は、プロジェクト内の特定のリソースファイル(設定ファイル、画像、テンプレートなど)のディレクトリや構造のこと

参考:

task

ビルドスクリプト内で追加のカスタムタスクを定義

build.gradle
/*
 * タスクは、Gradleビルドスクリプト内で定義される動作の単位のこと
 * ビルドプロセスの中で実行する特定の操作や処理を定義し、
 * ビルドのカスタマイズやビルドフローの制御を行うために使用される
 */

// すでにビルドスクリプトに組み込まれているタスクはtaskキーワード不要
clean {
    delete 'build'
}

// 自分で作成する場合はtaskキーワードを使用してタスクを定義し、
// その中で具体的な動作や処理を設定することができる
task myTask {
    doLast {
        println "Custom task executed"
    }
}

// defキーワードを使用した変数の定義とタスクの組み合わせは、
// ビルドスクリプト内の他の場所でもタスクを参照するために便利
def myTask = task('myTask') {
    // タスクの設定や動作を追加する
    doLast {
        println "Hello, World!"
    }
}

// あらかじめ用意されたタスクタイプを使用してタスクの宣言もできる
task hoge(type: Jar) {
    archiveFileName = 'fuga.jar'
}

タスクについては先人がいろいろな記事を残してくれているので参考にするとマジで参考になります。

参考:

タスクの依存関係や実行順の制御

taskの補足

build.gradle
task task1 {
    // 処理
}

task task2 {
    dependsOn task1 // task2はtask1に依存しているため、task2が実行される前にtask1が先に実行される
    // 処理
}

task task3 {
    // 処理
}

task2.mustRunAfter task1 // task2はtask1の後に実行される
task3.mustRunAfter task2 // task3はtask2の後に実行される

task compileJava {
    // 処理
}

task runTests {
    // 処理
}

task build(dependsOn: [compileJava, runTests]) {
    // buildタスクは、compileJavaタスクとrunTestsタスクの両方が実行される前に実行される
}

タスク関連のメソッドはたくさんある

参考:

ext

追加(拡張)プロパティ

build.gradle
/*
 * extブロック内で定義されたプロパティやメソッドは、
 * 裏側ではExtraPropertiesExtensionオブジェクトのプロパティとして扱われる
 * グローバルスコープでビルドスクリプト全体で使用されることが想定されているらしい
 */
ext {
    group = 'com.example' // プロジェクトのグループID
    version = '1.0.0' // プロジェクトのバージョン

    libraries = [
        junit: 'junit:junit:4.13.2', // 依存ライブラリの定義
        guava: 'com.google.guava:guava:30.1-jre'
    ]

    getVersionAndDate = {
        def dateFormat = new SimpleDateFormat('yyyy-MM-dd')
        return "Version: ${version}, Build Date: ${dateFormat.format(new Date())}"
    }
}

println "Group ID: ${project.ext.group}"
println project.ext.getVersionAndDate()

extブロックについての理解は以下のような認識です。

  • build.gradleファイル内で定義される特別なブロック
  • プロジェクトの追加プロパティや変数を定義するために使用される
  • プロジェクトのビルドスクリプト内で再利用可能な設定や値を定義するのに便利
  • extブロック内で定義した変数には、後続のスクリプトでproject.extを使用してアクセスできる
  • project.extは、ビルドスクリプト内でプロジェクト全体を表すオブジェクトであり、extオブジェクトのプロパティにアクセスするためのエイリアス

参考:

その他Gradleに関する情報など

おわりに

せっかくある程度理解深まったし、オープンソースのbuild.gradle見るか~てspring-bootのbuild.gradle 見にいったらこの記事で書いてることほぼないやんけ、となって泣いた。

18
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17