技術者向けテクニカルtips
 / 

Gradleにおけるcompile vs compileOnly vs compileIncludeの比較について

Gradleにおけるcompile vs compileOnly vs compileIncludeの比較を解説します。

依存関係管理設定の比較

こんにちは、日本ライフレイサポータビリティエンジニアの竹生です。

今回は、Gradleにおけるコンパイル、コンパイルオンリー、コンパイルインクルードの違いについて説明する記事を紹介します。


※本記事はLiferay Community Blogに投稿されている” Gradle: compile vs compileOnly vs compileInclude”を翻訳したものです。配信元または著者の許可を得て配信しています。
※オリジナルの英記事著者:David H Nebinger氏はサウスカロライナ州のサマーヴィルに住むLiferay, Inc.のSoftware Architect/リードコンサルタントです。彼はLiferay Communityサイトにて、多くの技術情報を投稿するなど精力的に活動しています。


今回はよく質問をもらう、compileと、compileOnly、そしてcompileIncludeの比較に関して説明する記事を書きたいと思います。

まず、これから紹介するのは実際にビルドプロセス中に使用されるさまざまな設定の名前ですが、依存関係管理にあたって、この名前をしっかり認識しておくことが重要です。 Mavenでは、これらはスコープとして実装されています。

これら3つのタイプの1つがdependencies{}セクションにリストされるたびに、識別された依存関係を構成に追加しています。

Javaコードがバイトコードにコンパイルされている場合、3つの設定はすべてビルドのコンパイル段階で依存関係を追加します。

これらの設定の本当の違いは、構築時のjarのマニフェストにあります。

compile


compileは最も理解しやすいものです。Javaコードがきれいにコンパイルする必要がある、という依存関係を宣言しています。

ベストプラクティスとしてコードをコンパイルするために必要なライブラリに対する、コンパイルの依存関係のみを一覧表示します。たとえば、Excelスプレッドシートの読み書きには、group: 'org.apache.poi'、name: 'poi-ooxml'、version: '4.0.0'が必要ですが、httpへのスピンアウトを避けたい場合があります。  http://mvnrepository.com/artifact/org.apache.poi/poi-ooxml/4.0.0をクリックしてから、POIが必要とするすべてのものに対してコンパイルの依存関係を宣言します。推移的依存関係として、Gradleはあなたに代わってそれらを処理します。

コンパイルが発生すると、この依存関係はjavacがJavaソースファイルをコンパイルするためのクラスパスに含まれます。

さらに、jarをビルドするとき、POIからJavaコードで使用するパッケージがImport-Packageマニフェストエントリとして追加されます。

OSGiコンテナ内の他モジュールから入手できない場合、欠落しているパッケージに関して、「未解決の参照」エラーになります。

Mavenユーザーのための補足として、、コンパイル設定はMavenのコンパイル範囲と同じです。

compileOnly


compileOnly設定は、上記のcompileと同じように、コードをコンパイルするために必要な依存関係を箇条書きにするために使用されます。

違いは、compileOnly依存関係からJavaコードが使用するパッケージがImport-Packageマニフェストエントリとして表示されないことです。

compileOnlyを使用する一般的な例は、通常、アノテーションの使用に関する問題を解決する点です。私は、FindBugsを使うのが好きです。しかし、時には、FindBugsが誤った結果を表示する、FindBugs自体のバグだと思うこともありますが、自分が思った通りに検出してくれていることを思い出します。

そのため、ここでの通常の解決策は、メソッドに@SuppressFBWarninsgアノテーションを追加することです。以下私が最近使ったものです:

@SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF", justification = "Code allocates always before call.")
public void emit(K key) { ... }

FindBugsは私がkeyのnullをチェックしなかったと指摘しましたが、実際にはMapエントリの処理中に発生しているので、keyがnullになることはあり得ません。 nullチェックを追加するのではなく、注釈を追加しました。

注釈を使用するには、もちろん依存関係を含める必要があります。

compileOnly 'com.google.code.findbugs:annotations:3.0.0'

コンパイル自体のアノテーションしか必要ないので、今回はcompileOnlyを使用しました。ランタイムアノテーションではないため、コンパイルラはバイトコードからアノテーション情報を取り除きます。コンパイルが終わった後はこの依存関係を必要としません。

そして、Import-Packageマニフェストエントリに決して現れないようにしたいのです

OSGiでは、org.osgi.coreとosgi.cmpnの依存関係にcompileOnlyを使用する傾向があります。実行時にそれらを必要としないからではなく、OSGiコンテナ内でこれらのパッケージが常に提供されるためです。(そのため、マニフェストはそれを強制する必要はありません)加えて、OSGiコンテナの外側で、jarファイルを使用する場合もあるかもしれません。

Mavenユーザーのための補足として、compileOnly設定はMavenが提供しているスコープと似ています。

compileInclude


  そして最後に、compileIncludeです。 compilecompileOnlyのように、この設定はコンパイルクラスパスに依存関係を含みます。

compileInclude設定は、実際にはLiferayによって導入され、LiferayのGradleプラグインに含まれています。

compileInclude設定は、私のOSGi Depencenciesブログ投稿、オプション#4(バンドル内のjarを含む)からの手動ステップを置き換えます。

実際、私のブログで、Bundle-ClassPath指定と-includeresource命令をbnd.bndファイルに追加することで説明しているものはすべて、このcompileIncludeでも可能です。ただし、compileIncludeが優れているのは、他の推移的な依存関係もモジュールに含まれることです。

いくつかの推移的な依存関係が含まれている、と私が言及したことに注意してください。どの推移的な依存関係を含めるかを、どのように決定するかについては、完全にはわかっていませんが、常に100%正しいとは限らないという点は確かです。私は、特定の推移的な依存関係を逃した場合がありました。他の依存関係を含まないことはわかっていたので、その推移的な依存関係が原因だったのかもしれません。こうした事態を修正するには、欠けている推移的な依存関係に対して、compileInclude設定行を追加するだけで良いのです。

宣言の最後に、フラグを追加することで、推移的な依存関係の包含を無効にすることができます。例えば、poi-ooxmlだけが欲しいが、何らかの理由で他動的な依存関係を望まない場合、以下のように使うことができます:

compileInclude group: 'org.apache.poi', name: 'poi-ooxml', version: '4.0.0', transitive:false

推移的な依存関係を含めるか、除外するかは、実装者次第ですが、少なくとも手動でbnd.bndファイルを更新する必要はなくなります。

compileIncludeは、大体うまくいくが悪影響を及ぼすかもしれないという印象を持っている場合、それも正しいでしょう。 Bundle-ClassPath-includeresourceの使用で、すべてが正確に制御が可能であることは決してありません。たまたま作業が少なく済んでいるだけです。

ただ、Mavenを使っている方は、残念ですが、本件に対応するMavenスコープはありません。。。

まとめ


本記事で、紹介した3つの設定で起こりうる様々な混乱が少しでも解決されたら嬉しく思います。

どの構成をいつ使用するかについて、推奨事項が必要な場合は、次のようにします。

OSGiコンテナーから入手できることがわかっているパッケージの場合は、コンパイル構成を使用してください。これは他のモジュールからのあなたのカスタムコードを含みます。(すべてのcom.liferayコードなど)

OSGiコンテナから不要なもの、あるはOSGiコンテナによって提供されるとは想定しないパッケージのために、compileInclude設定を使用してください。これは基本的に、モジュールとしてコンテナにプッシュしない、サードパーティのライブラリすべてです。

その他の場合はすべて、compileOnly構成を使用してください。


本記事は以上です。
いかがでしたでしょうか?

記事に関するご意見、ご感想などございましたら、お気軽に[email protected]までご連絡くだい。


■ これまで発信してきた日本語による技術コンテンツを、Qiitaでお読みいただけます。よろしければそちらの記事も合わせてご役立てください。
https://qiita.com/yasuflatland-lf

■ Doorkeeperのライフレイコミュニティメンバー大歓迎!
コーポレートブログの技術コンテンツ更新情報など定期的におとどけしています。
https://liferay.doorkeeper.jp/