Gradle with Kotlin
Gradle with Kotlin DSL: 詳細技術解説
目次
- はじめに
- Gradleの基礎概念
- Kotlin DSLの紹介
- アーキテクチャ概要
- 設定の具体例
- 依存関係管理
- マルチプロジェクト構成
- パフォーマンス最適化
- ベストプラクティス
- トラブルシューティング
1. はじめに
1.1 Gradleとは
Gradle は、Apache 2 ライセンスの下で公開されているビルドオートメーションツールです。元々は Java プロジェクト向けに開発されましたが、現在では Kotlin、Groovy、C/C++、Python など多くの言語をサポートしています。
Gradle の最大の特徴は、その柔軟性と拡張性にあります。従来の XML ベースの設定ツール(Maven など)と異なり、Gradle はプログラミング言語ベースの DSL(ドメイン固有言語)を使用することで、複雑なビルドロジックを簡潔かつ理解しやすく記述できます。
1.2 Kotlin DSL が選ばれる理由
Gradle は長年、設定言語として Groovy を使用してきました。しかし、以下の理由から Kotlin DSL が推奨されるようになりました:
- 型安全性: Kotlin の静的型システムにより、ビルド設定での型チェックが可能
- IDE サポート: コード補完やリファクタリング機能が充実
- コンパイル時チェック: 構文エラーをより早い段階で検出
- 保守性: クリーンで読みやすいコード
1.3 ドキュメント構成
本ドキュメントでは、Gradle and Kotlin DSL の以下の側面を詳しく解説します:
- Gradle のコアコンセプト(タスク、プロジェクト、プラグイン)
- Kotlin DSL の文法と使用方法
- アーキテクチャとビルドライフサイクル
- 実践的な設定例
- 大規模プロジェクトでの活用方法
2. Gradleの基礎概念
2.1 プロジェクト(Project)
Gradle における最小の作業単位はプロジェクトです。各プロジェクトは build.gradle.kts ファイルに設定を持ちます。
// build.gradle.kts (プロジェクト設定ファイル)
plugins {
kotlin("jvm") version "1.9.21"
id("application")
}
group = "com.example"
version = "1.0.0"
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenCentral()
maven {
url = uri("https://repo.example.com/maven")
}
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.21")
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
}
application {
mainClass.set("com.example.AppKt")
}
各プロジェクトには以下の属性があります:
| 属性 | 説明 |
|---|---|
name | プロジェクト名 |
group | グループ識別子(パッケージ名のような役割) |
version | バージョン番号 |
description | プロジェクトの説明 |
2.2 タスク(Task)
タスクは Gradle の実行単位です。コンパイル、テスト実行、パッケージング、デプロイなど、ビルドプロセスのあらゆるステップがタスクとして定義されます。
// タスクの定義例
tasks.register("customGreeting") {
description = "Simple greeting task"
group = "custom"
doLast {
println("Hello from Gradle!")
}
}
// 複数の依存関係を持つタスク
tasks.register("deployment") {
description = "Deploy the application"
group = "deploy"
dependsOn(tasks.build, tasks.test)
doLast {
println("Deploying application...")
// デプロイロジック
}
}
// 既存タスクの拡張
tasks.test {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
}
}
2.3 プラグイン(Plugin)
プラグインは、Gradle 機能を拡張するコンポーネントです。言語サポート、テストフレームワークサポート、IDE 統合、デプロイメント機能など、様々な機能を提供します。
plugins {
// Kotlin JVM プラグイン
kotlin("jvm") version "1.9.21"
// Java プラグイン
id("java")
// テストカバレッジプラグイン
id("jacoco")
// Spring Boot プラグイン
id("org.springframework.boot") version "3.1.5"
// カスタムプラグイン
id("com.example.custom-plugin") version "1.0"
}
2.4 プロパティとメタデータ
// プロジェクトプロパティの定義
val jvmVersion: String by project
val isCI: String by project
java {
sourceCompatibility = JavaVersion.VERSION_17
}
// カスタムプロパティの定義
extra["isReleaseVersion"] = !version.toString().endsWith("SNAPSHOT")
val isRelease: Boolean by extra
// 環境変数の読み込み
val buildNumber: String = System.getenv("BUILD_NUMBER") ?: "LOCAL"
// settings.gradle.kts から渡されるプロパティ
println("Project name: ${project.name}")
println("Root project: ${rootProject.name}")
3. Kotlin DSL の紹介
3.1 Kotlin DSL の構文基礎
Kotlin DSL は Kotlin のラムダ式と拡張関数を活用した、エレガントな DSL です。
// 基本的なブロック構造
dependencies {
// ラムダの中で依存関係を定義
implementation("org.jetbrains.kotlin:kotlin-stdlib")
testImplementation("junit:junit:4.13.2")
}
// 条件付き依存関係
dependencies {
if (project.property("includeTestLibs").toString().toBoolean()) {
testImplementation("org.mockito:mockito-core:5.2.0")
testImplementation("org.assertj:assertj-core:3.24.1")
}
}
// ループを使用した動的設定
val testFrameworks = listOf("junit", "testng", "spock")
dependencies {
testFrameworks.forEach { framework ->
if (framework == "junit") {
testImplementation("junit:junit:4.13.2")
}
}
}
3.2 型安全性とコード補完
Kotlin DSL の最大の利点は IDE によるコード補完です。
// IDE が自動補完を提供
tasks.named<Test>("test") {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed") // イベント名の補完
exceptionFormat = "full" // プロパティ名の補完
showStandardStreams = true // 値の型チェック
}
}
// プラグインの設定も型安全
repositories {
mavenCentral() // 定数から選択可能
google() // カスタムリポジトリの補完
}
3.3 拡張関数とカスタム DSL
// カスタム拡張関数の定義
fun Project.isCI(): Boolean = System.getenv("CI") != null
fun RepositoryHandler.customRepos() {
mavenCentral()
maven {
url = uri("https://repo.example.com/maven")
credentials {
username = System.getenv("REPO_USER")
password = System.getenv("REPO_PASSWORD")
}
}
}
// 使用例
repositories {
customRepos()
}
// 条件付き設定
if (isCI()) {
println("Running in CI environment")
}
3.4 Groovy DSL との互換性
多くのプロジェクトは Groovy DSL (build.gradle) を使用していますが、Kotlin DSL (build.gradle.kts) への移行は段階的に行えます。
// Groovy DSL (build.gradle)
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.5'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
同等の Kotlin DSL:
// Kotlin DSL (build.gradle.kts)
plugins {
id("java")
id("org.springframework.boot") version "3.1.5"
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
4. Gradle アーキテクチャ概要
4.1 ビルドライフサイクル
Gradle のビルドプロセスは 3 つのフェーズで構成されます:
フェーズ 1: 初期化フェーズ (Initialization)
この段階で、Gradle はビルドに参加するプロジェクトを特定します。
// settings.gradle.kts
rootProject.name = "my-application"
include(
"app",
"core",
"utils",
"api"
)
// 依存関係を持つモジュールの定義
project(":api").projectDir = file("modules/api")
フェーズ 2: 設定フェーズ (Configuration)
このフェーズで、すべての build.gradle.kts ファイルが読み込まれ、タスクグラフが構築されます。
// build.gradle.kts
// この部分は設定フェーズで実行される
println("Configuring project ${project.name}")
// タスク定義も設定フェーズで評価される
tasks.register("myTask") {
println("This runs during configuration")
doLast {
println("This runs during execution")
}
}
フェーズ 3: 実行フェーズ (Execution)
要求されたタスクが実行されます。
$ gradle build test
// 出力例:
// Configuring project app
// Configuring project core
// > Task :app:build
// > Task :app:test
// > Task :core:build
// > Task :core:test
4.2 タスクグラフ
タスク間の依存関係は DAG (有向非環グラフ) として表現されます。
// 依存関係の定義
tasks.register("compile") {
description = "Compile sources"
doLast {
println("Compiling...")
}
}
tasks.register("test") {
description = "Run tests"
dependsOn(tasks.named("compile"))
doLast {
println("Testing...")
}
}
tasks.register("build") {
description = "Build project"
dependsOn(tasks.named("test"))
doLast {
println("Building...")
}
}
// 実行順序: compile -> test -> build
ビジュアライゼーション:
compile
|
v
test
|
v
build
4.3 キャッシング機構
Gradle はビルド結果をキャッシュして、パフォーマンスを向上させます。
// タスクの出力キャッシングを有効化
tasks.register<JavaCompile>("compileKotlin") {
outputs.cacheIf {
// このタスクの出力をキャッシュしない条件
!isCI()
}
}
// インクリメンタルビルドのサポート
tasks.test {
inputs.files(sourceSets.main.get().output)
outputs.dir(layout.buildDirectory.dir("test-results"))
}
4.4 Gradle Wrapper
Gradle Wrapper は、プロジェクト固有の Gradle バージョンを管理するメカニズムです。
# Wrapper スクリプトの生成
gradle wrapper --gradle-version=8.5
# プロジェクトメンバーは常に同じバージョンを使用
./gradlew build
# gradle/wrapper/gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
5. 設定の具体例
5.1 マルチプラットフォーム Kotlin プロジェクト
// build.gradle.kts
plugins {
kotlin("multiplatform") version "1.9.21"
id("maven-publish")
}
group = "com.example"
version = "1.0.0"
kotlin {
jvm {
jvmToolchain(17)
compilations.all {
kotlinOptions {
freeCompilerArgs += "-Xjsr305=strict"
}
}
}
js {
browser {
commonWebpackConfig {
cssSupport {
enabled.set(true)
}
}
}
nodejs()
}
native {
val nativeTarget = when {
System.getProperty("os.name")!! == "Mac OS X" -> macosX64("native")
System.getProperty("os.arch") == "aarch64" -> macosArm64("native")
else -> linuxX64("native")
}
nativeTarget.apply {
binaries {
executable {
entryPoint = "main"
}
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("io.ktor:ktor-client-core:2.3.0")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
val jvmMain by getting {
dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind:2.15.3")
}
}
val jvmTest by getting {
dependencies {
implementation("org.junit.jupiter:junit-jupiter:5.9.2")
}
}
val jsMain by getting {
dependencies {
implementation("io.ktor:ktor-client-js:2.3.0")
}
}
}
}
5.2 Spring Boot アプリケーション
// build.gradle.kts
plugins {
kotlin("jvm") version "1.9.21"
kotlin("plugin.spring") version "1.9.21"
id("org.springframework.boot") version "3.1.5"
id("io.spring.dependency-management") version "1.1.3"
id("org.jetbrains.kotlin.plugin.jpa") version "1.9.21"
}
group = "com.example"
version = "1.0.0"
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
}
dependencies {
// Spring Boot Starters
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-security")
// Kotlin サポート
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
// データベース
runtimeOnly("org.postgresql:postgresql")
implementation("org.flywaydb:flyway-core")
// ログ
implementation("org.springframework.boot:spring-boot-starter-logging")
// テスト
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.security:spring-security-test")
}
springBoot {
mainClass.set("com.example.ApplicationKt")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs += "-Xjsr305=strict"
jvmTarget = "17"
}
}
tasks.test {
useJUnitPlatform()
}
5.3 ライブラリプロジェクト
// build.gradle.kts
plugins {
kotlin("jvm") version "1.9.21"
`java-library`
`maven-publish`
signing
id("org.jetbrains.dokka") version "1.9.10"
}
group = "com.example"
version = "2.0.0"
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
withSourcesJar()
withJavadocJar()
}
repositories {
mavenCentral()
}
dependencies {
// API dependencies(ライブラリのユーザーに公開される)
api("org.jetbrains.kotlin:kotlin-stdlib")
api("org.apache.commons:commons-lang3:3.13.0")
// Implementation dependencies(内部でのみ使用)
implementation("org.slf4j:slf4j-api:2.0.9")
implementation("org.json:json:20231013")
// Test dependencies
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
testImplementation("org.assertj:assertj-core:3.24.1")
testImplementation("org.mockito:mockito-core:5.2.0")
}
tasks.test {
useJUnitPlatform()
}
// Dokka ドキュメント生成
tasks.dokkaHtml.configure {
dokkaSourceSets {
configureEach {
moduleName.set("My Library")
includeNonPublic.set(false)
}
}
}
// 出版設定
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
pom {
name.set("My Awesome Library")
description.set("A powerful library for...")
url.set("https://github.com/example/library")
licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/licenses/MIT")
}
}
developers {
developer {
id.set("author")
name.set("John Doe")
email.set("john@example.com")
}
}
scm {
url.set("https://github.com/example/library")
connection.set("scm:git:https://github.com/example/library.git")
developerConnection.set("scm:git:ssh://git@github.com/example/library.git")
}
}
}
}
repositories {
maven {
name = "OSSRH"
url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = System.getenv("OSSRH_USERNAME")
password = System.getenv("OSSRH_PASSWORD")
}
}
}
}
// 署名設定
signing {
sign(publishing.publications["maven"])
}
6. 依存関係管理
6.1 依存関係の構成(Configuration)
Gradle では、依存関係を異なるコンテキストに対して指定できます:
dependencies {
// コンパイル時に必要
implementation("org.jetbrains.kotlin:kotlin-stdlib")
// コンパイル時に必要だが、ユーザーに公開されない
compileOnly("org.projectlombok:lombok:1.18.30")
// テスト実行時のみ必要
testImplementation("junit:junit:4.13.2")
// テストのコンパイル時のみ必要
testCompileOnly("org.mockito:mockito-core:5.2.0")
// 実行時のみ必要
runtimeOnly("mysql:mysql-connector-java:8.0.33")
// ライブラリの API に公開される
api("com.google.guava:guava:32.1.3-jre")
// アノテーション処理
annotationProcessor("com.google.dagger:dagger-compiler:2.47")
}
6.2 バージョン管理
// gradle/libs.versions.toml
[versions]
kotlin = "1.9.21"
junit = "5.9.2"
spring-boot = "3.1.5"
[libraries]
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" }
spring-boot-web = { group = "org.springframework.boot", name = "spring-boot-starter-web", version.ref = "spring-boot" }
[bundles]
junit = ["junit-api", "junit-params", "junit-engine"]
spring-boot = ["spring-boot-web", "spring-boot-security"]
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" }
// build.gradle.kts
dependencies {
implementation(libs.kotlin.stdlib)
testImplementation(libs.bundles.junit)
implementation(libs.bundles.spring.boot)
}
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.spring.boot)
}
6.3 依存関係の制限と除外
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web") {
// 不要な依存関係を除外
exclude(group = "org.springframework.boot", module = "spring-boot-starter-logging")
}
// バージョン競合の解決
implementation("com.google.guava:guava") {
version {
strictly("32.1.3-jre")
}
}
// バージョン範囲の指定
implementation("org.slf4j:slf4j-api:[1.7,1.8)")
}
// グローバルな除外設定
configurations.all {
exclude(group = "commons-logging")
resolutionStrategy {
force("org.slf4j:slf4j-api:2.0.9")
}
}
6.4 リポジトリの管理
repositories {
// 公式 Maven リポジトリ
mavenCentral()
// Google のリポジトリ
google()
// カスタムリポジトリ
maven {
url = uri("https://repo.example.com/maven")
credentials {
username = System.getenv("REPO_USERNAME")
password = System.getenv("REPO_PASSWORD")
}
authentication {
create<BasicAuthentication>("basic")
}
}
// Maven Local(ローカルキャッシュ)
mavenLocal()
}
// リポジトリの順序は重要:最初にマッチしたものが使用される
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
7. マルチプロジェクト構成
7.1 プロジェクト構造
my-application/
├── settings.gradle.kts
├── build.gradle.kts (ルート)
├── app/
│ └── build.gradle.kts
├── core/
│ ├── build.gradle.kts
│ ├── src/main/kotlin/
│ └── src/test/kotlin/
├── api/
│ └── build.gradle.kts
└── gradle/
├── wrapper/
│ └── gradle-wrapper.properties
└── libs.versions.toml
7.2 settings.gradle.kts の設定
// settings.gradle.kts
rootProject.name = "my-application"
// サブプロジェクトの定義
include(
"app",
"core",
"api"
)
// プロジェクトディレクトリのカスタマイズ
project(":api").projectDir = file("modules/api")
// グローバル設定
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
// コンフィグレーション
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
7.3 ルート build.gradle.kts
// build.gradle.kts (ルート)
plugins {
kotlin("jvm") version "1.9.21" apply false
id("org.springframework.boot") version "3.1.5" apply false
}
group = "com.example"
version = "1.0.0"
// すべてのサブプロジェクトに共通の設定を適用
subprojects {
apply(plugin = "kotlin")
repositories {
google()
mavenCentral()
}
extensions.configure<KotlinProjectExtension> {
jvmToolchain(17)
}
}
// 特定のサブプロジェクトにのみ適用
configure(listOf(project(":app"), project(":core"))) {
apply(plugin = "org.springframework.boot")
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
}
}
// タスク
tasks.register("printProjects") {
group = "help"
description = "Print all project names"
doLast {
rootProject.allprojects.forEach { project ->
println("Project: ${project.name}")
}
}
}
7.4 サブプロジェクトの設定
// app/build.gradle.kts
plugins {
id("org.springframework.boot")
id("io.spring.dependency-management")
kotlin("plugin.spring")
}
dependencies {
// 同じマルチプロジェクト内の他のプロジェクトに依存
implementation(project(":core"))
implementation(project(":api"))
// 外部ライブラリ
implementation("org.springframework.boot:spring-boot-starter-web")
}
springBoot {
mainClass.set("com.example.app.AppKt")
}
// core/build.gradle.kts
plugins {
kotlin("jvm")
`java-library`
}
dependencies {
api("org.slf4j:slf4j-api:2.0.9")
implementation("org.jetbrains.kotlin:kotlin-stdlib")
}
8. パフォーマンス最適化
8.1 ビルドキャッシング
// build.gradle.kts
tasks.register<JavaCompile>("compileKotlin") {
// タスク出力のキャッシング
outputs.cacheIf {
// CI 環境ではキャッシュ無効
!isCI()
}
}
// インクリメンタルビルドの有効化
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
incremental = true
}
}
// ビルドキャッシュの確認
gradle.addBuildListener(object : BuildListener {
override fun buildFinished(result: BuildResult) {
println("Build cache info:")
// キャッシュ統計の出力
}
})
8.2 並列実行と最適化
# gradle.properties
# 並列実行を有効化
org.gradle.parallel=true
# ワーカーの最大数を指定
org.gradle.workers.max=8
# デーモンプロセスを有効化(ビルドの高速化)
org.gradle.daemon=true
# Java メモリ設定
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m
# 設定キャッシング
org.gradle.configuration-cache=true
8.3 タスク出力のキャッシング
// build.gradle.kts
tasks.register<Copy>("copyDistribution") {
from("src/dist")
into("build/dist")
// このタスクの出力をキャッシュ
outputs.cacheIf {
// 条件付きキャッシング
!isCI()
}
}
// カスタムタスクの作成
abstract class GenerateConfig : DefaultTask() {
@get:InputFile
abstract val config: RegularFileProperty
@get:OutputFile
abstract val output: RegularFileProperty
@TaskAction
fun generate() {
// 処理
}
}
tasks.register<GenerateConfig>("generateConfig") {
config.set(project.layout.projectDirectory.file("config.json"))
output.set(project.layout.buildDirectory.file("generated/config.properties"))
}
8.4 ビルド時間の測定
// build.gradle.kts
import java.time.Instant
class TimingListener : BuildListener {
private val startTime = Instant.now()
override fun buildFinished(result: BuildResult) {
val duration = java.time.Duration.between(startTime, Instant.now())
println("Build completed in ${duration.seconds}s")
}
}
gradle.addListener(TimingListener())
// タスク実行時間の測定
tasks.withType<Task>().configureEach {
val taskStartTime = System.currentTimeMillis()
doLast {
val duration = (System.currentTimeMillis() - taskStartTime) / 1000
println("${this.name}: ${duration}s")
}
}
9. ベストプラクティス
9.1 ビルドスクリプト設計
// build.gradle.kts
// 1. プラグインは最初に
plugins {
kotlin("jvm") version "1.9.21"
id("org.springframework.boot") version "3.1.5"
}
// 2. プロジェクトメタデータ
group = "com.example"
version = "1.0.0"
description = "Example application"
// 3. Java/Kotlin 設定
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
// 4. リポジトリ
repositories {
google()
mavenCentral()
}
// 5. 依存関係
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
}
// 6. タスク
tasks {
// タスク設定
}
9.2 DRY 原則に基づいた設定
// buildSrc/src/main/kotlin/Versions.kt
object Versions {
const val KOTLIN = "1.9.21"
const val JUNIT = "5.9.2"
const val SPRING_BOOT = "3.1.5"
}
// buildSrc/src/main/kotlin/Dependencies.kt
object Dependencies {
const val KOTLIN_STDLIB = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.KOTLIN}"
const val JUNIT_API = "org.junit.jupiter:junit-jupiter-api:${Versions.JUNIT}"
const val SPRING_WEB = "org.springframework.boot:spring-boot-starter-web:${Versions.SPRING_BOOT}"
}
// build.gradle.kts
dependencies {
implementation(Dependencies.KOTLIN_STDLIB)
testImplementation(Dependencies.JUNIT_API)
implementation(Dependencies.SPRING_WEB)
}
9.3 カスタムプラグインの作成
// buildSrc/src/main/kotlin/CustomPlugin.kt
import org.gradle.api.Plugin
import org.gradle.api.Project
class CustomPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.tasks.register("myCustomTask") {
description = "A custom task"
group = "custom"
doLast {
println("Custom task executed")
}
}
// 拡張クラスの登録
project.extensions.create("customConfig", CustomExtension::class.java)
}
}
class CustomExtension {
var property: String = "default"
}
9.4 条件付きビルド設定
// build.gradle.kts
val isRelease = project.property("release").toString().toBoolean()
val isCI = System.getenv("CI") != null
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
// 開発環境のみ
if (!isRelease) {
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12")
}
}
tasks.test {
// CI 環境では詳細ログを有効化
if (isCI) {
testLogging {
exceptionFormat = "full"
showStandardStreams = true
}
}
}
10. トラブルシューティング
10.1 一般的な問題と解決方法
問題 1: メモリ不足エラー
java.lang.OutOfMemoryError: Java heap space
解決策:
# gradle.properties
org.gradle.jvmargs=-Xmx4096m -XX:+UseG1GC
問題 2: 依存関係競合
Execution failed for task ':dependencies'.
> Could not resolve all dependencies
解決策:
// build.gradle.kts
// 依存関係の競合を確認
tasks.register("dependencyTree") {
doLast {
exec {
commandLine("gradle", "dependencies")
}
}
}
// 競合を解決
configurations.all {
resolutionStrategy {
force("org.slf4j:slf4j-api:2.0.9")
exclude(group = "commons-logging")
}
}
問題 3: ビルドキャッシュが古い
Build cache contains stale outputs
解決策:
# ビルドキャッシュをクリア
gradle cleanBuildCache
# プロジェクトの再設定
gradle clean build --refresh-dependencies
10.2 デバッグ情報の取得
# 詳細ログを有効化
gradle build --debug
# タスク依存関係を表示
gradle build --dry-run
# ビルド情報を表示
gradle build --info
# スタックトレースを表示
gradle build -s
# プロフィリング情報を取得
gradle build --profile
# タスクグラフを可視化
gradle taskTree
// build.gradle.kts でのデバッグ
// タスク実行前後のログ
gradle.taskGraph.whenReady {
allTasks.forEach { task ->
task.doFirst {
println("Executing task: ${task.name}")
}
task.doLast {
println("Completed task: ${task.name}")
}
}
}
// 依存関係の詳細表示
tasks.register("debugDependencies") {
doLast {
configurations.forEach { config ->
println("Configuration: ${config.name}")
config.dependencies.forEach { dep ->
println(" - ${dep}")
}
}
}
}
10.3 パフォーマンスプロファイリング
# ビルドプロファイルレポート生成
gradle build --profile
# ビルド時間の詳細分析
gradle build -Dorg.gradle.profiler.log=build-profile.log
// build.gradle.kts
// タスク実行時間の追跡
class PerformanceListener : BuildListener {
private val taskTimings = mutableMapOf<Task, Long>()
override fun taskStarted(task: TaskExecutionListener.TaskStartEvent) {
taskTimings[task] = System.currentTimeMillis()
}
override fun taskFinished(task: TaskExecutionListener.TaskFinishEvent) {
val startTime = taskTimings.remove(task)
if (startTime != null) {
val duration = System.currentTimeMillis() - startTime
if (duration > 1000) { // 1秒以上の遅いタスクのみ表示
println("SLOW: ${task.name} took ${duration}ms")
}
}
}
}
gradle.addListener(PerformanceListener())
まとめ
Gradle with Kotlin DSL は、モダンな Java/Kotlin プロジェクトのビルドを効率的に管理するための強力なツールです。主なポイントは以下の通りです:
- 柔軟性: タスク、プラグイン、拡張関数により、複雑なビルドロジックを簡潔に記述できる
- 型安全性: Kotlin DSL の静的型チェックとコード補完により、ビルドスクリプトの品質向上
- スケーラビリティ: マルチプロジェクト構成や依存関係管理に適した機能
- パフォーマンス: ビルドキャッシング、並列実行、インクリメンタルビルドにより高速化
- 保守性: コンベンションとベストプラクティスに従うことで、長期的に保守しやすいビルドスクリプト
Gradle with Kotlin DSL を適切に活用することで、開発チームの生産性向上と品質の維持が実現します。