Crate tighterror_build

source ·
Expand description

tighterror-build is a library implementing the tighterror specification file parsing, processing and Rust code generation.

This library is part of the tighterror framework.

A project that uses the tighterror framework doesn’t need to have tighterror-build in its [dependencies]. This library is at most a build-dependency of the project, not required at runtime (unless the project implements a tool similar to cargo-tighterror).

tighterror-build itself uses the tighterror framework. The errors module is a good example of how the end result looks like.

The following sections compare two main ways to use tighterror-build.

§cargo-tighterror

The recommended way to use the library is through the framework’s cargo plugin cargo-tighterror. The plugin is a thin wrapper around tighterror-build exposing its capabilities on the command-line.

The benefits of this approach are:

  • tighterror Rust code is generated before a project is being built.
  • The generated Rust code can be reviewed.
  • The generated Rust code can be placed under source control to track changes.

The downsides of this approach are:

  • It requires external means to keep the tighterror specification file and the build artifacts in sync.
  • The sync needs to be done not only when the specification file changes, but also when tighterror-build version changes. Hence, the plugin is required to be periodically upgraded to follow the releases of tighterror-build.

Although the build artifacts’ sync can be tricky to solve automatically, in our opinion, having the generated code reviewable and under source control outweighs the cost.

See tighterror documentation for more information about the plugin.

§build.rs

In cases where using the cargo plugin is inconvenient or impossible tighterror-build can be used in [build-dependencies] of a project, i.e., from a build script.

The main (and pretty strong) benefit of this approach is that keeping the tighterror specification file and the build artifacts in sync is fully automated, both when the specification file changes and when tighterror-build version changes.

The downsides of this approach are:

  • tighterror Rust code is generated during the project build stage.
  • The build artifacts are placed in a temporary directory. This makes it hard to review the code.
  • The build artifacts aren’t versioned. This makes tracking of changes practically impossible, which is a big downside because the changes may be caused not only by specification (which itself is under source control), but also by an upgrade to a newer tighterror-build version.

tighterror-build tries to minimize the amount of changes not caused by specification file change. That said, especially in the early stages of framework’s development, such changes may occur.

§Example

Assuming there is a specification file tighterror.yaml in the root directory of a project, tighterror-build can be invoked from project’s build script as follows:

// build.rs
use tighterror_build::CodegenOptions;

fn tighterror_codegen() {
    println!("cargo:rerun-if-changed=tighterror.yaml");
    let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR isn't defined");
    let out_path = format!("{out_dir}/errors.rs");
    if let Err(e) = CodegenOptions::new().output(out_path).codegen() {
        panic!("tighterror-build failed: {e}; out_dir: {out_dir}");
    }
}

fn main() {
    env_logger::builder().init();
    tighterror_codegen();
}

Notes

  1. It is recommended to initialize some kind of logger in the build script because tighterror-build uses the log crate and in case of an error a detailed error description is traced. In the example above we used env_logger to trace to stderr.
  2. cargo takes care of rebuilding and rerunning the script when [build-dependencies] change, i.e., when tighterror-build version changes. To tell cargo that the specification file also affects the build we print the cargo:rerun-if-changed=tighterror.yaml instruction.

To use the generated code include the module somewhere in the project’s operational code, e.g., lib.rs or main.rs, as follows:

pub mod errors {
    include!(concat!(env!("OUT_DIR"), "/errors.rs"));
}

See CodegenOptions documentation for the full list of configurable attributes.

Modules§

Structs§

Constants§

Functions§

  • Generates Rust source code from a specification file.