Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mavlink-codegen documentaion #249

Merged
merged 6 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion mavlink-bindgen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ version = "0.13.1"
edition = "2021"
license = "MIT/Apache-2.0"
description = "Library used by rust-mavlink."
readme = "../README.md"
readme = "README.md"
repository = "https://github.com/mavlink/rust-mavlink"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
98 changes: 98 additions & 0 deletions mavlink-bindgen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# mavlink-bindgen

[![Build status](https://github.com/mavlink/rust-mavlink/actions/workflows/test.yml/badge.svg)](https://github.com/mavlink/rust-mavlink/actions/workflows/test.yml)
[![Crate info](https://img.shields.io/crates/v/mavlink-bindgen.svg)](https://crates.io/crates/mavlink-bindgen)
[![Documentation](https://docs.rs/mavlink-bindgen/badge.svg)](https://docs.rs/mavlink-bindgen)

Library and CLI for generating code for the Rust implementation of the [MAVLink](https://mavlink.io/en) UAV messaging protocol.

`mavlink-bindgen` can be used to create MAVLink bindings for Rust. This is used from `build.rs` in the [mavlink](https://crates.io/crates/mavlink) crate to create bindings from the standard MAVLink dialects in <https://github.com/mavlink/mavlink>.

## Usage

`mavlink-bindgen` can be used as a code generator from `build.rs` as done is the `mavlink` crate for a custom MAVLink dialect or as a CLI tool to generate rust binding from XML dialect definitions. The generated code will depend on the [mavlink-core](https://crates.io/crates/mavlink-core) crate in both use cases. Each dialect generated will be locked behind a feature flag of the same name, that must be enabled when using the generated code.

### CLI

Build the binary using cargo with `cli` feature enabled:

```shell
cd mavlink-bindgen
cargo build --features cli
```

Alternatively you can build and install `mavlink-bindgen` to your locally installed crates:

```shell
cargo install mavlink-bindgen --features cli
```

To generate code using the resulting binary:

```shell
mavlink-bindgen --format-generated-code message_definitions mavlink_dialects
```

The full command line options are shown below.

```shell
Usage: mavlink-bindgen [OPTIONS] <DEFINITIONS_DIR> <DESTINATION_DIR>

Arguments:
<DEFINITIONS_DIR> Path to the directory containing the MAVLink dialect definitions
<DESTINATION_DIR> Path to the directory where the code is generated into, must already exist

Options:
--format-generated-code format code generated code
--emit-cargo-build-messages prints cargo build message indicating when the code has to be rebuild
-h, --help Print help
```

The output dir will contain a `mod.rs` file with each dialect in its own file locked behind a feature flag.

### Library as build dependency

Add to your Cargo.toml:

```toml
mavlink-bindgen = "0.13.1"
```

Add a `build/main.rs` or `build.rs` to your project if it does not already exist. Then add the following to the `main` function to generate the code:

```rs
let out_dir = env::var("OUT_DIR").unwrap();
let result = match mavlink_bindgen::generate(definitions_dir, out_dir) {
Ok(r) => r,
Err(e) => {
eprintln!("{e}");
return ExitCode::FAILURE;
}
};
```

If the generated code should be formated use

```rs
mavlink_bindgen::format_generated_code(&result);
```

To tell cargo when to regenerate code from the definitions use:

```rs
mavlink_bindgen::emit_cargo_build_messages(&result);
```

Finally include the generated code into the `lib.rs` or `main.rs` :

```rs
#![cfg_attr(not(feature = "std"), no_std)]
// include generate definitions
include!(concat!(env!("OUT_DIR"), "/mod.rs"));

pub use mavlink_core::*;
```

Since each dialect is locked behind a feature flag these need to be enabled for the dialects to become available when using the generated code.

This approach is used by the `mavlink` crate see its build script for an example.
5 changes: 5 additions & 0 deletions mavlink-bindgen/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ use clap::Parser;
use mavlink_bindgen::{emit_cargo_build_messages, format_generated_code, generate, BindGenError};

#[derive(Parser)]
/// Generate Rust bindings from MAVLink message dialect XML files.
struct Cli {
/// Path to the directory containing the MAVLink dialect definitions.
definitions_dir: PathBuf,
/// Path to the directory where the code is generated into, must already exist.
destination_dir: PathBuf,
/// format code generated code
#[arg(long)]
format_generated_code: bool,
/// prints cargo build messages indicating when the code has to be rebuild
#[arg(long)]
emit_cargo_build_messages: bool,
}
Expand Down
2 changes: 1 addition & 1 deletion mavlink-bindgen/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub enum BindGenError {
source: std::io::Error,
path: std::path::PathBuf,
},
/// Represents a failure to read the MAVLink definitions directory.
/// Represents a failure to read a MAVLink definition file.
#[error("Could not read definition file {path}: {source}")]
CouldNotReadDefinitionFile {
source: std::io::Error,
Expand Down
5 changes: 5 additions & 0 deletions mavlink-bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
pub mod_rs: PathBuf,
}

/// Generate Rust MAVLink dialect binding for dialects present in `definitions_dir` into `destination_dir`.
///
/// If successful returns paths of generated bindings linked to their dialect definitions files.
pub fn generate<P1: AsRef<Path>, P2: AsRef<Path>>(
definitions_dir: P1,
destination_dir: P2,
Expand All @@ -36,7 +39,7 @@
) -> Result<GeneratedBindings, BindGenError> {
let mut bindings = vec![];

for entry_maybe in read_dir(&definitions_dir).map_err(|source| {

Check warning on line 42 in mavlink-bindgen/src/lib.rs

View workflow job for this annotation

GitHub Actions / linting

the borrowed expression implements the required traits

warning: the borrowed expression implements the required traits --> mavlink-bindgen/src/lib.rs:42:33 | 42 | for entry_maybe in read_dir(&definitions_dir).map_err(|source| { | ^^^^^^^^^^^^^^^^ help: change this to: `definitions_dir` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrows_for_generic_args = note: `#[warn(clippy::needless_borrows_for_generic_args)]` on by default
BindGenError::CouldNotReadDefinitionsDirectory {
source,
path: definitions_dir.to_path_buf(),
Expand Down Expand Up @@ -64,7 +67,7 @@
})?);

// generate code
parser::generate(&definitions_dir, &definition_file, &mut outf)?;

Check warning on line 70 in mavlink-bindgen/src/lib.rs

View workflow job for this annotation

GitHub Actions / linting

this expression creates a reference which is immediately dereferenced by the compiler

warning: this expression creates a reference which is immediately dereferenced by the compiler --> mavlink-bindgen/src/lib.rs:70:26 | 70 | parser::generate(&definitions_dir, &definition_file, &mut outf)?; | ^^^^^^^^^^^^^^^^ help: change this to: `definitions_dir` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `#[warn(clippy::needless_borrow)]` on by default

bindings.push(GeneratedBinding {
module_name,
Expand Down Expand Up @@ -99,6 +102,7 @@
}
}

/// Formats generated code using `rustfmt`.
pub fn format_generated_code(result: &GeneratedBindings) {
if let Err(error) = Command::new("rustfmt")
.args(
Expand All @@ -114,6 +118,7 @@
}
}

/// Prints definitions for cargo that describe which files the generated code depends on, indicating when it has to be regenerated.
pub fn emit_cargo_build_messages(result: &GeneratedBindings) {
for binding in &result.bindings {
// Re-run build if definition file changes
Expand Down
Loading