RFC-0097:FIDL 工具鍊

RFC-0097:FIDL 工具鍊
狀態已接受
領域
  • FIDL
說明

標準 FIDL 工具鍊的說明。

毛皮變化
作者
審查人員
提交日期 (年-月-日)2021-04-27
審查日期 (年-月-日)2021-05-26

摘要

我們說明 FIDL 工具鍊須符合哪些要求,並提供 如何分解這個問題

雖然特定實作計畫不在此 RFC 的涵蓋範圍內 所預期的工具 (例如 fidlcfidlgen_gobanjo) 和建構規則 Fuchsia 來源樹狀結構 (例如 fidl_library.gni) 才能符合這些規定

此外,位於 Fuchsia 來源樹之外的 FIDL 工具鍊 都符合此處列出的規定(此 RFC 沒有 因此,我們無法強制要求雙方遵循法規,但當然可以 建議)。

術語

開始之前,先解釋一些詞彙。FIDL 的簡化檢視畫面 工具鍊的摘要如下:

經過簡化的工具鍊

FIDL 語言屬於以下術語: fidlc,代表前端編譯器 (簡稱「前端」)。 這裡適用於所有語言驗證。

前端產生中階代表 (配音為 JSON IR) 為每個 FIDL 程式庫進行這項操作雖然名稱是 表示法不一定要以 JSON 檔案表示。

然後,一或多個後端會處理 JSON IR,以便 生成輸出內容請注意,從 FIDL 工具鍊的角度來看 JSON IR 的取用者是一個後端

最常見的輸出內容是目標語言的程式碼 (例如 C++、 或 Rust) 來管理型別、與通訊協定互動、 請開啟服務並使用常數這種後端類別稱為 FIDL 繫結1,而產生的程式碼應遵循繫結規範 規格。我們通常會使用 簡寫 fidlgen (或 fidlgen_<suffix>,例如 fidlgen_rustfidlgen_dart) 用來參照產生 FIDL 繫結的後端。我們稱為 以「網域物件」做為目標語言的一組類別和類型。 代表 FIDL 類型舉例來說,FIDL 列舉是 fuchsia.fonts/Slant敬上 在 C++ 中 (enum class) 或 Go (做為 type Slant uint32)。

其他各種後端也各有不同,且各有專屬的需求, 同義詞舉例來說:fidldoc 會產生 FIDL 文件,例如 fuchsia.fonts 頁面; fidl_api_summarize 會根據 FIDL 程式庫;fidlcat 使用 JSON IR 來提供執行階段 自我檢查,從 FIDL 工具鍊的角度來看,fidlcat 工具是 但這個工具實際上是一小部分的功能

提振精神

FIDL 持續在成長中。工具鍊的可辨識性已經過測試。 因此未能充分符合新的規定。新的已展開 需要工具鍊。

我們會先說明幾項新的規定,然後遵守 並採取支援所有裝置的方法

整個計畫檢視畫面

目前 FIDL 工具鍊假設後端在每個程式庫上運作 因此只需要這個程式庫的 JSON IR 就能運作。

越來越多後端需要存取多個 JSON IR, 他們的需求

舉例來說,fidldoc 需要所有要擷取的程式庫的 JSON IR ,以便產生全域索引。fidlcat 位於 需要查看所有程式庫才能運作measure-tape 需要透過目標傳輸程式庫的 JSON IR 產生捲尺的尺寸

整理中繼資料

部分後端需要程式庫的特殊中繼資料,才能正常運作。 通常,這類中繼資料需要從葉子開始反覆計算 程式庫依附元件樹狀結構 (「基本程式庫」) 及其中繼資料 與根 (正在編譯的程式庫) 有關。

舉例來說,「fidlgen_rust想知道 某類型是否可能包含浮點數,以判斷 也能安全地衍生特徵不包含任何浮動式的 struct 點編號可能含有 Eq,但沒有任何子類的 strict union 包含任何浮點數可以有 Eq,但 flexible table 目前沒有浮點欄位,因此無法使用 Eq,因為 否則就會違反來源相容性規則

另一個例子來自 fidlgen_cpp,這會產生無擁有權的網域 如需儲存大量結構化物件 建議使用 Cloud Bigtable如果這些網域的內嵌部分為 值,亦即非資源。我再次計算 稱為「內嵌資源」的中繼資料就需要反覆計算 因此從分葉到根的值

不久前,在探討為程式庫產生 ABI 指紋的新後端中, 有 來回切換 功能應在何處存在目前的想法是代管 fidlc 編譯器的功能,出於實際因素,但答案是 不滿意

我們發現,需要統合中繼資料的功能 等候,處理中 (通常 駭客)。 或轉換為新的編譯器功能,通常是強制一般化 過早 (例如上述的 ABI 指紋)。

此外,由於 Fuchsia FIDL 團隊能夠變更編譯器 相對地,我們會擁有優於第三方廠商的優勢因此 可能表示工具的狀態危害了我們的開放原始碼原則 讓所有後端都設在關卡玩法欄位

依據目標語言和每個程式庫後端選項

以用來說明核心 API 的 FIDL 語言為基礎, 驅動程式 SDK 已上線 變得越來越普及,FIDL 越來越普及。

如今,工具鍊中的「FIDL」 語言」和「後端」處理特定程式庫如果 目標需要 fuchsia.fonts 程式庫的 Rust 程式碼,我們叫用 fidlgen_rust

這個方法太簡單,並未說明某些程式庫需要 專門用於後端舉例來說,library zx; 是由 kazoo 處理。 為每個目標程式庫的纖維選擇選項包含進一步的影響。搭乘 zx/clock 列舉,而是使用 kazoo 一天的時間產生 目前手寫 zx_clock_t typedef,以及各種 #define 具體化列舉成員。 如果 fuchsia.fonts 程式庫仰賴 zx/clock,這意味著 fidlgen_cpp 必須瞭解 API 合約,才能自行產生 繫結程式碼正確地橋接2程式碼產生和 kazoo

每個平台各有一個程式庫

我們現在並非討論 FIDL 程式庫的多重定義 名稱相同雖然我們不建議這麼做 fuchsia.confusing 程式庫位於原始碼樹狀結構的不同位置,且使用所有 這些不同的程式庫

直接使用平台 ID 都屬於概念 Fuchsia 來源樹狀結構預設為 fuchsia。接著就能保證並強制執行 這個程式庫中不存在任何兩種名稱相似的程式庫定義。

因此,我們將平台稱為 FIDL 的一組平台。 多個程式庫共用同一個平台 ID。

沒有遲交的驗證作業

目前,我們不得選擇性地選擇後端適用的 FIDL 程式庫 不一定成功後端應處理任何有效的 JSON IR。也意味著我們不希望在 後端。您便能在後端新增驗證,將其識別為 表示尚未實作的 FIDL 功能;另一個範例驗證方法是 文件註解在 fidldoc 中的效力,並拒絕產生參考資料 文件。(在這兩個例子中,優雅降級都是正常的)。

允許延遲驗證邀請出門不愉快的旅程 (例如 https://fxbug.dev/42144169):在 FIDL 的世界 程式庫會以 SDK 構件的形式提供,並整合至下游服務 則執行後端的開發人員可能不同於 FIDL 程式庫作者。然後向開發人員提供警告或錯誤。 使用 FIDL 程式庫在更正 FIDL 的情況時 圖書館作者最令人困擾,使用 FIDL 程式庫。

因此,禁止延遲驗證的政策將維持良好的健康狀態 fidlc 編譯器的壓力,用於「驗證所有內容」和後端 「支援一切」這個問題在大部分情況下 因機位成本而損失的情況 (「未驗證 缺乏細微差異

限制來源的存取權

如果不思考長期的後果,我們逐漸允許 以 JSON IR 來複製來源的 FIDL 來源部分。舉例來說 新增複雜的運算式,我們公開已解決 價值 讓後端發出常數,同時保留運算式本身 (文字)雖然運算式文字有助於生成 這樣的做法有助於降低隱私權 的 SDK 發布商 (也就是發布 FIDL 構件的發布商),因為無法 隨時選擇提供來源

您可以輕鬆想像未來的發展方向,這個路徑能導向更多 FIDL 來源 結束於 IR,這並非理想的結果:這既是重複, 可能導致隱私權限制侵害

我們的目標是設計 FIDL 工具鍊,納入僅包含 無從得知適用於需要來源存取權的罕見後端 (例如 fidl-lsp)。 我們需要參照時距的參照前往設計詳細資料 專區

資源調度編譯

為簡單起見,fidlc 編譯器最初設計為 僅限來源,例如 .fidl 檔案。如果程式庫具有依附元件 程式庫編譯需要編譯所有依附元件

舉例來說,在編譯 fuchsia.fonts 程式庫時,我們必須一併編譯 fuchsia.memfuchsia.intl 程式庫,並以此方式遞補這個 意味著現今的編譯作業效率很低包括 fuchsia.mem 會多次重新編譯。這種架構效率不彰 從未發生問題:SDK 中只有超過 64K LoC 的 FIDL 來源 與相對的遞移依附元件相對來說,這種效率不彰 因此不要太覺得帶面了

不過,思考「理想」內容時FIDL 工具鍊,我們希望與 遵循編譯器設計的標準做法編譯器往往會擷取 產生輸出內容 (例如 x86 組合元件),阿斯 隨著程式碼集不斷擴增,編譯器還需要符合其他規定 提供一部分的工作分區,這樣對模型就會進行小幅更新 輸入值不需要重新編譯整個程式碼集。

javac 編譯器為例,如果您變更 某些檔案 SomeCode.java 中的 for 迴圈,可能無所預期 重新編譯數千個檔案以再次執行該程式。而是 只重新編譯單一檔案,就能重複使用所有其他預先編譯過的檔案 來源 (例如 .class 檔案)。

為了成功分區工作,標準方法是定義 編譯單位 (例如 FIDL 的程式庫) 並產生中介結果 (例如 JSON IR),因此編譯程序的輸入內容既是來源 以及直接依附元件的中繼結果您可以藉此限制 依附元件鏈結的總編譯時間 (假設無限平行處理) 編譯最長的延遲時間這也簡化了建構規則,也就是 du jour

設計

設計分為三個部分:

  1. 首先是決定設計選擇的指導原則 並錨定方法和採取的路徑
  2. 標準 FIDL 工具鍊的說明 說明如何根據所有需求分解建構 FIDL 的範例 描述;
  3. 最後,針對 Fuchsia FIDL 進行一些特定的清理。 團隊將根據此 RFC 指南調整核心工具
,瞭解如何調查及移除這項存取權。

指導原則

IR 應能隨時配合常見的後端

雖然開發人員應該盡量使用複雜的後端 (例如確保整個程式 view),則 IR 的設計必須讓共通後端的設計 可以只透過處理中程式庫的單一 IR 來建構。

根據經驗,大部分後端都不太簡單。以簡單為主 相較於專家用途 盡可能簡化 IR 並且這樣的話, 確保後端生態系統蓬勃發展

為了落實這項原則,不妨考慮使用「型別形狀」計算完成 fidlc。您可以選擇將這個項目移至專屬的 percolating 後端。不過,這會強制所有後端 也就是產生目標程式碼 (主要用途) 同時仰賴 IR 和 「輸入形狀」後端。

IR 應該盡量減少

追求基數是能夠輕鬆應對的重要反制措施 但卻可能讓人覺得「把所有事物都納入其中」 並仔細評估完成的工作

為了實踐這項原則,請考量目前在計算 「宣告順序」在「fidlc」中。只有少數後端依賴這個順序 甚至每天都可能產生大量複雜性 編碼器-解碼器架構它還會遮蔽水,大家需要下訂單 常常會令人困惑這個環境也不具彈性,因為後端的目標是要與時俱進 獨立與核心編譯器彼此獨立,這對企業 支援遞迴類型

IR 不得包含來源

IR 不得包含任何立即必要程度所需的來源 且支援通用後端 (例如名稱)。IR 可提供來源時距 參考檔案。來源時距參照是三元組:

(filename, start position, end position)

其中位置是元組 (line number, character number)

後端運作時不應仰賴來源的存取權。當後端必須 對原始碼的運作能力 (例如 fidl-lsp) 而言,開發人員必須清楚說明 並以優雅失敗的方式存取來源,以防萬一。

選擇這個分解時,我們明確選擇提供 SDK 也就是發布 FIDL 構件的發布者,可以選擇納入原始碼 FIDL。目前他們決定並不能完全採用,因為 來源就在 IR 中

除了名稱以外,在 IR 中,來源的重要部分是 說明文件註解。這些 註解的規格是 API 的一部分,例如 FIDL 程式庫 作者明確同意將這些評論設為公開。此外,大多數 後端會使用這些說明文件註解 (例如,在產生的 因此屬於普遍理解的共通點 原則這些說明文件註解 不會在留言中顯示為原始來源,而是經過一些預先處理 (前置縮排,/// 和空白字元已裁剪)。簡要 並探索 ,以利日後進一步處理文件註解。

以相同方式處理後端

FIDL 語言、其實作為 fidlc 編譯器,以及 中繼表示法的定義應設計為允許 包容性後端生態系統,包含所有後端 Fuchsia 專案是否積極踏出第一步。

在選擇這個分隔線時,我們明確地選擇避免 反之,Fchsia FIDL 團隊擁有後端的短期需求會縮短,但 設計上著重在 FIDL 生態系統的長期可行性

後端無法合併

後端必須在處理有效的 IR 時成功。如果後端 環境發生問題 (例如檔案系統存取錯誤) 或發生 IR 的情況 無效。如果後端無法處理符合 IR 結構定義的 IR, 不能因發生錯誤而失敗

在選擇這個分隔線時,我們明確強制要求所有驗證 發生在前端,因此驗證必須提升為 FIDL 語言 第二則是資源限制這麼做有兩個非常重要的理由:

  1. 這項規則的一大特徵是,指定有效的 IR、所有後端都相容 就可以使用這個 IR這代表身為 SDK 發布者 成功編譯 FIDL 程式庫可確保系統使用這些 適用於所有使用 FIDL 工具鍊的消費者程式庫 與發布商使用的廣告相容
  2. 從語言設計的角度來看,這項非常嚴格的規定 強制使用函式確保語言設計符合需求 後端舉例來說,謹慎地要求驗證 導致這個問題發生的原因 (fidl-dev@fuchsia.dev 或透過 RFC) 提供給 Fuchsia FIDL 團隊 規格。這有助於改善語言, 或調整後端可能適合 FIDL 工具鍊原則

如要實現這項原則,請考慮在 Rust 中特徵衍生:Eq 特徵 無法針對含有浮點數的類型衍生。 您嘗試將屬性 @for_rust_has_floats 加入包含 浮點數 (float32float64),然後利用這個引數 以便有條件地發出 Eq 特徵,以及fidlgen_rust 確認屬性已正確使用 (類似於 值資源 )。但 這個誘因就違反該原則,因為其暗示 fidlgen_rust 可能會遇到瓶頸不允許在 fidlc 中驗證這類小眾屬性 因為這會導致 FIDL 受到許多目標語言的複雜影響 問題。3

標準 FIDL 工具鍊

標準 FIDL 工具鍊是以程式庫分解為中心。 會有兩種建構節點

區隔建構節點

「協調節點」是資料庫和物件的程式庫來源和物件檔案。 將程式庫的依附元件直接導向工具,並產生最終結果 目標物件檔案

控制節點

以目前的 fidlgen 後端為例,這些後端採用的模式如下: 是 JSON IR,最終結果會產生程式碼它們並沒有相依關係 物件檔案 (DOF) 或工具會產生目標物件檔案 (TOF)。

另一個例子是預期中的 ABI 數位指紋採集 這項工具需要計算型別的結構屬性。這項工具 使用 JSON IR (來源),並產生 ABI 摘要 (最終結果)。 和隨附的目標物件檔案 (TOF)。如果在支援單調運作的程式庫上運作 具有依附元件,會使用這些程式庫的 TOF,即其 DOF 與 JSON IR 一起產生下一項結果。有時候 最終結果和 TOF 只有的格式不同,第一,做為參考 和其他使用工具剖析的

全檢視建構節點

系統會提供「整個檢視節點」做為來源,包括所有可間接存取的來源 產生最終結果,並產生最終結果。

整個檢視節點

舉例來說,measure-tape 會要求所有的 IR 定義要編譯的類型需要的可連線程式庫 會以整個檢視畫面節點的形式自然表示目前 fidlc 節點的運作方式為 整個檢視節點,因為該節點需要存取所有來源才能運作 (請參閱資源調度 編譯)。fidlcatfidldoc 需要完整的檢視區塊,且依賴於整個設備 平台進行編譯

雖然單一節點的效率不如收合單一節點 我們不希望重新建構所有工具,以簡化作業 而是將複雜性推送至建構系統

在 Fuchsia 來源樹狀結構中,我們產生 all_fidl_json.txt 檔案。 為整體檢視節點制定更明確的需求後, 建構這項匯總作業例如,將這項匯總資料整理成 平台、針對每個程式庫的錄製、JSON IR、 並能直接利用這項匯總資料 產生整個檢視畫面工具所需的輸入內容這些匯總資料 由 fidl-lspfidlbolt 等開發人員工具所使用。

工具選項

特定建構節點中的工具選項應取決於目標 (例如「generate」) 低階 c++ 程式碼」),以及要編譯的程式庫 (例如「library zx」)。 我們會定義使用元組 (目標產生、程式庫) 並傳回 工具 (例如 kazoofidlgen_cpp) 成為 工具鍊。

例如,在 Fuchsia 來源樹狀結構中,我們應預期設定:

(*, library zx) → kazoo
(low_level_cpp, not library zx) → fidlgen_llcpp
(high_level_cpp, not library zx) → fidlgen_hlcpp
(rust, not library zx) → fidlgen_rust
(docs, *) → fidldoc

使用統合式 C++ 繫結、 這項設定會變更為:

(*, library zx) → kazoo
(cpp, not library zx) → fidlgen_cpp
(rust, not library zx) → fidlgen_rust
(docs, *) → fidldoc

對漸進式編譯的影響

評估漸進式編譯時,例如追求最少 將現有編譯過的 含有新編譯成品的構件,這裡說明的兩種節點 有點不同

一般來說,在執行一或多個項目時,必須叫用編譯圖表中的節點 的來源 (也稱為「來源集」) 變更。

與整個檢視畫面節點相比,區隔節點的來源集小很多 來源集為直接「來源」和目標物件檔案 (TOF)儘管如此 這些依附行為 (如有) 都會將來源變更套用到 TOF 變更,而會使相依項目的來源集變更 節點。舉例來說,假設 fidlgen_rust 後端擴充為 也會產生 TOF fuchsia.some.library.fidlgen_rust.tof。使用單一圖書館時 如果 TOF 變更,所有相依程式庫也會需要改用 進行變更,導致對 fidlgen_rust 後端的叫用次數增加 ( 依此類推)。

相較於整理節點,整個檢視節點的來源集更廣。 整個檢視節點可大致分為兩種類別,其取決於所有節點 遞移依附元件 (例如 measure-tape) 和依賴所有依附元件的依附元件 存放在平台上 (例如 fidldoc) 的程式庫因此,任何變更 因此需要叫用這些節點

整體檢視節點的編譯成本增幅是雙倍, 執行節點的頻率變高,且會執行更多工作,因為 資料來源經過些許工作,知名人士說:「 程式設計」-- 任何需要整個視圖的後端皆可進化成 產生交錯的節點要考量這類演變的健康壓力 通常複雜度和維護負擔都很複雜 加快漸進式編譯速度,並可在 畢竟成本至關重要

除了工具鍊本身的編譯增量成本外, 需要多加考量由於大部分工具鍊都會產生原始碼 (例如 C++、Rust 和 Dart),通常會更接近整體建構作業的根層級 所有變更工具鍊輸出內容 (例如變更 產生的 C++ 標頭) 會對下游編譯作業造成重大影響 (例如 所有程式碼)。 因此,應盡量減少對生成來源所做的變更。適用對象 例如,將產生器的輸出結果標準化 (避免變更 非有意義的空白字元),或是比較輸出內容與快取 避免以相同內容覆寫內容 只有時間戳記會改變 (請參閱 GN 輸出內容範例 詳情)。

清理舊版技術債,並避免進一步

按照本文說明的原則,我們會移動 C 繫結和 產生程式碼表格 (共 fidlc 個)將這些兩代嵌入 核心編譯器是因過去的建構小工具而完成。

此外,我們計劃移除「宣告順序」而是將任何 YAML 檔案 以特殊順序排列至特定後端

資源調度編譯中所述,FIDL 編譯器 fidlc 會改為只要求直接輸出的輸出內容,以便將工作分區 依附元件 (可能是 JSON IR 本身),而不是所有依附元件的來源 遞移依附元件

最後,我們會避免累積更多技術債,而是將重心放在 配合本文所述的方向舉例來說 也就是 ABI 數位指紋採集的後端 而不要嵌入核心編譯器

舊版藝術品

將此情況與 C++ 編譯進行比較/對比:C++ 編譯器通常會在 C++ 來源檔案並產生一個物件檔案。最終的程式組裝過程 稱為「連結」的階段,連結器會將所有物件檔案合併為一個二進位檔案 這個做法很有效,因為在單獨編譯一個 C++ 來源檔案時, 編譯器會在其他 C++ 來源中看見關於外部函式的函式宣告 找出目前檔案依附的檔案,透過使用標頭。同樣地 我們目前的 JSON IR 大致提供 關於外程式庫型別的資訊 類似於函式宣告

然而,在進行深入最佳化處理的情況下,這個 C++ 編譯模型明顯不佳 當編譯器只能查看宣告時, 請務必保守函式的實際行為 (例如, 要終止嗎?會改變指標 X 嗎?是否保留指標 Y, 逸出?)。在 FIDL 中也是如此,我們的程式碼生成後端可能 如果能進一步瞭解 參照的外語類型就資源性和來源相容性而言 導致後端無法產生正確結果 程式碼,除非他們知道所有參照的外語類型資源。

為解決這個問題,在 C++ 中,啟動了各種編譯器實作程序 將更多輔助資料插入物件檔案。例如: GCC 和 Clang 自行開發的可序列化 IR 格式,更能傳達 並將這些 C++ 函式的行為與組件一起封裝。 連結器會同時使用組件和 IR,並產生較佳的程式碼 。在 FIDL 中,因為不同的後端 因此若外語知識的 「輔助資料」例如產生後端特定檔案 主要 JSON IR 旁的補充資訊。資源確實是常見現象 以及許多後端所需的屬性但在未來,由 LLCPP 來看, 最好也知道類型是否 物件。 解碼器);Rust 想要判斷型別是否 在更多情況下,浮點值會導出 Eq (不過編譯器保證 來避免來源相容性問題)。

說明文件

此 RFC 做為 FIDL 工具鍊說明文件的參考依據 我們建議和工具鍊作者正確記錄建構規則 因此,使用 Kubernetes Engine 即可。

實作

如先前所述。

成效

不影響效能,這個 RFC 說明瞭需求條件和問題 即使已達成分解,但純粹不一定簡潔。

人體工學

不適用。

回溯相容性

不適用。

安全性考量

無安全性考量。

隱私權注意事項

由於與 IR 的來源更明確區隔,因此隱私權提升幅度。

測試

工具鍊的標準測試。

缺點、替代方案和未知

如文字所示。


  1. 嚴格來說,我們稱之為 FIDL 繫結程式碼產生工具, 支援需要使用產生的程式碼所需的執行階段程式庫 產生的程式碼

  2. C-family fidlgens 不想產生自己的領域物件 針對 zx/clock,請改為選擇#include kazoo。同樣地,Rust Fidlgen 會匯入 zx 繫結 ,而不是根據 kazoo 產生自己的網域物件 有關 zx 程式庫定義的問題

  3. 目前無法證明新增 @has_floats 屬性的正當性 (或 has_float 修飾符),因為唯有 FIDL 是唯一用途 fidlgen_rust,但沒有重大問題。如果這些 例如,有其他幾個後端 PartialEq 個問題 (共 Eq 個),該問題可能會出於合理原因。