本文件說明 FIDL 的 API 版本管理功能。如需 Fuchsia API 演進指南的相關指引,請參閱 Fuchsia API 演進指南。
摘要
FIDL 版本管理可讓您代表 FIDL 程式庫隨時間的變化。變更時,您可以使用 @available 屬性說明變更發生的時間 (即哪個版本)。如要產生繫結,請將 --available 標記傳送至 fidlc,並指定一或多個版本。
FIDL 版本管理提供 API 版本管理,而非 ABI 版本管理。無法在執行階段查詢版本。變更可能會造成 API 破壞,但應與 ABI 相容。FIDL 編譯器會執行一些基本驗證,但無法保證 ABI 相容性。
概念
版本管理的單位是一組稱為「平台」的程式庫。按照慣例,程式庫是以平台名稱開頭。舉例來說,fuchsia.mem 和 fuchsia.web 程式庫屬於 fuchsia 平台。
每個平台都有線性版本記錄。版本是介於 1 到 2^31-1 (含) 之間的整數,或特殊版本 NEXT 和 HEAD 之一。NEXT 版本用於計畫在下一個編號版本中進行的變更。HEAD 版本用於最新的不穩定變更。
如果 FIDL 程式庫沒有任何 @available 屬性,則屬於 unversioned 平台。這個平台只有一個版本:HEAD。fuchsia.git 中的 FIDL 程式庫必須指定 @available 屬性。
目標版本
當您指定單一版本時,繫結會包含該版本中可用的所有元素,如 FIDL 檔案中的 @available 引數所指定。
指定一組版本時,繫結會包含組合中任何版本可用的所有元素。對於屬於 replaced 的元素,繫結只會包含最新定義。
無論您指定哪個版本組合,如果 FIDL 編譯成功,則該組合的所有子集和所有可能的單例組合也保證會成功。
語法
任何 FIDL 元素都可以使用 @available 屬性。它採用下列引數:
| 引數 | 類型 | 說明 | 
|---|---|---|
| platform | string | 程式庫群組名稱 (請參閱概念);僅適用於 library | 
| added | uint64 | 整數、 NEXT或HEAD | 
| deprecated | uint64 | 整數、 NEXT或HEAD | 
| removed | uint64 | 整數、 NEXT或HEAD | 
| replaced | uint64 | 整數、 NEXT或HEAD | 
| note | string | 提供 deprecated、removed和/或replaced的背景資訊 | 
| renamed | string | removed或replaced元素的新名稱;僅供成員使用 | 
引數有一些限制:
- 所有引數皆為選用,但至少須提供一個引數。
- 引數必須是常值,而非 const宣告的參照。
- removed和- replaced引數互斥。
- 引數必須遵循 added <= deprecated < removed或added <= deprecated < replaced。
- 如未指定,added、deprecated、removed和replaced引數就會「繼承」父項元素。
例如:
@available(added=1, deprecated=2, removed=3)
const ANSWER uint64 = 42;
如果 @available 用於程式庫中的任何位置,也必須顯示在程式庫宣告中。對於單一檔案的程式庫,這項作業相當簡單。如果程式庫具有兩個以上的 .fidl 檔案,則只有一個檔案能為其程式庫宣告加註。(理論上,程式庫會被視為單一「元素」,且其屬性會與各個檔案中的屬性合併,因此為多個檔案加上註解會產生重複的屬性錯誤)。FIDL 風格指南建議為此目的建立名為 overview.fidl 的檔案。
在程式庫宣告中,@available 屬性需要 added 引數,並允許 platform 引數。如果省略 platform,系統會預設為程式庫名稱的第一個元件。例如:
// Equivalent to `@available(platform="fuchsia", added=1)`.
@available(added=1)
library fuchsia.examples.docs;
修飾符
您可以透過 FIDL 版本管理功能,在特定版本中新增或移除修飾符。修飾符之後,您可以像在 @available 之後編寫引數一樣,使用括號編寫引數。不過,系統只允許使用 added 和 removed 引數。
以下範例說明如何將列舉從嚴格變更為彈性:
type Color = strict(removed=2) flexible(added=2) enum {
    RED = 1;
};
所有修飾符都支援以下語法:strict、flexible、resource、closed、ajar 和 open。不過,如果在雙向方法中變更 strict 或 flexible 修飾符,則不允許使用錯誤語法。
指定一組版本時,編譯器會使用最新的修飾符。在上述範例中,如果組合包含任何等於或大於 2 的版本,則列舉會彈性,即使其中也包含 1。
繼承
@available 的引數會從程式庫宣告流程到頂層宣告,以及從各個頂層宣告傳至其成員。例如,如果在第 5 版新增資料表,就無須在其成員上重複這項註解,因為它們不能存在於資料表本身之前。以下是較複雜的繼承範例:
@available(added=2, deprecated=3)
open protocol Versioned {
    // Equivalent to `@available(added=2, deprecated=3, removed=4)`.
    @available(removed=4)
    flexible Removed(table {
        // Equivalent to `@available(added=3, deprecated=3, removed=4)`.
        @available(added=3)
        1: message string;
    });
};
淘汰
淘汰用於表示元素日後會遭到移除。淘汰元素時,請在文件註解中加入 # Deprecation 部分,並提供詳細說明,並在 @available 屬性中加入 note 引數,並提供簡短操作說明。例如:
open protocol Example {
    /// (Description of the method.)
    ///
    /// # Deprecation
    ///
    /// (Detailed explanation of why the method is deprecated, the timeline for
    /// removing it, and what should be used instead.)
    @available(deprecated=5, removed=6, note="use Replacement")
    flexible Deprecated();
    @available(added=5)
    flexible Replacement();
};
自 2024 年 6 月起,廢止不會對繫結造成影響。不過,FIDL 團隊計畫讓其以目標語言產生淘汰註解。舉例來說,上述範例可以在 Rust 繫結中產生#[deprecated = "Use替換項目."]。
身分識別
FIDL 版本管理的用途是區分移除和取代元素。為此,它會依據 API 和 ABI 身分概念。元素的 API 身分即為元素的名稱。ABI 身分會因元素類型而異:
- 位元/列舉成員:值,例如 VALUE = 5;中的 5
- 結構成員:偏移,例如 0 代表第一位成員
- 資料表/聯集成員:序數,例如 5: name string;中的 5
- 通訊協定成員:選取器,例如 library example; protocol Foo { Bar(); };中的「example/Foo.Bar」
其他元素 (例如類型宣告和通訊協定) 則沒有 ABI 身分。
取代
replaced 引數可讓您編寫全新的定義,變更特定版本的元素。這是變更 FIDL 元素特定層面的唯一方法,包括:
- 常數的值
- struct、資料表或聯集成員的類型
- 宣告的種類,例如將結構體變更為別名
- 方法上存在 error語法
- 元素的屬性
如要取代 N 版的元素,請使用 @available(replaced=N) 為舊定義加上註解,並使用 @available(added=N) 為新定義加上註解。
以下舉例說明如何變更常數值:
@available(replaced=5)
const MAX_NAME_LEN uint32 = 32;
@available(added=5)
const MAX_NAME_LEN uint32 = 64;
以下是另一個範例,說明如何變更表格欄位的類型:
type Data = resource table {
    @available(replaced=5)
    1: name string:32;
    @available(added=5)
    1: name string:64;
};
FIDL 編譯器會驗證每個 @available(replaced=N) 元素是否有與之相符的 @available(added=N) 元素,且具有相同的身分。也會驗證每個 @available(removed=N) 元素是否「沒有」這類替代項目。這項驗證僅適用於直接加註的元素,不適用於「繼承」removed 或 replaced 引數的元素。
重新命名
如要重新命名成員,請以新定義取代該成員,並使用舊定義的 renamed 引數指定新名稱。例如:
type User = table {
    @available(replaced=2, renamed="first_name")
    1: name string;
    @available(added=2)
    1: first_name string;
};
只有成員可以使用 renamed 引數,因為 FIDL 編譯器會根據自己的 ABI 身分進行驗證。如要重新命名宣告,只需移除舊定義,以新的定義即可:
@available(deprecated=2, removed=3, note="renamed to Information")
type Info = table {};
@available(added=2)
type Information = table {};
移除後
通常 renamed 引數會與 replaced=N 搭配使用,但您也可以與 removed=N 搭配使用。這樣一來,您就能在移除成員後,以新名稱參照該成員。運作方式取決於目標版本組合:
- 如果您只指定版本低於 N,繫結會使用舊名稱。
- 如果您只指定等於或大於 N的版本,綁定作業就不會納入成員。
- 如果指定的組合包含版本低於 N「且」包含大於或等於N的版本,繫結會使用新名稱。
這樣做的其中一個原因,是為了避免使用者採用新的 API,同時繼續支援其導入作業。例如:
open protocol Door {
    @available(removed=5, renamed="DeprecatedOpen")
    flexible Open() -> ();
};
如果 Door 伺服器是在指定版本集 {4, 5} 的程式碼集中實作,該方法的名稱將為 DeprecatedOpen,導致開發人員無法新增該方法。如果其他程式碼集指定 4 以下版本,方法將命名為 Open。如果目標版本為第 5 版,此方法完全不會顯示。
使用這項功能的另一個原因,是為了重複使用新 ABI 的名稱。例如,請考慮變更 Open 方法以傳回錯誤:
open protocol Door2 {
    @available(removed=5, renamed="DeprecatedOpen")
    flexible Open() -> ();
    @available(added=5)
    @selector("NewOpen")
    flexible Open() -> () error uint32;
};
我們必須定義新方法,因為若用戶端未預期發生錯誤,就會在收到錯誤回應時關閉管道。不過,只要我們 (1) 使用 @selector 為新方法提供不同的 ABI 身分,以及 (2) 在舊定義中使用 renamed,即可繼續使用 Open 名稱,讓版本組合 {4, 5} 的繫結包含這兩種方法。
參照 FIDL 類型
每個 FIDL 元素可以參照其他元素的方式有很多種,例如:
const VALUE uint32 = 5;
const REFERENCES_VALUE uint32 = VALUE;
type Type = struct {};
type ReferencesType = table {
    1: t Type;
};
alias ReferencesTypeAndValue = vector<Type>:VALUE;
參照元素時,您必須遵守 @available 屬性。舉例來說,由於 A 從第 1 版起存在,但嘗試參照僅存在於版本 2 的 B,因此下列程式碼無效:
// Does not compile!
@available(added=1)
const A bool = B;
@available(added=2, removed=3)
const B bool = true;
同樣地,非淘汰元素也無法參照淘汰元素。舉例來說,以下程式碼在版本 1 中無效,因為 A 參照 B,但 B 已淘汰,A 則無效。
// Does not compile!
@available(deprecated=2)
const A bool = B;
@available(deprecated=1)
const B bool = true;
fidlc 指令列
FIDL 編譯器接受 --available 標記來指定平台版本。
舉例來說,假設 example.fidl 在 fuchsia 平台中定義了一個不含依附元件的程式庫,您可以在版本 22 進行編譯,如下所示:
fidlc --available fuchsia:22 --out example.json --files example.fidl如要指定多個版本,請以半形逗號分隔,例如 --available fuchsia:19,22,23,NEXT,HEAD。
如果程式庫 A 具有來自不同平台的 B 程式庫的依附元件,您可以使用 --available 標記兩次指定兩個平台的版本。不過,A 必須在整個版本記錄中與 B 所選的固定版本相容。