Options file

The size of a repeated, string, bytes or map field is normally set with a custom option in the proto file, as described for repeated fields:

message SensorFrame
{
  repeated int32 samples = 1 [(EmbeddedProto.options).maxLength = 128];
}

A proto file is a shared contract, however. It is used by other languages and other teams, while these options describe one embedded target. When the proto file is not yours to edit, for instance because it comes from a library, you can supply the same options from a JSON file instead. This is possible as of version 4.0.0.

The file

The file mirrors the structure of your messages: the parts of the package, the message names, any nested messages and finally the field. Options are set on a field. Take the following proto file:

package foo.telemetry;

message Reading
{
  string sensor_id = 1;
  repeated double values = 2;
  bytes raw = 3;

  message Meta
  {
    repeated string tags = 1;
  }
}

The options file for it reads:

{
  "foo": {
    "telemetry": {
      "Reading": {
        "sensor_id": { "maxLength": 16 },
        "values":    { "maxLength": 64 },
        "raw":       { "callbackStorage": true },
        "Meta": {
          "tags": { "maxLength": 4, "nestedMaxLength": 12 }
        }
      }
    }
  }
}

A scope may also be written as a dotted path. The line "foo.telemetry.Reading.sensor_id": { "maxLength": 16 } says the same as the nested objects above. Both spellings may be mixed in one file. The file is keyed by package and message, never by file name. It therefore has no relation to where your proto files are, and one file can hold the options of every message in your build.

All options of Embedded Proto can be set this way: maxLength, nestedMaxLength, keyMaxLength, valueMaxLength, customStorage and callbackStorage.

Generating with an options file

Point the plugin at the file with the options_file parameter:

embeddedproto -I LOCATION/PROTO/FILES --eams_out=GENERATED/SRC/DIR --eams_opt=options_file=board_x.options.json PROTO_MESSAGE_FILE.proto

Give --eams_opt more than once to layer files, for instance a base file and one per board. The last file to set an option wins. Protoc also accepts the parameter in front of the output folder, as --eams_out=options_file=board_x.options.json:GENERATED/SRC/DIR. That works too, --eams_opt is just easier to read.

Please note the following rules:

  1. An option in the file wins over the same option written in the proto file. The plugin reports this on the console, so it does not happen unnoticed.
  2. An entry naming a field or message that does not exist is an error. A typo may not quietly leave a buffer at its default size.
  3. Entries for a package that this protoc run does not compile are skipped, so one file can serve several builds.
  4. A file that does not exist is an error, for the same reason as above.

Settings

The same file can carry settings for the generator as a whole. They live under one reserved key, $EmbeddedProtoSetting. A proto identifier cannot start with a dollar sign, so the key never collides with a package name. There is one setting at the moment: the extension of the generated headers, which is .h by default.

{
  "$EmbeddedProtoSetting": { "headerExtension": ".pb.hpp" },

  "foo": {
    "telemetry": { "Reading": { "sensor_id": { "maxLength": 16 } } }
  }
}

The generated file for reading.proto is then called reading.pb.hpp, and a generated file which imports another includes it by that name. The extension must start with a dot. A setting applies to the whole build, so when several files set it, the first file wins and a later file that disagrees is reported. A file holding only settings is fine.