feat: add C++ header-only exporter for embedded/MCU use - #526
Conversation
| @@ -0,0 +1,215 @@ | |||
| # Copyright (c) 2024 Contributors to COVESA | |||
There was a problem hiding this comment.
New file, change to 2026 unless copied in full from somewhere else
| @@ -0,0 +1,81 @@ | |||
| // SPDX-FileCopyrightText: Copyright (c) 2024 Contributors to COVESA | |||
There was a problem hiding this comment.
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.
|
@JMorceaux - is this what you need? |
|
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 |
|
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 :) |
| @click.option( | ||
| "--include-branches/--no-include-branches", | ||
| default=False, | ||
| show_default=True, | ||
| help="Include branch nodes in addition to leaf signals.", | ||
| ) |
There was a problem hiding this comment.
@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.
| "sensor", | ||
| "float", | ||
| "float", | ||
| "km", |
There was a problem hiding this comment.
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>
75c7b8e to
274e05f
Compare
|
Updated in the latest commit:
@JMorceaux — on the vspec export cpp-header --signal Vehicle.Speed --signal Vehicle.Body.Lights.IsBackupOn -s spec/... -o out.hppOnly the named paths (and their parent branches, if 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. |
|
|
||
| namespace vss { | ||
|
|
||
| struct VssSignal { |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
should use datatypes.py definitions
| } | ||
|
|
||
| _NODE_TYPE_ENUM: dict[str, str] = { | ||
| "sensor": "VssNodeType::kSensor", |
There was a problem hiding this comment.
Why not just NodeType?
| } | ||
|
|
||
| _DATATYPE_ENUM: dict[str, str] = { | ||
| "uint8": "VssDataType::kUint8", |
| } | ||
|
|
||
| _CPP_TYPE_ENUM: dict[str, str] = { | ||
| "uint8_t": "VssCppType::kUint8T", |
There was a problem hiding this comment.
| "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_") |
There was a problem hiding this comment.
what vss unit contains those symbols?
| else: | ||
| allowed_ref = "nullptr" | ||
|
|
||
| lines.append(f"constexpr VssSignal {ident} = {{") |
There was a problem hiding this comment.
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") |
| "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", |
Addresses sschleemilch's review (Jul 21):
- Renamed VssSignal -> Signal, VssNodeType -> NodeType, VssDataType ->
DataType, VssCppType -> CppType, VssUnit -> Unit. All are already
scoped inside 'namespace vss', so the prefix was redundant.
- _CPP_TYPE_MAP is now derived from vss_tools.datatypes.Datatypes
instead of a hand-duplicated dict, so it can't drift out of sync
with the datatype list vss-tools already treats as canonical.
- _unit_enum_member() dropped its handling of degree/percent/middle-dot/
asterisk symbols - checked the real spec/units.yaml and no VSS unit
uses them (only '/', '^', '-' actually occur, e.g. cm/s^2, mpg-uk).
- The hand-rolled out.append(...) boilerplate is now a Jinja2
template (src/vss_tools/exporters/templates/cpp_header.hpp.j2).
jinja2 is a new dependency (pyproject.toml, uv.lock).
- The enum-value dicts (_NODE_TYPE_ENUM etc.) now hold bare member
names ('kUint8T') rather than prefixed ones ('VssCppType::kUint8T'),
per Sebastian's suggested diff on line 92 - the prefix is added by
the template instead.
Also implements JMorceaux's still-open request for a signal filter:
- New repeatable --signal option (dotted path, glob '*' supported)
to restrict output to specific signals - the original motivation
for this exporter was reducing .text/.bss on MCU targets, which
exporting the entire spec works against.
- With --include-branches, only the ancestor branches of matched
signals are pulled in, not the whole tree, to keep that goal intact.
docs/cpp-header.md rewritten to match: renamed types, --signal
documented, and the worked example now runs from the actual exporter
output rather than hand-written text (it had drifted from reality -
the doc's example wasn't buildable, since the Vehicle.Powertrain
branch it uses was never declared).
expected.hpp regenerated from tool output; added 4 new tests for the
--signal filter (exact match, glob, no-match warning, ancestor-branch
inclusion). Full suite (431 tests) passes; ruff, ruff format and mypy
clean. Manually verified the generated header compiles with both g++
and clang++ (-std=c++17).
Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com>
|
@sschleemilch — pushed a round addressing your review:
@JMorceaux — also implemented the Also updated Full suite (431 tests, 4 new for |
|
Hello @SoundMatt ! First of all, I wanted to apologize for the lack of response on my end this last few weeks ! I was away and coulnd't reach out. Secondly, thank you again for all of your work. The Thank you again ! |
Summary
vspec export cpp-header(new filesrc/vss_tools/exporters/cpp_header.py).hppwith aVssSignalstruct and oneconstexpraggregate per leaf signalconstexpr const char*[]arrays declared immediately above their signalVssSignal.cpp_typemaps VSS datatypes to C++ equivalents (uint8_t,float,const char*,bool, …) using the same type table asdatatypes.py--namespace(defaultvss) and--include-branches/--no-include-branchesCLI flags<cstddef>and<cstdint>Resolves #513.
Test plan
uv run pytest tests/vspec/test_cpp_header/passesvspec export cpp-header -s <spec> -o out.hppproduces valid C++ (compile-checked manually withg++ -std=c++17 -c out.hpp)nullptrforallowed_values