From 9f8bac191d26da43f50faab4bd187acd0431b2e0 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Fri, 17 Jul 2026 13:10:48 +0200 Subject: [PATCH 1/2] Restore TestNode source compatibility The move of TestNode's state behind a PImpl (#1169) removed two things that consumers may rely on: - the transitive includes of script_parser.hpp and timer_queue.h, which test_node.h had always pulled in. Restore them (tagged IWYU keep) so code using e.g. BT::ScriptFunction through this header keeps compiling. - the protected _config member, visible to subclasses since TestNode was introduced. Restore it as a direct member, first in the class so it also sits at the same byte offset as in 4.9. Only the internal machinery (executors, timer, completed flag) stays behind the PImpl; new state must be added there. Co-Authored-By: Claude Fable 5 --- include/behaviortree_cpp/actions/test_node.h | 13 +++++++-- src/actions/test_node.cpp | 28 ++++++++++---------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/include/behaviortree_cpp/actions/test_node.h b/include/behaviortree_cpp/actions/test_node.h index c675d2e4c..9e571500d 100644 --- a/include/behaviortree_cpp/actions/test_node.h +++ b/include/behaviortree_cpp/actions/test_node.h @@ -15,6 +15,11 @@ #include "behaviortree_cpp/action_node.h" +// Not used by this header anymore, but included since 4.x: kept so that +// consumers relying on them transitively do not break. +#include "behaviortree_cpp/scripting/script_parser.hpp" // IWYU pragma: keep +#include "behaviortree_cpp/utils/timer_queue.h" // IWYU pragma: keep + #include #include #include @@ -112,8 +117,12 @@ class TestNode : public BT::StatefulActionNode NodeStatus onCompleted(); - // All state lives behind this pointer, so that adding or changing it does not - // alter the layout that consumers compile against. + // Kept as a direct member (first, at the same offset as in 4.9) for + // compatibility with subclasses that access it. Everything else lives behind + // the PImpl, so that adding or changing state does not alter the layout that + // consumers compile against. + std::shared_ptr _config; + struct PImpl; std::unique_ptr _p; }; diff --git a/src/actions/test_node.cpp b/src/actions/test_node.cpp index 6990ffe14..a1f91d0fc 100644 --- a/src/actions/test_node.cpp +++ b/src/actions/test_node.cpp @@ -79,7 +79,6 @@ NodeStatus convertScriptResultToStatus(const Any& result) struct TestNode::PImpl { - std::shared_ptr config; ScriptFunction return_status_executor; ScriptFunction success_executor; ScriptFunction failure_executor; @@ -95,14 +94,15 @@ TestNode::TestNode(const std::string& name, const NodeConfig& config, TestNode::TestNode(const std::string& name, const NodeConfig& config, std::shared_ptr test_config) - : StatefulActionNode(name, config), _p(std::make_unique()) + : StatefulActionNode(name, config) + , _config(std::move(test_config)) + , _p(std::make_unique()) { - _p->config = std::move(test_config); setRegistrationID("TestNode"); - if(_p->config->return_status_script.empty()) + if(_config->return_status_script.empty()) { - validateTestNodeStatus(_p->config->return_status, "return_status"); + validateTestNodeStatus(_config->return_status, "return_status"); } auto prepareScript = [](const std::string& script, auto& executor) { @@ -116,24 +116,24 @@ TestNode::TestNode(const std::string& name, const NodeConfig& config, executor = result.value(); } }; - prepareScript(_p->config->return_status_script, _p->return_status_executor); - prepareScript(_p->config->success_script, _p->success_executor); - prepareScript(_p->config->failure_script, _p->failure_executor); - prepareScript(_p->config->post_script, _p->post_executor); + prepareScript(_config->return_status_script, _p->return_status_executor); + prepareScript(_config->success_script, _p->success_executor); + prepareScript(_config->failure_script, _p->failure_executor); + prepareScript(_config->post_script, _p->post_executor); } TestNode::~TestNode() = default; NodeStatus TestNode::onStart() { - if(_p->config->async_delay <= std::chrono::milliseconds(0)) + if(_config->async_delay <= std::chrono::milliseconds(0)) { return onCompleted(); } // convert this in an asynchronous operation. Use another thread to count // a certain amount of time. _p->completed = false; - _p->timer.add(std::chrono::milliseconds(_p->config->async_delay), [this](bool aborted) { + _p->timer.add(std::chrono::milliseconds(_config->async_delay), [this](bool aborted) { if(!aborted) { _p->completed.store(true); @@ -165,9 +165,9 @@ NodeStatus TestNode::onCompleted() { NodeStatus status = NodeStatus::IDLE; - if(_p->config->complete_func) + if(_config->complete_func) { - status = _p->config->complete_func(); + status = _config->complete_func(); } else if(_p->return_status_executor) { @@ -180,7 +180,7 @@ NodeStatus TestNode::onCompleted() } else { - status = _p->config->return_status; + status = _config->return_status; } validateTestNodeStatus(status, "completion"); From 1e3632d80752412e5b10661990cf880f6d3ba549 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Fri, 17 Jul 2026 13:10:48 +0200 Subject: [PATCH 2/2] Bump version to 4.10.0 The changes since 4.9.1 (TestNodeConfig gaining a field, TestNode and StatusChangeLogger moving state behind a PImpl) are a one-time ABI break: binaries built against 4.9 headers must be recompiled. Bump the minor version so this cannot ship as a patch release that package managers would treat as ABI-compatible. Co-Authored-By: Claude Fable 5 --- CMakeLists.txt | 2 +- package.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04854e740..b222eca73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16.3) # version on Ubuntu Focal -project(behaviortree_cpp VERSION 4.9.1 LANGUAGES C CXX) +project(behaviortree_cpp VERSION 4.10.0 LANGUAGES C CXX) # create compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/package.xml b/package.xml index 4d5d2fe03..3ab80bc66 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ behaviortree_cpp - 4.9.1 + 4.10.0 This package provides the Behavior Trees core library.