Skip to content

feat: add C++ header-only exporter for embedded/MCU use - #526

Open
SoundMatt wants to merge 4 commits into
COVESA:masterfrom
SoundMatt:feat/cpph-exporter
Open

feat: add C++ header-only exporter for embedded/MCU use#526
SoundMatt wants to merge 4 commits into
COVESA:masterfrom
SoundMatt:feat/cpph-exporter

Conversation

@SoundMatt

Copy link
Copy Markdown
Contributor

Summary

  • Adds vspec export cpp-header (new file src/vss_tools/exporters/cpp_header.py)
  • Emits a single .hpp with a VssSignal struct and one constexpr aggregate per leaf signal
  • Allowed-value lists become null-terminated constexpr const char*[] arrays declared immediately above their signal
  • VssSignal.cpp_type maps VSS datatypes to C++ equivalents (uint8_t, float, const char*, bool, …) using the same type table as datatypes.py
  • --namespace (default vss) and --include-branches/--no-include-branches CLI flags
  • No new runtime dependencies; header requires only <cstddef> and <cstdint>

Resolves #513.

Test plan

  • uv run pytest tests/vspec/test_cpp_header/ passes
  • vspec export cpp-header -s <spec> -o out.hpp produces valid C++ (compile-checked manually with g++ -std=c++17 -c out.hpp)
  • Signals with no allowed values emit nullptr for allowed_values
  • Signals with allowed values emit a named null-terminated array above the aggregate

Comment thread src/vss_tools/exporters/cpp_header.py Outdated
@@ -0,0 +1,215 @@
# Copyright (c) 2024 Contributors to COVESA

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New file, change to 2026 unless copied in full from somewhere else

@@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: Copyright (c) 2024 Contributors to COVESA

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New file, use 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way - does our license checker complains if this file does not have a license text? If this tool is intended to be used by customers the output does not necessarily needs to be with a MPL license, and copyright is not necessarily only COVESA as it is based on signal definitions that might be proprietary.

I am thinking of removing the copyright/license part here, and if needed adjust the license reviewer so it does not care about this file.

@erikbosch

Copy link
Copy Markdown
Collaborator

@JMorceaux - is this what you need?

@erikbosch

Copy link
Copy Markdown
Collaborator

Awaiting feedback from Jeremy. before merging the file https://github.com/COVESA/vss-tools/blob/master/docs/vspec.md shall be expanded and reference a file cpp-header.mdthat gives a short overview of this tool. See how other tools are documented

@JMorceaux

Copy link
Copy Markdown

Thanks @erikbosch for the ping ! Just came back from vacation, I'll definitely look at at this PR in details because it might indeed be exactly what I need :)

Comment on lines +176 to +181
@click.option(
"--include-branches/--no-include-branches",
default=False,
show_default=True,
help="Include branch nodes in addition to leaf signals.",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SoundMatt Thank you for this PR. In the current state, your exporter would export the entire vss specs and put all signals in the .hpp. The VSS specs is starting to be a bit heavy and I fear the .text/.bss is gonna be huge if we export all signals. I think it would be nice if the user could give the tool a list of signals (as an option) to export and only these signals would be exported. This would reduce .text/.bss and better suited for MCU use.

Comment on lines +29 to +32
"sensor",
"float",
"float",
"km",

@JMorceaux JMorceaux Jun 1, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The advantage of using const char*/string is that it's pretty robust to change but if we want to make an exporter for embedded system, it is best to think about memory footprint.

I think it would be best if an enum was created for unit/type/datatype/cpp_type

Same thing for the min/max value, I don't think a string is appropriate here

Adds `vspec export cpp-header` which emits a single `.hpp` containing
a `VssSignal` struct and one `constexpr` instance per leaf signal.
Allowed-value lists become null-terminated `constexpr const char*[]`
arrays declared immediately above the signal aggregate.

The struct includes a `cpp_type` field that maps VSS datatypes to their
C++ equivalents (uint8_t, float, const char*, bool, etc.) derived from
the existing Datatypes enum.

Resolves COVESA#513.

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
Adds docs/cpp-header.md covering the exporter's purpose, CLI flags
(--namespace, --include-branches), VSS→C++ type mapping table, and a
concrete model.vspec → vss.hpp example. Adds a reference link in
docs/vspec.md alongside the other exporter docs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
…or min/max

Replace all const char* metadata fields in VssSignal with typed enums:
- VssNodeType (sensor/actuator/attribute/branch)
- VssDataType (all VSS primitive and array types)
- VssCppType (all C++ type mappings)
- VssUnit (per-export enum of units actually present; kNone for unset)

min_value/max_value change from const char* to double (kNoValue sentinel
= std::numeric_limits<double>::quiet_NaN() for unset). Requires <limits>.

Also updates copyright year to 2026 in the exporter source and generated
header output.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
@SoundMatt
SoundMatt force-pushed the feat/cpph-exporter branch from 75c7b8e to 274e05f Compare June 15, 2026 13:46
@SoundMatt

Copy link
Copy Markdown
Contributor Author

Updated in the latest commit:

  • Enums for type/datatype/cpp_type/unitVssNodeType, VssDataType, VssCppType are fixed enums covering all VSS types. VssUnit is a per-export enum containing only the units present in the output (so the emitted enum stays small on a filtered spec). All four replace the previous const char* fields.
  • double for min/maxmin_value/max_value are now double with a kNoValue = std::numeric_limits<double>::quiet_NaN() sentinel for unset values (requires <limits>).
  • Copyright year — updated to 2026 in both the exporter source and the generated header.

@JMorceaux — on the --signals filter: before I build it, can you describe the expected UX? My current thinking is a repeatable --signal option that accepts dotted paths, e.g.:

vspec export cpp-header --signal Vehicle.Speed --signal Vehicle.Body.Lights.IsBackupOn -s spec/... -o out.hpp

Only the named paths (and their parent branches, if --include-branches is set) would be emitted. Glob patterns welcome too (Vehicle.ADAS.*).

Does that match what you had in mind, or did you want something different (e.g., a file listing paths, prefix-based filtering, etc.)? Happy to implement once we're aligned on scope.

Comment thread docs/cpp-header.md

namespace vss {

struct VssSignal {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just Signal. Its already in the vss namespace

from vss_tools.tree import VSSNode

_CPP_TYPE_MAP: dict[str, str] = {
"uint8": "uint8_t",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use datatypes.py definitions

}

_NODE_TYPE_ENUM: dict[str, str] = {
"sensor": "VssNodeType::kSensor",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just NodeType?

}

_DATATYPE_ENUM: dict[str, str] = {
"uint8": "VssDataType::kUint8",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DataType

}

_CPP_TYPE_ENUM: dict[str, str] = {
"uint8_t": "VssCppType::kUint8T",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"uint8_t": "VssCppType::kUint8T",
"uint8_t": "kUint8T",

"""Convert a VSS unit string to a C++ enum member name prefixed with k."""
s = unit
s = s.replace("/", "_Per_")
s = s.replace("^", "_Pow_")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what vss unit contains those symbols?

else:
allowed_ref = "nullptr"

lines.append(f"constexpr VssSignal {ident} = {{")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this should be a real template engine like jinja2

unit_map = {u: f"VssUnit::{m}" for u, m in seen_units.items()}

out: list[str] = []
out.append("// SPDX-FileCopyrightText: Copyright (c) 2026 Contributors to COVESA")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jinja2

Comment thread src/vss_tools/cli.py
"yaml": "vss_tools.exporters.yaml:cli",
"tree": "vss_tools.exporters.tree:cli",
"samm": "vss_tools.exporters.samm:cli",
"cpp-header": "vss_tools.exporters.cpp_header:cli",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about hpp?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C++ exporter (and why not Rust later)

4 participants