Skip to content

CLI Reference

The wirespec compiler is invoked from the command line:

bash
wirespec <command> [options]

wirespec compile

Compiles one or more .wspec files to the target language.

Usage:

bash
wirespec compile <file> [options]

Options:

FlagDescription
-o, --output DIROutput directory for generated files (default: build)
-t, --target c|rustTarget language (default: c). Use rust to generate a .rs file instead of .h/.c.
-I, --include-path DIRAdditional search path for resolving imports (repeatable)
--recursiveCompile all transitive dependencies discovered via imports
--fuzzGenerate a libFuzzer harness alongside the normal output (C target only)

Examples:

Compile a single file:

bash
wirespec compile examples/quic/varint.wspec -o build/

Compile with import resolution across a directory tree:

bash
wirespec compile examples/quic/frames.wspec -I examples/ --recursive -o build/

Compile to Rust:

bash
wirespec compile examples/quic/varint.wspec -t rust -o build/

Compile and generate a libFuzzer harness:

bash
wirespec compile examples/quic/frames.wspec -t c --fuzz -o build/

Output files:

For a module named quic.frames compiled to C (the default), the following files are emitted in the output directory:

FileContents
quic_frames.hStruct/enum type declarations, function prototypes
quic_frames.cParse, serialize, and serialized_len implementations
fuzz_quic_frames.clibFuzzer harness (only with --fuzz)

When --recursive is used, each transitive dependency gets its own pair of .h/.c files.

For -t rust, a single .rs file is emitted:

FileContents
quic_varint.rsRust structs, parse, serialize, and serialized_len implementations

The generated Rust code uses the wirespec-rt crate for Cursor, Writer, and Error types.


wirespec check

Type-checks a .wspec file without generating output. Useful for CI and editor integration.

Usage:

bash
wirespec check <file>

The check command only takes an input file — no -I or other flags are supported.

Example:

bash
wirespec check examples/quic/frames.wspec

On success, prints ok: <path> to stderr and exits with code 0. On failure, prints diagnostics to stderr and exits non-zero:

error: undefined type 'VarItn'
 --> examples/quic/frames.wspec:34:42
  |
34 | frame QuicFrame = match frame_type: VarItn {
  |                                     ^^^^^^
  = in frame 'QuicFrame'
  hint: did you mean 'VarInt'?

Fuzz Build Workflow

Generate and build a libFuzzer harness:

bash
# Step 1: Compile with --fuzz
wirespec compile examples/quic/frames.wspec -t c --fuzz -o build/

# Step 2: Build the fuzzer with sanitizers
cd build
clang -fsanitize=fuzzer,address,undefined \
    -o fuzz_frames \
    quic_frames.c fuzz_quic_frames.c \
    -I../runtime

# Step 3: Run a timed smoke pass
./fuzz_frames -max_total_time=10

# Step 4: Run against a seed corpus (if available)
./fuzz_frames fuzz/corpus/quic_frames/ -max_total_time=60

The generated harness calls _parse() on arbitrary input and verifies that parse → serialize → parse round-trips produce identical results (when parse succeeds).


Import Search Path Resolution

When a .wspec file contains an import statement, the compiler searches for the imported module in the following order:

  1. The directory containing the importing file.
  2. Any directory specified with -I / --include-path, in the order given.

Module quic.varint resolves to a file named quic/varint.wspec (or quic/varint.wspec) — dots become path separators — relative to each search root.

Example:

examples/
  quic/
    varint.wspec     # module quic.varint
    frames.wspec     # import quic.varint.VarInt
bash
wirespec compile examples/quic/frames.wspec -I examples/ -o build/

With -I examples/, the import quic.varint resolves to examples/quic/varint.wspec.


Exit Codes

CodeMeaning
0Success
1Compile error (parse, type check, or codegen failure)