-
Notifications
You must be signed in to change notification settings - Fork 0
Code Generation
Protocyte is a protoc plugin. It accepts protobuf source descriptors and emits C++20 headers and translation units.
For most C++ projects, let the CMake integration own generation. Invoke protoc directly when another build system owns the generated files, when inspecting plugin behavior, or when producing checked-in output intentionally.
| Workflow | Recommended use |
|---|---|
protocyte_add_proto_library() |
Generate and compile a reusable CMake target |
protocyte_add_descriptor_set_library() |
Generate a CMake target from a descriptor set |
protocyte_generate() |
Integrate generation into custom CMake target logic |
Direct protoc
|
Non-CMake builds, inspection, or intentionally checked-in output |
Protocyte requires Python 3.12 or newer.
From a Protocyte checkout:
uv sync
$env:PATH = "$PWD\.venv\Scripts;$env:PATH"uv sync
export PATH="$PWD/.venv/bin:$PATH"Verify the command:
protoc-gen-protocyte --version
protoc-gen-protocyte --helpCMake consumers normally do not need this step. The CMake package provisions an isolated plugin environment automatically unless PROTOCYTE_PLUGIN_EXECUTABLE is supplied.
Schemas using Protocyte extensions must make protocyte/options.proto visible to protoc.
From a source checkout, its import root is:
src/protocyte/proto
From an installed Python package, locate it with:
python -c "from pathlib import Path; import protocyte; print((Path(protocyte.__file__).resolve().parent / 'proto').as_posix())"An installed CMake package exposes:
PROTOCYTE_PROTO_DIR
PROTOCYTE_OPTIONS_PROTOA schema that does not import Protocyte extensions does not need this additional import root.
Assume this layout:
project/
|-- proto/
| `-- reading.proto
`-- generated/
The output directory must exist before protoc runs.
New-Item -ItemType Directory -Force generated | Out-Null
protoc `
--proto_path=proto `
--protocyte_out=runtime=emit:generated `
proto/reading.protomkdir -p generated
protoc \
--proto_path=proto \
--protocyte_out=runtime=emit:generated \
proto/reading.protoWhen the schema imports protocyte/options.proto, add its import root:
--proto_path=/path/to/protocyte/protoprotoc locates protoc-gen-protocyte on PATH. Select another executable explicitly when needed:
--plugin=protoc-gen-protocyte=/path/to/protoc-gen-protocyteFor a virtual descriptor named reading.proto, Protocyte emits:
reading.protocyte.hpp
reading.protocyte.cpp
With runtime=emit, it also emits:
protocyte/runtime/runtime.hpp
Compile the generated .cpp file and add the generation root to the target's include directories.
Use runtime=omit when the application supplies the runtime header through an installed or reusable CMake target. Direct invocations commonly use runtime=emit so the generated tree is self-contained.
Simple parameters can be placed in the combined --protocyte_out=<parameters>:<directory> form:
--protocyte_out=runtime=emit:generatedUse --protocyte_opt when parameter values contain colons or when several settings are easier to read separately:
protoc `
--proto_path=proto `
--protocyte_out=generated `
--protocyte_opt=runtime=emit:vendor/protocyte,namespace_prefix=mycorp::wire,include_prefix=generated `
proto/reading.protoprotoc \
--proto_path=proto \
--protocyte_out=generated \
--protocyte_opt=runtime=emit:vendor/protocyte,namespace_prefix=mycorp::wire,include_prefix=generated \
proto/reading.protoprotoc treats the first colon in the combined output form as the parameter/output separator. Keeping colon-valued options in --protocyte_opt prevents a prefix from being mistaken for the output directory.
See Plugin Parameters for all supported settings.
Use a descriptor set when .proto source files are not the generation authority:
New-Item -ItemType Directory -Force generated | Out-Null
protoc `
--descriptor_set_in=descriptor_set.pb `
--plugin=protoc-gen-protocyte=path\to\protoc-gen-protocyte.exe `
--protocyte_out=runtime=emit:generated `
core.proto messages.proto settings.protomkdir -p generated
protoc \
--descriptor_set_in=descriptor_set.pb \
--plugin=protoc-gen-protocyte="$(command -v protoc-gen-protocyte)" \
--protocyte_out=runtime=emit:generated \
core.proto messages.proto settings.protoThe trailing names are virtual descriptors inside descriptor_set.pb, not host filesystem paths.
Imported descriptors remain available for type and custom-option resolution, but Protocyte emits code only for descriptors selected for generation and any required runtime message or enum types.
List the descriptors Protocyte can discover:
protoc-gen-protocyte descriptor-set list descriptor_set.pbThe command uses the same generator environment as descriptor-set DISCOVER in CMake.
Unsupported descriptors may remain dependency-only when generated fields do not require their message or enum types. Discovery reports a targeted error when a selected type depends on a descriptor Protocyte cannot generate.
Generated C++ documentation requires protobuf source information.
When producing a descriptor set, pass:
--include_source_infoDescriptor sets without source information remain valid, but Protocyte cannot reproduce their source comments as generated C++ documentation.
Source-mode protoc invocations receive source information directly.
The recommended target-oriented source flow is:
protocyte_add_proto_library(
TARGET application_proto
ALIAS application::proto
PROTO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/proto"
DISCOVER
HOSTED_ALLOCATOR
)CMake tracks:
- selected schemas;
- transitive imports;
- changes in discovered source membership;
- generator and runtime support files;
- the selected plugin and protobuf compiler;
- declared generated outputs.
Changing an existing schema or import regenerates affected files. With DISCOVER, adding or removing a .proto file also causes reconfiguration.
Use explicit PROTOS when the selected set should remain fixed.
See the CMake API Reference for lower-level generation and output variables.
Protobuf descriptor names are portable virtual paths, not necessarily valid host paths.
Protocyte preserves ordinary segments and escapes nonportable UTF-8 bytes as ~HH:
api/bad"name.proto -> api/bad~22name.protocyte.hpp
a:b.proto -> a~3Ab.protocyte.hpp
A literal ~ is escaped as well, preventing aliases between original and escaped names. Semicolons become ~3B, so generated paths remain safe inside CMake lists.
If a path component would exceed a common 255-byte filesystem limit, Protocyte retains a readable prefix and appends a SHA-256 digest. Visual Studio builds also compact complete paths when necessary to remain within legacy MSBuild source-item limits.
Protocyte rejects:
- descriptor names beginning with
-, becauseprotocinterprets them as options; - distinct names whose generated paths differ only by letter case;
- carriage returns or line feeds in descriptor names or CMake tool/source/output paths;
- generated output collisions between separately selected descriptors.
The collision checks are portable even on a case-sensitive host.
CMake-launched generation and dependency scans use protoc UTF-8 response files.
Spaces, non-ASCII characters, quotes, semicolons, and portable colons remain literal arguments on Windows and POSIX. Newlines are rejected because the response-file format has no escaping for line breaks.
Direct non-CMake integrations are responsible for preserving the same argument boundaries.
For checked-in or release-generated output:
- pin the Protocyte revision;
- pin or record the protobuf compiler version;
- use explicit plugin parameters;
- keep formatter configuration under version control;
- regenerate every output with the same command;
- compile and test the generated sources;
- review the generated diff.
Protocyte is pre-1.0. Regenerate all checked outputs when changing versions rather than relying on migration shims.
Repository · Releases · Issues · Apache License 2.0
Canonical source: docs/wiki/