From e210966c27acc015f2bc4f9db66a7fb997ed9f63 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 1 Jul 2026 17:22:30 +0200 Subject: [PATCH 1/3] build(sdk): gate -Werror behind PJ_WARNINGS_AS_ERRORS + add Conan Center recipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the option PJ_WARNINGS_AS_ERRORS (default ON, so our own builds and CI are unchanged) and gate -Werror / /WX behind it. Third-party packaging — Conan Center's multi-compiler matrix in particular — sets it OFF so a not-yet-pinned compiler version cannot fail an otherwise-fine build on a new warning. wasm32 still never gets -Werror (unchanged). Stage the Conan Center Index recipe under packaging/conan-center-index/ (copy recipes/plotjuggler_sdk/ into a fork of conan-io/conan-center-index to submit): - all/conanfile.py: downloads the released tag tarball (no vendored sources), validate()s C++20 + compiler minimums, builds with PJ_WARNINGS_AS_ERRORS=OFF, strips the project-installed CMake config/targets (CCI re-derives them from package_info()) while keeping PjPluginManifest.cmake as a build module. - all/conandata.yml, config.yml: v0.14.0 source url + sha256 (placeholder tag; re-point at the release that ships the -Werror gate before submitting). - all/test_package/: minimal consumer that links libpj_base.a via parseNumber to exercise real linkage, not just headers. - README.md: submission + local-test workflow, prerequisites, recurring cost. Verified: conan create with -s compiler.cppstd=20 succeeds (deps resolve from Conan Center; test_package links and runs); validate() rejects sub-C++20; packaged tree drops Config*/Targets* and keeps PjPluginManifest.cmake + both licenses. ./build.sh --debug && ./test.sh green (48/48). Co-Authored-By: Claude Opus 4.8 --- CMakeLists.txt | 24 ++- packaging/conan-center-index/README.md | 75 ++++++++ .../recipes/plotjuggler_sdk/all/conandata.yml | 10 + .../recipes/plotjuggler_sdk/all/conanfile.py | 181 ++++++++++++++++++ .../all/test_package/CMakeLists.txt | 12 ++ .../all/test_package/conanfile.py | 27 +++ .../all/test_package/test_package.cpp | 11 ++ .../recipes/plotjuggler_sdk/config.yml | 3 + 8 files changed, 335 insertions(+), 8 deletions(-) create mode 100644 packaging/conan-center-index/README.md create mode 100644 packaging/conan-center-index/recipes/plotjuggler_sdk/all/conandata.yml create mode 100644 packaging/conan-center-index/recipes/plotjuggler_sdk/all/conanfile.py create mode 100644 packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/CMakeLists.txt create mode 100644 packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/conanfile.py create mode 100644 packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/test_package.cpp create mode 100644 packaging/conan-center-index/recipes/plotjuggler_sdk/config.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index a733b12..6e7a09e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,10 @@ option(PJ_INSTALL_SDK "Install plotjuggler_sdk CMake package (base/plugin_sdk/pl option(PJ_BUILD_PORTED_PLUGINS "Build pj_ported_plugins (ported plugins collection)" ON) option(PJ_BUILD_TESTS "Build tests, benchmarks, and examples" ON) 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 +# may emit new warnings that would otherwise fail an otherwise-fine build. +option(PJ_WARNINGS_AS_ERRORS "Treat compiler warnings as errors (-Werror / /WX)" ON) # --------------------------------------------------------------------------- # Compiler warnings @@ -29,18 +33,22 @@ if(MSVC) # /Zc:preprocessor: conformant preprocessor — required so __VA_ARGS__ inside # nested macro calls (e.g. PJ_DIALOG_PLUGIN's overload-by-arg-count idiom) # splits on commas instead of being passed as a single token. - set(PJ_WARNING_FLAGS /W4 /WX /permissive- /Zc:preprocessor) + set(PJ_WARNING_FLAGS /W4 /permissive- /Zc:preprocessor) + if(PJ_WARNINGS_AS_ERRORS) + list(APPEND PJ_WARNING_FLAGS /WX) + endif() else() set(PJ_WARNING_FLAGS - -Wall -Wextra -Werror -Wshadow -Wnon-virtual-dtor -Wold-style-cast + -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-qual -Wconversion -Woverloaded-virtual -Wpedantic ) - # On wasm32 size_t is 32-bit, so many uint64_t->size_t conversions trip - # -Wshorten-64-to-32 / -Wsign-conversion that never fire on 64-bit desktop - # (see SUSTAINABILITY.md T0-3). Keep the warnings visible but don't fail the - # build for the WASM prototype. TODO: make the ABI/size types 32-bit-clean. - if(EMSCRIPTEN) - list(APPEND PJ_WARNING_FLAGS -Wno-error) + # -Werror only when explicitly requested (default ON, see option above) and + # never on wasm32: there size_t is 32-bit, so many uint64_t->size_t + # conversions trip -Wshorten-64-to-32 / -Wsign-conversion that never fire on + # 64-bit desktop (see SUSTAINABILITY.md T0-3). TODO: make the ABI/size types + # 32-bit-clean, then wasm can opt back into -Werror. + if(PJ_WARNINGS_AS_ERRORS AND NOT EMSCRIPTEN) + list(APPEND PJ_WARNING_FLAGS -Werror) endif() endif() diff --git a/packaging/conan-center-index/README.md b/packaging/conan-center-index/README.md new file mode 100644 index 0000000..37f485d --- /dev/null +++ b/packaging/conan-center-index/README.md @@ -0,0 +1,75 @@ +# Conan Center submission for `plotjuggler_sdk` + +These files are the **Conan Center Index (CCI) recipe** for this SDK. They do +**not** belong to the plotjuggler_sdk build — they are staged here so the recipe +is version-controlled and kept in sync with the source. To publish, copy the +`recipes/plotjuggler_sdk/` tree into a fork of +[`conan-io/conan-center-index`](https://github.com/conan-io/conan-center-index) +and open a PR. + +``` +recipes/plotjuggler_sdk/ +├── config.yml # version -> folder map +└── all/ + ├── conanfile.py # the recipe (downloads a released tag, no vendored sources) + ├── conandata.yml # tag url + sha256 per version + └── test_package/ # minimal consumer CCI builds to validate the package +``` + +This is separate from the repo's own `conanfile.py`, which vendors the working +tree for local dev/consume. The CCI recipe instead downloads the released +**tag tarball** by URL + sha256 and never sees your working tree. + +## Prerequisites before submitting + +1. **Ship the `-Werror` gate in a released tag.** The recipe sets + `-DPJ_WARNINGS_AS_ERRORS=OFF` so a not-yet-pinned compiler on CCI's build + matrix cannot fail the build on a new warning. That option was added on this + branch (`CMakeLists.txt`). It must be present in the tag CCI consumes: + merge this branch, cut a new release tag, then update `config.yml` + + `conandata.yml` (new version + new sha256). The sha256 currently pinned is + for the *pre-gate* `v0.14.0` tag and is only good for local smoke testing. +2. **Pick the entry version.** Per the SDK's own versioning note, the first + public release carrying the unified `pj.data_processors.v1` service must be + `1.0.0`. Decide whether CCI is seeded with `0.14.x` or `1.0.0`. +3. **Confirm dependencies exist in CCI** (verified 2026-07-01, all present): + `nlohmann_json/3.12.0`, `fmt/12.1.0`, `fast_float/8.1.0`. + +## Test locally before opening the PR + +From inside a checkout of the conan-center-index fork: + +```bash +cd recipes/plotjuggler_sdk +# Build + run the test_package for the default profile: +conan create all --version=0.14.0 --build=missing +# Exercise the option matrix CCI will build: +conan create all --version=0.14.0 -o "&:with_host=False" --build=missing +conan create all --version=0.14.0 -o "&:assert_throws=True" --build=missing +conan create all --version=0.14.0 -s compiler.cppstd=20 --build=missing +``` + +Then run the Conan Center hooks locally (catches KB-Hxxx violations the reviewer +bot will flag): + +```bash +conan config install https://github.com/conan-io/conan-center-index.git \ + -sf .c3i/hooks -tf .conan2/extensions/hooks # one-time +conan create all --version=0.14.0 --build=missing # hooks run inline +``` + +## Open the PR + +Fork `conan-io/conan-center-index`, drop this tree under `recipes/`, commit, and +open a PR titled `plotjuggler_sdk/0.14.0`. Expect one or more review rounds — +the usual notes are around option count (`with_host`, `assert_throws`), license +packaging, and the compiler-minimum map. Acceptance is at CCI maintainer +discretion. + +## Recurring cost per release + +Each future SDK release needs a follow-up CCI PR: add the new version to +`config.yml`, add its `url` + `sha256` to `conandata.yml`. Weigh this against the +Cloudsmith Conan remote (`conan.cloudsmith.io/plotjuggler/plotjuggler`) you +already operate, which needs no external review but requires consumers to add +the remote. diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conandata.yml b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conandata.yml new file mode 100644 index 0000000..cdca00d --- /dev/null +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conandata.yml @@ -0,0 +1,10 @@ +sources: + # NOTE: this sha256 is for the v0.14.0 tag *as it exists today*, which does + # NOT yet contain the PJ_WARNINGS_AS_ERRORS gate (added on the conan-center + # branch). Before submitting to Conan Center, cut a release tag that includes + # that CMake change and replace both the version (here + config.yml) and the + # sha256 below. Recompute with: + # curl -sL https://github.com/PlotJuggler/plotjuggler_sdk/archive/refs/tags/vX.Y.Z.tar.gz | sha256sum + "0.14.0": + url: "https://github.com/PlotJuggler/plotjuggler_sdk/archive/refs/tags/v0.14.0.tar.gz" + sha256: "49aecfdc5ddf46930e56a5ee4843a1435c3fb8e47b1a4ab0289fd9646dc1986d" diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conanfile.py b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conanfile.py new file mode 100644 index 0000000..294f5b7 --- /dev/null +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conanfile.py @@ -0,0 +1,181 @@ +import os + +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.build import check_min_cppstd +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +from conan.tools.files import copy, get, rm +from conan.tools.scm import Version + +required_conan_version = ">=2.1" + + +class PlotjugglerSdkConan(ConanFile): + name = "plotjuggler_sdk" + description = ( + "C++20 foundation libraries for PlotJuggler: plugin SDK and plugin host loaders." + ) + license = "Apache-2.0" + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://github.com/PlotJuggler/plotjuggler_sdk" + topics = ("plotjuggler", "plugin-sdk", "telemetry", "data-visualization") + package_type = "static-library" + settings = "os", "arch", "compiler", "build_type" + + # The SDK ships as static archives only (host loaders + vocabulary types); + # there is intentionally no `shared` option. `with_host` lets consumers that + # only author plugins skip the host-side loader libraries. `assert_throws` + # switches PJ_ASSERT from assert() to throwing. + options = { + "fPIC": [True, False], + "with_host": [True, False], + "assert_throws": [True, False], + } + default_options = { + "fPIC": True, + "with_host": True, + "assert_throws": False, + } + + @property + def _min_cppstd(self): + return 20 + + @property + def _compilers_minimum_version(self): + # Tune these against the oldest toolchains you actually intend to + # support; these are conservative C++20 baselines. + return { + "gcc": "11", + "clang": "14", + "apple-clang": "14", + "msvc": "192", + "Visual Studio": "16", + } + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def layout(self): + cmake_layout(self, src_folder="src") + + def requirements(self): + # nlohmann_json is in PUBLIC installed headers (config_envelope.hpp, + # widget_data, plugin_catalog) and is find_dependency()'d by the + # installed CMake usage, so it must propagate to consumers. + self.requires("nlohmann_json/3.12.0", transitive_headers=True) + + # fmt and fast_float are header-only, private implementation details: + # they never appear in an installed pj_base header and are never linked + # into the archives' public surface. Keep them invisible so they do not + # propagate to downstream consumers of this static-library package. + self.requires( + "fmt/12.1.0", + headers=True, + libs=False, + visible=False, + transitive_headers=False, + transitive_libs=False, + ) + self.requires( + "fast_float/8.1.0", + headers=True, + libs=False, + visible=False, + transitive_headers=False, + transitive_libs=False, + ) + + def validate(self): + if self.settings.compiler.cppstd: + check_min_cppstd(self, self._min_cppstd) + minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler)) + if minimum_version and Version(self.settings.compiler.version) < minimum_version: + raise ConanInvalidConfiguration( + f"{self.ref} requires C++{self._min_cppstd}, which needs at least " + f"{self.settings.compiler} {minimum_version} " + f"(got {self.settings.compiler.version})." + ) + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def generate(self): + tc = CMakeToolchain(self) + tc.cache_variables["PJ_INSTALL_SDK"] = True + tc.cache_variables["PJ_BUILD_TESTS"] = False + tc.cache_variables["PJ_BUILD_PORTED_PLUGINS"] = False + # Never fail a third-party package build on a warning from a compiler + # version upstream has not pinned. Requires the PJ_WARNINGS_AS_ERRORS + # option (SDK >= the release that added it). + tc.cache_variables["PJ_WARNINGS_AS_ERRORS"] = False + tc.cache_variables["PJ_ASSERT_THROWS"] = bool(self.options.assert_throws) + tc.generate() + + deps = CMakeDeps(self) + deps.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy( + self, + "LICENSE*", + src=self.source_folder, + dst=os.path.join(self.package_folder, "licenses"), + ) + cmake = CMake(self) + cmake.install() + + # Conan Center re-derives the CMake package from package_info() below, so + # the project-installed find/config/targets files must be removed. Keep + # PjPluginManifest.cmake — it is a genuine build helper shipped as a + # cmake_build_module, not a generated find script. + cmake_dir = os.path.join(self.package_folder, "lib", "cmake", "plotjuggler_sdk") + rm(self, "plotjuggler_sdkConfig*.cmake", cmake_dir) + rm(self, "plotjuggler_sdkTargets*.cmake", cmake_dir) + + def package_info(self): + self.cpp_info.set_property("cmake_file_name", "plotjuggler_sdk") + + # Ship the PjPluginManifest helper as a build module so consumers can + # call pj_emit_plugin_manifest() after find_package() returns. + self.cpp_info.set_property( + "cmake_build_modules", + [os.path.join("lib", "cmake", "plotjuggler_sdk", "PjPluginManifest.cmake")], + ) + + # --- base --- + base = self.cpp_info.components["base"] + base.set_property("cmake_target_name", "plotjuggler_sdk::base") + base.libs = ["pj_base"] + base.includedirs = ["include"] + + # --- plugin_sdk (umbrella INTERFACE: pj_base + nlohmann_json) --- + sdk = self.cpp_info.components["plugin_sdk"] + sdk.set_property("cmake_target_name", "plotjuggler_sdk::plugin_sdk") + sdk.libs = [] # INTERFACE only + sdk.includedirs = ["include"] + sdk.requires = ["base", "nlohmann_json::nlohmann_json"] + + # --- plugin_host (umbrella linking every host-side loader) --- + if self.options.with_host: + host = self.cpp_info.components["plugin_host"] + host.set_property("cmake_target_name", "plotjuggler_sdk::plugin_host") + host.libs = [ + "pj_plugin_runtime_catalog", + "pj_data_source_host", + "pj_message_parser_host", + "pj_toolbox_host", + "pj_dialog_library", + "pj_plugin_catalog", + "pj_plugin_loader_detail", + ] + host.includedirs = ["include"] + host.requires = ["base", "nlohmann_json::nlohmann_json"] + if self.settings.os in ("Linux", "FreeBSD"): + host.system_libs = ["dl"] diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/CMakeLists.txt b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/CMakeLists.txt new file mode 100644 index 0000000..5b72889 --- /dev/null +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.22) +project(test_package LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(plotjuggler_sdk REQUIRED CONFIG) + +add_executable(test_package test_package.cpp) +# plugin_sdk transitively pulls in the `base` component (libpj_base.a) and +# nlohmann_json, exercising real linkage — not just header availability. +target_link_libraries(test_package PRIVATE plotjuggler_sdk::plugin_sdk) diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/conanfile.py b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/conanfile.py new file mode 100644 index 0000000..172244b --- /dev/null +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/conanfile.py @@ -0,0 +1,27 @@ +import os + +from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.cmake import CMake, cmake_layout + + +class TestPackageConan(ConanFile): + settings = "os", "arch", "compiler", "build_type" + generators = "CMakeDeps", "CMakeToolchain" + test_type = "explicit" + + def requirements(self): + self.requires(self.tested_reference_str) + + def layout(self): + cmake_layout(self) + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if can_run(self): + bin_path = os.path.join(self.cpp.build.bindir, "test_package") + self.run(bin_path, env="conanrun") diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/test_package.cpp b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/test_package.cpp new file mode 100644 index 0000000..d07adfb --- /dev/null +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/test_package.cpp @@ -0,0 +1,11 @@ +#include +#include + +// parseNumber dispatches to PJ::detail::parseDoubleImpl, which is +// compiled out-of-line into libpj_base.a. Calling it therefore verifies that +// the static archive is actually linked through the plugin_sdk component, not +// merely that the headers are on the include path. +int main() { + const auto value = PJ::parseNumber("1.5"); + return (value && *value == 1.5) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/config.yml b/packaging/conan-center-index/recipes/plotjuggler_sdk/config.yml new file mode 100644 index 0000000..c7af7f7 --- /dev/null +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/config.yml @@ -0,0 +1,3 @@ +versions: + "0.14.0": + folder: all From b56e7c83a0b9d2cd4dda8648984c6320b87cb487 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 1 Jul 2026 17:51:06 +0200 Subject: [PATCH 2/3] build(sdk): address Codex review of the Conan Center recipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three verified correctness fixes to the staged CCI recipe (conanfile.py only; no change to the SDK build): - assert_throws: export PJ_ASSERT_THROWS as a `base` component define when the option is set. assert.hpp branches on it at the consumer's compile time and upstream marks it PUBLIC on pj_base; stripping the project CMake targets for CCI dropped it, so a package built to throw would hand consumers assert(). Verified: the generated consumer CMakeDeps data now carries `-DPJ_ASSERT_THROWS` on the base component. - MSVC: restore `/Zc:preprocessor` on the plugin_sdk component (via is_msvc). Upstream sets it INTERFACE on the dialog SDK target for PJ_DIALOG_PLUGIN's variadic macro; it was lost when the project targets were stripped. - fPIC: drop the option. Every static target hardcodes POSITION_INDEPENDENT_CODE ON upstream (plugins are dlopen'd shared objects), so fPIC was a no-op knob — CCI requires options to have an observable effect. Verified: `-o &:fPIC=False` now errors "option 'fPIC' doesn't exist". Not changed: the pre-gate v0.14.0 sha256 in conandata.yml stays a documented placeholder (re-point at a tag containing the PJ_WARNINGS_AS_ERRORS gate before submitting). README already carries no fPIC reference. Co-Authored-By: Claude Opus 4.8 --- .../recipes/plotjuggler_sdk/all/conanfile.py | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conanfile.py b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conanfile.py index 294f5b7..54fe468 100644 --- a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conanfile.py +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/conanfile.py @@ -5,6 +5,7 @@ from conan.tools.build import check_min_cppstd from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout from conan.tools.files import copy, get, rm +from conan.tools.microsoft import is_msvc from conan.tools.scm import Version required_conan_version = ">=2.1" @@ -23,16 +24,18 @@ class PlotjugglerSdkConan(ConanFile): settings = "os", "arch", "compiler", "build_type" # The SDK ships as static archives only (host loaders + vocabulary types); - # there is intentionally no `shared` option. `with_host` lets consumers that - # only author plugins skip the host-side loader libraries. `assert_throws` - # switches PJ_ASSERT from assert() to throwing. + # there is intentionally no `shared` option. There is deliberately no `fPIC` + # option either: PlotJuggler plugins are shared objects and the host loaders + # dlopen() them, so every target hardcodes POSITION_INDEPENDENT_CODE ON + # upstream. Exposing fPIC would be a no-op knob (CCI requires options to have + # an observable effect). `with_host` lets consumers that only author plugins + # skip the host-side loader libraries. `assert_throws` switches PJ_ASSERT + # from assert() to throwing. options = { - "fPIC": [True, False], "with_host": [True, False], "assert_throws": [True, False], } default_options = { - "fPIC": True, "with_host": True, "assert_throws": False, } @@ -53,10 +56,6 @@ def _compilers_minimum_version(self): "Visual Studio": "16", } - def config_options(self): - if self.settings.os == "Windows": - del self.options.fPIC - def layout(self): cmake_layout(self, src_folder="src") @@ -154,6 +153,13 @@ def package_info(self): base.set_property("cmake_target_name", "plotjuggler_sdk::base") base.libs = ["pj_base"] base.includedirs = ["include"] + # assert.hpp is a header that branches on PJ_ASSERT_THROWS at the + # *consumer's* compile time; upstream exports it PUBLIC on pj_base. The + # define must ride along or consumers get assert() while the archive was + # built to throw (and vice versa). Propagated to plugin_sdk/plugin_host + # via their `requires = ["base", ...]`. + if self.options.assert_throws: + base.defines = ["PJ_ASSERT_THROWS"] # --- plugin_sdk (umbrella INTERFACE: pj_base + nlohmann_json) --- sdk = self.cpp_info.components["plugin_sdk"] @@ -161,6 +167,12 @@ def package_info(self): sdk.libs = [] # INTERFACE only sdk.includedirs = ["include"] sdk.requires = ["base", "nlohmann_json::nlohmann_json"] + # PJ_DIALOG_PLUGIN's variadic-overload macro needs conformant __VA_ARGS__ + # expansion on MSVC. Upstream sets this as an INTERFACE option on the + # dialog SDK target, which is dropped when we strip the project's CMake + # targets — restore it here so MSVC dialog-plugin authors still compile. + if is_msvc(self): + sdk.cxxflags = ["/Zc:preprocessor"] # --- plugin_host (umbrella linking every host-side loader) --- if self.options.with_host: From 0c5847348973b7bcdc756c676ae2466b431e3013 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 1 Jul 2026 18:10:30 +0200 Subject: [PATCH 3/3] build(sdk): exercise plugin_host in the CCI test_package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the remaining Codex nit: the test_package linked only plugin_sdk and never touched plugin_host, so a mis-wired plugin_host lib list or missing `dl` system_lib would go uncaught. Now, when the package is built with_host (default), the consumer also links plotjuggler_sdk::plugin_host and constructs an empty PluginRuntimeCatalog — a disk-less, no-throw default ctor that lives in libpj_plugin_runtime_catalog.a and cascades the loader archives (and libdl) onto the link line. The test_package conanfile mirrors the tested package's with_host option into a TEST_WITH_HOST cache variable so `-o with_host=False` still builds (the plugin_host component does not exist there). Verified both matrix points: with_host=True links plugin_host and runs with no undefined references (proving the lib/syslib wiring); with_host=False builds and runs without it. Co-Authored-By: Claude Opus 4.8 --- .../all/test_package/CMakeLists.txt | 8 ++++++++ .../all/test_package/conanfile.py | 13 +++++++++++-- .../all/test_package/test_package.cpp | 18 +++++++++++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/CMakeLists.txt b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/CMakeLists.txt index 5b72889..ab417d9 100644 --- a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/CMakeLists.txt +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/CMakeLists.txt @@ -10,3 +10,11 @@ add_executable(test_package test_package.cpp) # plugin_sdk transitively pulls in the `base` component (libpj_base.a) and # nlohmann_json, exercising real linkage — not just header availability. target_link_libraries(test_package PRIVATE plotjuggler_sdk::plugin_sdk) + +# When the package was built with_host (default), also link and exercise the +# host loaders so the plugin_host component's lib list and its `dl` syslib +# wiring are validated. Gated so `-o with_host=False` still builds. +if(TEST_WITH_HOST) + target_link_libraries(test_package PRIVATE plotjuggler_sdk::plugin_host) + target_compile_definitions(test_package PRIVATE PJ_TEST_WITH_HOST) +endif() diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/conanfile.py b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/conanfile.py index 172244b..1c56201 100644 --- a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/conanfile.py +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/conanfile.py @@ -2,12 +2,11 @@ from conan import ConanFile from conan.tools.build import can_run -from conan.tools.cmake import CMake, cmake_layout +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout class TestPackageConan(ConanFile): settings = "os", "arch", "compiler", "build_type" - generators = "CMakeDeps", "CMakeToolchain" test_type = "explicit" def requirements(self): @@ -16,6 +15,16 @@ def requirements(self): def layout(self): cmake_layout(self) + def generate(self): + # Mirror the tested package's with_host option: the plugin_host + # component only exists when the package was built with it, so the + # consumer must only link plotjuggler_sdk::plugin_host in that case. + with_host = bool(self.dependencies["plotjuggler_sdk"].options.with_host) + tc = CMakeToolchain(self) + tc.cache_variables["TEST_WITH_HOST"] = with_host + tc.generate() + CMakeDeps(self).generate() + def build(self): cmake = CMake(self) cmake.configure() diff --git a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/test_package.cpp b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/test_package.cpp index d07adfb..6c0eaac 100644 --- a/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/test_package.cpp +++ b/packaging/conan-center-index/recipes/plotjuggler_sdk/all/test_package/test_package.cpp @@ -1,11 +1,27 @@ #include #include +#ifdef PJ_TEST_WITH_HOST +#include +#endif + // parseNumber dispatches to PJ::detail::parseDoubleImpl, which is // compiled out-of-line into libpj_base.a. Calling it therefore verifies that // the static archive is actually linked through the plugin_sdk component, not // merely that the headers are on the include path. int main() { const auto value = PJ::parseNumber("1.5"); - return (value && *value == 1.5) ? EXIT_SUCCESS : EXIT_FAILURE; + if (!value || *value != 1.5) { + return EXIT_FAILURE; + } + +#ifdef PJ_TEST_WITH_HOST + // Constructing an empty catalog (default, disk-less) forces the plugin_host + // archives — and the dlopen-backed loader, hence libdl — onto the link line, + // validating the plugin_host component's lib list and system_libs wiring. + const PJ::PluginRuntimeCatalog catalog; + (void)catalog; +#endif + + return EXIT_SUCCESS; }