mcpField
K
kotlin-tooling-gradle-to-kotlin-toolchain-project

kotlin-tooling-gradle-to-kotlin-toolchain-project

github.com/kotlin開発1.1k457 回インストール7 週間前に更新
リポジトリ

kotlin-tooling-gradle-to-kotlin-toolchain-project について

この移行スキルは、GradleプロジェクトをKotlin Toolchainへ移す手順を案内し、依存関係や設定の変換、Gradleプラグインの置き換えを扱います。ソースコードの維持を重視し、調査からプラグイン対応、CI更新、全体検証までを段階的に示します。

主な機能

  1. 01Gradleプラグイン、タスク、設定の棚卸し
  2. 02共有設定をモジュールテンプレートに変換
  3. 03標準機能またはローカルプラグインで置換
  4. 04依存関係をバージョンカタログに集約
  5. 05CIのビルドとチェック手順を改訂
  6. 06移行後のプロジェクトとタスクを検証

活用シーン

  1. 01既存JVMプロジェクトの移行計画
  2. 02標準の代替機能がないGradleプラグインへの対応
  3. 03バージョンカタログと共有ビルド設定の移行
  4. 04CI更新とビルド成果物の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kotlin/kotlin-agent-skills --skill kotlin-tooling-gradle-to-kotlin-toolchain-project

インストール後、Claude Code で/kotlin-tooling-gradle-to-kotlin-toolchain-projectを入力して読み込まれたか確認します。

同梱ファイルreferences/examples.md

詳細

Gradle → Kotlin Toolchain プロジェクトの移行

依存関係と設定を機械的に変換すると同時に、Toolchain にネイティブな代替手段がない Gradle プラグインをすべて置き換えます。実際の移行事例をもとにした、適用できるテンプレートは references/examples.md にあります。

プラグインに関する個別の課題には、関連するスキルを活用してください。構文については kotlin-tooling-kotlin-toolchain、ネイティブな代替手段のない Gradle プラグインごとの移植手順については kotlin-tooling-gradle-to-kotlin-toolchain-plugin(Gradle プラグインごとに一度実行します)、一から作成するプラグインについては kotlin-tooling-kotlin-toolchain-plugin-authoring を利用してください。

原則

  1. ソースコードを維持します。 移行によってビジネスロジックの編集が必要になるなら、代わりにローカルプラグインで不足を補える可能性があります。クラスパスから release.properties を読み込むコードは、そのまま動作する必要があります。利用側を書き換えるのではなく、まったく同じファイルを公開してください。
  2. サードパーティ製の Gradle プラグインは、削除、ネイティブ対応、または再実装のいずれかです。「Gradle プラグインをそのまま使い続ける」ことはできません。 独自の規約プラグインは別です。 buildSrc / build-logic のプリコンパイル済みスクリプトは共有 設定 であるため、ローカルプラグインではなくモジュールテンプレートになります。詳しくは No buildSrc / convention plugins を参照してください。
  3. ローカルプラグインを作成する前に、GitHub で検索してください。 すでに誰かが作成している可能性があります。一から移植するより、動作する実装をベンダリングするほうが常に優れています。検索場所と検索語については、Phase 2 の「Scope」を参照してください。検索して見つからなかった場合にのみ作成してください。組み込む前に、ベンダリングするコードを最初から最後まで確認してください。ビルド時に、ファイルシステムとネットワークへの完全なアクセス権を持って実行されます。
  4. すべての依存関係をバージョンカタログに記述してください。 gradle/libs.versions.toml は組み込みの $libs.* カタログとしてそのまま使えます。すべてのモジュール/プラグイン YAML 内の各座標は、最終的に $libs.* 参照にする必要があります。[bundles] に Toolchain の同等機能はないため、モジュールテンプレートに変換します。詳しくは No version-catalog bundles を参照してください。

ワークフロー

フェーズ 1 — Gradle ビルドの棚卸し

YAML を作成する前に棚卸し内容を書き留めます(例:MIGRATION_PLAN.md)。これは PR の説明で確認するチェックリストになります。

  • plugins { } ブロック内のプラグインを、ネイティブプラグインとローカルプラグインに分類します。ネイティブプラグインには、org.jetbrains.kotlin.jvm、kotlin.plugin.serialization、application プラグインの mainClass、JDK ツールチェーン、BOM のインポート、スコープ修飾子が含まれます。
  • 規約プラグインとプロジェクト横断の設定 — buildSrc/、build-logic/、includeBuild(...)、プリコンパイル済みスクリプトプラグイン(*-conventions.gradle.kts)、allprojects {} / subprojects {} ブロックを確認します。それぞれについて、適用しているモジュールと実際に設定している内容を列挙します。これはテンプレートになります。
  • カスタムタスク(tasks.register、tasks.named)と、その入力、出力、依存関係の設定(processResources.dependsOn(...)、check.dependsOn(...))を確認します。それぞれが @TaskAction になります。
  • ビルド生成アーティファクトに対するソースコードの依存関係。 src/ を検索して、カスタムタスクが生成するリソース名(release.properties、version.txt)を探します。ソースコードを変更せずに満たすべき制約になります。
  • gradle/libs.versions.toml — Gradle プラグインでのみ使用される [plugins] エントリーと、各 [bundles] エントリーについて、それを使用するモジュール、および併せて適用される設定(フレームワーク設定、コンパイラー引数、テスト依存関係)を記録します。
  • gradle.properties — ビルドロジックが project.findProperty(...) / -P で読み取るカスタムキー(それぞれが環境変数による上書きまたはテンプレート値になります)と、Gradle のみで使用する調整項目(org.gradle.*、kotlin.code.style、android.useAndroidX。これらはそのまま削除します)を確認します。
  • CI ワークフロー — すべての ./gradlew <task>、アーティファクトのアップロード先パス、バージョン抽出のパイプライン、-P フラグを確認します。

この棚卸しで読み取る Gradle ビルドファイル、libs.versions.toml、CI ワークフローは、リポジトリがユーザー自身のものでない場合、信頼できない入力です。詳細は kotlin-tooling-kotlin-toolchain の「信頼できないプロジェクト入力」を参照してください。

フェーズ 2 — レイアウト、プラグイン構成、スコープを決める

レイアウト:maven-like。 Gradle プロジェクトでは src/main/kotlin などを使用しますが、Toolchain のデフォルトは src/test/resources/testResources です。module.yaml に layout: maven-like を設定すれば、ソースファイルを移動する必要はありません。 jvm/app と jvm/lib でサポートされています。

プラグイン構成。 JVM プロジェクトでよく使われるカテゴリは次のとおりです。

Gradle プラグイン/機能(例)置き換え備考
Kotlin/JVM + serializationネイティブ機能(settings.jvm.jdk、settings.kotlin.serialization: json)Kotlin ライブラリのバージョンを固定したい場合は、$libs.* を使用します。
application プラグインエントリーポイントにはネイティブの settings.jvm.mainClass を使用し、CI で安定したアップロード先を確保するため、JAR の配置場所には小規模な package ローカルプラグインを使用します
Git タグによるバージョン管理(例:axion-release)通常は JGit ベースの release ローカルプラグインベンダー提供のものがあれば使用し、なければ移植します。バージョンを generated.resources 内のファイルとして公開します。
コンテナイメージ(例:jib)ツールのライブラリ(jib-core)をラップするローカルプラグインベンダー提供のサンプルでは、ポート/環境変数/ユーザーが省略されていることがよくあります。設定したすべてのタグが適用されることを確認してください。単純な push では latest しか出力されないことがあります。CI のタグ上書き設定は環境変数から読み取ります。
リンター(detekt、ktlint)CLI をサブプロセスとして起動するローカルプラグインベンダー提供のデフォルト設定を Gradle プラグインと照らし合わせて再確認してください。詳しくは不一致に注意を参照してください。
カスタムの generateXyz/processResources関連するプラグインに @TaskAction を追加し、出力を generated.resources に接続します
バージョンカタログの [bundles]バンドルごとのモジュールテンプレート(<name>.module-template.yaml + apply:)フレームワークの設定とテスト依存関係もテンプレートにまとめてください。詳しくはバージョンカタログのバンドルを使わないを参照してください。
buildSrc/build-logic の規約プラグイン、allprojects {}/subprojects {}規約スクリプトごとのモジュールテンプレート。命令型の部分だけをローカルプラグインにします規約の階層は、入れ子のテンプレートに対応します。詳しくはbuildSrc/規約プラグインを使わないを参照してください。

各ローカルプラグインは jvm/amper-plugin モジュールです。

スコープ。 リストにある各プラグインについて、Kotlin を書く前に必ず GitHub を検索してください。エコシステムは小規模ですが、繰り返し使われるプラグインはすでにどこかに存在しています。検索順序は次のとおりです。

  1. JetBrains/kotlin-toolchain → build-sources/ (detekt、dokka、binary-compatibility-validator、protobuf、generate-build-properties、 project-commands)。Toolchain 自体が利用しているローカルプラグインであり、事実上のリファレンス実装です。同じリポジトリの plugin-samples/ と docs/ も確認してください。
  2. ツール名ではなく、プラグインのマーカーを使って GitHub のコード検索を行います。 "product: jvm/amper-plugin"、path:plugin.yaml "@TaskAction"、"jvm/amper-plugin" jib を検索します。
  3. ツール自体のリポジトリを確認します。多くのリンターやパッケージャーは -cli または -core アーティファクトを提供しています。薄いラッパープラグインに必要なのはそれだけなので、「プラグインがない」場合でも「50 行程度のラッパーがある」ことはよくあります。

次に、プラグインごとにベンダー提供のものを使う(見つかったものをそのままコピーし、ライセンスヘッダーを残したうえで、再同期できるようソース URL とコミットを記したコメントを追加する)、拡張する(ベンダー提供のものに Settings フィールドを追加する)、または作成する(何も見つからない場合、あるいは固有の要件がある場合)を選びます。1 つの PR であれば、既存のものはベンダー提供のものを使い、固有要件のある小規模なプラグイン(package プラグインや薄いリンターラッパーなど)を作成し、残りは後回しにするのが妥当なデフォルトです。ベンダー提供のプラグインを信頼して使う前に、必ず置き換え対象の Gradle プラグインと動作を差分比較してください。詳しくはベンダー提供のリンタープラグインは Gradle プラグインより厳格な場合があるを参照してください。

フェーズ 3 — 実装する
  1. 参考となる Toolchain プロジェクト(例:こちら)から kotlin / kotlin.bat をコピーするか、作業用ディレクトリで kotlin init を実行します。ラッパーに合わせて .sdkmanrc の kotlintoolchain=<version> を固定します。
  2. すべてのプラグインモジュールのパスを記載した project.yaml を作成します。
  3. プラグインごとに、まず GitHub を検索し(フェーズ 2 の「スコープ」を参照)、その後 plugins/<name>/ にベンダー提供するか自作します。その都度 ./kotlin show modules を実行し、モデルが引き続き読み込まれることを確認します。
  4. プロジェクトのルートにテンプレートを作成します。規約スクリプトごとに 1 つの <name>.module-template.yaml を用意し、さらに 2 つ以上の利用箇所がある [bundles] エントリーごとに、依存関係と、それらに付随する設定、テスト依存関係、リポジトリを含むテンプレートを用意します。Gradle 規約と同じネスト構造にします。
  5. ルートの module.yaml を作成します。product: jvm/app、layout: maven-like、$libs.* 依存関係、テンプレートを指定する apply: リスト、および各ローカルプラグインをデフォルト以外の設定で有効化する plugins: ブロックを記述します。
  6. 各プラグインを単独で検証します。./kotlin task :<module>:<task>@<plugin> または ./kotlin do <command> を実行します。
  7. CI を書き換えます(フェーズ 4)。
  8. build.gradle.kts、gradlew、gradlew.bat、gradle/wrapper/ を削除します。ただし、 gradle/libs.versions.toml は残します。
  9. カタログを整理します。[plugins] ブロック全体と、そこだけで使われている [versions] のキーを削除します。また、すべての利用箇所でテンプレートが適用されるようになったら [bundles] も削除します。
  10. すべての module.yaml / plugin.yaml を確認し、Maven 座標が直接記述されている箇所を $libs.<key> に置き換えます。
フェーズ 4 — CI を書き換える
  • KOTLIN_CLI_NO_WELCOME_BANNER: "1" を設定します。
  • ./gradlew build && ./gradlew check を ./kotlin build && ./kotlin check に置き換えます(これにより、すべてのプラグインの checks: 登録とテストが実行されます)。
  • ./gradlew jib -Djib.to.tags=… を ./kotlin do jib に置き換え、プラグインが読み取る環境変数を通じてタグを渡します。 ベンダー提供の Jib 形式プラグインには通常、そのためのフックがありません。ベンダー提供する際に追加してください。
  • アーティファクトのアップロード先が変わります。Gradle の build/libs/<name>.jar は使われなくなり、jarJvm は Toolchain 内部のパスに書き込みます。アーティファクトのアップロードを簡単に保つため、JAR を ${module.rootDir}/build/libs/${module.name}.jar にステージングする package プラグインを作成します。
フェーズ 5 — エンドツーエンドで検証する

ユーザー向けの各コマンドをローカルで実行し、その出力を PR のテスト計画に記録します。

./kotlin show modules            # project model loads, all expected modules listed
./kotlin clean && ./kotlin build
./kotlin test
./kotlin check                   # linters + tests; expect zero violations after Phase 3
./kotlin do currentVersion       # if applicable
./kotlin do jib                  # or jibBuildTar to avoid pushing locally (if applicable)
./kotlin do package              # verify build/libs/<name>.jar and its Main-Class manifest (if applicable)
./kotlin do ktlintFormat         # if applicable

注意すべき不一致

module.yaml では ${...} による補間は行われない

configFile: ${module.rootDir}/detekt.yml はそのまま文字列として扱われます。モジュール相対パスを使用してください(configFile: detekt.yml)。補間が機能するのは plugin.yaml のみです。

モジュール名はディレクトリ名から決まる

name: フィールドはありません。actions/checkout は GitHub リポジトリ名のディレクトリにクローンしますが、ローカルのワークツリーでは ${module.name} が別の値に解決される場合があります。プラグインタスクの出力パスにモジュール名をハードコードせず、${module.name} を使用してください。

enabled: true のないプラグイン設定は無視される
plugins:
  release: enabled         # shorthand — only valid with no other settings
  jib:                     # long form — required as soon as any setting is present
    enabled: true
    container:
      mainClass: com.example.App

enabled: true のない設定は警告(「Plugin X is not enabled, but has some explicit configuration」)のみを出力し、プラグインはスキップされます。

ベンダー提供のリンタープラグインは Gradle プラグインより厳しい場合がある

ベンダー提供プラグインが渡すフラグを Gradle プラグインのデフォルトタスクと比較し、より厳しい設定はオプトイン設定で有効化するようにして、デフォルトの動作が以前と一致するようにします。

代表例は、アップストリームの detekt プラグイン(amper/build-sources/detekt/)です。このプラグインは常に detekt-cli に --classpath を渡して型解決を有効にしますが、Gradle のデフォルトの detekt タスクでは有効になりません。そのまま使用すると、Gradle では報告されなかった違反(特に Elvis 演算子と return の組み合わせにおける UnreachableCode)が検出されます。対処方法として、プラグインの Settings に useTypeResolution: Boolean get() = false を追加し、その値に応じてフラグを切り替えます。修正例は references/examples.md を参照してください。

バージョンカタログのバンドルは使えない

解決されるのは [libraries] のキー($libs.<key>)だけです。$libs.bundles.<name> は存在せず、カタログ内の [bundles] はツールチェーンが決して読まない死んだ設定です。公式の回答(KTC-4759)は、バンドルごとに モジュールテンプレート を用意し、そのバンドルが使われていたすべての場所に適用するというものです。

# gradle/libs.versions.toml — before
[bundles]
ktor-server = ["ktor-server-core", "ktor-server-netty", "ktor-server-content-negotiation"]
# ktor-server.module-template.yaml — at the project root; templates cannot declare product:
dependencies:
  - $libs.ktor.server.core
  - $libs.ktor.server.netty
  - $libs.ktor.server.content.negotiation

settings:
  kotlin:
    serialization: json

test-dependencies:
  - $libs.ktor.server.test.host
# module.yaml
product: jvm/app

apply:
  - //ktor-server.module-template.yaml

テンプレートは単なる回避策ではなく、より良い対象です。バンドルが運ぶのは座標だけである一方、それが有効化するフレームワークは通常 settings(kotlin.serialization、springBoot、freeCompilerArgs)、test-dependencies、場合によっては repositories も必要とします。これらをすべてテンプレートに入れておけば、1 行の apply: で、むき出しのクラスパスではなく動作するフレームワークが得られます。

注意すべきルール:

  • パス表記は //<name>.module-template.yaml で、プロジェクトルート(project.yaml がある場所)からの相対パスです。
  • テンプレートに product: はありません。テンプレートは他のテンプレートを apply: できます。それぞれ 2 つの経路から到達しても 1 回だけ適用されるため、依存関係のリストは 1 回だけ現れます。
  • マージのセマンティクス: リストは追加され、スカラーは上書きされ、module.yaml はファイル内のどこに apply: があっても常に優先されます。
  • 兄弟テンプレート 2 つが同じスカラー(例: settings.jvm.release)を設定すると、ハードエラー("Conflicting values for property")になります。消費する module.yaml で値を設定するか、両方を適用する 3 つ目のテンプレートで解決してください。
  • 単一の消費者のためだけにバンドルを変換しないでください。テンプレートは 2 つ目のモジュールから元が取れます。それ未満なら $libs.* のリストをインライン化してください。
  • テンプレートはプラットフォーム修飾されたセクション(dependencies@jvm、settings@android)の和集合も表現するため、ソースセットをまたいで分割された KMP バンドルでも 1 つのテンプレートに収まります。
buildSrc / 規約プラグインは使えない — 共有設定はテンプレートに置く

buildSrc/、build-logic/、includeBuild(...) に対応するものはなく、project.yaml が持つのは modules: と plugins: だけです。ルートプロジェクトの継承はなく、命令的な共有ビルドロジックを置く場所もありません。ローカルプラグインもまた間違った対象です。プラグインが提供するのは タスク であり、モジュール設定を注入するものではありません。事前コンパイル済みスクリプトプラグインはほぼ宣言的であるため、1 つの <name>.module-template.yaml に変換され、plugins { id("<name>") } を使っていたモジュールによって適用されます。

// buildSrc/src/main/kotlin/service-conventions.gradle.kts
plugins {
    kotlin("jvm")
    kotlin("plugin.serialization")
}
kotlin { jvmToolchain(21) }
repositories { maven("https://jitpack.io") }
dependencies {
    implementation(libs.ktor.server.core)
    testImplementation(libs.kotest.runner.junit5)
}
# service-conventions.module-template.yaml
settings:
  jvm:
    jdk:
      version: 21
  kotlin:
    serialization: json

repositories:
  - id: jitpack
    url: https://jitpack.io

dependencies:
  - $libs.ktor.server.core

test-dependencies:
  - $libs.kotest.runner.junit5
規約スクリプトの構成要素テンプレート側の対応物
plugins { kotlin("jvm"), kotlin("plugin.serialization"), id("org.springframework.boot") }ネイティブの settings:(settings.kotlin.*、settings.springBoot など)
kotlin { jvmToolchain(21) }、java { targetCompatibility }settings.jvm.jdk.version、settings.jvm.release
dependencies { implementation / api / testImplementation }dependencies:(api には : exported)と test-dependencies:
repositories { }repositories:
tasks.withType<Test> { useJUnitPlatform() }組み込み / settings.junit
ある規約スクリプトが別の規約スクリプトを適用するネストされたテンプレート(テンプレート内の apply:)
ルートスクリプト内の allprojects {} / subprojects {}すべての module.yaml が適用する 1 つのテンプレート
tasks.register(…)、doLast { }、あらゆる命令的なもの残りの部分 — 振る舞いごとに 1 つのローカルプラグイン

さらに:

  • buildSrc/ は完全に削除してください。その libs カタログアクセサは、テンプレート内で直接使用する $libs.* に置き換わります。
  • 1 つの肥大化した規約スクリプトを複数の小さなテンプレート(jvm、ktor-server、testing)に分割するのが通常はより良い形であり、バンドルテンプレートも同じ階層に畳み込まれます。マージ / 競合のルールについては バージョンカタログのバンドルは使えない を参照してください。ここでもまったく同じように適用されます。
  • テンプレート内でのローカルプラグインの有効化(*.module-template.yaml 内の plugins: ブロック)は未検証です。再実装したプラグインを規約スクリプトが有効化していた場合は、テンプレート形式が読み込まれることを確認するまで(./kotlin show modules と実際のタスク実行)、各 module.yaml に plugins: ブロックを残してください。
依存関係の除外はできません

Gradle の exclude(group, module) に相当する機能はありません。推移的な依存関係の除外はすべて無視され、ライブラリがランタイムクラスパスに追加されます。トレードオフ(通常は数百 KB の未使用領域)を PR に記載してください。

プラグイン間の依存関係は設定できません

プラグインは分離されています。2 つのプラグインが論理的に関連している場合は、両方のタスクアクションを同じプラグインモジュールに配置するか、ライブラリとして切り出してください。

-P / -D による CLI オーバーライドはできません

一時的なオーバーライド(バージョンの強制、チェックのスキップ、動的なイメージタグ)は、@TaskAction 内で環境変数から読み取ってください。また、--setting フラグも使えるとは限りません(固定された CLI が拒否する場合があります)。kotlin-tooling-gradle-to-kotlin-toolchain-plugin スキルのパターンを参照してください。

コマンドの出力値を取得する

@TaskAction からの println は、機械可読な出力手段ではありません。Toolchain はこれを <ts> INFO :<module>:<task>@<plugin> <value> としてラップし、<task> successful のバナーを追加します。そのため、./kotlin do currentVersion | tail -n1 ではバナーが出力されます。また、--log-level を error/off に下げると、値の行は INFO レベルで出力されるため完全に消えてしまいます。代わりに、次の方法を使ってください。

  • タスクに環境変数で指定したファイルへ値を書き込ませ、cat で読み取ります。さらに、後続の他のタスクでもこの値を再利用できます。
  • または、コマンドが生成した Git の状態を読み取ります:git describe --tags --exact-match HEAD。
  • 標準出力を解析する必要がある場合は、タスクの識別子に一致させます:awk '/<task>@<plugin>/ { v = $NF } END { print v }'。
テストリソースが generated.resources を隠します

プラグインが release.properties を生成し、src/test/resources/release.properties が存在する場合、クラスパスの順序によりテストフィクスチャが優先されます。通常は意図どおりに動作しますが、壊れやすい方法です。テストで特定の値をアサートする場合は、優先順位に頼るのではなく、スタブサービスを注入してください。

Dependabot にはスタブの build.gradle.kts が必要です

Dependabot の Gradle ファイル取得機能は、gradle/libs.versions.toml をスキャンする前に、設定されたディレクトリ内に build.gradle(.kts) があることを要求します。ない場合、package-ecosystem: "gradle" は何もせずに終了します。理由を説明するコメントを付けた空の build.gradle.kts をルートに置いてください。Toolchain はこれを無視します。

Apple Silicon での amd64 専用コンテナイメージ

mongo:3.2 のようなイメージは、M シリーズ Mac 上で Rosetta/QEMU を使うとクラッシュします(runtime: failed to create new OS thread (have 2 already; errno=22))。これは移行による変更ではありません。同じイメージは ./gradlew check でも失敗します。既存の問題として報告してください。ubuntu-latest 上の CI には影響しません。

iOS(KMP):移行後の Info.plist から CFBundle* キーが失われます

Gradle/KMP の iOS アプリでは、バンドルのメタデータを手動管理の iosApp.xcodeproj(GENERATE_INFOPLIST_FILE = YES)に保持するため、Xcode が CFBundle* キーを生成します。そのため、チェックイン済みの Info.plist は意図的に一部のキーだけを含んでいます。Toolchain はその .xcodeproj を無視して独自のプロジェクトを生成し、指定された plist をそのまま使用します。キーを生成するものがなく、.app にバンドル ID が設定されません。

Simulator device failed to install the application. Missing bundle ID.

修正方法:plist を自己完結型にし、アプリ固有のキーとともに次のキーを保持します。

<key>CFBundleDevelopmentRegion</key><string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key><string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key><string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
<key>CFBundleName</key><string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleShortVersionString</key><string>1.0</string>
<key>CFBundleVersion</key><string>1</string>

PRODUCT_BUNDLE_IDENTIFIER は生成されたターゲットに設定されます。根本的な動作については、kotlin-tooling-kotlin-toolchain スキルの「iOS apps」セクションを参照してください。

KMP: すべてのソースセットの依存関係を引き継ぐ

各 Gradle ソースセット(commonMain、jvmMain、androidMain、iosMain、commonTest、jvmTest、 …)を Amper の対応するもの — dependencies、dependencies@jvm/@android/@ios、test-dependencies、 test-dependencies@<platform> — に変換します。明らかなライブラリ依存だけを選り好みしてはいけません。

  • *Main の依存関係は、そのターゲットのテストクラスパスにも含まれます(jvmTest は jvmMain を継承します)。 そのため、1 つ削除するとコンパイルエラーなしでテストが壊れることがあります。

  • 依存関係が別のモジュールに属しているように見えても、実際に重要な役割を担っていることがあります。典型的な例: 共有ライブラリ内の jvmMain { implementation(compose.desktop.currentOs) } はデスクトップアプリの依存関係のように 見えますが、これは Skiko ネイティブランタイム(libskiko-<os>.dylib + .sha256 を伴う skiko-awt-runtime-<os>)を提供しており、そのモジュール自身の JVM Compose UI テスト(compose.uiTest / runComposeUiTest)が実行時にこれを読み込みます。 compose.ui:ui-test は Skiko のクラスのみを取得し、ネイティブは決して取得しません。これを削除してもコンパイルは 通りますが、その後次のエラーで失敗します:

    org.jetbrains.skiko.LibraryLoadException: Cannot find libskiko-macos-arm64.dylib.sha256, proper native dependency missing.
    

    これは Toolchain のバグではありません。これがなくても Gradle は同じように失敗します。dependencies@jvm の下に 復元するか、test-dependencies@jvm にスコープを限定して、Skiko ネイティブを利用側のクラスパスに載せないようにします。

削除を防ぐためのチェック: 各 Gradle ソースセットの依存関係リストを、対応する Kotlin Toolchain セクションと 突き合わせて差分を確認し(名前と数)、次に ./kotlin show dependencies -m <module> を実行して Gradle ビルドと比較します。

よくある落とし穴

  • package プラグインがない。 その結果、CI は JAR の代わりに build/artifacts/CompiledJvmArtifact/(内部のクラスファイルツリー)をアップロードしてしまいます。アップロード パスを切り替える前に、プラグインを追加してください。
  • build/ をコミットしてしまう。 早い段階で .gitignore に追加し、古い .gradle/ のエントリは削除してください。
  • Maven コーディネート内での文字列補間。 plugin.yaml 内の com.example:foo:${pluginSettings.version} は「Value of type 'ShadowDependency' doesn't support string interpolation」 で失敗します。$libs.foo を使用してください。

Kotlin Toolchain のドキュメント: https://kotlin-toolchain.org/dev/

コメント