Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions .claude/skills/plotjuggler-plugin/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: plotjuggler-plugin
description: >-
Write or modify a PlotJuggler plugin (DataSource, MessageParser, Toolbox, or
Dialog) or native functional parser module using the plotjuggler_sdk. Use this
Dialog) using the plotjuggler_sdk. Use this
whenever the task is to implement, extend, debug, or build a PlotJuggler
extension — importing a file format, streaming live data, parsing message
payloads, mapping a custom type to a canonical object or scalars, adding a
Expand All @@ -20,12 +20,6 @@ class and export it from a shared library (`.so`/`.dll`/`.dylib`).
point, version symbol, exception trampolines and symbol folding.
**You never touch the raw ABI.** Override a few virtual methods and ship the library.

There is also a lighter extension shape: a **functional parser module** is one
C++17 source compiled as a native shared library, with no plugin-family
boilerplate. Write a MessageParser plugin when you own a whole encoding. Write a
parser module when you only need one or a few custom message types rendered as
canonical objects or scalars. Start at `references/parser-module.md`.

This skill is the author-oriented fast path. The repo's `pj_plugins/docs/` guides
are the full reference; this steers you to the right one and front-loads the
things that silently break a plugin.
Expand Down Expand Up @@ -69,7 +63,6 @@ plotjuggler_sdk::plugin_sdk)` — only the acquisition step differs:
|---|---|---|
| Turn a **file** or a **live source** (socket, serial, hardware) into topics | **DataSource** | `references/data-source.md` |
| Decode a **byte payload** on a topic into named fields (JSON, protobuf, ROS, custom) | **MessageParser** | `references/message-parser.md` |
| Map **one or a few message types** to canonical objects or scalars without owning the encoding | **Functional parser module** | `references/parser-module.md` |
| A **tool** that reads existing data, transforms it, and writes new topics | **Toolbox** | `references/toolbox.md` |
| A **configuration UI** (for a source/parser/toolbox, or standalone) | **Dialog** | `references/dialog.md` |

Expand Down Expand Up @@ -289,7 +282,6 @@ coalescing, etc.) — read them.
| What each family may do; capabilities; permission matrix; config contract | `pj_plugins/docs/REQUIREMENTS.md` |
| How the C ABI / loaders / host bridge work (mostly maintainer detail) | `pj_plugins/docs/ARCHITECTURE.md` |
| Writing each family, in depth | `pj_plugins/docs/{data-source,message-parser,toolbox,dialog-plugin}-guide.md` |
| Authoring a native functional parser module | `references/parser-module.md`, `pj_base/include/pj_base/parser_module/README.md` |
| Dialog `WidgetData` setters + event-handler signatures | `docs/dialog-sdk-reference.md` |
| Builtin object types + their wire codecs | `docs/builtin_type.md`, `pj_base/include/pj_base/builtin/` |
| Object store: publish/read objects, ownership, lazy fetch | `V4_STORE.md` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ not a parser. A parser only decodes payloads the host hands it. A parser is righ
when many payloads on a topic share an encoding (JSON, protobuf, ROS, a custom
binary) and you decode each into fields.

If an existing encoding already carries one custom type that you want to render
as a canonical object or scalars, use a **functional parser module** instead of
forking or replacing the encoding's MessageParser. See `parser-module.md`.

## Header (trap)

```cpp
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ by hand, because an older host cannot decode the object. `Log` gains an optional
one on the same wire, and the widget-protocol changes are documentation only; `pj.playback.v1`
already has its floor in `feature_floors.json`.

Functional parser modules leave the installed SDK:

- **Breaking (source, packaging):** the parser-module kit is no longer installed or packaged. It
moves to `experimental/parser_module/`, where it is still built and tested but carries no
compatibility promise; no host loads modules yet, so its export ABI and manifest schema are not
frozen by 1.0. Removed from the package: the `plotjuggler_sdk::parser_module` component and
`pj_add_parser_module()` (`PjParserModule.cmake`), the headers `pj_base/parser_module/*.hpp`,
`pj_base/parser_module_abi.h`, `pj_base/parser_module_manifest.hpp`,
`pj_plugins/host/native_parser_module.hpp` and `pj_plugins/host/parser_module_runtime.hpp`, and
the `pj_parser_module_host` archive that `plotjuggler_sdk::plugin_host` linked. The
`PJ::parser_module` block codecs leave the `pj_base` archive.
- **Breaking (source):** `ParserClaimCatalog::ingestModuleManifest`, `decodeParserModuleManifest`
and `ParserModuleManifest` leave `pj_plugins/host/parser_claim_catalog.hpp`. Claim admission,
`synthesizeParserPluginClaims` and `ParserRouteResolver` are unchanged.
- `PJ_MODULE_PARSE_INPUT_FLAG_HAS_TIMESTAMP` leaves the `feature_floors.json` baseline with the
header that declared it.

Log:

- `PJ::sdk::Log` gains an optional `category` (proto field 5 of `PJ.Log`): a source-defined grouping
Expand Down
11 changes: 8 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ protocol lives in `pj_plugins/dialog_protocol/` and the Widget protocol in
plugin-resolution catalog belong to the application, not this SDK.

The installed `cmake/` helpers (`pj_configure_plugin`, `pj_embed_file`,
`pj_harden_plugin_exports`, `pj_add_parser_module`, `pj_add_sdk_test_fixture`)
are public API and follow the same versioning contract as headers.
`pj_harden_plugin_exports`, `pj_add_sdk_test_fixture`) are public API and follow
the same versioning contract as headers.

`experimental/` holds components that are built and tested here but never
installed or packaged, and that carry no compatibility promise. It currently
holds functional parser modules: see
[experimental/parser_module/README.md](experimental/parser_module/README.md).

## Build and test

Expand Down Expand Up @@ -133,7 +138,7 @@ release. The real `X.Y.Z` is cut once, when the feature's contract is complete.
- `CamelCase` types, `camelBack` functions, `lower_case` variables,
`lower_case_` members, `kCamelCase` constants.
- Match module ownership: vocabulary in `PJ`, SDK helpers in `PJ::sdk`,
provider helpers in `PJ::sdk::source`, standalone parser modules in `pj`.
provider helpers in `PJ::sdk::source`, experimental parser modules in `pj`.
- Fallible operations use `PJ::Expected<T>` / `PJ::Status`; invariants use
`PJ_ASSERT`. Warnings: `-Wall -Wextra -Werror`.

Expand Down
8 changes: 5 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
include(GNUInstallDirs) # CMAKE_INSTALL_LIBDIR, etc. used by PjPlugin
include(PjPlugin)
include(PjParserModule)
include(PjSdkTestFixtures)

# ---------------------------------------------------------------------------
Expand All @@ -35,6 +34,8 @@ option(PJ_ENABLE_TSAN "Enable ThreadSanitizer for Debug builds" OFF)
option(PJ_INSTALL_SDK "Install plotjuggler_sdk CMake package (base/plugin_sdk/plugin_host)" OFF)
option(PJ_BUILD_PORTED_PLUGINS "Build pj_ported_plugins (ported plugins collection)" ON)
option(PJ_BUILD_TESTS "Build tests, benchmarks, and examples" ON)
# experimental/ is never installed or packaged and carries no compatibility promise.
option(PJ_BUILD_EXPERIMENTAL "Build experimental components (functional parser modules)" ${PJ_BUILD_TESTS})
option(PJ_ENABLE_ABI_CHECK "Enable abidiff-based ABI drift gate (requires libabigail)" OFF)
# -Werror is on for our own builds/CI, but must be off for third-party
# packaging (Conan Center, distro builds) where an unpredicted compiler version
Expand Down Expand Up @@ -133,6 +134,9 @@ endif()

add_subdirectory(pj_base)
add_subdirectory(pj_plugins)
if(PJ_BUILD_EXPERIMENTAL)
add_subdirectory(experimental/parser_module)
endif()

if(PJ_BUILD_PORTED_PLUGINS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/pj_ported_plugins/CMakeLists.txt")
set(PJ_HAS_PORTED_PLUGINS TRUE)
Expand All @@ -145,7 +149,6 @@ endif()
# Exported CMake namespace: plotjuggler_sdk::
# Components:
# base — vocabulary types (always available)
# parser_module — standalone header-only functional module authoring kit
# plugin_sdk — plugin-author surface: base + dialog SDK + parser SDK
# source — compiled provider helpers (descriptor_import_support is an alias)
# plugin_host — host-side loaders (data_source, message_parser, toolbox,
Expand Down Expand Up @@ -196,7 +199,6 @@ if(PJ_INSTALL_SDK)
"${CMAKE_CURRENT_BINARY_DIR}/plotjuggler_sdkConfigVersion.cmake"
cmake/PjPlugin.cmake
cmake/PjCheckElfPluginExports.cmake
cmake/PjParserModule.cmake
cmake/PjSdkTestFixtures.cmake
DESTINATION ${PJ_PACKAGE_CMAKE_DIR}
)
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Both guides ship under `share/plotjuggler_sdk/docs/` in the installed package.
| **pj_base** | Vocabulary types: `Timestamp`, `DatasetId`, `TopicId`, type trees, `Expected<T>`, `Span<T>` | None | Apache-2.0 |
| **pj_source** | Provider descriptors, origins, artifact cache, jobs, limits, presentation, completion and Stop; link `plotjuggler_sdk::source` | pj_base, nlohmann/json | Apache-2.0 |
| **pj_plugins** | C-ABI plugin protocol (DataSource, MessageParser, Dialog, Toolbox, Widget families), C++ SDK base classes, plugin discovery, host-side loaders, and config helpers | pj_base, nlohmann/json | Apache-2.0 |
| **cmake/** | Plugin-authoring CMake helpers shipped with `plugin_sdk`: `pj_configure_plugin()` (symbol isolation, export allowlist + gate, manifest validation/sidecar/embed), `pj_embed_file()`, `pj_harden_plugin_exports()`, `pj_add_parser_module()`, `pj_add_sdk_test_fixture()` — see `examples/sdk_consumer` | — | Apache-2.0 |
| **cmake/** | Plugin-authoring CMake helpers shipped with `plugin_sdk`: `pj_configure_plugin()` (symbol isolation, export allowlist + gate, manifest validation/sidecar/embed), `pj_embed_file()`, `pj_harden_plugin_exports()`, `pj_add_sdk_test_fixture()` — see `examples/sdk_consumer` | — | Apache-2.0 |

## Getting Started

Expand Down Expand Up @@ -48,7 +48,7 @@ git ls-files -z '*.cpp' | xargs -0 clang-tidy-22 -p build # clang-tidy
```
pj_base/ Vocabulary, builtin codecs and sdk/source/ provider support
pj_plugins/ C-ABI plugin protocol, SDK, host loaders
cmake/ Installed CMake helpers for plugin authors (PjPlugin.cmake, PjParserModule.cmake, PjSdkTestFixtures.cmake)
cmake/ Installed CMake helpers for plugin authors (PjPlugin.cmake, PjSdkTestFixtures.cmake)
examples/sdk_consumer/ find_package() consumer exercising the helpers (built by the release + conda checks)
docs/ Project-wide design guides
```
Expand Down
5 changes: 0 additions & 5 deletions cmake/plotjuggler_sdkConfig.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@ foreach(_comp ${plotjuggler_sdk_FIND_COMPONENTS})
if(_comp STREQUAL "base")
set(plotjuggler_sdk_base_FOUND TRUE)

elseif(_comp STREQUAL "parser_module")
# Header-only authoring surface plus its native module target helper.
include("${CMAKE_CURRENT_LIST_DIR}/PjParserModule.cmake")
set(plotjuggler_sdk_parser_module_FOUND TRUE)

elseif(_comp STREQUAL "plugin_sdk")
find_dependency(nlohmann_json)
# Plugin-authoring CMake helpers (pj_configure_plugin, pj_embed_file,
Expand Down
17 changes: 4 additions & 13 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
base — pj_base, vocabulary types (always available)
plugin_sdk — umbrella for plugin authors (base + dialog SDK + parser SDK)
plugin_host — umbrella for host loaders (data_source/parser/toolbox/dialog)
parser_module — standalone functional parser-module authoring headers
source — compiled source-provider support
descriptor_import_support — compatibility alias for source

Expand Down Expand Up @@ -70,6 +69,7 @@ class PlotjugglerSdkConan(ConanFile):
"pj_base/*",
"tools/feature_floors/*",
"pj_plugins/*",
"experimental/*", # built only with_tests=True; never packaged
"examples/*",
"!*/__pycache__/*",
)
Expand Down Expand Up @@ -150,12 +150,11 @@ def package_info(self):
# the package level (self.cpp_info), not at component level — declaring
# it on the `sdk` component below silently produced an empty
# plotjuggler_sdk_BUILD_MODULES_PATHS_RELEASE in the generated data
# file. Ship the plugin-authoring helpers (PjPlugin.cmake) and the
# parser-module helper from the package root so CMakeDeps actually
# include()s them after find_package() returns.
# file. Ship the plugin-authoring helpers (PjPlugin.cmake) from the
# package root so CMakeDeps actually include()s them after
# find_package() returns.
self.cpp_info.set_property("cmake_build_modules", [
os.path.join("lib", "cmake", "plotjuggler_sdk", "PjPlugin.cmake"),
os.path.join("lib", "cmake", "plotjuggler_sdk", "PjParserModule.cmake"),
os.path.join("lib", "cmake", "plotjuggler_sdk", "PjSdkTestFixtures.cmake"),
])

Expand All @@ -172,13 +171,6 @@ def package_info(self):
sdk.includedirs = ["include"]
sdk.requires = ["base", "nlohmann_json::nlohmann_json"]

# --- parser_module (header-only functional parser-module authoring kit;
# pj_add_parser_module() comes from the PjParserModule build module) ---
kit = self.cpp_info.components["parser_module"]
kit.set_property("cmake_target_name", "plotjuggler_sdk::parser_module")
kit.libs = [] # INTERFACE only: authored modules link no SDK library
kit.includedirs = ["include"]

# --- source (descriptor-import provider support) ---
source = self.cpp_info.components["source"]
source.set_property("cmake_target_name", "plotjuggler_sdk::source")
Expand All @@ -204,7 +196,6 @@ def package_info(self):
"pj_dialog_library",
"pj_widget_host",
"pj_plugin_catalog",
"pj_parser_module_host",
"pj_parser_claim_catalog",
"pj_plugin_loader_detail",
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Functional parser module

> Experimental: see [README.md](README.md). Not part of the installed SDK.

A functional parser module maps one or a few message types from an existing
encoding to canonical PlotJuggler objects or scalar fields. It is a single C++17
source compiled as a native shared library, with no plugin-family vtable or
Expand Down Expand Up @@ -110,9 +112,11 @@ embedded bytes; catalog ingestion validates the complete JSON transactionally.

## Build

```cmake
find_package(plotjuggler_sdk 0.22 REQUIRED COMPONENTS parser_module)
`pj_add_parser_module()` exists only inside this repository's build (this
directory's `CMakeLists.txt` includes `cmake/PjParserModule.cmake`); there is no
installed component to `find_package`.

```cmake
pj_add_parser_module(raw_mono_image_parser
SOURCE raw_mono_image_parser.cpp
MANIFEST raw_mono_image_parser.module.json
Expand All @@ -121,9 +125,9 @@ pj_add_parser_module(raw_mono_image_parser
```

The helper embeds the manifest, hides every non-ABI symbol, and exports the
complete native `pj_module_*` set. SDK 0.22 accepts only `TARGETS native`;
complete native `pj_module_*` set. Only `TARGETS native` is accepted;
requesting `TARGETS wasm` stops configuration with “wasm support arrives with
the SDK wasm loader milestone”. The shipped WASI check is structural
the SDK wasm loader milestone”. The WASI check is structural
conformance testing, not a wasm authoring or execution target.

## Choose a schema-compatibility strategy
Expand Down Expand Up @@ -171,8 +175,8 @@ selection before it can emit an invalid descriptor.
## Traps

- The kit is header-only and WASI-clean: no threads, filesystem, iostream, host
SDK linkage, or exceptions across its API. In SDK 0.22 the supported build
product is nevertheless native-only.
SDK linkage, or exceptions across its API. The supported build product is
nevertheless native-only.
- Return `pj::Status` / `pj::Expected<T>`; do not throw. `Blob` uses nothrow
allocation and protobuf matching is bounded, so allocation failure is a
reported data error rather than a process abort or contract strike.
Expand Down
Loading
Loading