本教學課程涵蓋使用
Bazel。您會設定工作區並建構簡單的 Java 專案,
說明 Bazel 的重要概念,例如目標和 BUILD
檔案。
預計完成時間:30 分鐘。
課程內容
在本教學課程中,您會瞭解如何執行下列作業:
- 建立目標
- 以圖表呈現專案的依附元件
- 將專案分割為多個目標和套件
- 控管所有套件的目標瀏覽權限
- 透過標籤參照目標
- 部署目標
事前準備
安裝 Bazel
如要為教學課程做好準備,請先安裝 Bazel (如有) 你還沒有安裝這個應用程式。
安裝 JDK
安裝 Java JDK (建議版本為 11,但系統支援 8 到 15 的版本)。
將 JAVA_HOME 環境變數設為指向 JDK。
Linux/macOS:
export JAVA_HOME="$(dirname $(dirname $(realpath $(which javac))))"
Windows:
- 開啟控制台。
- 前往「系統與安全性」頁面>「系統」>「進階系統設定」>「進階」Tab >「環境變數...」。
- 在「使用者變數」下方清單,然後按一下「新增...」即可。
- 在「變數名稱」中欄位中輸入
JAVA_HOME
。 - 按一下 [瀏覽目錄...]。
- 前往 JDK 目錄 (例如
C:\Program Files\Java\jdk1.8.0_152
)。 - 按一下「確定」所有對話方塊視窗
取得範例專案
從 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
└── MODULE.bazel
使用 Bazel 進行建構
設定工作區
您必須先設定專案工作區,才能建立專案。工作區是 存放專案來源檔案和 Bazel 建構輸出內容的目錄。這項服務 也包含 Bazel 視為特殊的檔案:
MODULE.bazel
檔案,用來將目錄和其內容識別為 Bazel 工作區和專案目錄結構的根目錄一或多個
BUILD
檔案,用於告知 Bazel 如何建構 專案。(工作區中含有BUILD
檔案的目錄) 是套件。稍後,本教學課程會說明套件。)
如要將目錄指定為 Bazel 工作區,請建立名為
MODULE.bazel
。
當 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
會指定
包含主要方法的類別。(您可能已經注意到我們的範例
使用 glob 將一組來源檔案傳送至 Bazel
而不要逐一列出)。
建構專案
如要建立範例專案,請前往 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 中。
如您所見,專案只有一個目標,可透過 沒有其他依附元件:
設定工作區後,即可建構及檢查專案 那就增加一些複雜度
修正 Bazel 建構作業
雖然一個目標就足以滿足小型專案的需求,而您可能想要 轉化成多個目標和套件 (也就是只重新建構已變更的內容) 並利用 同時建構專案的多個部分
指定多個建構目標
您可以將範例專案版本分割為兩個目標。將內容
加入含有以下內容的 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_binary
中的 deps
屬性會向 Bazel 告知
需要 greeter
程式庫才能建構 ProjectRunner
二進位檔。
如要建構這個新版專案,請執行下列指令:
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
目標版本
一個來源檔案並依附於另一個目標 (:greeter
),也就是版本
還有一個來源檔案
使用多個套件
現在,我們將專案拆分為多個套件。如果查看
src/main/java/com/example/cmdline
目錄,就能看到該目錄包含
BUILD
檔案和一些來源檔案。因此,在 Bazel 中
包含兩個套件://src/main/java/com/example/cmdline
和 //
(自
工作區的根目錄下有 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
與以下區域的目標可見度:
//BUILD
使用 visibility
屬性。這是因為系統會根據預設目標
只會向同一個 BUILD
檔案中的其他目標顯示。(Bazel 會使用目標
防止出現問題,例如程式庫內含實作詳細資料
外洩至公用 API)
方法是將 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__"],
)
現在,您可以在根目錄執行下列指令,以建構新的套件 工作區:
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
您已修改專案,建構為兩個套件,每個套件各有一個套件 並掌握兩者之間的依附關係
使用標籤參照目標
在 BUILD
檔案中和指令列,Bazel 會使用目標標籤來參照
指定目標:例如 //:ProjectRunner
或
//src/main/java/com/example/cmdline:runner
。其語法如下:
//path/to/package:target-name
如果目標為規則目標,則 path/to/package
是
目錄,其中含有 BUILD
檔案,而 target-name
是您命名的
BUILD
檔案 (name
屬性) 中的指定目標。如果目標為檔案
目標,則 path/to/package
是套件的根目錄路徑,
target-name
是目標檔案的名稱,包括其完整路徑。
在存放區根目錄參照目標時,套件路徑為空白。
只要使用 //:target-name
。參照相同BUILD
內的目標時
檔案,您甚至可以略過 //
工作區的根 ID,只使用
:target-name
。
例如,對於 java-tutorial/BUILD
檔案中的目標,您無須
指定套件路徑,因為工作區根目錄本身是套件 (//
)。
您的兩個目標標籤都是 //:ProjectRunner
和 //:greeter
。
不過,對於 //src/main/java/com/example/cmdline/BUILD
檔案中目標
必須指定 //src/main/java/com/example/cmdline
的完整套件路徑
,您的目標標籤為 //src/main/java/com/example/cmdline:runner
。
封裝用於部署的 Java 目標
現在,請建構用於部署的 Java 目標的 其執行階段依附元件的容器這可讓您在 開發環境的專區
如您所知,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
延伸閱讀
相關詳情請參閱:
rules_jvm_external: 管理遞移 Maven 依附元件的規則
外部依附元件:進一步瞭解如何處理 本機和遠端存放區
進一步瞭解 Bazel 的其他規則。
C++ 建構教學課程可開始建構 搭配 Bazel 使用 C++ 專案。
Android 應用程式教學課程和 iOS 應用程式教學課程) 即可開始使用 使用 Bazel 建構適用於 Android 和 iOS 的行動應用程式。
祝您建構愉快!