教程:绑定库生成代码

bind 库可以自动生成代码,以帮助驱动程序作者参考 绑定库目前,build 将为 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 属性,只需将库名称作为 build 目标名称即可)。 但在这里,我们分别对其进行了定义,以便于以后区分每个变量的用途。

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

build 会根据绑定库的 target_name 自动为我们提供一个新目标, :{target_name}_cpp

在前面的示例中,这是 my_bindlib_target。因此目标为 :my_bindlib_target_cpp

Rust

build 会根据绑定库的 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;

生成的常量

对于绑定库中的每个键,都有一个同名的字符串常量标识符, 而是全部大写该字符串的值将是键的全名。 全名包含绑定库的 library_name 和键名,并且没有 大小写调整,以 . 分隔。

C++

如果在名为 fuchsia.example.library 的库中有一个名为 keyName 的键,则这将是 生成的常量:std::string KEYNAME = "fuchsia.example.library.keyName";

Rust

如果在名为 fuchsia.example.library 的库中有一个名为 keyName 的键,则这将是 生成的常量:pub const KEYNAME: &str = "fuchsia.example.library.keyName";

对于绑定库中为键定义的每个值,都有一个基于类型 键(请参阅下表)。该常量的标识符是 键和值的名称之间用下划线分隔。

例如,如果某个键 foo 为它定义了两个值 barbaz,则有 值的两个标识符:FOO_BARFOO_BAZ

C++

密钥类型 C++ 常量类型 C++ 常量值
uint uint32_t 条目中的整数值
string std::string 条目中的字符串值
bool bool 条目中的布尔值
枚举 std::string 枚举的全名(见下文)

Rust

密钥类型 Rust 常量类型 Rust 常量值
uint u32 条目中的整数值
string &str 条目中的字符串值
bool bool 条目中的布尔值
枚举 &str 枚举的全名(见下文)

枚举的全名包含 library_name、键名和值名称。 全部用 . 分隔。

C++

如果我们库中基于枚举的键 enumeratedKey 下有一个名为 someValue 的值 名为 fuchsia.example.library,则生成的常量将 std::string ENUMERATEDKEY_SOMEVALUE = "fuchsia.example.library.enumeratedKey.someValue";

Rust

如果我们库中基于枚举的键 enumeratedKey 下有一个名为 someValue 的值 名为 fuchsia.example.library,则生成的常量将 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" ]
}

composite-node-specification Creator

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 中自动生成绑定库工件 请参阅 为驱动程序创建新的绑定库