繫結程式庫程式碼的教學課程

繫結程式庫可自動產生程式碼,協助驅動程式庫作者透過驅動程式庫程式碼參照繫結程式庫中的項目。目前建構作業會產生 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

Rust

建構作業會根據繫結程式庫的 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_namefuchsia.example.library。因此我們有 #include <bind/fuchsia/example/library/cpp/bind.h>namespace bind_fuchsia_example_library

Rust

這是 rustc_library 目標,是具有根模組的 Rust Crate,當中包含由繫結程式庫產生的常數。驅動程式作者可在建立節點屬性時使用。他們只需要從其 Rust 目標建立依附元件即可。

使用陳述式中要參照的 Crate 名稱將根據繫結程式庫的 library_name (部分取代程式庫名稱中的 .) use bind_{library_name with underscores};

在先前範例中,library_namefuchsia.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 std::string NAME = "fuchsia.example.library.Name";

static const std::string DEVICECATEGORY = "fuchsia.example.library.DeviceCategory";
static const std::string DEVICECATEGORY_KB = "keyboard";
static const std::string DEVICECATEGORY_MOUSE = "mouse";

static const std::string I2C_ADDRESS = "fuchsia.example.library.I2C_ADDRESS";

static const std::string I2C_PROTOCOL = "fuchsia.example.library.I2C_PROTOCOL";
static const std::string I2C_PROTOCOL_DEVICE = "fuchsia.example.library.I2C_PROTOCOL.Device";
static const std::string I2C_PROTOCOL_IMPL = "fuchsia.example.library.I2C_PROTOCOL.Impl";

static const std::string 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_

Rust


// 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++

如果程式庫中有名為 keyName 的金鑰,則產生的常數如下:std::string KEYNAME = "fuchsia.example.library.keyName";fuchsia.example.library

Rust

如果程式庫中有名為 keyName 的金鑰,則產生的常數如下:pub const KEYNAME: &str = "fuchsia.example.library.keyName";fuchsia.example.library

針對在繫結程式庫中為某個鍵定義的每個值,每個鍵都會有一個以索引鍵類型為基礎的常數 (如下表所示)。常數 ID 是鍵和值名稱的所有大寫版本,並以底線分隔。

舉例來說,如果索引鍵 foo 已為 barbaz 定義兩個值,則值 FOO_BARFOO_BAZ 有兩個 ID。

C++

金鑰類型 C++ 常數類型 C++ 常數值
紫光 uint32_t 項目中的整數值
string std::string 項目的字串值
bool bool 項目的布林值
列舉 std::string 列舉的全名 (請見下方)

Rust

金鑰類型 Rust 常數類型 Rust 常數值
紫光 u32 項目中的整數值
string &str 項目的字串值
bool bool 項目的布林值
列舉 &str 列舉的全名 (請見下方)

列舉的全名包含 library_name、鍵名稱和值名稱,並以 . 分隔。

C++

如果我們在程式庫中名為 fuchsia.example.library 的列舉型索引鍵 enumeratedKey 底下有名為 someValue 的值,則產生的常數將會是 std::string ENUMERATEDKEY_SOMEVALUE = "fuchsia.example.library.enumeratedKey.someValue";

Rust

如果我們在程式庫中名為 fuchsia.example.library 的列舉型索引鍵 enumeratedKey 底下有名為 someValue 的值,則產生的常數將會是 pub const ENUMERATEDKEY_SOMEVALUE: &str = "fuchsia.example.library.enumeratedKey.someValue";

依附元件

C++

由於繫結程式庫範例依附於 //src/devices/bind/fuchsia.pci (另一個繫結程式庫),因此我們產生的程式碼也已自動納入從該程式庫產生的標頭。因此,只要加入這個標頭,程式碼也可參照基本繫結程式庫的值。

Rust

由於繫結程式庫依附於 //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" ]
}

Rust

rustc_binary("parent_rust_code") {
  edition = "2021"
  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;

Rust

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 開發環境中自動產生繫結程式庫構件,請參閱「為驅動程式建立新的繫結程式庫」。