本文件說明 FIDL 的 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
。
指令列
FIDL 編譯器接受 --available
旗標來指定平台版本。
舉例來說,假設 example.fidl
在 fuchsia
平台中定義了程式庫
沒有依附元件,您可以在第 8 版編譯應用程式,如下所示:
fidlc --available fuchsia:8 --out example.json --files example.fidl
您可以指定多個版本並以半形逗號分隔,例如:
--available fuchsia:7,8,9
。
如果程式庫 A
具有來自不同平台程式庫 B
的依附元件,
您可以使用 --available
旗標兩次,指定兩個平台的版本。
不過,A
必須與固定版本記錄的整個版本記錄相容
已為 B
選擇版本。
目標版本
如果指定單一版本,繫結會包含
該版本提供的是,由 FIDL 中的 @available
引數指定
檔案。
指定一組版本時,繫結會包含
可與任何版本搭配使用對於
replaced
,繫結僅包含最新的定義。
無論您指定哪種版本,只要 FIDL 編譯成功,就會: 也會保證在所有可能的組合中順利執行 單例模式
語法
@available
屬性適用於所有 FIDL 元素。虛擬機器
下列引數:
引數 | 類型 | 附註 |
---|---|---|
platform |
string |
僅允許於 library 使用 |
added |
uint64 |
整數、NEXT 或 HEAD |
deprecated |
uint64 |
整數、NEXT 或 HEAD |
removed |
uint64 |
整數、NEXT 或 HEAD |
replaced |
uint64 |
整數、NEXT 或 HEAD |
note |
string |
與deprecated 共度 |
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
包含詳細說明,且 note
引數的
附有簡短的指示的 @available
屬性。例如:
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
Replacement"]
。
身分識別
FIDL 版本管理的用途是區分移除和取代 元素。為此,我們採用 API 和 ABI 身分的概念。API 則是元素的名稱ABI 身分取決於元素的種類:
- 位元/列舉成員:值,例如
VALUE = 5;
中有 5 人 - 結構成員:偏移,例如第 0 名成員可享 0 折扣
- 資料表/聯集成員:序數,例如
5: name string;
中有 5 人 - 通訊協定成員:選取器,例如「example/Foo.Bar」英吋
library example; protocol 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
為新方法提供Open
不同的 ABI 身分,以及 (2) 在舊定義上使用 renamed
。
允許版本集 {4, 5} 的繫結納入這兩種方法。
參考資料
每個 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;