隔離專案是一個 pre-alpha Gradle 功能,它擴展了配置快取,以進一步提高效能,特別是 Android Studio 和 IDEA 同步的效能。

啟用隔離專案後,Gradle 專案的配置模型將彼此「隔離」。這表示應用於專案的建置邏輯(例如建置腳本或外掛)無法直接存取另一個專案的可變狀態。這允許每個專案的配置和工具模型建立安全地並行執行,結果會被快取,並且每個專案獨立失效。

截至 Gradle 8.11 的狀態

啟用隔離專案後,Gradle 在 IDE 同步期間套用兩個層級的快取

  1. Gradle 首先套用粗粒度快取。

    為了做到這一點,Gradle 會快取整個同步操作的結果,並在影響 IDE 模型的事物沒有變更時重複使用它。當快取條目可以重複使用時,Gradle 會短路整個同步操作,並將快取結果傳回 IDE。

  2. 一般來說,設定和建置腳本會影響 IDE 模型,但專案的原始碼則不會。因此,當這些腳本變更時,快取條目無法重複使用。當這種情況發生時,Gradle 會回退到細粒度快取。

    為了做到這一點,Gradle 會快取每個專案建立工具模型的結果,並在影響它們的事物沒有變更時重複使用這些模型。當專案的快取模型可以重複使用時,Gradle 會短路該專案的所有工作,包括配置階段和其他工作,例如依賴解析。

這表示 Gradle 將僅針對配置已變更的專案配置和建立工具模型。這項工作會針對每個專案平行完成。

目前限制

隔離專案是一個 pre-alpha 功能,因此,目前的實作有許多限制。這些將在未來的 Gradle 版本中解決

  • Gradle、IntelliJ IDEA、Android Studio 和 Kotlin 外掛程式尚未 100% 與隔離專案相容,因此您應該會看到一些違規回報。團隊正在積極努力解決這些不相容性。

  • 並行配置不支援隨需配置。所有專案都會被配置,即使它們沒有執行任務。

  • 包含的建置的變更會使所有快取結果失效,即使變更不會影響快取結果。

  • 實作不會利用隔離來限制峰值記憶體消耗。目前,峰值記憶體消耗是必須配置多少專案的函數。

  • 所有快取,包括配置快取,都在本機上完成。尚不支援遠端快取。

我該如何使用它?

您需要 Gradle 8.5 或更高版本才能使用隔離專案,最好是最近的 nightly 版本。您也應該使用最新版本的 IDEA 或 Android Studio。

此功能預設為關閉。您可以將 org.gradle.unsafe.isolated-projects 系統屬性設定為 true 來啟用它。例如

$ gradle build -Dorg.gradle.unsafe.isolated-projects=true

啟用後,每當建置邏輯嘗試跨專案邊界並存取另一個專案的模型時,Gradle 都會使建置失敗。Gradle 會在配置快取報告中收集所有這些存取問題,就像處理其他問題一樣。

配置快取命令列選項可用於控制 Gradle 如何處理這些問題。例如

  • --configuration-cache-problems=warn 可用於將存取問題視為警告而不是錯誤。

  • -Dorg.gradle.configuration-cache.max-problems=x 可用於增加報告中包含的最大問題數量。

您也可以使用 -Dorg.gradle.internal.invalidate-coupled-projects=false 在存在存取問題時強制執行並行配置。

請注意,這些選項會停用驗證,該驗證在啟用隔離專案時使執行並行且快取安全,因此當您使用它們時,您可能會看到一些意外的行為。

建置邏輯約束

隔離專案會阻止建置邏輯存取另一個專案的狀態。這包括

  • 使用 Project 類型上的大多數方法。允許少量傳回關於專案的不可變資訊的方法

    • getName()

    • getPath()

    • getBuildTreePath()

    • getProjectDir()

    • getRootDir()

    • getChildProjects()

    • getSubprojects()

    • getAllProjects()

    • project() 多載

    • subprojects() 多載

    • allprojects() 多載

請注意,隔離專案是一個 pre-alpha 功能。這些約束不是最終的,並且隨時可能變更。

變更日誌

Gradle 8.11

並行配置的專案

當從命令列建置(即用於任務執行)並啟用隔離專案時,專案現在會並行配置。

並行配置尚不支援隨需配置。所有專案都會被配置,即使是那些沒有任務要執行的專案。如果這種權衡是不受歡迎的,並且您希望專案使用隨需配置依序配置,請將 org.gradle.internal.isolated-projects.configure-on-demand.tasks 系統屬性設定為 true

Gradle 8.9

解除基於字串的任務依賴表示法的限制

以字串表示法形式依賴另一個專案的任務是一種常見的慣用語

foo.dependsOn(":a:bar")

從此版本開始,這不再被視為違反隔離專案邊界。

gradle init 產生與隔離專案相容的專案

建置初始化外掛支援建立多模組專案。

從此版本開始,gradle init 產生的專案與隔離專案限制相容。

IsolatedProject 在複合建置中提供專案識別符

IsolatedProject 類型在 Gradle 8.8 中引入,以明確標記跨專案安全存取的專案狀態。

Gradle 8.9 新增了 buildTreePath 成員,它在 複合建置 設定中充當唯一的專案識別符。

Gradle 8.8

新的 Gradle 生命周期回呼

此版本引入了新的 GradleLifecycle API,可透過 gradle.lifecycle 存取,外掛程式作者和建置工程師可以使用它來註冊在建置生命週期的特定點執行的動作。

註冊為 GradleLifecycle 回呼(目前為 beforeProjectafterProject)的動作是隔離的,在每個專案私有的隔離上下文中執行。這將允許 Gradle 執行額外的效能最佳化,並且在未來需要利用建置配置階段的並行性。

雖然現有的回呼繼續運作,但我們鼓勵所有人採用新的 API,並向我們提供早期回饋。

下面的範例顯示了如何在設定腳本或 設定外掛程式中使用此新 API 來將配置套用於所有專案,同時避免 跨專案配置

settings.gradle.kts
include("sub1")
include("sub2")

gradle.lifecycle.beforeProject {
    apply(plugin = "base")
    repositories {
        mavenCentral()
    }
}

隔離的專案視圖

現在支援透過 Project.getIsolated() 取得專案的隔離視圖,作為 IsolatedProject

該視圖僅公開那些在並行執行建置配置階段(在未來版本中支援)時跨專案邊界安全存取的屬性。

下面的範例顯示了如何從 Project 配置回呼中使用 API,以並行安全的方式查詢根專案目錄

gradle.lifecycle.beforeProject {
    val rootDir = project.isolated.rootProject.projectDirectory
    println("The root project directory is $rootDir")
}