Bazel チュートリアル: Java プロジェクトをビルドする

<ph type="x-smartling-placeholder"></ph> 問題を報告する ソースを表示 夜間 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

このチュートリアルでは、Terraform を使用した Java アプリケーションのビルドの基本について説明します。 Bazel。ワークスペースを設定し、簡単な Java プロジェクトを作成します。 ターゲットや BUILD ファイルなど、Bazel の主なコンセプトを示しています。

完了までの予想時間: 30 分。

学習内容

このチュートリアルでは、次の方法について学びます。

  • ターゲットを構築する
  • プロジェクトの依存関係を可視化する
  • プロジェクトを複数のターゲットとパッケージに分割する
  • パッケージ全体でターゲットの公開設定を制御する
  • ラベルによる参照ターゲット
  • ターゲットをデプロイする

始める前に

Bazel をインストールする

チュートリアルの準備として、次の場合は、まず Bazel をインストールします。 できます。

JDK をインストールする

  1. Java JDK をインストールします(推奨バージョンは 11 ですが、バージョン 8 ~ 15 がサポートされています)。

  2. JDK を指すように JAVA_HOME 環境変数を設定します。

    • Linux/macOS の場合:

      export JAVA_HOME="$(dirname $(dirname $(realpath $(which javac))))"
      
    • Windows の場合:

      1. コントロール パネルを開きます。
      2. [システムとセキュリティ] に移動します&gt;システム&gt;[システムの詳細設定]&gt;「上級」タブ >「環境変数...」.
      3. [ユーザー変数] で上部の [新規...] をクリックします。
      4. [変数名] で、フィールドに「JAVA_HOME」と入力します。
      5. [Browse Directory...] をクリックします。
      6. JDK ディレクトリ(C:\Program Files\Java\jdk1.8.0_152 など)に移動します。
      7. [OK] をクリックします。すべてのダイアログウィンドウで 表示できます

サンプル プロジェクトを取得する

Bazel の GitHub リポジトリからサンプル プロジェクトを取得します。

git clone https://github.com/bazelbuild/examples

このチュートリアルのサンプル プロジェクトは examples/java-tutorial にあります。 構成されており、次のように構成されています。

java-tutorial
├── BUILD
├── src
│   └── main
│       └── java
│           └── com
│               └── example
│                   ├── cmdline
│                   │   ├── BUILD
│                   │   └── Runner.java
│                   ├── Greeting.java
│                   └── ProjectRunner.java
└── WORKSPACE

Bazel を使用したビルド

ワークスペースを設定する

プロジェクトを作成する前に、ワークスペースを設定する必要があります。ワークスペースとは プロジェクトのソースファイルと Bazel のビルド出力を保持するディレクトリです。これは、 Bazel が特殊なファイルとして認識するファイルも含まれています。

  • WORKSPACE ファイル。ディレクトリとその内容を Bazel ワークスペースであり、プロジェクトのディレクトリ構造のルートに存在します。

  • 1 つ以上の BUILD ファイル。Bazel にさまざまな部分のビルド方法を指示します。 できます。(BUILD ファイルを含むワークスペース内のディレクトリ) パッケージです。パッケージについては、このチュートリアルの後半で説明します)。

ディレクトリを Bazel ワークスペースとして指定するには、 そのディレクトリ内の WORKSPACE

Bazel がプロジェクトをビルドする際、すべての入力と依存関係を同じものにする必要があります。 見てみましょう。別々のワークスペースに存在するファイルはそれぞれ別のワークスペースに存在する これについては、このチュートリアルでは扱いません。

BUILD ファイルについて

BUILD ファイルには、Bazel に関するさまざまな種類の手順が含まれています。 最も重要なタイプはビルドルールです。これは、Bazel にビルド方法を指示します。 必要な出力(実行可能なバイナリやライブラリなど)を出力できます。各インスタンス BUILD ファイル内のビルドルールの「ターゲット」は、 特定のソースファイルと依存関係のセットを 提供しますまた、ターゲットは他の できます。

java-tutorial/BUILD ファイルを確認します。

java_binary(
    name = "ProjectRunner",
    srcs = glob(["src/main/java/com/example/*.java"]),
)

この例では、ProjectRunner ターゲットが Bazel の組み込みツールをインスタンス化します。 java_binary ルール。このルールは、Bazel に以下を指示します。 .jar ファイルとラッパー シェル スクリプト(どちらもターゲットにちなんで名付けられています)をビルドします。

ターゲットの属性は、依存関係とオプションを明示的に記述します。 name 属性は必須ですが、多くは省略可能です。たとえば、 ProjectRunner ルール ターゲット。name はターゲットの名前、srcs は指定します。 Bazel がターゲットのビルドに使用するソースファイル。main_class で、 main メソッドを含むクラス。(先ほどの例で、 glob を使用して、一連のソースファイルを Bazel に渡します。 (1 つずつリストするのではなく)

プロジェクトをビルドする

サンプル プロジェクトをビルドするには、java-tutorial ディレクトリに移動します。 次のコマンドを実行します。

bazel build //:ProjectRunner

ターゲット ラベルの // 部分は BUILD ファイルの場所です。 ワークスペースのルート(この場合はルート自体)を基準とします。 ProjectRunner は、BUILD ファイルのターゲット名です。( ターゲット ラベルの詳細については、このチュートリアルの最後に記載してください)。

Bazel は、次のような出力を生成します。

   INFO: Found 1 target...
   Target //:ProjectRunner up-to-date:
      bazel-bin/ProjectRunner.jar
      bazel-bin/ProjectRunner
   INFO: Elapsed time: 1.021s, Critical Path: 0.83s

これで、最初の Bazel ターゲットがビルドされました。Bazel の場所のビルド ワークスペースのルートの bazel-bin ディレクトリに出力されます。探す Bazel の出力構造を理解してください。

新しくビルドされたバイナリをテストします。

bazel-bin/ProjectRunner

依存関係グラフを確認する

Bazel では、ビルド依存関係を BUILD ファイルで明示的に宣言する必要があります。 Bazel はこれらのステートメントを使用して、プロジェクトの依存関係グラフを作成します。 正確な増分ビルドが可能になります。

サンプル プロジェクトの依存関係を可視化するために、サンプル プロジェクトの依存関係を 依存関係グラフの表現を ワークスペースのルート:

bazel query  --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph

上記のコマンドは、ターゲットのすべての依存関係を検索するよう Bazel に指示します //:ProjectRunner(ホストと暗黙的な依存関係を除く)を使用し、 グラフとして表示できます

次に、テキストを GraphViz に貼り付けます。

ご覧のとおり、プロジェクトには 1 つのターゲットがあり、このファイルで 2 つのソースファイルをビルドしています。 追加の依存関係はありません。

ターゲット「ProjectRunner」の依存関係グラフ

ワークスペースを設定したら、プロジェクトをビルドして内容を確認します。 複雑さが増す可能性があります。

Bazel ビルドの改良

小規模プロジェクトでは 1 つのターゲットで十分ですが、 大規模なプロジェクトを複数のターゲットとパッケージに分けて、 (変更された部分のみを再ビルドする)こともでき、 プロジェクトの複数の部分を一度に構築するのに適しています。

複数のビルド ターゲットを指定する

サンプル プロジェクトのビルドは、2 つのターゲットに分割できます。次の内容を置き換える java-tutorial/BUILD ファイルを次のように置き換えます。

java_binary(
    name = "ProjectRunner",
    srcs = ["src/main/java/com/example/ProjectRunner.java"],
    main_class = "com.example.ProjectRunner",
    deps = [":greeter"],
)

java_library(
    name = "greeter",
    srcs = ["src/main/java/com/example/Greeting.java"],
)

この構成では、Bazel はまず greeter ライブラリをビルドし、次に ProjectRunner バイナリ。java_binarydeps 属性は、Bazel に次のことを通知します。 ProjectRunner バイナリをビルドするには、greeter ライブラリが必要です。

プロジェクトの新しいバージョンをビルドするには、次のコマンドを実行します。

bazel build //:ProjectRunner

Bazel は、次のような出力を生成します。

INFO: Found 1 target...
Target //:ProjectRunner up-to-date:
  bazel-bin/ProjectRunner.jar
  bazel-bin/ProjectRunner
INFO: Elapsed time: 2.454s, Critical Path: 1.58s

新しくビルドされたバイナリをテストします。

bazel-bin/ProjectRunner

ここで ProjectRunner.java を変更してプロジェクトを再ビルドすると、Bazel のみが そのファイルを再コンパイルします。

依存関係グラフを見ると、ProjectRunner が 入力は以前と同じですが、ビルドの構造は異なります。

ターゲット「ProjectRunner」の依存関係グラフ依存関係を追加した後

これで、2 つのターゲットを持つプロジェクトがビルドされました。ProjectRunner ターゲットのビルド 2 つのソースファイルがあり、他の 1 つのターゲット(:greeter)に依存。 追加のソースファイルです。

複数のパッケージを使用する

プロジェクトを複数のパッケージに分割しましょう。こちらの src/main/java/com/example/cmdline ディレクトリには、このフォルダにも BUILD ファイルといくつかのソースファイル。つまり Bazel では //src/main/java/com/example/cmdline// の 2 つのパッケージが含まれています( (ワークスペースのルートに BUILD ファイルがある)。

src/main/java/com/example/cmdline/BUILD ファイルを確認します。

java_binary(
    name = "runner",
    srcs = ["Runner.java"],
    main_class = "com.example.cmdline.Runner",
    deps = ["//:greeter"],
)

runner ターゲットは // パッケージの greeter ターゲットに依存します(したがって、 ターゲット ラベル //:greeter) - Bazel は deps 属性を通じてこれを認識します。 依存関係グラフを見てみましょう。

ターゲット「ランナー」の依存関係グラフ

ただし、ビルドを成功させるには、runner ターゲットを明示的に指定する必要があります。 目標に対する//src/main/java/com/example/cmdline/BUILDの公開設定 visibility 属性を使用する //BUILD。これは、デフォルトでターゲットが 同じ BUILD ファイル内の他のターゲットからのみ参照可能です。(Bazel はターゲット 実装の詳細を含むライブラリなどの問題を防止するための可視性 発生しがちです)。

これを行うには、visibility 属性を greeter ターゲットに追加します。 java-tutorial/BUILD を次のように変更します。

java_library(
    name = "greeter",
    srcs = ["src/main/java/com/example/Greeting.java"],
    visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
)

これで、root で次のコマンドを実行し、新しいパッケージをビルドできます。 できます。

bazel build //src/main/java/com/example/cmdline:runner

Bazel は、次のような出力を生成します。

INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner up-to-date:
  bazel-bin/src/main/java/com/example/cmdline/runner.jar
  bazel-bin/src/main/java/com/example/cmdline/runner
  INFO: Elapsed time: 1.576s, Critical Path: 0.81s

新しくビルドされたバイナリをテストします。

./bazel-bin/src/main/java/com/example/cmdline/runner

これで、プロジェクトを 2 つのパッケージとしてビルドするよう変更できました。それぞれのパッケージには 1 つのパッケージが含まれています。 それらの依存関係を理解します。

ラベルを使用してターゲットを参照する

BUILD ファイルとコマンドラインで、Bazel はターゲット ラベルを使用して参照します。 ターゲット(例: //:ProjectRunner//src/main/java/com/example/cmdline:runner。構文は次のとおりです。

//path/to/package:target-name

ターゲットがルール ターゲットの場合、path/to/package はルール ターゲットのパス BUILD ファイルを含むディレクトリがあり、target-name は名前を付けたものです BUILD ファイル内の(name 属性)ターゲット。ターゲットがファイルの場合 target の場合、path/to/package はパッケージのルートへのパスです。 target-name は、フルパスを含むターゲット ファイルの名前です。

リポジトリ ルートでターゲットを参照する場合、パッケージパスは空になります。 //:target-name を使用してください。同じ BUILD 内でターゲットを参照する場合 // というワークスペースのルート識別子を省略して、 :target-name

たとえば、java-tutorial/BUILD ファイル内のターゲットでは、この操作を行う必要はありません。 ワークスペースのルート自体がパッケージ(//)であるため、パッケージパスを指定します。 2 つのターゲット ラベルは単純に //:ProjectRunner//:greeter でした。

ただし、//src/main/java/com/example/cmdline/BUILD ファイルのターゲットについては、 //src/main/java/com/example/cmdline のフル パッケージ パスを指定する必要がありました。 ターゲット ラベルは「//src/main/java/com/example/cmdline:runner」でした。

デプロイ用に Java ターゲットをパッケージ化する

それでは、Java ターゲットをデプロイ用にパッケージ化しましょう。すべてのリソースでバイナリをビルドします。 依存関係を定義します。これにより、Cloud Shell の外部でバイナリを 開発環境です。

すでに説明したように、java_binary ビルドルールが .jar とラッパー シェル スクリプトを生成します。詳しくは、 このコマンドを使用した runner.jar:

jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar

内容は次のとおりです。

META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class

ご覧のとおり、runner.jar には Runner.class が含まれていますが、依存関係は含まれていません。 Greeting.class。Bazel が生成する runner スクリプトが greeter.jar を追加する クラスパスに渡されるため、このままにするとローカルで実行されますが、 別のマシンではスタンドアロンで実行できません幸いなことに、java_binary ルールは を使用すると、デプロイ可能な自己完結型のバイナリを構築できます。これをビルドするには、 _deploy.jar をターゲット名に追加します。

bazel build //src/main/java/com/example/cmdline:runner_deploy.jar

Bazel は、次のような出力を生成します。

INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date:
  bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
INFO: Elapsed time: 1.700s, Critical Path: 0.23s

runner_deploy.jar をビルドしました。これは、 開発環境には必要なランタイムが含まれているので、 確認します。このスタンドアロン JAR の内容を確認するには、 実行します。

jar tf bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar

コンテンツには、実行に必要なクラスがすべて含まれています。

META-INF/
META-INF/MANIFEST.MF
build-data.properties
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
com/example/Greeting.class

関連情報

詳しくは以下をご覧ください。

ご利用をお待ちしております。