Skip to content

Latest commit

 

History

History
237 lines (193 loc) · 7.39 KB

File metadata and controls

237 lines (193 loc) · 7.39 KB

protoc-gen-prost-crate

A protoc plugin that generates Cargo crates and include files.

When used in projects that use only Rust code, the preferred mechanism for generating protobuf definitions with Prost! is to use prost-build from within a build.rs file. However, when working in polyglot environments, it can be advantageous to utilize common tooling in the Protocol Buffers ecosystem. One common tool used for this purpose is buf, which simplifies the code generation process and includes several useful features, including linting, package management, and breaking change detection.

Usage

Ensure that protoc-gen-prost-crate has been installed within a directory on your $PATH. Then invoke protoc from the command line as follows:

protoc --prost-crate_out=proto/gen -I proto proto/greeter/v1/greeter.proto

Options

The following options can be specified:

  • default_package_filename=<value>: This should match the value of the main protoc-gen-prost step so that the include file references the correct output file. (see also default package filename from prost-build)
  • include_file(=<value>): Sets the name for the generated include file. If not specified, then the default value depends on whether gen_crate is specified. If it is, then <value> defaults to src/lib.rs. Otherwise, it defaults to mod.rs. The generated include file will add feature markers to each produced module to allow for faster compilation and reduced sizes for unnecessary features. This can be disabled by specifying no_features.
  • only_include=<proto_path>: Will only include packages with the specified prefix in the generated include file and generated features list, if enabled. Paths must be fully-qualified and begin with ..
  • gen_crate(=<template_path>): Indicates that a Cargo crate should be generated with the manifest based on the template at the path provided. The template should include a placeholder to inject the crate features graph unless no_features is specified. The template generation does not take into account crate dependencies. These must be managed separately. If not specified, Cargo.toml is assumed. This allows automatic updating of the features in the Cargo manifest.
  • no_features(=<boolean>): Disables the generation of feature flags in the include file or in the Cargo manifest.
  • package_separator=[-_.+]: Changes the character used to separate parts of a package name when used as a feature flag. Defaults to - if not specified. Note: . results in feature names that are not legal for publishing to crates.io.

A note on parameter values:

  • (=<boolean>): Boolean values may be specified after a parameter, but if not, the value is assumed to be true by virtue of having listed the parameter.

Usage with buf

When used with buf, options can be specified in the buf.gen.yaml file. This plugin must be run with strategy: all in order to have a complete view of the protobuf schemas and correctly identify dependencies for the input files.

The following will just produce an include file mod.rs in the output gen directory without any conditional compilation feature flags:

version: v1
plugins:
  - plugin: prost-crate
    out: gen
    strategy: all
    opt:
      - no_features

When using the gen_crate option, later Rust generators should generate into the src directory which will be created by this plugin:

version: v1
plugins:
  - plugin: prost
    out: gen/src
    opt:
      - bytes=.
      - file_descriptor_set
  - plugin: prost-crate
    out: gen
    strategy: all
    opt:
      - gen_crate

When working with private, vendored package dependencies, buf tends to push more files for output than desired. To limit the packages that get put into the include file, used the only_include option:

version: v1
plugins:
  - plugin: prost
    out: gen/src
    opt:
      - bytes=.
      - file_descriptor_set
  - plugin: prost-crate
    out: gen
    strategy: all
    opt:
      - gen_crate
      - only_include=.my_company

The protoc-gen-prost-crate plugin is also published on the Buf Schema Registry as a plugin which you can execute remotely, without needing to explicitly install this tool. See the plugin listing to identify the latest published version for use. Note that the remote plugin form is not compatible with the gen_crate option, as the plugin is executed outside the context of the current file system, so template information cannot be used. The plugin is referenced as follows:

version: v1
plugins:
  - plugin: buf.build/community/neoeinstein-prost-crate:v0.3.1
    out: gen

Cargo manifest template

When using the gen_crate option, the template specified will be placed in the output folder. The template should include a commented insertion point that can be referenced for the placement of the features dependency graph. The template will be Cargo.toml by default, and will do an in-place update of the Cargo.toml file, updating the exposed features to match the generated code.

protoc will insert the computed dependency graph above the insertion point. If this commented line is not included, then protoc will not know where to place the features list and the insertion will be silently skipped.

[package]
name = "my-cool-proto-defs"
version = "0.1.0"
edition = "2021"

[dependencies]
prost = "0.10.0"

[features]
default = []
## @@protoc_insertion_point(features)

Once generated, the manifest will include a set of features that allow limiting the compilation to only those modules that are required. Each feature will automatically activate the relevant features required.

[package]
name = "my-cool-proto-defs"
version = "0.1.0"
edition = "2021"

[dependencies]
prost = "0.10.0"

[features]
default = []
## @@protoc_deletion_point(features)
## This section is automatically generated by protoc-gen-prost-crate. 
## Changes in this area may be lost on regeneration.
proto_full = ["helloworld-v1", "greeter-v1"]
"greeter-v1" = ["helloworld-v1"]
"helloworld-v1" = []
## @@protoc_insertion_point(features)

Customizing after generation

In general, I counsel against manually editing the generated code files. Doing so makes it more difficult to evolve your schema, as regenerating the code will result in needing to manually edit again in order to re-add the customizations. Instead, I recommend using a subdirectory to host the generated code and include that file in src/lib.rs as in the build-with-buf example.

src/lib.rs:

include!("gen/mod.rs");

// Any additional traits or other impls can go here or in other related files.
// These won't be touched by the code generation process.

Cargo.toml (prior to first generation):

[package]
name = "my-cool-proto-defs"
version = "0.1.0"
edition = "2021"

[features]
default = ["proto_full"]
## @@protoc_insertion_point(features)

[dependencies]
prost = "0.10.0"

buf.gen.yaml:

version: v1
plugins:
  - plugin: prost
    out: src
    opt:
      - bytes=.
      - file_descriptor_set
  - plugin: prost-crate
    out: gen
    strategy: all
    opt:
      - include_file=src/gen/mod.rs
      - gen_crate