Gradle 支援多專案建置。

gradle basic 9

雖然有些小型專案和單體式應用程式可能只包含單一建置檔和原始碼樹狀結構,但更常見的情況是專案已拆分為更小的、相互依賴的模組。「相互依賴」這個詞至關重要,因為您通常希望透過單一建置將許多模組連結在一起。

Gradle 透過多專案建置來支援這種情境。這有時也稱為多模組專案。Gradle 將模組稱為子專案。

多專案建置包含一個根專案和一個或多個子專案。

多專案結構

以下代表包含三個子專案的多專案建置結構

multi project structure

目錄結構應如下所示

├── .gradle
│   └── ⋮
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
├── gradlew
├── gradlew.bat
├── settings.gradle.kts (1)
├── sub-project-1
│   └── build.gradle.kts    (2)
├── sub-project-2
│   └── build.gradle.kts    (2)
└── sub-project-3
    └── build.gradle.kts    (2)
1 settings.gradle.kts 檔案應包含所有子專案。
2 每個子專案都應有自己的 build.gradle.kts 檔案。

多專案標準

Gradle 社群有多專案建置結構的兩個標準

  1. 使用 buildSrc 的多專案建置 - 其中 buildSrc 是 Gradle 專案根目錄中類似子專案的目錄,包含所有建置邏輯。

  2. 複合建置 - 一種包含其他建置的建置,其中 build-logic 是 Gradle 專案根目錄中包含可重複使用建置邏輯的建置目錄。

multi project standards

1. 使用 buildSrc 的多專案建置

多專案建置可讓您組織具有多個模組的專案、連接這些模組之間的相依性,並輕鬆地在它們之間共用常見的建置邏輯。

例如,具有多個模組(稱為 mobile-appweb-appapilibdocumentation)的建置可以結構化如下

.
├── gradle
├── gradlew
├── settings.gradle.kts
├── buildSrc
│   ├── build.gradle.kts
│   └── src/main/kotlin/shared-build-conventions.gradle.kts
├── mobile-app
│   └── build.gradle.kts
├── web-app
│   └── build.gradle.kts
├── api
│   └── build.gradle.kts
├── lib
│   └── build.gradle.kts
└── documentation
    └── build.gradle.kts

模組之間將存在相依性,例如 web-appmobile-app 依賴於 lib。這表示為了讓 Gradle 建置 web-appmobile-app,它必須先建置 lib

在此範例中,根設定檔如下所示

settings.gradle.kts
include("mobile-app", "web-app", "api", "lib", "documentation")
settings.gradle
include("mobile-app", "web-app", "api", "lib", "documentation")
包含子專案(模組)的順序無關緊要。

Gradle 會自動識別 buildSrc 目錄。它是定義和維護共用配置或命令式建置邏輯(例如自訂任務或外掛程式)的好地方。

如果在 buildSrc 下找到 build.gradle(.kts) 檔案,則 buildSrc 會自動作為特殊子專案包含在您的建置中。

如果將 java 外掛程式應用於 buildSrc 專案,則來自 buildSrc/src/main/java 的編譯程式碼會放入根建置腳本的類別路徑中,使其可供建置中的任何子專案(web-appmobile-applib 等)使用。

請參閱如何宣告子專案之間的相依性以了解更多資訊。

2. 複合建置

複合建置也稱為包含的建置,最適合在建置之間(而非子專案)共用邏輯或隔離對共用建置邏輯(即慣例外掛程式)的存取。

讓我們以先前的範例為例。buildSrc 中的邏輯已轉換為包含外掛程式的專案,並且可以獨立於根專案建置進行發佈和處理。

外掛程式已移至其自己的建置(稱為 build-logic),其中包含建置腳本和設定檔

.
├── gradle
├── gradlew
├── settings.gradle.kts
├── build-logic
│   ├── settings.gradle.kts
│   └── conventions
│       ├── build.gradle.kts
│       └── src/main/kotlin/shared-build-conventions.gradle.kts
├── mobile-app
│   └── build.gradle.kts
├── web-app
│   └── build.gradle.kts
├── api
│   └── build.gradle.kts
├── lib
│   └── build.gradle.kts
└── documentation
    └── build.gradle.kts
build-logic 位於根專案的子目錄中這個事實並不重要。如果需要,該資料夾可以位於根專案之外。

根設定檔包含整個 build-logic 建置

settings.gradle.kts
pluginManagement {
    includeBuild("build-logic")
}
include("mobile-app", "web-app", "api", "lib", "documentation")

請參閱如何使用 includeBuild 建立複合建置以了解更多資訊。

多專案路徑

專案路徑具有以下模式:它以可選的冒號開頭,表示根專案。

根專案 : 是路徑中唯一未按名稱指定的專案。

專案路徑的其餘部分是以冒號分隔的專案名稱序列,其中下一個專案是前一個專案的子專案

:sub-project-1

您可以在執行 gradle projects 時看到專案路徑

------------------------------------------------------------
Root project 'project'
------------------------------------------------------------

Root project 'project'
+--- Project ':sub-project-1'
\--- Project ':sub-project-2'

專案路徑通常反映檔案系統佈局,但也有例外。最值得注意的是 複合建置

識別專案結構

您可以使用 gradle projects 命令來識別專案結構。

作為範例,讓我們使用具有以下結構的多專案建置

$ gradle -q projects

Projects:

------------------------------------------------------------
Root project 'multiproject'
------------------------------------------------------------

Root project 'multiproject'
+--- Project ':api'
+--- Project ':services'
|    +--- Project ':services:shared'
|    \--- Project ':services:webservice'
\--- Project ':shared'

To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :api:tasks

多專案建置是您可以執行的任務集合。不同之處在於您可能想要控制哪些專案的任務會被執行。

以下章節將介紹在多專案建置中執行任務的兩個選項。

依名稱執行任務

命令 gradle test 將在相對於目前工作目錄且具有該任務的任何子專案中執行 test 任務。

如果您從根專案目錄執行命令,您將在 apisharedservices:sharedservices:webservice 中執行 test

如果您從 services 專案目錄執行命令,您將僅在 services:sharedservices:webservice 中執行任務。

Gradle 行為背後的基本規則是執行階層結構中具有名稱的所有任務。並且如果沒有在任何遍歷的子專案中找到此類任務,則發出抱怨

某些任務選擇器(例如 helpdependencies)將僅在調用它們的專案上執行任務,而不會在所有子專案上執行,以減少螢幕上列印的資訊量。

依完整限定名稱執行任務

您可以使用任務的完整限定名稱,在特定的子專案中執行特定的任務。例如:gradle :services:webservice:build 將執行 webservice 子專案的 build 任務。

任務的完整限定名稱是其專案路徑加上任務名稱。

此方法適用於任何任務,因此如果您想知道特定子專案中有哪些任務,請使用 tasks 任務,例如 gradle :services:webservice:tasks

多專案建置與測試

build 任務通常用於編譯、測試和檢查單一專案。

在多專案建置中,您可能經常希望跨多個專案執行所有這些任務。buildNeededbuildDependents 任務可以幫助您做到這一點。

此範例中,:services:person-service 專案同時依賴於 :api:shared 專案。:api 專案也依賴於 :shared 專案。

假設您正在處理單一專案 :api 專案,您一直在進行變更,但自執行 clean 以來尚未建置整個專案。您想要建置任何必要的支援 JAR,但僅在您已變更的專案部分執行程式碼品質和單元測試。

build 任務會執行此操作

$ gradle :api:build
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build

BUILD SUCCESSFUL in 0s

如果您剛從版本控制系統取得來源的最新版本,其中包括 :api 依賴的其他專案中的變更,您可能想要建置您依賴的所有專案並對它們進行測試。

buildNeeded 任務會建置和測試來自 testRuntime 配置的專案相依性的所有專案

$ gradle :api:buildNeeded
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build
> Task :shared:assemble
> Task :shared:compileTestJava
> Task :shared:processTestResources
> Task :shared:testClasses
> Task :shared:test
> Task :shared:check
> Task :shared:build
> Task :shared:buildNeeded
> Task :api:buildNeeded

BUILD SUCCESSFUL in 0s

您可能想要重構 :api 專案中其他專案使用的某些部分。如果您進行這些變更,則僅測試 :api 專案是不夠的。您必須測試所有依賴於 :api 專案的專案。

buildDependents 任務會測試所有在 testRuntime 配置中具有對指定專案的專案相依性的專案

$ gradle :api:buildDependents
> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build
> Task :services:person-service:compileJava
> Task :services:person-service:processResources
> Task :services:person-service:classes
> Task :services:person-service:jar
> Task :services:person-service:assemble
> Task :services:person-service:compileTestJava
> Task :services:person-service:processTestResources
> Task :services:person-service:testClasses
> Task :services:person-service:test
> Task :services:person-service:check
> Task :services:person-service:build
> Task :services:person-service:buildDependents
> Task :api:buildDependents

BUILD SUCCESSFUL in 0s

最後,您可以建置和測試所有專案中的所有內容。您在根專案資料夾中執行的任何任務都將導致在所有子專案上執行相同的命名任務。

您可以執行 gradle build 來建置和測試所有專案。

請參閱建置結構化章節以了解更多資訊。