Skip to main content

NROS_CODEGEN_VERSION_MIN

Constant NROS_CODEGEN_VERSION_MIN 

Source
pub const NROS_CODEGEN_VERSION_MIN: u32 = 18;
Expand description

The oldest codegen version this runtime still accepts.

Equal to NROS_CODEGEN_VERSION at introduction: no window, because generated/ is never committed and regeneration is therefore always available. Raise the floor only when a real migration needs one, and lower it never.

Held at 1 while NROS_CODEGEN_VERSION moved to 2 (phase-417, rebased onto phase-429’s gate). That surface move is ADDITIVE plus one relocation, so a tree generated against version 1 still runs: the C additions are new entry points, the two C++ changes add size()/empty() and std::string interop to FixedString/HeapString, and the four rcl_ret_t declarations that left action.h / client.h / parameter.h / service.h were CONSOLIDATED into nros_generated.h, which all four still reach through rclc/types.h — the headers say so in a comment, and keeping that include is what makes #include <rclc/action.h> continue to compile. Nothing a version-1 tree names was withdrawn, so this is the window the doc above describes rather than a migration.

Still 2 while NROS_CODEGEN_VERSION moved to 3 (issues 1148/1149). That move is one ADDED runtime entry point, rclc_cdr_align, which the header-only rclc_cdr_borrow_le_slice_* now call so an 8-byte borrowed sequence starts on its stream boundary. A version-2 tree names nothing that was withdrawn: it compiles against the corrected rclc/detail/view.h and picks the fix up for free, because the view helpers are static inline in the header rather than symbols the generated code defines.

Still 2 while NROS_CODEGEN_VERSION moved to 4 (phase-427 W7). That move is a SPELLING change and nothing else: nros::bind_subscription_sized — the one demanded C++ signature that names the node type — now writes its parameter ::rclcpp::Node& where it wrote Node&, because the class moved to rclcpp:: and nros::Node became a deprecated alias for it. The two spellings are ONE TYPE (std::is_same<rclcpp::Node, nros::Node> is asserted by tests/compile/one_node_type.cpp), so a version-3 tree — which declares its node static ::nros::Node __nros_node_0; — still compiles and still links, with a deprecation warning naming its replacement. Nothing it names was withdrawn, which is the window the doc above describes.

The version moves anyway because the gate is fail-closed on the TEXT of a demanded declaration and should stay that way: it cannot know that two spellings are one type, and a gate that tried to would be one that misses a real rename.

Still 2 while NROS_CODEGEN_VERSION moved to 5 (phase-417 W5.b/c/d). That move is ADDITIVE and, in most of its entries, is not a change to the runtime at all: the rclc preset constructors landed as static inline forwarders in <nros/{publisher,subscription,service,client,action}.h>, and naming a type inside one of those headers is what puts a c|type|<header>|<name> row in the extracted surface — rclc_message_type_t, rcl_node_t, rclc_service_type_t and rclc_action_type_t were already declared in nros_generated.h and still are, reached the same way. The one genuinely new declaration a demanded name resolves to is rclc_service_init_with_qos, which is an entry point that already existed and is now also visible from <rclc/service.h>. Nothing a version-4 tree names was withdrawn, so this is the window the doc above describes rather than a migration.

The version moves anyway for the reason the version-4 paragraph gives: the gate is fail-closed on the TEXT of a demanded declaration and should stay that way. A gate that tried to decide which additions are “really” runtime changes is one that misses a real withdrawal.

Still 2 while NROS_CODEGEN_VERSION moved to 6 (phase-417 W4.b). That move is a WITHDRAWAL, and it is the first one — nros_core::action stopped re-exporting ActionServer and ActionClient, two “type-level marker” structs. A version-5 tree still runs, because no generated tree has ever named them: measured before the deletion, they had ZERO references anywhere in this repository, and they were UNREACHABLE through the nros facade at all, which re-exports nros_node’s live ActionServer / ActionClient under exactly those spellings. So the floor stays where it is. The gate is fail-closed on the extracted surface and cannot know which names nothing reached, which is the property that makes it worth keeping.

Still 2 while NROS_CODEGEN_VERSION moved to 7 (issue 1437, phase-444). ADDITIVE on the surface generated code names, plus one APPEND to a struct nothing generated declares. The additions are six new C entry points (nros_{publisher,subscription}_get_actual_qos and the four service / client halves) and two enumerators on each of the four nros_qos_*_t enums (UNKNOWN, and SYSTEM_DEFAULT on three of them), appended so every existing discriminant keeps its value. The append is _executor on rcl_subscription_t, placed after _opaque so every existing field offset is unchanged — it grows the struct, which is why this is a surface move at all, and a version-6 tree that only names the struct by pointer is unaffected. Nothing was withdrawn, so the floor stays where it is.

The gate reports the move as two CHANGED types rather than as the four added prototypes, because a const struct rcl_service_t * parameter is a tagged reference and keys on the same c|type|<header>|<name> row as the struct itself. That is the gate being fail-closed on text, which is the property the version-4 paragraph above argues for keeping.

Still 2 while NROS_CODEGEN_VERSION moved to 8 (phase-467 Q3). ADDITIVE, and the first move that adds a TRAIT generated code implements — which is the trigger the doc above names first. nros_core::SecNanosecMsg is the Rust stand-in for the C++ template <typename TimeMsgT> Time::to_msg: Rust has no structural bound for “has sec and nanosec”, so rosidl-codegen emits impl nros_core::SecNanosecMsg for <Msg> for every generated message with that exact field set, and nros_core::Time::to_ros_msg() returns through it. The surface moved by two rows, both additions: the trait, and the pub use time:: re-export that publishes it.

A version-7 tree still runs: it names nothing that was withdrawn, and the impl is something a NEWER tree emits rather than something an older one is missing. What an older tree loses is only the conversion itself — t.to_ros_msg() into one of ITS types will not resolve until it is regenerated, which is a compile error at the call site on the day someone writes the call, not a silent mismatch. So the floor stays where it is.

Still 2 while NROS_CODEGEN_VERSION moved to 9 (issue 1293, phase-480 W4). ADDITIVE: nros_serdes::schema::EMPTY_STRUCT_MEMBER, the name of rosidl’s uint8 structure_needs_at_least_one_member, which a version-9 tree names as the schema of every empty message and whose byte it writes. A version-8 tree still compiles and runs against this runtime: it names nothing that was withdrawn. What it keeps is the defect 1293 fixes for a regenerated tree, and only for ITS OWN empty messages: they still go out with no byte (which every stock RMW refuses) and still have no Cyclone descriptor (BuildError::EmptySchema, which says to regenerate). That is the behaviour the tree already had, not a new mismatch the runtime introduces, so the floor stays where it is.

RAISED to 10 when NROS_CODEGEN_VERSION moved to 10 (phase-483 W1), and this is the first move that needs it. The C++ user API left nros:: for rclcpp::, and nros:: was deleted rather than kept as an alias, so every name a version-9 C++ tree spells — nros::FixedString<N>, nros::FixedSequence<T, N>, nros::HeapString, nros::HeapSequence<T>, nros::Span<T> / LeSpan<T> / StringView, nros::bind_subscription_sized and nros::detail::size_bound_dependent_false — is WITHDRAWN. A version-9 C++ tree does not compile against this runtime, so accepting it would replace the version mismatch this constant reports with a wall of unresolved-name errors. Rust and C trees are unaffected by the move, but the version is one number for all three, so they regenerate too.

Still 10 while NROS_CODEGEN_VERSION moved to 11 (phase-487 W1). The surface the gate saw move is subscription.h’s static inline rclc_subscription_init_best_effort, whose body forwards to rclc_subscription_init_with_qos and lost the two NULLs that function no longer takes. Generated C does not call either: a message header’s typed registration is rclc_executor_add_subscription_typed_sized, whose signature is unchanged, and it passes struct rcl_subscription_t *, whose layout shrank but which generated code never dereferences. A version-10 tree therefore still compiles and runs.

RAISED to 12 when NROS_CODEGEN_VERSION moved to 12 (phase-487 W2). A generated C service header’s <Srv>_service_init called rclc_service_init_with_qos with the trampoline and handler in two positions that function no longer has, because the executor arena owns a dispatched server’s callback and the struct keeps none. The binding moved to a new generated <Srv>_executor_add_service over rclc_executor_add_service_raw. A version-10 or -11 C tree with a service therefore does not compile against this runtime, so it is refused by version rather than by a wall of argument-count errors.

RAISED to 13 with NROS_CODEGEN_VERSION (phase-492 W3, RFC-0089 amended 2026-10-12). The C API dropped nros_: every function, type and constant generated C names took its upstream spelling or rclc_ (docs/reference/c-api-rename-map.tsv), with no forwarders. A version-12 C tree calls names this runtime no longer defines, so it is refused by version rather than by a wall of undeclared identifiers. Rust and C++ trees are unaffected, but the version is one number for all three.

RAISED to 14 with NROS_CODEGEN_VERSION (phase-492 W7/W8, RFC-0089 “Messages take rosidl’s C names AND its member shape” and “ROSIDL_GET_*_TYPE_SUPPORT adopted as a pass-through”). Generated C messages take rosidl’s names (std_msgs__msg__String in <std_msgs/msg/string.h>) and member shape (rosidl_runtime_c__String, __Sequence, wired by a generated __Storage + __init_in); the type descriptors rclc_message_type_t / rclc_service_type_t / rclc_action_type_t gained codec slots and the generated <pkg>__<sub>__<Name>__nros_type fills them; the typed helpers (<Msg>_publish, <Msg>_executor_add_subscription*, _subscribe*) and rclc_executor_add_subscription_typed{,_sized} retired for rcl_publish and rclc’s six-argument rclc_executor_add_subscription_with_context. A version-13 C tree names a descriptor layout and entry points this runtime no longer has, so it is refused by version. Rust and C++ trees are unaffected, but the version is one number for all three.

Still 14 while NROS_CODEGEN_VERSION moved to 15 (issue 1179, phase-498 W3). Generated RosMessage impls now state MAX_SERIALIZED_BOUND, the type’s size bound, so a typed subscription is sized from its type on every backend. The trait const is DEFAULTED (None), so a version-14 tree still compiles against this runtime and only keeps the image-wide receive size it had. Nothing it names is gone, so it is accepted.

Was 14 while NROS_CODEGEN_VERSION moved to 16 (issue 1913). Generated actions now carry the hash each of their five endpoints is keyed on: Rust impls state RosAction::{CANCEL_GOAL_SERVICE,STATUS_MESSAGE}_HASH, the C descriptor rclc_action_type_t gained a trailing endpoint_hashes, and C++ action types gained five <Endpoint>_HASH members. All three are ADDITIVE on the runtime side: the Rust consts default to ACTION_HASH, an older C designated initializer leaves the trailing member NULL (read as “use type_hash”), and rclcpp::detail::action_endpoint_hashes<A>() detects the C++ members. So an older tree still compiles and runs with the single hash it always had, and is accepted; a NEW tree names a member an older runtime lacks, which is what the bump refuses.

17 with NROS_CODEGEN_VERSION (phase-501 W1): the C API’s headers moved from nros/ into rclc/ (<rclc/types.h>, <rclc/detail/cdr.h>, <rclc/detail/view.h>, …), with no forwarding headers left behind. A version-16 C tree includes <nros/types.h>, which this runtime no longer ships, so it cannot compile and is refused by version instead. Rust and C++ trees are unaffected, but the version is one number for all three.

18 with NROS_CODEGEN_VERSION (phase-503 W1): the same move for C++. The nros-cpp headers left nros/ for rclcpp/, rclcpp/detail/, rclcpp_action/ and rclcpp_lifecycle/, again with no forwarding headers. A version-17 C++ tree includes <nros/heap_string.hpp>, which this runtime no longer ships, so it is refused by version rather than failing to compile.

The range [NROS_CODEGEN_VERSION_MIN, NROS_CODEGEN_VERSION] is expressed to C and C++ as a SET OF DEFINED SYMBOLS rather than as a comparison — see nros-build-helpers’ codegen-version anchor — so there is no range check on that side that could itself be wrong.