Skip to content

fix(build): rerun rclrs's build script when AMENT_PREFIX_PATH changes - #718

Open
rosterloh wants to merge 1 commit into
ros2-rust:mainfrom
rosterloh:build/rerun-on-ament-prefix-path
Open

rosterloh wants to merge 1 commit into
ros2-rust:mainfrom
rosterloh:build/rerun-on-ament-prefix-path

Conversation

@rosterloh

Copy link
Copy Markdown

Problem

rclrs/build.rs emits a rustc-link-search path for every prefix
get_search_paths() returns from AMENT_PREFIX_PATH, but declares only ROS_DISTRO as a rerun
trigger. Once a build script emits any rerun-if line, Cargo reruns it
only for the listed triggers. So the search paths stay whatever they were
on the first build.

ros-env does declare rerun-if-env-changed=AMENT_PREFIX_PATH. So after
sourcing a workspace that adds an interface package, ros-env reruns and
compiles that package in, with a #[link] to its typesupport library, but no
build script offers the new prefix's lib/ to the linker:

ld: library not found for -leit_capture_interfaces__rosidl_typesupport_c

The library is on the new prefix. cargo clean -p rclrs -p rosidl_runtime_rs
fixes it, which is how it has been worked around.

Reproduction

A crate depending on rclrs 0.8.0 and ros-env 0.3.0, in a fresh target
directory:

  1. Build with only the base ROS environment sourced → ok.
  2. Source a workspace that adds an interface package, rebuild without cleaning.
Build step 2
crates.io rclrs 0.8.0 + rosidl_runtime_rs 0.7.0 fails (library not found)
the rosidl_runtime_rs companion only links
this PR only links
both links

Cargo collects link search paths from every build script, so this repro links
once either crate reruns. The rosidl_runtime_rs companion is the one that
clears the symptom for everyone: every rclrs user also builds it, and crates
that use ros-env without rclrs get their search paths only from it.

This PR is still needed on its own terms. rclrs/build.rs reads
AMENT_PREFIX_PATH and should declare it as a rerun trigger. Without that,
rclrs keeps handing the linker the old prefixes, and an older copy of a
library left in one of them can be picked ahead of the new one.

Change

One println!("cargo:rerun-if-env-changed={AMENT_PREFIX_PATH_ENV_VAR}"), using
ament_rs's own constant, next to the get_search_paths() call that reads it.

Testing

  • The reproduction above (ROS 2 Lyrical, RoboStack, macOS arm64).
  • cargo test -F default (RoboStack Lyrical with test_msgs and
    example_interfaces, Rust 1.98.1 stable, macOS arm64): 120 tests and 51
    doc-tests pass, the same as on main.
  • cargo clippy --no-deps --all-targets -F default -- -D warnings fails with
    the same 123 findings on main and on this branch under clippy 0.1.98
    (the library's deref and doc-list lints). None of them are in build.rs,
    so main doesn't pass this gate on current stable either.
  • Stable cargo fmt --check: clean. CI uses nightly rustfmt, which I didn't run.

build.rs emits a rustc-link-search path for every prefix from
get_search_paths(), which reads AMENT_PREFIX_PATH, but declares only
ROS_DISTRO as a rerun trigger. Once a build script emits any rerun-if line,
Cargo reruns it only for the listed triggers, so the search paths stay
whatever they were on the first build.

Reproduced with a crate that depends on rclrs 0.8.0 and ros-env 0.3.0: build
it, source a workspace that adds an interface package, and rebuild without
`cargo clean`. ros-env declares rerun-if-env-changed=AMENT_PREFIX_PATH, so it
reruns and compiles the new package in, with a #[link] to its typesupport
library. rclrs and rosidl_runtime_rs, which emit the per-prefix link search
paths, do not rerun, so the final link fails with
"library not found for -l<pkg>__rosidl_typesupport_c" although the library is
on the new prefix. With this change the rebuild links.

Assisted-by: Claude Code:claude-opus-5-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant