本文件說明 FIDL 的 API 版本管理功能。如要瞭解如何改善 Fuchsia API,請參閱 Fuchsia API 演進指南。
提振精神
FIDL 版本管理功能可讓您隨著時間變更 FIDL 程式庫,同時保有為舊版程式庫產生繫結的功能。您可以透過下列方式手動執行此操作:
將
.fidl
檔案儲存在v1/
目錄中。如要變更,請將v1/
複製到v2/
,然後在該處變更檔案。如要產生舊版本的繫結,請使用v1/
程式庫,而非v2/
。將
.fidl
檔案儲存在 Git 存放區,並在修訂版本中進行變更。如要產生舊版本的繫結,請查看存放區的舊版本。
第一個解決方案相當繁瑣,且會產生許多重複項目。除了特定 FIDL 程式庫 (例如主要的 Fuchsia 存放區) 以外,第二個解決方案在包含許多項目的大型存放區中無法正常運作。
FIDL 版本設定也有同樣的效果,但不能有這些缺點。進行變更時,請使用 @available
屬性來描述變更發生的時間 (即哪個版本)。如要產生舊版本的繫結,請將 --available
標記傳遞至 fidlc,並指定較舊版本。
使用 FIDL 版本管理功能時,請注意兩點重要事項:
這項設定會影響「僅限 API」。版本僅於編譯期間存在,對執行階段行為沒有影響。
這可以代表任何語法的有效變更。只因為版本管理表示可以表示變更,並不代表該變更就安全。
概念
版本管理的單位是一組程式庫,稱為「平台」。按照慣例,程式庫的名稱會以平台名稱開頭。例如,fuchsia.mem
和 fuchsia.web
程式庫屬於 fuchsia
平台。
每個平台都有線性「版本」記錄。版本是介於 1 到 2^63-1 (含) 之間的整數,或特殊版本 HEAD
和 LEGACY
之一。HEAD
版本適用於最新的不穩定版變更。LEGACY
版本與 HEAD
類似,但包含舊版元素。
如果 FIDL 程式庫沒有任何 @available
屬性,就會屬於 unversioned
平台。這個平台只有一個版本:HEAD
。
指令列
FIDL 編譯器接受 --available
標記來指定平台版本。
舉例來說,假設 example.fidl
在 fuchsia
平台中定義了一個不含依附元件的程式庫,您可以在第 8 版進行編譯,如下所示:
fidlc --available fuchsia:8 --out example.json --files example.fidl
無論您選取哪個版本,Fidlc 一律會驗證所有可能的版本。舉例來說,即使只有版本 5 發生錯誤,上述指令仍可回報錯誤。
如果程式庫 A
有來自不同平台的 B
程式庫的依附元件,您可以使用 --available
標記兩次,為這兩個平台指定版本。不過,A
必須與為 B
選擇的修正版本完整相容於其整個版本記錄。
語法
@available
屬性適用於所有 FIDL 元素。該函式採用的是下列引數:
引數 | 類型 | 附註 |
---|---|---|
platform |
string |
僅允許 library 存取 |
added |
uint64 |
整數或 HEAD |
deprecated |
uint64 |
整數或 HEAD |
removed |
uint64 |
整數或 HEAD |
replaced |
uint64 |
整數或 HEAD |
note |
string |
與deprecated 一起出現 |
legacy |
boolean |
與removed 一起出現 |
引數有一些限制:
- 所有引數皆為選用,但至少須提供一個引數。
- 引數必須是常值,而非
const
宣告的參照。 removed
和replaced
引數互斥,無法共同存在。- 引數必須遵循
added <= deprecated < removed
或added <= deprecated < replaced
。 - 如未指定,
added
、deprecated
、removed
、replaced
和legacy
引數會繼承父項元素。
例如:
@available(added=1, deprecated=2, removed=3, legacy=true)
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;
繼承
@available
的引數資料流從程式庫宣告到頂層宣告,以及從每個頂層宣告到其成員。舉例來說,如果在第 5 版新增資料表,則無須對成員重複此註解,因為這些註解不存在於資料表本身之前。以下是更複雜的繼承範例:
@available(added=2, deprecated=3)
protocol Versioned {
// Equivalent to `@available(added=2, deprecated=3, removed=4, legacy=true)`.
@available(removed=4, legacy=true)
Removed(table {
// Equivalent to `@available(added=3, deprecated=3, removed=4, legacy=true)`.
@available(added=3)
1: message string;
// Equivalent to `@available(added=2, deprecated=3, removed=4, legacy=false)`.
@available(legacy=false)
2: count uint32;
});
};
淘汰
淘汰用於表示元素日後將遭到移除。淘汰元素時,則應在文件註解中加入 # Deprecation
區段和詳細說明,並在 @available
屬性中加入 note
引數,以便簡單指示。例如:
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")
Deprecated();
@available(added=5)
Replacement();
};
但自 2022 年 5 月起,淘汰對繫結沒有任何影響。然而,FIDL 團隊會規劃使其發出譯文語言的淘汰註解。舉例來說,上述範例可能會在 Rust 繫結中產生 #[deprecated = "use
Replacement"]
。
取代中
replaced
引數可讓您編寫全新的定義,以變更特定版本的元素。這是變更 FIDL 元素特定部分的唯一方法,包括:
- 常數的值
- 結構體、資料表或聯集成員的類型
- 資料表或聯集成員的序數
- 宣告的種類,例如將結構體變更為別名
- 方法上有
error
語法 - 元素中的其他屬性,例如
@selector
- 修飾符,例如
strict
、flexible
和resource
如要取代版本 N
的元素,請使用 @available(replaced=N)
為舊定義加上註解,並使用 @available(added=N)
為新定義加上註解。例如,以下是將列舉從 strict
變更為 flexible
的方法:
@available(replaced=5)
type Color = strict enum {
RED = 1;
};
@available(added=5)
type Color = flexible enum { // Note: flexible instead of strict
RED = 1;
};
您也可以使用取代功能,清除因長期 API 變更記錄而雜亂的 FIDL 程式庫。只要將所有元素替換為全新的定義,然後將舊定義移至另一個名稱 (例如 history.fidl
) 的檔案即可。
FIDL 編譯器會驗證每個 @available(replaced=N)
元素都有相符的 @available(added=N)
取代項目。也會驗證每個 @available(removed=N)
元素是否「沒有」這類替換。這項驗證僅適用於直接加註的元素,不適用於沿用 removed
或 replaced
引數的元素。
Legacy
移除元素時,您可以使用 legacy=true
將其保留在 LEGACY
版本中。由於 Fuchsia 系統映像檔是以 LEGACY
FIDL 繫結為基礎,因此可讓您針對指定 API 級別的用戶端保留 ABI。例如:
protocol LegacyExample {
@available(deprecated=5, removed=6, legacy=true, note="...")
LegacyMethod();
};
在本例中,LegacyMethod
不會顯示在 6 以上版本或 HEAD
的繫結中,但會加回 LEGACY
版本。
參考資料
有很多 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 版起,但嘗試參照的 B
只存在於第 2 版:
// 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;