| # Bind library code generation tutorial |
| |
| Bind libraries can auto-generate code to help driver authors refer to items in |
| bind libraries from driver code. Currently the build will produce code for C++ and Rust. |
| This tutorial will go into detail on using these auto-generated code targets. |
| |
| This guide assumes familiarity with the following concepts: |
| |
| * [Driver Bind Rules](/docs/development/drivers/tutorials/bind-rules-tutorial.md) |
| * [Driver Binding](/docs/development/drivers/concepts/device_driver_model/driver-binding.md) |
| |
| ## An example bind library |
| |
| First let's define an example bind library with some different definitions. We will also make it |
| depend on another existing bind library. This is optional but for completeness we'll include it. |
| |
| ### BUILD.gn |
| |
| ```gn {:.devsite-disable-click-to-copy} |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/drivers/bind/bindlib_codegen/BUILD.gn" region_tag="example_bind_lib_target" %} |
| ``` |
| |
| Most of the time the build target name and the library name are the same (it's |
| not necessary to supply the `name` property, just put the library name as the build target name). |
| But here we define them separately to help distinguish where each one is used later on. |
| |
| ### mybindlib.bind |
| |
| ```none {:.devsite-disable-click-to-copy} |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/drivers/bind/bindlib_codegen/mybindlib.bind" %} |
| ``` |
| |
| ## Auto-generated libraries |
| |
| ### The generated build target |
| |
| * {C++} |
| |
| The build will automatically give us a new target based on the `target_name` of the bind library, |
| `:{target_name}_cpp` |
| |
| In our example from earlier this was `my_bindlib_target`. So the target will be |
| `:my_bindlib_target_cpp`. |
| |
| * {Rust} |
| |
| The build will automatically give us a new target based on the `target_name` of the bind library, |
| `:{target_name}_rust` |
| |
| In our example from earlier this was `my_bindlib_target`. So the target will be |
| `:my_bindlib_target_rust`. |
| |
| ### Using the generated library |
| |
| * {C++} |
| |
| This is a `source_set` target that contains a header file with constants generated from the |
| bind library. Driver authors can use this when they are creating node properties. They just need |
| to create a dependency from their executable or other C++ based target on this. |
| |
| The include path and namespace will be based on the `library_name` of the bind library (with |
| some replacements of the `.`s in the library name), |
| `#include <bind/{library_name with slashes}/cpp/bind.h>` and |
| `namespace bind_{library_name with underscores}`. |
| |
| In our example from earlier the `library_name` was `fuchsia.example.library`. So we will have |
| `#include <bind/fuchsia/example/library/cpp/bind.h>` and `namespace bind_fuchsia_example_library`. |
| |
| * {Rust} |
| |
| This is a `rustc_library` target, which is a Rust crate with a root module with constants |
| generated from the bind library. Driver authors can use this when they are creating node |
| properties. They just need to create a dependency from their Rust based targets on this. |
| |
| The crate name to reference in use statements will be based on the `library_name` of the |
| bind library (with some replacements of the `.`s in the library name), |
| `use bind_{library_name with underscores};`. |
| |
| In our example from earlier the `library_name` was `fuchsia.example.library` so we will have |
| `use bind_fuchsia_example_library;`. |
| |
| ### The generated header file |
| |
| * {C++} |
| |
| ```cpp {:.devsite-disable-click-to-copy} |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/drivers/bind/bindlib_codegen/cpp_codegen.h.golden" exclude_regexp="// Copyright.*|// Use of.*|// found in.*" %} |
| ``` |
| |
| * {Rust} |
| |
| ```rust {:.devsite-disable-click-to-copy} |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/drivers/bind/bindlib_codegen/rust_codegen.rs.golden" exclude_regexp="// Copyright.*|// Use of.*|// found in.*" %} |
| ``` |
| |
| ### The generated constants |
| |
| #### Keys |
| |
| For every key in the bind library, there is a string constant identifier of the same name, |
| but in all uppercase. The value of the string will be the full name of the key. |
| The full name contains the `library_name` of the bind library and the key name, with no |
| casing adjustments, separated by a `.`. |
| |
| * {C++} |
| |
| If we have a key called `keyName` in a library called `fuchsia.example.library`, this will be the |
| generated constant: `std::string KEYNAME = "fuchsia.example.library.keyName";`. |
| |
| * {Rust} |
| |
| If we have a key called `keyName` in a library called `fuchsia.example.library`, this will be the |
| generated constant: `pub const KEYNAME: &str = "fuchsia.example.library.keyName";`. |
| |
| #### Values |
| |
| For every value defined for a key in the bind library there is a constant based on the type |
| of the key (see table below). The identifier of the constant is the all uppercase version of |
| the key and value name separated by an underscore. |
| |
| For example if there is a key `foo` with two values defined for it `bar` and `baz`, then there are |
| two identifiers for the values, `FOO_BAR` and `FOO_BAZ`. |
| |
| * {C++} |
| |
| Key type | C++ constant type | C++ constant value |
| -------- | ----------------- | ------------------ |
| uint | uint32_t | Integer value from entry |
| string | std::string | String value from entry |
| bool | bool | Boolean value from entry |
| enum | std::string | Full name of the enum (see below) |
| |
| * {Rust} |
| |
| Key type | Rust constant type | Rust constant value |
| -------- | ------------------ | ------------------ |
| uint | u32 | Integer value from entry |
| string | &str | String value from entry |
| bool | bool | Boolean value from entry |
| enum | &str | Full name of the enum (see below) |
| |
| |
| The full name of an enum contains the `library_name`, key name, and value name, |
| all separated by `.`s. |
| |
| * {C++} |
| |
| If we have a value called `someValue` under a enum based key `enumeratedKey` in our library |
| called `fuchsia.example.library`, then the generated constant will be |
| `std::string ENUMERATEDKEY_SOMEVALUE = "fuchsia.example.library.enumeratedKey.someValue";`. |
| |
| * {Rust} |
| |
| If we have a value called `someValue` under a enum based key `enumeratedKey` in our library |
| called `fuchsia.example.library`, then the generated constant will be |
| `pub const ENUMERATEDKEY_SOMEVALUE: &str = "fuchsia.example.library.enumeratedKey.someValue";`. |
| |
| #### Dependencies |
| |
| * {C++} |
| |
| Because our bind library example depended on `//src/devices/bind/fuchsia.pci`, another bind |
| library, our generated code has automatically included the header generated from that as well. |
| So by including this header, the code can refer to values from the base bind library as well. |
| |
| * {Rust} |
| |
| Because our bind library depended on `//src/devices/bind/fuchsia.pci`, another bind |
| library, our generated code has automatically imported the generated crate from that as well. |
| The difference with the C++ header is that in Rust the user will have to nest the crate names |
| when referring to a dependency crate. See example below for what this looks like. |
| |
| ### Example usage |
| |
| #### BUILD.gn |
| |
| * {C++} |
| |
| ```gn {:.devsite-disable-click-to-copy} |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/drivers/bind/bindlib_codegen/BUILD.gn" region_tag="example_cpp_target" %} |
| ``` |
| |
| * {Rust} |
| |
| ```gn {:.devsite-disable-click-to-copy} |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/drivers/bind/bindlib_codegen/BUILD.gn" region_tag="example_rust_target" %} |
| ``` |
| |
| #### composite-node-specification creator |
| |
| * {C++} |
| |
| ```cpp {:.devsite-disable-click-to-copy} |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/drivers/bind/bindlib_codegen/parent-driver.cc" region_tag="code" %} |
| ``` |
| |
| * {Rust} |
| |
| ```rust {:.devsite-disable-click-to-copy} |
| {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/drivers/bind/bindlib_codegen/parent-driver.rs" region_tag="code" %} |
| ``` |
| |
| ## Auto-generated libraries in the SDK |
| |
| To learn how to auto-generate bind library artifacts in the Fuchsia SDK |
| development environment, see |
| [Create a new bind library for a driver](/docs/development/sdk/create-new-bind-library-for-driver.md). |