From 6506b12020df59cc9d70c27c0e6af3e86fab3e17 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Tue, 18 Aug 2026 14:44:45 -0500 Subject: [PATCH 1/2] fix(odrive_native): repair the interop gate broken by the golden's espp-lib section The lib_wrapper_roundtrip section added to pc/tests/odrive_native_golden.cpp includes odrive_native.hpp (the espp::OdriveNative wrapper), but the interop harness builds that file with only c++ -std=c++20 -I components/odrive_native/include so base_component.hpp could not resolve and the gate failed at the build step (and #721 was merged with the last rerun cancelled, so main's gate is red). Guard the wrapper section with __has_include("base_component.hpp"): the pc-package build (full espp::espp) still compiles and runs it, while the minimal harness build compiles it out and prints an explicit skip line. Verified: the exact minimal CI compile now builds + ALL PASSED (wrapper skipped), the full-lib build runs the wrapper section (ALL PASSED), and the complete interop harness passes 7/7 in an ubuntu:24.04 container. Co-Authored-By: Claude Opus 4.8 --- pc/tests/odrive_native_golden.cpp | 32 +++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/pc/tests/odrive_native_golden.cpp b/pc/tests/odrive_native_golden.cpp index 3a8fe2d77b..66dc8e636a 100644 --- a/pc/tests/odrive_native_golden.cpp +++ b/pc/tests/odrive_native_golden.cpp @@ -4,9 +4,14 @@ // round-trip, all verified against the fw-v0.5.1 reference (and proven end-to-end // by the serial-loopback interop harness in components/odrive_native/interop). // -// Built by the pc harness against the installed espp package: odrive_native is -// part of the x-platform espp lib, so its headers come from the espp::espp -// target like every other test here. Exits 0 when every golden matches. +// Built two ways: +// - by the pc harness against the installed espp package (full espp::espp +// target, so the espp::OdriveNative wrapper section below also runs); +// - by the interop harness (components/odrive_native/interop/run_interop.sh) +// with ONLY `c++ -std=c++20 -I components/odrive_native/include` — no espp +// lib, so the wrapper section (which needs base_component/logger/fmt and +// the compiled Logger) is compiled out via the __has_include guard. +// Exits 0 when every golden matches. #include #include @@ -18,7 +23,19 @@ #include "detail/odrive_native_core.hpp" #include "detail/odrive_native_stream.hpp" + +// The espp::OdriveNative wrapper is only testable when the full espp package +// (base_component + logger + fmt headers AND the compiled Logger) is on the +// include/link path — i.e. the pc build. The minimal interop-harness build +// sees only the odrive_native component headers. +#if defined(__has_include) +#if __has_include("base_component.hpp") +#define ODRIVE_GOLDEN_HAS_ESPP_LIB 1 +#endif +#endif +#if ODRIVE_GOLDEN_HAS_ESPP_LIB #include "odrive_native.hpp" +#endif using espp::detail::kProtocolVersion; using espp::detail::odrive_crc16; @@ -132,7 +149,9 @@ static void golden_packet_roundtrip() { // The espp::OdriveNative wrapper (BaseComponent + the core) is what the lib // exposes; exercise it through the same read/write path to prove the -// x-platform packaging end-to-end (not just the detail/ headers). +// x-platform packaging end-to-end (not just the detail/ headers). Only built +// when the full espp package is available (see the guard at the top). +#if ODRIVE_GOLDEN_HAS_ESPP_LIB static void lib_wrapper_roundtrip() { std::printf("lib_wrapper_roundtrip\n"); espp::OdriveNative dev(espp::OdriveNative::Config{.log_level = espp::Logger::Verbosity::WARN}); @@ -178,13 +197,18 @@ static void lib_wrapper_roundtrip() { CHECK(rb == wrote); } } +#endif // ODRIVE_GOLDEN_HAS_ESPP_LIB int main() { golden_crc8(); golden_crc16(); golden_frame(); golden_packet_roundtrip(); +#if ODRIVE_GOLDEN_HAS_ESPP_LIB lib_wrapper_roundtrip(); +#else + std::printf("lib_wrapper_roundtrip skipped (minimal build without the espp lib)\n"); +#endif if (g_failures == 0) { std::printf("\nODRIVE_NATIVE GOLDEN: ALL PASSED\n"); return 0; From f6e0a48214873ae350fd466f7c6f0a9f207f8806 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Tue, 18 Aug 2026 15:28:28 -0500 Subject: [PATCH 2/2] fix(odrive_native): drive the golden's espp-lib guard from the build system Per PR review: ODRIVE_GOLDEN_HAS_ESPP_LIB is now ALWAYS defined to 0 or 1 (-Wundef-clean), the pc harness defines it to 1 explicitly (it links the whole espp::espp archive, so headers AND the compiled Logger are guaranteed -- closing the headers-present-but-not-linked gap), and __has_include remains only as the fallback for bare compiles with no build-system signal. Verified: minimal harness compile with -Werror=undef (wrapper skipped), explicit -D...=0 with headers present (skipped, no link error), header fallback with Logger linked (wrapper runs), and the pc harness build against the installed package (wrapper runs). ALL PASSED in every mode. Co-Authored-By: Claude Opus 4.8 --- pc/CMakeLists.txt | 7 +++++++ pc/tests/odrive_native_golden.cpp | 13 +++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pc/CMakeLists.txt b/pc/CMakeLists.txt index 1a7fec227e..d57263cae8 100644 --- a/pc/CMakeLists.txt +++ b/pc/CMakeLists.txt @@ -18,6 +18,13 @@ set(CMAKE_CXX_STANDARD 23) # needed here. find_package(espp REQUIRED) +# Every test here links the WHOLE espp::espp archive (below), so the full espp +# package — headers AND compiled objects like Logger — is guaranteed available. +# Declare that to the tests explicitly: pc/tests/odrive_native_golden.cpp keys +# its espp::OdriveNative wrapper section off this (the minimal interop-harness +# build of the same file gets no define and falls back to header detection). +add_compile_definitions(ODRIVE_GOLDEN_HAS_ESPP_LIB=1) + MACRO(GEN_TESTS curdir) # get test files FILE(GLOB tests RELATIVE ${curdir} ${curdir}/tests/*.cpp) diff --git a/pc/tests/odrive_native_golden.cpp b/pc/tests/odrive_native_golden.cpp index 66dc8e636a..89cfbb1d8f 100644 --- a/pc/tests/odrive_native_golden.cpp +++ b/pc/tests/odrive_native_golden.cpp @@ -26,11 +26,16 @@ // The espp::OdriveNative wrapper is only testable when the full espp package // (base_component + logger + fmt headers AND the compiled Logger) is on the -// include/link path — i.e. the pc build. The minimal interop-harness build -// sees only the odrive_native component headers. -#if defined(__has_include) -#if __has_include("base_component.hpp") +// include/link path — i.e. the pc build, whose harness defines +// ODRIVE_GOLDEN_HAS_ESPP_LIB=1 (see ../CMakeLists.txt) because it links the +// whole espp::espp archive. When the build system says nothing (e.g. a bare +// compile of this file), fall back to header detection; the macro is ALWAYS +// defined to 0 or 1 so `#if` is -Wundef-clean. +#if !defined(ODRIVE_GOLDEN_HAS_ESPP_LIB) +#if defined(__has_include) && __has_include("base_component.hpp") #define ODRIVE_GOLDEN_HAS_ESPP_LIB 1 +#else +#define ODRIVE_GOLDEN_HAS_ESPP_LIB 0 #endif #endif #if ODRIVE_GOLDEN_HAS_ESPP_LIB