Gradleで複数サブプロジェクトをもつプロジェクトを作成する - kdnakt blog を見て、buildSrcディレクトリ周りで混乱した記憶が蘇ってきました。
gradle initでサブプロジェクトを持つプロジェクトを作るとbuildSrcを使ったプロジェクトが生成されるらしい。知らんかった。buildSrcまわりはドキュメントわかりにくいので、実コード読めるのは助かる。
— 書けない猫はただの猫さ (@Kengo_TODA) July 7, 2021
Gradleで複数サブプロジェクトをもつプロジェクトを作成するhttps://t.co/XVozfs9Zqu
書く場所がbuildSrcとbuild.gradleの2つに増えるので、何をどこに書けばいいのかよくわかんないんだよね。Gradleはこういう悩みが多い、最近ではbaseプラグインに書くべき処理とそうでないconventionもわかりにくかった。
— 書けない猫はただの猫さ (@Kengo_TODA) July 7, 2021
ということで「Gradleの設定やコードをどこに書くべきか」のうち、答えが明確なbuild.gradleファイルとbuildSrcディレクトリの使い分けについて現時点での見解をまとめておきます。
宣言的か命令的か
Gradleのビルドスクリプトを分割統治する手法として、昔はscript pluginと呼ばれる手法が使われていましたが、Gradle 7.1.1時点ではbuildSrcプロジェクトを使ってimperative logicを抽象化することが推奨されています。
imperative logicというのはつまり”命令口調”なビルドスクリプトのことですね。ビルドスクリプト自身が極力宣言的(declarative)になるように、命令的なスクリプトをビルドスクリプトとは別のところに書いておこうということです。ビルドスクリプトを宣言的に保つことは、Gradleベストプラクティス堂々の一位に位置づけられており、その重要性が伺えます。
そしてimperative logicを隠しビルドスクリプトを宣言的に保つことは、プラグインの説明に書かれているように、プラグインの設計意図そのままです:
What plugins do (omit) Encapsulates imperative logic and allows build scripts to be as declarative as possible
自分が最近書いた例でいうと、チェックサムをGitHub Releasesに掲載するためのタスク定義はTHE・命令的でした。この定義、あるいは抽象化した定義をプラグインとして書いておいてビルドスクリプトに適用することで、ビルドスクリプトそのものを宣言的に保てるということです。
命令的なコードを置くためのbuildSrcディレクトリ
通常プラグインはGradle Plugin Portalにpublishして使いますが、プロジェクトごとにpublishしていたらキリがありません。そこでプロジェクト固有のローカルな"命令的"スクリプトを置くための場所として buildSrc
プロジェクトが存在します。プロジェクトルートに buildSrc
ディレクトリを置くと、中のコードをコンパイルしたものをビルドスクリプトのCLASSPATHに置いてくれるのです。
以上のように、全体像がわかってしまえばbuild.gradle
ファイルとbuildSrc
ディレクトリどちらを使うべきかは見えてきます。
宣言的なコードはbuild.gradle
ファイルに、命令的なコードはbuildSrc
ディレクトリに置きましょう。
buildSrc
プロジェクトの書き方はmike-neckさんのブログに詳しいのでオススメです。プラグインはテスト手法も確立しているので、ビルド性能だけでなくビルドスクリプト管理の生産性も上がるといいですね。