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_name
为 fuchsia.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_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 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
为它定义了两个值 bar
和 baz
,则有
值的两个标识符:FOO_BAR
和 FOO_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 中自动生成绑定库工件 请参阅 为驱动程序创建新的绑定库。