Skip to content

Emit a .dsv env hook so the plugin path resolves under colcon - #1

Open
MonkeScripts wants to merge 1 commit into
mainfrom
fix/env-hook-dsv-descriptor
Open

Emit a .dsv env hook so the plugin path resolves under colcon#1
MonkeScripts wants to merge 1 commit into
mainfrom
fix/env-hook-dsv-descriptor

Conversation

@MonkeScripts

Copy link
Copy Markdown
Contributor

Problem

The environment hook was a .sh-only file that hardcoded the configure-time install prefix:

export GZ_SIM_SYSTEM_PLUGIN_PATH="@CMAKE_INSTALL_PREFIX@/lib:${GZ_SIM_SYSTEM_PLUGIN_PATH}"

That works, but bakes an absolute path into the installed hook, so the install tree cannot be moved, copied into an image, or reused under a different mount without rebuilding.

Fix

Switch to the ament-native hook and declare the DSV descriptor so ament_environment_hooks() also emits gz_led_plugin.dsv:

set(AMENT_CMAKE_ENVIRONMENT_HOOKS_DESC_gz_led_plugin
  "prepend-non-duplicate;GZ_SIM_SYSTEM_PLUGIN_PATH;lib")

This is the same mechanism ament uses for its own ament_prefix_path / path / library_path hooks, which all ship both forms.

Why the descriptor matters

_local_setup_util_sh.py prefers a sibling .dsv and only falls back to sourcing the .sh:

if os.path.exists(basename + '.dsv'):
    extensions.add('dsv')
...
if 'dsv' in extensions:
    commands += process_dsv_file(basename + '.dsv', ...)
elif ...:
    commands += [FORMAT_STR_INVOKE_SCRIPT.format_map(...)]

and that fallback exports COLCON_CURRENT_PREFIX, never AMENT_CURRENT_PREFIX:

FORMAT_STR_INVOKE_SCRIPT = 'COLCON_CURRENT_PREFIX="{prefix}" _colcon_prefix_sh_source_script "{script_path}"'

So a .sh-only hook using ament_prepend_unique_value "$AMENT_CURRENT_PREFIX/lib" would silently prepend whichever prefix was sourced last (e.g. /opt/ros/humble/lib). Emitting the .dsv avoids that path entirely.

The descriptor value is relative (lib), which colcon resolves against the package prefix — so the install tree stays relocatable.

Verification

Clean rebuild, then loading a world that uses the plugin (headless, isolated GZ_PARTITION):

  • gz_led_plugin.dsv emitted alongside the .sh
  • GZ_SIM_SYSTEM_PLUGIN_PATH head is install/gz_led_plugin/lib; no /opt/ros/humble/lib contamination
  • libgz_led_plugin.so resolvable on the path
  • 0 Failed to load system plugin errors, 0 LedPlugin errors

@MonkeScripts
MonkeScripts force-pushed the fix/env-hook-dsv-descriptor branch from 18d5d92 to a04352d Compare August 16, 2026 03:54
The hook was a .sh-only file that hardcoded the configure-time install
prefix. It worked, but baked an absolute path into the installed hook, so
the install tree could not be relocated.

Switch to the ament-native form and declare
AMENT_CMAKE_ENVIRONMENT_HOOKS_DESC_gz_led_plugin so ament_environment_hooks
also emits gz_led_plugin.dsv. colcon's setup chain prefers the .dsv when one
exists and only falls back to sourcing the .sh otherwise -- and that fallback
exports COLCON_CURRENT_PREFIX, never AMENT_CURRENT_PREFIX, which is why a
.sh-only hook using ament_prepend_unique_value would silently prepend
whichever prefix was sourced last (e.g. /opt/ros/humble/lib).

The descriptor's path is relative, so colcon resolves it against the package
prefix and the install tree stays relocatable.
@MonkeScripts
MonkeScripts force-pushed the fix/env-hook-dsv-descriptor branch from a04352d to a57ccb0 Compare August 16, 2026 04:02
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