Skip to content

Commit 1fb5d3d

Browse files
author
Davide Faconti
committed
chore: bump plugin ABI to v5
1 parent a62f1ae commit 1fb5d3d

10 files changed

Lines changed: 56 additions & 51 deletions

cmake/PjAbiCheck.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# bumping PJ_ABI_VERSION for a major break).
1616
#
1717
# Baseline location: pj_base/abi/baseline.abi — the single source of
18-
# truth for what the v4 ABI looks like. The baseline is generated from
18+
# truth for what the current ABI looks like. The baseline is generated from
1919
# a canary plugin DSO (mock_data_source_plugin) whose symbol surface
2020
# exercises the full ABI header set via the SDK.
2121
#

cmake/PjPluginManifest.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ function(pj_emit_plugin_manifest TARGET)
8383

8484
if(NOT ARG_ABI_MAJOR)
8585
# Matches PJ_ABI_VERSION in pj_base/plugin_data_api.h. Bump in lockstep.
86-
set(ARG_ABI_MAJOR 4)
86+
set(ARG_ABI_MAJOR 5)
8787
endif()
8888

8989
# Track manifest edits so CMake reconfigures when the source changes.

pj_base/include/pj_base/builtin_object_abi.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
*
1010
* Canonical-object production (any concrete sdk::* type listed in
1111
* BuiltinObjectType — see pj_base/builtin/builtin_object.hpp) and the
12-
* pure-functional scalar production (Expected<vector<NamedFieldValue>>)
13-
* are C++ SDK contracts: plugins inheriting from MessageParserPluginBase
14-
* register handlers in SchemaHandler, and the in-process host consumes
15-
* them via MessageParserPluginBase::parseObject() and parseScalars()
16-
* called directly on the C++ pointer. Pure-C plugins emit scalars via
17-
* the parse() slot (writing to writeHost).
12+
* pure-functional scalar production (Expected<ObjectRecord> /
13+
* Expected<ScalarRecord>) are C++ SDK contracts: plugins inheriting from
14+
* MessageParserPluginBase register handlers in SchemaHandler, and the
15+
* in-process host consumes them via MessageParserPluginBase::parseObject()
16+
* and parseScalars() called directly on the C++ pointer. Pure-C plugins
17+
* emit scalars via the parse() slot (writing to writeHost).
1818
*/
1919
// Copyright 2026 Davide Faconti
2020
// SPDX-License-Identifier: MIT

pj_base/include/pj_base/plugin_data_api.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,20 @@ extern "C" {
4545
* (e.g. DataSource + Dialog in one .so) work without any extra ceremony.
4646
* Do not redefine it manually.
4747
*
48-
* v4 plugins advertise version 4. Data-plane changes from the pre-v4 design:
48+
* v5 plugins advertise version 5. Relative to v4, this bump rejects
49+
* pre-v5 parser DSOs because the C++ MessageParserPluginBase
50+
* pure-functional contract changed parseScalars()/parseObject() return
51+
* types to ScalarRecord/ObjectRecord.
52+
*
53+
* The C data-plane layout remains the v4 layout:
4954
* - Arrow C Data Interface replaces Arrow IPC bytes at the boundary
5055
* (append_arrow_stream + read_series_arrow).
5156
* - append_arrow_ipc removed from all write hosts.
5257
* - read_series (PJ_materialized_series_t) removed from toolbox host.
5358
* - Every vtable slot is PJ_NOEXCEPT.
5459
* - Every slot carries a thread-class tag (// [main-thread], etc.).
5560
*/
56-
#define PJ_ABI_VERSION 4
61+
#define PJ_ABI_VERSION 5
5762

5863
/**
5964
* Convention for plugin-loaders:
@@ -90,13 +95,13 @@ typedef enum {
9095
PJ_PRIMITIVE_TYPE_UNSPECIFIED = 0xFF,
9196
} PJ_primitive_type_t;
9297

93-
/* ABI-FROZEN: layout permanent; changes = v4 break. */
98+
/* ABI-FROZEN: layout permanent; changes = ABI break. */
9499
typedef struct {
95100
const char* data;
96101
size_t size;
97102
} PJ_string_view_t;
98103

99-
/* ABI-FROZEN: layout permanent; changes = v4 break. */
104+
/* ABI-FROZEN: layout permanent; changes = ABI break. */
100105
typedef struct {
101106
const uint8_t* data;
102107
size_t size;
@@ -162,17 +167,17 @@ struct ArrowArrayStream {
162167

163168
#endif /* ARROW_C_DATA_INTERFACE */
164169

165-
/* ABI-FROZEN: layout permanent; changes = v4 break. */
170+
/* ABI-FROZEN: layout permanent; changes = ABI break. */
166171
typedef struct {
167172
uint32_t id;
168173
} PJ_data_source_handle_t;
169174

170-
/* ABI-FROZEN: layout permanent; changes = v4 break. */
175+
/* ABI-FROZEN: layout permanent; changes = ABI break. */
171176
typedef struct {
172177
uint32_t id;
173178
} PJ_topic_handle_t;
174179

175-
/* ABI-FROZEN: layout permanent; changes = v4 break. */
180+
/* ABI-FROZEN: layout permanent; changes = ABI break. */
176181
typedef struct {
177182
PJ_topic_handle_t topic;
178183
uint32_t id;
@@ -506,7 +511,7 @@ typedef struct {
506511
* `pj.parser_object_write.v1` in addition to `pj.parser_write.v1`.
507512
* ========================================================================== */
508513

509-
/* ABI-FROZEN: layout permanent; changes = v5 break. */
514+
/* ABI-FROZEN: layout permanent; changes = ABI break. */
510515
typedef struct {
511516
uint32_t id; /* 0 == invalid handle */
512517
} PJ_object_topic_handle_t;

pj_base/tests/abi_layout_sentinels_test.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/**
22
* @file abi_layout_sentinels_test.cpp
3-
* @brief Compile-time sentinels that pin the v4 plugin ABI layout.
3+
* @brief Compile-time sentinels that pin the plugin C ABI layout.
44
*
55
* Every assertion here is a static_assert. A failure at compile time means
66
* a struct defined in the ABI-visible headers has shifted in a way that
7-
* would silently break binary compatibility with existing v4 plugins.
7+
* would silently break binary compatibility with existing plugins.
88
*
99
* Maintenance rule:
1010
* - Sizes and alignments are allowed to GROW at the tail (new slots
@@ -16,7 +16,8 @@
1616
* break.
1717
* - MIN-size constants (PJ_*_MIN_VTABLE_SIZE) MUST NEVER INCREASE
1818
* within a major version. They are pinned at v4.0 release and are
19-
* the floor that forward compatibility relies on within the v4 series.
19+
* the floor that forward compatibility relies on within the current
20+
* major series.
2021
*
2122
* Pinning target: x86-64 System V (Linux/macOS on Intel/AMD). For other
2223
* ABIs (ARM64, MSVC), either confirm identical layout during initial
@@ -63,7 +64,7 @@ static_assert(sizeof(PJ_borrowed_dialog_t) == 16, "PJ_borrowed_dialog_t fat poin
6364

6465
// --- DataSource vtable (ABI-APPENDABLE within v4) ----------------------------
6566
// Offsets of v4.0 slots: PINNED. sizeof and MIN_VTABLE_SIZE are allowed to
66-
// grow at the tail via future appends within the v4 series.
67+
// grow at the tail via future appends within the current major series.
6768
static_assert(offsetof(PJ_data_source_vtable_t, protocol_version) == 0, "v4 prefix pinned");
6869
static_assert(offsetof(PJ_data_source_vtable_t, struct_size) == 4, "v4 prefix pinned");
6970
static_assert(offsetof(PJ_data_source_vtable_t, bind) == 40, "v4 bind slot pinned");
@@ -174,7 +175,7 @@ static_assert(offsetof(PJ_toolbox_host_vtable_t, read_series_arrow) == 64, "tool
174175
static_assert(sizeof(PJ_toolbox_host_vtable_t) == 72, "Toolbox host size");
175176

176177
// --- ABI version symbol ------------------------------------------------------
177-
static_assert(PJ_ABI_VERSION == 4, "v4 ABI version");
178+
static_assert(PJ_ABI_VERSION == 5, "v5 ABI version");
178179

179180
// This translation unit has no runtime behavior; the above are all
180181
// compile-time assertions. Linking only confirms the TU compiled.

pj_plugins/docs/ARCHITECTURE.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Plugin System Architecture
22

3-
## 0a. ABI stability and evolution rules (v4)
3+
## 0a. ABI stability and evolution rules (v5)
44

55
Seven rules the loader and every plugin author rely on. Breaking any of
6-
these is an ABI break and requires a v5 bump.
6+
these is an ABI break and requires a future `PJ_ABI_VERSION` bump.
77

88
1. **Boot-level ABI symbol.** Every plugin .so exports
99
`pj_plugin_abi_version` as a `uint32_t` symbol independent of any
@@ -18,13 +18,13 @@ these is an ABI break and requires a v5 bump.
1818
duplicate definitions across translation units in one DSO, so a single
1919
.so can host multiple plugin families (e.g. DataSource + Dialog) with
2020
one `PJ_*_PLUGIN(...)` macro per family — no duplicate-symbol error.
21-
Current value is `PJ_ABI_VERSION == 4`.
21+
Current value is `PJ_ABI_VERSION == 5`.
2222

2323
2. **Min-vtable-size floor, pinned at v4.0.** Each family header defines
2424
`PJ_<FAMILY>_MIN_VTABLE_SIZE` — the byte count of the vtable as
2525
shipped in v4.0. The loader accepts
2626
`struct_size >= MIN_VTABLE_SIZE`. This constant MUST NEVER GROW
27-
within the v4 series. Growing it would reject plugins compiled
27+
within a major series. Growing it would reject plugins compiled
2828
against older v4 headers (which correctly report a smaller size),
2929
silently breaking the forward-compatibility promise.
3030

@@ -40,7 +40,7 @@ these is an ABI break and requires a v5 bump.
4040
- **ABI-FROZEN**: `PJ_error_t`, `PJ_string_view_t`, `PJ_bytes_view_t`,
4141
`PJ_borrowed_dialog_t`, `PJ_service_t`, `PJ_service_registry_t`,
4242
handle types, primitive-value unions. Layout permanent; any change
43-
is a v4 break. `PJ_error_t` has `extended` + `extended_kind` slots
43+
is an ABI break. `PJ_error_t` has `extended` + `extended_kind` slots
4444
reserved as its one growth path — do not add further top-level
4545
fields.
4646
- **ABI-APPENDABLE**: all `*_vtable_t` types, service-host vtables,
@@ -101,10 +101,11 @@ for known ids or `nullptr`. Hosts call via `handle.getPluginExtension(id)`
101101
(tail-slot-gated). Use the experimental namespace for work-in-progress
102102
extensions; graduate to stable (`pj.<name>.v1`) once locked in.
103103

104-
## 0. Protocol v4 (current)
104+
## 0. C protocol v4 (current under ABI v5)
105105

106-
All four plugin families (DataSource, MessageParser, Toolbox, Dialog) track
107-
protocol v4. Key v4 distinguishing features (a superset of everything the
106+
All four plugin families (DataSource, MessageParser, Toolbox, Dialog) keep
107+
the v4 C protocol layouts under the v5 boot ABI. Key v4 distinguishing
108+
features (a superset of everything the
108109
previously-circulated pre-v4 design included):
109110

110111
- **Arrow C Data Interface at the data boundary.** The write-host

pj_plugins/docs/data-source-guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Writing a DataSource Plugin
22

3-
> **Tracks the v4 plugin ABI** (`PJ_ABI_VERSION == 4`). For the full
3+
> **Tracks the v5 plugin ABI** (`PJ_ABI_VERSION == 5`). For the full
44
> evolution rules (tail-slot gating, MIN_VTABLE_SIZE, ABI-FROZEN vs
55
> ABI-APPENDABLE structs, Arrow C Data Interface at the write boundary,
66
> PJ_NOEXCEPT discipline) see `ARCHITECTURE.md`. This guide walks

pj_plugins/docs/dialog-plugin-guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Writing a Dialog Plugin
22

3-
> **Tracks the v4 plugin ABI** (`PJ_ABI_VERSION == 4`). Every dialog
3+
> **Tracks the v5 plugin ABI** (`PJ_ABI_VERSION == 5`). Every dialog
44
> vtable slot is `PJ_NOEXCEPT` — the SDK trampolines in
55
> `DialogPluginBase` catch exceptions automatically, but your overrides
66
> must assume no exception ever crosses the ABI boundary. All dialog

pj_plugins/docs/message-parser-guide.md

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Writing a MessageParser Plugin
22

3-
> **Tracks the v4 plugin ABI** (`PJ_ABI_VERSION == 4`). The parser
3+
> **Tracks the v5 plugin ABI** (`PJ_ABI_VERSION == 5`). The parser
44
> write-host supports per-record writes and an optional Arrow stream
55
> batch path for parser-shaped formats that naturally decode batches.
66
> For ABI evolution rules, error semantics, and noexcept discipline see
@@ -534,21 +534,18 @@ depth image, point cloud, image annotations, frame transforms) returned by name
534534
from the parser, decoded once, and visualised by widgets that never learn the
535535
wire format.
536536

537-
Three optional virtual entry points on `MessageParserPluginBase`
537+
The table-driven `SchemaHandler` routes on `MessageParserPluginBase`
538538
participate:
539539

540540
```cpp
541-
// In your subclass — every override is optional. The base provides
542-
// safe `unexpected(...)` defaults so legacy parsers compile unchanged.
543-
PJ::Expected<PJ::sdk::SchemaClassification>
544-
classifySchema(std::string_view type_name,
545-
PJ::Span<const uint8_t> schema) override;
546-
547-
PJ::Expected<std::vector<PJ::sdk::NamedFieldValue>>
548-
parseScalars(PJ::Timestamp ts, PJ::sdk::PayloadView payload) override;
549-
550-
PJ::Expected<PJ::sdk::BuiltinObject>
551-
parseObject(PJ::Timestamp ts, PJ::sdk::PayloadView payload) override;
541+
PJ::sdk::SchemaHandler handler;
542+
handler.object_type = PJ::sdk::BuiltinObjectType::kImage;
543+
handler.parse_scalars =
544+
[](PJ::Timestamp ts, PJ::Span<const uint8_t> payload)
545+
-> PJ::Expected<PJ::sdk::ScalarRecord> { /* ... */ };
546+
handler.parse_object =
547+
[](PJ::Timestamp ts, PJ::sdk::PayloadView payload)
548+
-> PJ::Expected<PJ::sdk::ObjectRecord> { /* ... */ };
552549
```
553550
554551
- `classifySchema` is the *a-priori* declaration — given a type name +
@@ -557,12 +554,13 @@ parseObject(PJ::Timestamp ts, PJ::sdk::PayloadView payload) override;
557554
`kNone`) this schema produces. The host consults the answer **before** it
558555
ever sees the payload, so it can pick the right `ObjectIngestPolicy` for the
559556
topic.
560-
- `parseScalars` writes the small-metadata fields (`width`, `height`,
561-
`frame_id`, …) that should land in the curve tree as scalar columns.
562-
- `parseObject` returns the actual builtin value, type-erased as
563-
`PJ::sdk::BuiltinObject` (which is `std::any`). The host downcasts
564-
with `std::any_cast<PJ::sdk::Image>(&obj)` to dispatch to the
565-
matching viewer.
557+
- `parse_scalars` returns a `ScalarRecord`: small-metadata fields
558+
(`width`, `height`, `frame_id`, …) plus an optional parser-controlled
559+
timestamp.
560+
- `parse_object` returns an `ObjectRecord`: the actual builtin value,
561+
type-erased as `PJ::sdk::BuiltinObject` (which is `std::any`), plus an
562+
optional parser-controlled timestamp. The host downcasts with
563+
`std::any_cast<PJ::sdk::Image>(&obj)` to dispatch to the matching viewer.
566564
567565
Builtin types live under `pj_base/builtin/`, one header per
568566
type. `sdk::Image` carries an open-ended `std::string encoding`

pj_plugins/docs/toolbox-guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Writing a Toolbox Plugin
22

3-
> **Tracks the v4 plugin ABI** (`PJ_ABI_VERSION == 4`). Toolbox plugins
3+
> **Tracks the v5 plugin ABI** (`PJ_ABI_VERSION == 5`). Toolbox plugins
44
> read time series via the host's `read_series_arrow` slot, which
55
> returns a caller-owned `ArrowSchema` + `ArrowArray` pair (no more
66
> materialised `std::vector`). Wrap returns in

0 commit comments

Comments
 (0)