繫結程式庫可自動生成程式碼,協助驅動程式庫作者從驅動程式庫程式碼參照繫結程式庫中的項目。目前建構作業會產生 C++ 和 Rust 的程式碼。 本教學課程會詳細說明如何使用這些自動產生的程式碼目標。
本指南假設您熟悉下列概念:
繫結程式庫範例
首先,讓我們定義一個範例繫結程式庫,其中包含一些不同的定義。我們也會讓它依附於另一個現有的繫結程式庫。這是選用項目,但為了完整性,我們還是會加入。
BUILD.gn
bind_library("my_bindlib_target") { # target_name
source = "mybindlib.bind"
name = "fuchsia.example.library" # library_name (optional, defaults to
# target_name)
public_deps = [ "//src/devices/bind/fuchsia.pci" ]
}
在大多數情況下,建構目標名稱和程式庫名稱相同 (不必提供 name 屬性,只要將程式庫名稱做為建構目標名稱即可)。但我們在此分別定義這些項目,有助於區分後續使用位置。
mybindlib.bind
library fuchsia.example.library;
using fuchsia.pci;
string Name;
string DeviceCategory {
KB = "keyboard",
Mouse = "mouse",
};
uint I2C_ADDRESS;
enum I2C_PROTOCOL {
Device,
Impl,
};
bool Flag {
ENABLE = true,
DISABLE = false,
};
extend uint fuchsia.BIND_PCI_VID {
GIZMOTRONICS = 0x314159,
};
自動產生的程式庫
產生的建構目標
C++
建構作業會根據繫結程式庫的 target_name,自動提供新的目標。
:{target_name}_cpp
在先前的範例中,這是 my_bindlib_target。因此目標會是 :my_bindlib_target_cpp。
荒漠油廠
建構作業會根據繫結程式庫的 target_name,自動提供新的目標。
:{target_name}_rust
在先前的範例中,這是 my_bindlib_target。因此目標會是 :my_bindlib_target_rust。
使用產生的程式庫
C++
這是 source_set 目標,內含從繫結程式庫產生的常數標頭檔案。驅動程式作者建立節點屬性時,可以使用這項功能。他們只需要從可執行檔或其他以 C++ 為基礎的目標建立依附元件即可。
包含路徑和命名空間會以繫結程式庫的 library_name 為準 (並替換程式庫名稱中的部分 .),以及 #include <bind/{library_name with slashes}/cpp/bind.h> 和 namespace bind_{library_name with underscores}。
在先前的範例中,library_name 是 fuchsia.example.library。因此我們會有 #include <bind/fuchsia/example/library/cpp/bind.h> 和 namespace bind_fuchsia_example_library。
荒漠油廠
這是 rustc_library 目標,也就是具有根模組的 Rust Crate,其中包含從繫結程式庫產生的常數。驅動程式作者建立節點屬性時,可以使用這個函式。他們只需要從 Rust 目標建立這個目標的依附元件即可。
在 use 陳述式中參照的 Crate 名稱,會以繫結程式庫的 library_name 為準 (並替換程式庫名稱中的部分 .),use bind_{library_name with underscores};。
在先前的範例中,library_name 是 fuchsia.example.library,因此我們會有 use bind_fuchsia_example_library;。
產生的標頭檔案
C++
// WARNING: This file is machine generated by bindc.
#ifndef BIND_FUCHSIA_EXAMPLE_LIBRARY_BINDLIB_
#define BIND_FUCHSIA_EXAMPLE_LIBRARY_BINDLIB_
#include <string>
#include <bind/fuchsia/pci/cpp/bind.h>
namespace bind_fuchsia_example_library {
static const char NAME[] = "fuchsia.example.library.Name";
static const char DEVICECATEGORY[] = "fuchsia.example.library.DeviceCategory";
static const char DEVICECATEGORY_KB[] = "keyboard";
static const char DEVICECATEGORY_MOUSE[] = "mouse";
static const char I2C_ADDRESS[] = "fuchsia.example.library.I2C_ADDRESS";
static const char I2C_PROTOCOL[] = "fuchsia.example.library.I2C_PROTOCOL";
static const char I2C_PROTOCOL_DEVICE[] = "fuchsia.example.library.I2C_PROTOCOL.Device";
static const char I2C_PROTOCOL_IMPL[] = "fuchsia.example.library.I2C_PROTOCOL.Impl";
static const char FLAG[] = "fuchsia.example.library.Flag";
static constexpr bool FLAG_ENABLE = true;
static constexpr bool FLAG_DISABLE = false;
static constexpr uint32_t BIND_PCI_VID_GIZMOTRONICS = 3227993;
} // namespace bind_fuchsia_example_library
#endif // BIND_FUCHSIA_EXAMPLE_LIBRARY_BINDLIB_
荒漠油廠
// WARNING: This file is machine generated by bindc.
pub use bind_fuchsia_pci;
pub const NAME: &str = "fuchsia.example.library.Name";
pub const DEVICECATEGORY: &str = "fuchsia.example.library.DeviceCategory";
pub const DEVICECATEGORY_KB: &str = "keyboard";
pub const DEVICECATEGORY_MOUSE: &str = "mouse";
pub const I2C_ADDRESS: &str = "fuchsia.example.library.I2C_ADDRESS";
pub const I2C_PROTOCOL: &str = "fuchsia.example.library.I2C_PROTOCOL";
pub const I2C_PROTOCOL_DEVICE: &str = "fuchsia.example.library.I2C_PROTOCOL.Device";
pub const I2C_PROTOCOL_IMPL: &str = "fuchsia.example.library.I2C_PROTOCOL.Impl";
pub const FLAG: &str = "fuchsia.example.library.Flag";
pub const FLAG_ENABLE: bool = true;
pub const FLAG_DISABLE: bool = false;
pub const BIND_PCI_VID_GIZMOTRONICS: u32 = 3227993;
產生的常數
鍵
繫結程式庫中的每個鍵都有一個名稱相同但全為大寫的字串常數 ID。字串的值會是金鑰的完整名稱。
完整名稱包含繫結程式庫的 library_name 和金鑰名稱,且不調整大小寫,並以 . 分隔。
C++
如果我們在名為 fuchsia.example.library 的程式庫中有名為 keyName 的鍵,則產生的常數會是 std::string KEYNAME = "fuchsia.example.library.keyName";。
荒漠油廠
如果我們在名為 fuchsia.example.library 的程式庫中有名為 keyName 的鍵,則產生的常數會是 pub const KEYNAME: &str = "fuchsia.example.library.keyName";。
值
針對繫結程式庫中為鍵定義的每個值,都有一個常數 (根據鍵的類型,請參閱下表)。常數的 ID 是以全大寫形式表示的鍵和值名稱,並以底線分隔。
舉例來說,如果有一個鍵 foo,並為其定義兩個值 bar 和 baz,則這兩個值會分別有 FOO_BAR 和 FOO_BAZ 兩個 ID。
C++
| 金鑰類型 | C++ 常數型別 | C++ 常數值 |
|---|---|---|
| uint | uint32_t | 輸入的整數值 |
| string | std::string | 項目中的字串值 |
| bool | bool | 項目的布林值 |
| enum | std::string | 列舉的全名 (請參閱下文) |
荒漠油廠
| 金鑰類型 | Rust 常數類型 | Rust 常數值 |
|---|---|---|
| uint | u32 | 輸入的整數值 |
| string | &str | 項目中的字串值 |
| bool | bool | 項目的布林值 |
| enum | &str | 列舉的全名 (請參閱下文) |
列舉的完整名稱包含 library_name、鍵名和值名,並以 . 分隔。
C++
如果程式庫 (稱為 fuchsia.example.library) 的列舉型鍵 enumeratedKey 下有名為 someValue 的值,則產生的常數會是 std::string ENUMERATEDKEY_SOMEVALUE = "fuchsia.example.library.enumeratedKey.someValue";。
荒漠油廠
如果程式庫 (稱為 fuchsia.example.library) 的列舉型鍵 enumeratedKey 下有名為 someValue 的值,則產生的常數會是 pub const ENUMERATEDKEY_SOMEVALUE: &str = "fuchsia.example.library.enumeratedKey.someValue";。
依附元件
C++
由於我們的繫結程式庫範例依附於 //src/devices/bind/fuchsia.pci (另一個繫結程式庫),因此產生的程式碼也會自動納入從該程式庫產生的標頭。因此,只要加入這個標頭,程式碼也能參照基本繫結程式庫中的值。
荒漠油廠
由於繫結程式庫依附於另一個繫結程式庫 //src/devices/bind/fuchsia.pci,因此產生的程式碼也會自動從該程式庫匯入產生的 Crate。與 C++ 標頭不同的是,在 Rust 中,使用者參照依附元件 Crate 時,必須巢狀化 Crate 名稱。請參閱下方的範例。
使用範例
BUILD.gn
C++
source_set("parent_cpp_code") {
sources = [ "parent-driver.cc" ]
deps = [ ":my_bindlib_target_cpp" ]
}
荒漠油廠
rustc_binary("parent_rust_code") {
edition = "2024"
source_root = "parent-driver.rs"
sources = [ "parent-driver.rs" ]
deps = [ ":my_bindlib_target_rust" ]
}
複合節點規格建立器
C++
#include <bind/fuchsia/example/library/cpp/bind.h>
std::string a = bind_fuchsia_example_library::NAME;
uint32_t b = bind_fuchsia_example_library::BIND_PCI_VID_GIZMOTRONICS;
uint32_t c = bind_fuchsia_pci::BIND_PROTOCOL_DEVICE;
荒漠油廠
use bind_fuchsia_example_library::bind_fuchsia_pci;
fn main() {
let _a: &str = bind_fuchsia_example_library::NAME;
let _b: u32 = bind_fuchsia_example_library::BIND_PCI_VID_GIZMOTRONICS;
let _c: u32 = bind_fuchsia_pci::BIND_PROTOCOL_DEVICE;
}
SDK 中自動產生的程式庫
如要瞭解如何在 Fuchsia SDK 開發環境中自動產生繫結程式庫構件,請參閱「為驅動程式建立新的繫結程式庫」。