あらまし
- Kotlin版Gradle 7.1.1触った
-
src/main/java
にJavaコードとKotlinコードを混在させて双方向呼び出し - Mavenリポジトリを推移的依存性ごと全部お取り寄せするのに奮闘した挙句最終的に
mvn dependency:copy-dependencies
した - gradle.ktsでshadowJar 7.0.0を使ってfat jarを作った
- おまけで選択的同封もした
- 成果物を公開した
- GitHub Actionsの中でビルド&実行もできた
背景
通信速度がときどき激烈に遅くなる場所にあるRaspberry Pi端末上でGradleでのjavaのビルドをしようとしたら、依存jarのダウンロードだけで非常に時間がかかってしまうという問題を、知っていたけど放置していました。
それはそれとして、自分がGroovy版からKotlin版のgradleに移住して色んなプロジェクトのビルドスクリプトを最初から書き直す機会があったので、この際にオフラインビルドもできるようにしました。
重い依存jarをgitリポジトリ内に含めてしまい、最初から持たせた状態で戦地に送り出そうという作戦です。
環境
- コーディング環境
- Windows 10
- WSL
- openjdk 11.0.11
- javac 1.8.0_292
- Apache Maven 3.6.3
- IntelliJ IDEA (Android Studio 4.2.1)
- ※Androidは今回関係ないです
- WSL
- Windows 10
- 実行環境
- Raspberry Pi 4
- java 8
- Raspberry Pi 4
- ビルド環境
- Gradle 7.1.1
- Kotlin 1.4.31
手順
作業ディレクトリ
適当な場所に作業ディレクトリを作って、その中でbashを開いて作業をします。
$ mkdir hoge
$ cd hoge
以下、$
で始まるコマンドはWSL上のbashのコマンドで、$
の前はカレントディレクトリを表します。
最新のgradlewの取得
gradle download
とかでググるとたどり着けるページから、gradleの本体のビルド済みのバイナリを取得して、ついでに展開もします。
hoge$ wget https://services.gradle.org/distributions/gradle-7.1.1-bin.zip
hoge$ unzip gradle-7.1.1-bin.zip
これで、hoge/gradle-7.1.1/bin/gradle
にgradleの実行ファイルが出現しました。
プロジェクトの生成
プロジェクトのディレクトリを生成してその中に移動します。
hoge$ mkdir project1
hoge$ cd project1
gradlewの生成
gradle本体のコマンドからgradlewを生成します。
ダミービルドスクリプトの用意
gradleでwrapperコマンドを実行するにはビルドスクリプトがないといけないため、まずダミーのビルドスクリプトを書きます(【TODO】ビルドスクリプトなしで実行する方法はありそう)。
hoge/project1$ touch build.gradle.kts
gradlewの生成
hoge/project1$ ../gradle-7.1.1/bin/gradle wrapper
これにより、次のファイルおよびディレクトリが出現します。
.gradle
gradle/
gradlew
gradlew.bat
gradlewを起動してみる
hoge/project1$ bash gradlew
Downloading https://services.gradle.org/distributions/gradle-7.1.1-bin.zip
..........10%...........20%...........30%..........40%...........50%...........60%..........70%...........80%...........90%...........100%
> Task :help
Welcome to Gradle 7.1.1.
To run a build, run gradlew <task> ...
To see a list of available tasks, run gradlew tasks
To see a list of command-line options, run gradlew --help
To see more detail about a task, run gradlew help --task <task>
For troubleshooting, visit https://help.gradle.org
BUILD SUCCESSFUL in 5s
1 actionable task: 1 executed
これで、この時点で単体で正常に動作するgradlewが手に入っていることが分かりました。
単体で動作するといっても、冒頭のDownloading https://services.gradle.org/distributions/gradle-7.1.1-bin.zip
でダウンロードしたはずのファイルがhoge/project1
以下の何処にも見当たらないため、おそらく~/.gradle
か何かが何らかの影響を受けていると思います。
プロジェクトをIDEAで開く
プロジェクトディレクトリはもうIDEAで開くことができます。
オフラインでjavaのコンパイルをしてみる
ビルドスクリプトの編集
ビルドスクリプトにjavaをコンパイルするためのプラグインを追加します。
plugins {
application
}
ビルドスクリプト上ではIDEAの補完が利きます。
gradleタスクの実行
jarを作ってみます。
IDEAでは次のボタンからgradleコマンドを実行できます。
次のトグルボタンをONにすると、gradleがタスクの実行中にインターネットに接続しないようです(ただしgradlewがgradle本体をダウンロードする部分は防げない模様)。
jarタスクを実行してjarファイルを作ります。
この呼び出しはコンソール上ではおそらく次のようになります。
hoge/project1$ bash gradlew jar --offline
BUILD SUCCESSFUL in 606ms
1 actionable task: 1 executed
これにより、hoge/project1/build/libs/project1.jar
が出現しました。
ソースコードが全くないため中身はメタ情報しかありません。
Javaソースファイルを追加してみる
次のファイルを作って再びjarを生成します。
public class Main {
public static void main(String[] args) {
System.out.println("Main");
}
}
jarの中にはMainクラスが現れました。
実行もできます。
hoge/project1$ java -cp build/libs/project1.jar Main
Main
mavenの依存性を追加してみる
JUnit 4.13.2を依存性に追加してみます。
dependencies {
implementation("junit:junit:4.13.2")
}
jarの中に含める実験のために、testImplementationではなく敢えてimplementationコンフィギュレーションに追加しています(jarタスクはtestImplementationコンフィギュレーションへの依存がない)。
こうすると、次のように依存性の解決ができずビルドが失敗します。
Execution failed for task ':compileJava'.
> Could not resolve all files for configuration ':compileClasspath'.
> Cannot resolve external dependency junit:junit:4.13.2 because no repositories are defined.
Required by:
project :
Possible solution:
- Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html
これは、ビルドスクリプト上でリポジトリが定義されていないからであり、そのためオフラインモードでなくても発生します。
これを解決するにはビルドスクリプト上でmavenセントラルリポジトリを登録します。
plugins {
application
}
repositories {
mavenCentral()
}
dependencies {
implementation("junit:junit:4.13.2")
}
これをすることでオフラインでのビルドが出来なくなりました(実は何も書かなくてもデフォルトでGradle Pluginsへの依存性があるのでオフラインでのビルドはできない)。
オンライン状態では問題なくコンパイルできますが、オフライン状態ではローカル(Windowsの場合は
%HOMEPATH%\.gradle\caches\modules-2\files-2.1\
の下)にキャッシュがない限り失敗します。
目標はリポジトリの指定を次のようにプロジェクト内のローカルディレクトリにしてビルドおよび実行ができることです。
repositories {
maven("./maven")
}
maven依存関係をオフライン化するには
作戦1 依存jarをローカルディレクトリに入れて参照する
次のサイトの方法を試しました。
結果、成果物を作るためのコンパイル環境の依存性はこれで解決できましたが、のちの段階でkotlinのjavaクラスファイルへのコンパイルに使用するgradleプラグインの指定時にモジュールではなくファイル名指定でのやり方が分からず、断念しました。
plugins {
id("org.jetbrains.kotlin.jvm") version "1.4.31"
}
プラグインを指定するときはPluginDependenciesSpecScope#id(String)
関数を呼び出していますが、このときの引数はこのあとDefaultPluginId#of(String)
に持っていかれ、異常なフォーマットをしていないか確認されます。
そして、その中でプラグインIDは正規表現で表すと、[a-zA-Z0-9.\-_]
の文字しか受け付けません。
ディレクトリの区切り文字などを入れた場合、InvalidPluginIdExceptionが発生します。
つまりプラグインIDの指定段階でローカルファイルを指定することはできないようです。
次にsettings.gradle.kts
内でresolutionStrategyを使ってorg.jetbrains.kotlin.jvm
というプラグインIDに特定のローカルファイルを関連付けるということを試みました。
次のようにモジュール指定になっている記述を書き換えてファイル名指定にできればゴールです。
pluginManagement {
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
}
}
}
}
ここで、PluginResolveDetails#useModule(notation : Object)
の中を辿ってみると、このnotation
という引数はNotationParser
クラスに渡され、
ModuleVersionSelector
クラスのオブジェクトに変換されています。
そして、プラグインの管理がPluginRequest
インターフェースで行われていること、プラグインの実体の記述がModuleVersionSelector
というクラスでされていることが分かりました。
そしてなんだかんだでファイル名指定(もしくはクラス名指定)はできなそうな雰囲気を感じたので、諦めました(投げやり)。
以上により、kotlinコードをコンパイルするにはおそらくgroupとnameで表されるモジュール名を解決する仕組みの利用が必須であると結論付けました。
作戦2 org.ysb33r.ivypot
Gradleプラグインを使用してローカルにivyのミラーを作る
org.ysb33r.ivypot
を試しました。
結果、リポジトリのコピーが作られたものの、肝心のjarファイルが入っていないという問題が起こりました。
その理由は以下のもののようです。
実は当初勘違いしていて、Ivyって依存関係を".ivy"とかにDLして、そこに全部jarを保存しておいてくれるものかと思ってました。Mavenの".m2/repository/"みたいな感じで、classpathは適当にAntのbuild.xml中で自動解決してくれる~みたいな。
しかしこれは完全な勘違いで、Ivyのメインはあくまでも依存関係を「ダウンロード」することにあります。classpathの調整はやってくれないんですね。じゃあどう使うのかというと、Antプロジェクトの中に"lib"ディレクトリを作っておいて、"ivy:retrieve/"を実行することでその中にjarをダウンロードしてくれます。
これでは依存関係を先に計算しおき、jarだけ格納されたmavenリポジトリ風ディレクトリを読みに行った方が早いではないか、ということでこの作戦は諦めました。
作戦3 maven
Gradleプラグインのinstall
タスクを使用する
Mavenメタデータの生成を含め、関連するアーティファクトをローカルMavenキャッシュにインストールする。 デフォルトではinstallタスクはarchivesコンフィグレーションに関連付けられる。 このコンフィグレーションのデフォルトでは要素としてJARのみを持つ。 ローカルリポジトリへのインストールに関して詳しく学ぶためには「ローカルリポジトリへのインストール」を参照のこと。
当初、このタスクは依存先のモジュールをローカルリポジトリへ格納するものだと考えていました。
実際にはプロジェクトの成果物をローカルリポジトリへ格納するというタスクでした。
【余談】Gradle 7でmaven
Gradleプラグインが全く見つからず、「install
」タスクを含むアレがなんでこんなに見つからないの!と思ったら、丁度7で削除されていたというドラマがありました。
作戦4 mvn
コマンドのdependency:go-offline
ゴールを使う
次のサイトの手法を試しました。
これはdependency:go-offline
ゴールを使ってローカルリポジトリにすべての依存関係をダウンロードする手法です。
ビルド環境(実用上はgitホスティングサービスのCI上)でmvn
コマンドが利用できる必要があります(※下記)が、「mavenリポジトリをローカルにミラーするgradleのタスクは存在しない」と思い始めたのでこの方法を試しました。
【※】gradleのビルドスクリプトの依存関係にmavenを追加して直接呼び出すという方法がありそうですが、やってみたところヤケクソに長いエラーが出て諦めました。
まずmvn
コマンドを利用できるようにします。
$ sudo apt update
$ sudo apt install maven
pom.xml
をいい感じに編集したあとで、次のコマンドでローカルリポジトリの場所を指定してgo-offline
を実行します。
hoge/project1$ mvn dependency:go-offline -Dmaven.repo.local=maven
その結果、ちゃんと目的のファイルはありましたが、やたら色んなものがダウンロードされていました。
本当に必要なjunit-4.13.2.jar
のサイズは375KBですが、このmavenディレクトリのサイズは100MB以上ありました。
ログを見たところ、mavenプラグインの
依存先もすべてダウンロードされていました。
【物凄い上のmavenプラグインの列】
[INFO] Resolved plugin: doxia-core-1.9.1.jar
[INFO] Resolved plugin: plexus-utils-1.5.10.jar
[INFO] Resolved plugin: jtidy-4aug2000r7-dev.jar
[INFO] Resolved plugin: maven-artifact-2.0.9.jar
[INFO] Resolved plugin: plexus-io-2.0.2.jar
[INFO] Resolved plugin: maven-artifact-manager-2.0.6.jar
[INFO] Resolved dependency: junit-4.13.2.jar
[INFO] Resolved dependency: hamcrest-core-1.3.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.090 s
[INFO] Finished at: 2021-07-09T15:53:41+09:00
[INFO] ------------------------------------------------------------------------
どうにかして
mavenプラグインに起因する依存関係を含めずにダウンロードできればよいみたいです。
そこでソースを調べたところ、このゴールは実行時にプラグインのダウンロードを行わないという選択肢は持っていないことが分かりました。
「mavenモジュールを依存関係ごとローカルにコピーすること」を目的としたゴールがあれば解決できそうです。
作戦5 mvn
コマンドのdependency:copy-dependencies
ゴールを使う
次に試したのは次のサイトの手法です。
結果、mavenリポジトリではなくjarのみがダウンロードされました。
また、mvn
コマンドはどのゴールを実行しても初回起動時にすべてのmavenプラグインに起因する依存jarをローカルリポジトリにダウンロードするようなので、ローカルリポジトリにダウンロードさせてそれをいただくという手法は無理っぽいです。
作戦6 dependency:copy
ゴールのlocalRepositoryDirectory
オプションを使う
Apache Maven Dependency Pluginの中を漁りました。
そして、copy
ゴールには<localRepositoryDirectory>
というオプションがあり、
Path to override default local repository during plugin's execution. To remove all downloaded artifacts as part of the build, set this value to a location under your project's target directory
とありました(ちなみにcopy-dependencies
側にはこのオプションは存在しませんでした)。
よくわからないけど、このオプションを付与するとローカルリポジトリが2個になるっぽいです。そして、新たに指定した方のローカルリポジトリにはこのタスクの生成物しか格納されないような気がします。
<localRepositoryDirectory>
オプションに対するもう一つ見つけた説明文です。
dependency:copy always downloads artifacts to default local repository first, and then copy the artifacts to the desired locations. For large size unique snapshot artifacts, the downloads can quickly fill up default local repository, and therefore local disk, after many executions. To clean up the downloaded artifacts as part the build, set localRepositoryDirectory's value to a location in your project's target directory.
このオプションの本来の用途は、大きな単一jarでローカルリポジトリを圧迫しないためにゴミ箱を別途指定することのようです。つまりmavenリポジトリの依存ツリーが丸ごと出力される場所ではないようです。
このオプションが使われているゴールが他にないか調べたところ、このオプションはAbstractFromConfigurationMojo#localRepositoryDirectory
フィールドに由来し、そのサブクラスはcopy
タスクとunpack
タスクの丁度2個のみでした。後者は出力先ディレクトリにjarそのものではなくjarの内容物をドバッと出します。
まとめると、
-
mvn
コマンドの -
dependency:copy
ゴールを -
outputDirectory
オプションにダミーの値を指定したうえで -
localRepositoryDirectory
にリポジトリ格納先ディレクトリを指定して -
artifact
で依存アーティファクトを指定して
起動すると、初回実行時にホームディレクトリ下のローカルリポジトリに大量の余計なjarをダウンロードしつつ、別途指定した固有ローカルリポジトリに指定されたアーティファクトのmavenリポジトリをキャッシュしながら、出力先にそのjarを配置します。
それを行うには、カレントディレクトリに次のpomファイルを配置したうえで、次のコマンドを打ちます。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>null</groupId>
<artifactId>null</artifactId>
<version>0.0.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<localRepositoryDirectory>./maven</localRepositoryDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
hoge/project1$ mvn dependency:copy -DoutputDirectory=build/maven-dependency-copy -Dartifact=junit:junit:4.13.2
その結果、無事タスクは完了しました。
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------< null:null >------------------------------
[INFO] Building null 0.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:3.2.0:copy (default-cli) @ null ---
[INFO] Configured Artifact: junit:junit:4.13.2:jar
Downloading from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.pom
Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.pom (27 kB at 35 kB/s)
Downloading from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar
Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar (385 kB at 704 kB/s)
[INFO] Copying junit-4.13.2.jar to /mnt/i/workspace/hoge/project1/build/maven-dependency-copy/junit-4.13.2.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.600 s
[INFO] Finished at: 2021-07-10T07:50:15+09:00
[INFO] ------------------------------------------------------------------------
しかしながら、指定したローカルリポジトリの中にはjunitの依存先であるorg.hamcrest:hamcrest-core:1.3
が存在しません。
依存性を推移的に解決しているなら同じ場所にダウンロードされているはずです。
compileClasspath - Compile classpath for source set 'main'.
\--- junit:junit:4.13.2
\--- org.hamcrest:hamcrest-core:1.3
この挙動は、-Dmaven.repo.local=maven2
オプションにより空のローカルリポジトリの下で実行しても変わりませんでした。
また、junitではなくorg.jetbrains.kotlin:kotlin-stdlib:1.4.31
で試しても推移的に依存性を解決しないようでした。
testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- junit:junit:4.13.2
| \--- org.hamcrest:hamcrest-core:1.3
\--- org.jetbrains.kotlin:kotlin-stdlib:1.4.31
+--- org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31
\--- org.jetbrains:annotations:13.0
作戦7 dependency:copy-dependencies
ゴールのuseRepositoryLayout
オプションを使う
copy
ゴールが依存関係を推移的に解決しないとしても、copy-dependencies
ゴールの方は少なくとも推移的に解決はしてくれるだろう(実際説明文にもtransitiveって書いてあるし)と思いました。
takes the list of project direct dependencies and optionally transitive dependencies and copies them to a specified location, stripping the version if desired. This goal can also be run from the command line.
このタスクの問題は出力がjarファイルしかないところなので、mavenリポジトリをそのまま出力するオプションがないかと調べたところ、<useRepositoryLayout>
(mdep.useRepositoryLayout
)がまさにそんな感じでした。
Place each artifact in the same directory layout as a default repository.
このオプションはAbstractFromDependenciesMojo#useRepositoryLayout
フィールドに由来するらしく、copy-dependencies
ゴールの他にunpack-dependencies
ゴールでも使えるようでした(逆に言うとcopy
get
などでは利用不可(別のフィールド実体に由来する同名のオプションも見当たらず))。
また、copyPom
およびaddParentPoms
オプションを付けなければgradleの段階で例外が発生したため、これも付与します。
これらのオプションは、pom.xml
上でプラグインの使用を明示しなければ無視されるようです。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>
このタスクはgroupId
のような個別のアーティファクトを特定するオプションを持たないため、多分pom上に定義された依存関係しか見に行かないんじゃないかと思うので、pom.xml
に依存関係を追加します。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>null</groupId>
<artifactId>null</artifactId>
<version>0.0.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>
</project>
そして次のコマンドで実行します。
hoge/project1$ mvn dependency:copy-dependencies -DoutputDirectory=maven -Dmdep.useRepositoryLayout=true -Dmdep.copyPom=true -Dmdep.addParentPoms=true
結果、無事推移的に依存するすべてのリポジトリがその構造のままjarとpomがダウンロードされました。
なお、maven-dependency-plugin
のバージョンは3.0.0以上では「親のpomがMaven Central Repositoryに存在しないような依存性を(推移的に)含むアーティファクト(具体的にはorg.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.4.31
など)」をaddParentPoms
を付けて指定するとなぜか解決失敗するということがのちに分かりました。
バージョン2.10では正常に解決できました。理由は謎です(AbstractDependencyFilterMojo#getDependencySets
内で依存先の親を解決する部分で落ちているようですが、なぜか追加リポジトリが無視されているようでした【TODO】)。
org.apache.maven.plugins:maven-dependency-plugin:3.0.0:copy-dependencies (default-cli) on project null: Error resolving project artifact: Failure to find org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:pom:1.4.31 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced for project org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:pom:1.4.31
プロジェクト下のリポジトリを指定してjavaコンパイル
前節で作戦7によってhoge/project1/maven
ディレクトリがmavenリポジトリになっているので、それをそのまま指定してビルドします。
作戦1~6は全部ボツです。
ビルドスクリプト側でプロジェクト内のリポジトリを見るように変更
plugins {
application
}
repositories {
maven("./maven")
}
dependencies {
implementation("junit:junit:4.13.2")
}
javaコード上で依存jarのクラスを呼び出してみる
正常にクラスがロードできていなければ例外になるようなコードを書いてみます。
import org.junit.Test;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) {
System.out.println("Main");
for (Method method : Test.class.getMethods()) {
System.out.println(method);
}
}
}
この時点で既にIDEA上でgradleプロジェクトのsyncをするとコードの補完ができるようになっていました。
キャッシュ削除
ここで、一旦IDEAのGradleのオフラインモードをONにし、IDEAを終了し、他に起動しているEclipseなどのjavaコンパイラもすべて閉じて、次のキャッシュディレクトリを削除しておきます。
%HOMEPATH%\.gradle
%HOMEPATH%\.m2
hoge/project1/.gradle
hoge/project1/build
念のためIDEAのここにあるこれも行いました。
ビルド・実行
この状態でIDEAからgradle jar
を実行すると、無事jarファイルが生成されました。
9:13:40: タスクを実行中 'jar'...
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :jar
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
9:13:42: タスクの実行を完了しました 'jar'。
出力されたjarを依存先とともに呼び出してみると、ちゃんと依存先のjarに依存した動作を成功させました。
hoge/project1$ java -cp build/libs/project1.jar:maven/junit/junit/4.13.2/junit-4.13.2.jar Main
Main
public abstract java.lang.Class org.junit.Test.expected()
public abstract long org.junit.Test.timeout()
public abstract boolean java.lang.annotation.Annotation.equals(java.lang.Object)
public abstract java.lang.String java.lang.annotation.Annotation.toString()
public abstract int java.lang.annotation.Annotation.hashCode()
public abstract java.lang.Class java.lang.annotation.Annotation.annotationType()
kotlinをjvmコードにコンパイルする
ビルドスクリプトの改変
gradleにkotlinプラグインを追加して、ソースコードの依存性にkotlinのライブラリを追加します。
plugins {
application
kotlin("jvm") version "1.4.31"
}
repositories {
maven("./maven")
}
dependencies {
implementation("junit:junit:4.13.2")
implementation(kotlin("stdlib-jdk8", "1.4.31"))
}
gradle.ktsを使う場合、kotlinプラグインのバージョンはgradle.ktsのランタイムのkotlinバージョンに合わせなければバージョン衝突になるようです。Gradle 7.1.1ではKotlin 1.4.31が指定のバージョンでした。
プラグインの依存性解決の失敗
オフラインかつプロジェクト内のリポジトリにもkotlinのプラグインの依存性を追加していないため、当然次のような問題が起こります。
* What went wrong:
Plugin [id: 'org.jetbrains.kotlin.jvm', version: '1.4.31'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.4.31')
Searched in the following repositories:
Gradle Central Plugin Repository
org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.4.31
を依存性に追加すればいいということが分かりました。
org.jetbrains.kotlin.jvm.gradle.plugin
はGradle Pluginsリポジトリにある
当初pomに単に依存アーティファクトを追加しましたが、解決に失敗しました。
Maven Central Repositoryには無いようです。
オンライン状態で実行するとちゃんとプラグインが使えたため、デフォルトで追加されるGradle Core Pluginsというリポジトリの方にあるということになります。
このページを見ると、そのURLはhttps://plugins.gradle.org/m2/
のようです。
中身を確認してみると、このアーティファクトはpomのみでjarがないようです。そのため、pom.xml
内ではこの依存性の<type>
をpom
にしておきます。
依存性の<type>
と依存先成果物の<packaging>
には次のような対応があるようです。
ちなみにkotlin("stdlib-jdk8", "1.4.31")
はorg.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31
というアーティファクトを表します。
settings.gradle.kts
の記述
プラグインの依存関係は(おそらくビルドスクリプトよりも先にコンパイルおよび実行されるために)特別な場所に記述しなければなりません。
pluginManagement {
repositories {
maven("./maven")
}
}
pom.xml
の編集・リポジトリダウンロード
アーティファクト名とリポジトリが分かったのでpom.xml
を更新します。ついでにオプションもここに書いてしまいます。
依存性の記述時には<type>
に気を付けてください。コピペすると地味に<type>pom</type>
がくっついてきたりします。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>null</groupId>
<artifactId>null</artifactId>
<version>0.0.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<configuration>
<outputDirectory>maven</outputDirectory>
<useRepositoryLayout>true</useRepositoryLayout>
<copyPom>true</copyPom>
<addParentPoms>true</addParentPoms>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>plugins.gradle.org</id>
<name>plugins.gradle.org</name>
<url>https://plugins.gradle.org/m2/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin.jvm</groupId>
<artifactId>org.jetbrains.kotlin.jvm.gradle.plugin</artifactId>
<version>1.4.31</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>1.4.31</version>
</dependency>
</dependencies>
</project>
これで次のコマンドによりkotlinのGradleプラグインをダウンロードします。
hoge/project1$ mvn dependency:copy-dependencies
結果、めっちゃ大量の依存性が解決できました。
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------< null:null >------------------------------
[INFO] Building null 0.0.0
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.31/kotlin-stdlib-jdk8-1.4.31.pom
Downloaded from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.31/kotlin-stdlib-jdk8-1.4.31.pom (1.6 kB at 876 B/s)
Downloading from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.pom
Downloaded from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.pom (1.4 kB at 875 B/s)
Downloading from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.jar
Downloaded from plugins.gradle.org: https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.jar (23 kB at 14 kB/s)
[INFO]
[INFO] --- maven-dependency-plugin:2.10:copy-dependencies (default-cli) @ null ---
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.4.31/kotlin-stdlib-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib/1.4.31/kotlin-stdlib-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.4.31/kotlin-stdlib-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib/1.4.31/kotlin-stdlib-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.31/kotlin-stdlib-jdk8-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.31/kotlin-stdlib-jdk8-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/antlr/antlr4-master/4.5.2-1/antlr4-master-4.5.2-1.pom to /mnt/i/workspace/hoge/project1/maven/org/antlr/antlr4-master/4.5.2-1/antlr4-master-4.5.2-1.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-runner/1.4.31/kotlin-compiler-runner-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-compiler-runner/1.4.31/kotlin-compiler-runner-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-runner/1.4.31/kotlin-compiler-runner-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-compiler-runner/1.4.31/kotlin-compiler-runner-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin-model/1.4.31/kotlin-gradle-plugin-model-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin-model/1.4.31/kotlin-gradle-plugin-model-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin-model/1.4.31/kotlin-gradle-plugin-model-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin-model/1.4.31/kotlin-gradle-plugin-model-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.jar to /mnt/i/workspace/hoge/project1/maven/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.jar
[INFO] Installing /home/riana/.m2/repository/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.pom to /mnt/i/workspace/hoge/project1/maven/org/antlr/antlr4-runtime/4.5.2-1/antlr4-runtime-4.5.2-1.pom
[INFO] Installing /home/riana/.m2/repository/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar to /mnt/i/workspace/hoge/project1/maven/com/google/code/gson/gson/2.8.6/gson-2.8.6.jar
[INFO] Installing /home/riana/.m2/repository/com/google/code/gson/gson/2.8.6/gson-2.8.6.pom to /mnt/i/workspace/hoge/project1/maven/com/google/code/gson/gson/2.8.6/gson-2.8.6.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-compiler-embeddable/1.4.31/kotlin-scripting-compiler-embeddable-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-compiler-embeddable/1.4.31/kotlin-scripting-compiler-embeddable-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-compiler-embeddable/1.4.31/kotlin-scripting-compiler-embeddable-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-compiler-embeddable/1.4.31/kotlin-scripting-compiler-embeddable-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-jvm/1.4.31/kotlin-scripting-jvm-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-jvm/1.4.31/kotlin-scripting-jvm-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-jvm/1.4.31/kotlin-scripting-jvm-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-jvm/1.4.31/kotlin-scripting-jvm-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-android-extensions/1.4.31/kotlin-android-extensions-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-android-extensions/1.4.31/kotlin-android-extensions-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-android-extensions/1.4.31/kotlin-android-extensions-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-android-extensions/1.4.31/kotlin-android-extensions-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4.jar to /mnt/i/workspace/hoge/project1/maven/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4.jar
[INFO] Installing /home/riana/.m2/repository/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4.pom to /mnt/i/workspace/hoge/project1/maven/com/github/gundy/semver4j/0.16.4/semver4j-0.16.4.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.4.31/kotlin-compiler-embeddable-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.4.31/kotlin-compiler-embeddable-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.4.31/kotlin-compiler-embeddable-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-compiler-embeddable/1.4.31/kotlin-compiler-embeddable-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin-api/1.4.31/kotlin-gradle-plugin-api-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin-api/1.4.31/kotlin-gradle-plugin-api-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin-api/1.4.31/kotlin-gradle-plugin-api-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin-api/1.4.31/kotlin-gradle-plugin-api-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-util-io/1.4.31/kotlin-util-io-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-util-io/1.4.31/kotlin-util-io-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-util-io/1.4.31/kotlin-util-io-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-util-io/1.4.31/kotlin-util-io-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-util-klib/1.4.31/kotlin-util-klib-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-util-klib/1.4.31/kotlin-util-klib-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-util-klib/1.4.31/kotlin-util-klib-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-util-klib/1.4.31/kotlin-util-klib-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin/1.4.31/kotlin-gradle-plugin-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin/1.4.31/kotlin-gradle-plugin-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-gradle-plugin/1.4.31/kotlin-gradle-plugin-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-gradle-plugin/1.4.31/kotlin-gradle-plugin-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-common/1.4.31/kotlin-scripting-common-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-common/1.4.31/kotlin-scripting-common-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-common/1.4.31/kotlin-scripting-common-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-common/1.4.31/kotlin-scripting-common-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-common/1.4.31/kotlin-stdlib-common-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/junit/junit/4.13.2/junit-4.13.2.jar to /mnt/i/workspace/hoge/project1/maven/junit/junit/4.13.2/junit-4.13.2.jar
[INFO] Installing /home/riana/.m2/repository/junit/junit/4.13.2/junit-4.13.2.pom to /mnt/i/workspace/hoge/project1/maven/junit/junit/4.13.2/junit-4.13.2.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-script-runtime/1.4.31/kotlin-script-runtime-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-script-runtime/1.4.31/kotlin-script-runtime-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-script-runtime/1.4.31/kotlin-script-runtime-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-script-runtime/1.4.31/kotlin-script-runtime-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar to /mnt/i/workspace/hoge/project1/maven/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
[INFO] Installing /home/riana/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom to /mnt/i/workspace/hoge/project1/maven/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/jvm/org.jetbrains.kotlin.jvm.gradle.plugin/1.4.31/org.jetbrains.kotlin.jvm.gradle.plugin-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/jvm/org.jetbrains.kotlin.jvm.gradle.plugin/1.4.31/org.jetbrains.kotlin.jvm.gradle.plugin-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-build-common/1.4.31/kotlin-build-common-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-build-common/1.4.31/kotlin-build-common-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-build-common/1.4.31/kotlin-build-common-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-build-common/1.4.31/kotlin-build-common-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/com/google/code/gson/gson-parent/2.8.6/gson-parent-2.8.6.pom to /mnt/i/workspace/hoge/project1/maven/com/google/code/gson/gson-parent/2.8.6/gson-parent-2.8.6.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-annotation-processing-gradle/1.4.31/kotlin-annotation-processing-gradle-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-annotation-processing-gradle/1.4.31/kotlin-annotation-processing-gradle-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-annotation-processing-gradle/1.4.31/kotlin-annotation-processing-gradle-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-annotation-processing-gradle/1.4.31/kotlin-annotation-processing-gradle-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.4.31/kotlin-stdlib-jdk7-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/sonatype/oss/oss-parent/7/oss-parent-7.pom to /mnt/i/workspace/hoge/project1/maven/org/sonatype/oss/oss-parent/7/oss-parent-7.pom
[INFO] Installing /home/riana/.m2/repository/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.jar to /mnt/i/workspace/hoge/project1/maven/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.jar
[INFO] Installing /home/riana/.m2/repository/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.pom to /mnt/i/workspace/hoge/project1/maven/de/undercouch/gradle-download-task/4.0.2/gradle-download-task-4.0.2.pom
[INFO] Installing /home/riana/.m2/repository/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom to /mnt/i/workspace/hoge/project1/maven/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-daemon-embeddable/1.4.31/kotlin-daemon-embeddable-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-daemon-embeddable/1.4.31/kotlin-daemon-embeddable-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-daemon-embeddable/1.4.31/kotlin-daemon-embeddable-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-daemon-embeddable/1.4.31/kotlin-daemon-embeddable-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-reflect/1.4.31/kotlin-reflect-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-reflect/1.4.31/kotlin-reflect-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-reflect/1.4.31/kotlin-reflect-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-reflect/1.4.31/kotlin-reflect-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-compiler-impl-embeddable/1.4.31/kotlin-scripting-compiler-impl-embeddable-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-compiler-impl-embeddable/1.4.31/kotlin-scripting-compiler-impl-embeddable-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-scripting-compiler-impl-embeddable/1.4.31/kotlin-scripting-compiler-impl-embeddable-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-scripting-compiler-impl-embeddable/1.4.31/kotlin-scripting-compiler-impl-embeddable-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/intellij/deps/trove4j/1.0.20181211/trove4j-1.0.20181211.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.3.8/kotlinx-coroutines-core-1.3.8.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.3.8/kotlinx-coroutines-core-1.3.8.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.3.8/kotlinx-coroutines-core-1.3.8.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlinx/kotlinx-coroutines-core/1.3.8/kotlinx-coroutines-core-1.3.8.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-daemon-client/1.4.31/kotlin-daemon-client-1.4.31.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-daemon-client/1.4.31/kotlin-daemon-client-1.4.31.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/kotlin/kotlin-daemon-client/1.4.31/kotlin-daemon-client-1.4.31.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/kotlin/kotlin-daemon-client/1.4.31/kotlin-daemon-client-1.4.31.pom
[INFO] Installing /home/riana/.m2/repository/org/sonatype/oss/oss-parent/9/oss-parent-9.pom to /mnt/i/workspace/hoge/project1/maven/org/sonatype/oss/oss-parent/9/oss-parent-9.pom
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/annotations/13.0/annotations-13.0.jar
[INFO] Installing /home/riana/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.pom to /mnt/i/workspace/hoge/project1/maven/org/jetbrains/annotations/13.0/annotations-13.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.830 s
[INFO] Finished at: 2021-07-11T03:28:38+09:00
[INFO] ------------------------------------------------------------------------
実はここで1回前述のエラーで止まりましたが、次の記事にあるとおり.m2
ディレクトリを削除してもできず、結局maven-dependency-plugin
のバージョンを2.10に下げました。
ビルド
キャッシュを削除してjarの生成を試みます。
gradle jar
無事jarができました。よく見るとKotlinを含むタスクが実行されているのが分かります。
3:33:13: タスクを実行中 'jar'...
> Task :compileKotlin
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :inspectClassesForKotlinIC
> Task :jar
BUILD SUCCESSFUL in 432ms
4 actionable tasks: 4 executed
3:33:14: タスクの実行を完了しました 'jar'。
src/main/java
にKotlinコードを書いてjavaと双方向に呼び出す
JavaとKotlinで双方向にメソッドの呼び出しを行うような対称的なソースコードを書いてみます。
public class Main {
public static void main(String[] args) {
System.out.println(MainKotlin.functionKotlin("Hello from Java!"));
}
public static String functionJava(String param) {
return "JAVA[" + param + "]";
}
}
class MainKotlin {
companion object {
@JvmStatic
fun main(args: Array<String>) {
println(Main.functionJava("Hello from Kotlin!"))
}
@JvmStatic
fun functionKotlin(param: String) = "KOTLIN[$param]"
}
}
これらは同ディレクトリに混在して配置することができます。
ビルドするとjarの中身は実質的に同じ動きをするコードがちゃんと生成されています。
たとえKotlinらしいことをしなくてもNullチェックのためにkotlin.jvm.internal.Intrinsics
のようなKotlinのクラスを利用しているので、実行時にロードしなければならないことが分かります。
実行のためのコマンドの生成
application
Gradleプラグインにより提供されるinstallDist
タスクを実行すると、build/install/project1/bin/project1
という場所にシェルスクリプトが出力されます。
これは依存先のjarがすべてクラスパスに追加されたjavaコマンドと考えてよいです。
ちなみに実行時の依存性は次のようになってしました。
runtimeClasspath - Runtime classpath of compilation 'main' (target (jvm)).
+--- junit:junit:4.13.2
| \--- org.hamcrest:hamcrest-core:1.3
\--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.31
+--- org.jetbrains.kotlin:kotlin-stdlib:1.4.31
| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.4.31
| \--- org.jetbrains:annotations:13.0
\--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.31
\--- org.jetbrains.kotlin:kotlin-stdlib:1.4.31 (*)
これはinstallDist
タスクの出力結果とも対応します。
先のクラスを実行するためのコマンドは次のようになります。
hoge/project1$ ./build/install/project1/bin/project1 Main
hoge/project1$ ./build/install/project1/bin/project1 MainKotlin
実行
結果、プログラム通りの挙動が得られました。
hoge/project1$ ./build/install/project1/bin/project1 Main
KOTLIN[Hello from Java!]
hoge/project1$ ./build/install/project1/bin/project1 MainKotlin
JAVA[Hello from Kotlin!]
一体化Jarを作る
com.github.johnrengelman.shadow
プラグインを使用してfat jarを作ります。
プロジェクト内のMavenリポジトリへ追加
ここを見ると、依存先はgradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0
とあります。
おそらくアーティファクトはcom.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:pom:7.0.0
です。
よってpomに追加し、mvn dependency:copy-dependencies
コマンドを叩きます。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>null</groupId>
<artifactId>null</artifactId>
<version>0.0.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<configuration>
<outputDirectory>maven</outputDirectory>
<useRepositoryLayout>true</useRepositoryLayout>
<copyPom>true</copyPom>
<addParentPoms>true</addParentPoms>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>plugins.gradle.org</id>
<name>plugins.gradle.org</name>
<url>https://plugins.gradle.org/m2/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin.jvm</groupId>
<artifactId>org.jetbrains.kotlin.jvm.gradle.plugin</artifactId>
<version>1.4.31</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.github.johnrengelman.shadow</groupId>
<artifactId>com.github.johnrengelman.shadow.gradle.plugin</artifactId>
<version>7.0.0</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>1.4.31</version>
</dependency>
</dependencies>
</project>
Gradleプラグインを追加
shadowプラグインをplugins
ブロックに追加します。
plugins {
application
kotlin("jvm") version "1.4.31"
+ id("com.github.johnrengelman.shadow") version "7.0.0"
}
この時点でIDEAからgradle tasks --all
を実行するとshadowJar
タスクが出来上がっています。
【中略】
Shadow tasks
------------
knows - Do you know who knows?
shadowJar - Create a combined JAR of project and runtime dependencies
【中略】
shadowJar
タスクのためのメインクラスの設定
メインクラスがなければエラーになるらしいので、ダミーの値をセットしておきます。
application {
mainClass.set("dummy")
}
ビルドスクリプトの状態
ここまでのことを反映させたビルドスクリプトが次のコードです。
plugins {
application
kotlin("jvm") version "1.4.31"
id("com.github.johnrengelman.shadow") version "7.0.0"
}
repositories {
maven("./maven")
}
dependencies {
implementation("junit:junit:4.13.2")
implementation(kotlin("stdlib-jdk8", "1.4.31"))
}
application {
mainClass.set("dummy")
}
fat jarを出力する
shadowJar
タスクを実行すると、build/libs/project1-all.jar
が出力されます。
5:20:41: タスクを実行中 'shadowJar'...
> Task :compileKotlin UP-TO-DATE
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :shadowJar
BUILD SUCCESSFUL in 2s
3 actionable tasks: 2 executed, 1 up-to-date
5:20:43: タスクの実行を完了しました 'shadowJar'。
生成されたjarの中には依存性に追加したjunitやkotlinなどのパッケージが同封されています。
重さも約2MBあります。
実行
今度は出力されたjarをjavaコマンドから呼び出します。
hoge/project1$ java -cp build/libs/project1-all.jar Main
KOTLIN[Hello from Java!]
hoge/project1$ java -cp build/libs/project1-all.jar MainKotlin
JAVA[Hello from Kotlin!]
【応用】依存性を選択的にfat jarに追加する
詳しいことは省略しますが、次のコードが参考になります。
Groovy版Gradleでは検索で出てきたけど、Kotlin版ではどう書くの?的なメモです。
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
lateinit var implementationAppending: Configuration
configurations {
register("implementationAppending") {
implementationAppending = this
configurations.implementation.get().extendsFrom(this)
}
}
dependencies {
// 同封しない依存性
implementation("junit:junit:4.13.2")
// 同封する依存性
implementationAppending(kotlin("stdlib-jdk8", "1.4.31"))
}
(tasks["shadowJar"] as ShadowJar).run {
configurations = listOf(implementationAppending)
}
同封するようにした依存性に由来するクラスのみが格納されているの図
公開
この記事に書かれているものを公開しました。
【応用】GitHub Actions上でのビルド
完全オフラインでできるかどうかはともかく、GitHub Actionsの中でも同じことが出来たら安心感があるのでやりました。
mavenリポジトリを取り寄せてビルドしてjavaコマンドで叩くだけです。
name: CI
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: |
bash maven-copy.sh || exit
bash gradlew shadowJar || exit
- name: Test
run: |
command=(java -cp build/libs/java-kotlin-project-sample-all.jar Main)
out=$("${command[@]}")
echo "$out"
[ 'KOTLIN[Hello from Java!]' = "$out" ] || exit
command=(java -cp build/libs/java-kotlin-project-sample-all.jar MainKotlin)
out=$("${command[@]}")
echo "$out"
[ 'JAVA[Hello from Kotlin!]' = "$out" ] || exit
無事テストが通りました。
よかった。
TODO
%HOMEPATH%/.gradle
%HOMEPATH%/.m2
./maven
を削除してダウンロード済みのmavenリポジトリをすべて削除したうえで、初めてgradlewを起動すると、次のようにgradleの本体(なぜかバージョン6.5)のダウンロードを勝手に行ってしまう。
Download https://services.gradle.org/distributions/gradle-6.5-bin.zip finished, took 2 s 925 ms (102.36 MB)
gradle-6.5-bin.zip
は100MB近くあるので結局解決してなさそう。