Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pluginlib plugin loading does not work in composable nodes #330

Open
hacker1024 opened this issue Nov 18, 2023 · 3 comments
Open

pluginlib plugin loading does not work in composable nodes #330

hacker1024 opened this issue Nov 18, 2023 · 3 comments

Comments

@hacker1024
Copy link
Contributor

hacker1024 commented Nov 18, 2023

pluginlib plugins fail to load in nodes launched as components.

When executed from a composable node, this line in class_loader seems to return nullptr when it would normally not. I have not found out why.

To reproduce

Setup:

$ nix-build \
    -I nix-ros-overlay=https://github.com/lopsided98/nix-ros-overlay/archive/develop.tar.gz \
    --extra-substituters 'https://ros.cachix.org' \
    --extra-trusted-public-keys 'ros.cachix.org-1:dSyZxI8geDCJrwgvCOHDoAfOm5sV1wCPjBkKL+38Rvo=' \
    -E 'with import <nix-ros-overlay> { }; with rosPackages.humble; buildEnv {
          paths = [
            ros-core
            nav2-controller
          ];
        }'

Working: Regular nodes

Note that the static_layer plugin loads successfully.

$ ./result/bin/ros2 run nav2_controller controller_server
$ ./result/bin/ros2 lifecycle set /controller_server configure

Broken: Composable nodes

Note that the static_layer plugin fails to load.

$ ./result/bin/ros2 component standalone nav2_controller nav2_controller::ControllerServer
$ ./result/bin/ros2 lifecycle set /controller_server configure
@mbeutelspacher
Copy link
Contributor

I faced a similar issue and looked a bit into it

With the regular node https://github.com/ros/class_loader/blob/iron/include/class_loader/class_loader_core.hpp#L313 calls addOwningClassLoader with a nullptr whereas in the component container getCurrentlyActiveClassLoader() returns a not-nullptr.

For the regular node the else if in branch https://github.com/ros/class_loader/blob/iron/include/class_loader/class_loader_core.hpp#L418 than matches (because the owner is nullptr) whereas for the component container neither of the two branches match (I guess expected is the first branch), and therefore for the component container it cannot load the plugin.

I still need to find out why

  1. getCurrentlyActiveClassLoader() == nullptr and getCurrentlyLoadingLibraryName() == "" for the regular node but not for the component container
    and
  2. why the first branch does not match in the component container case

but when I hack in that I always override the output of getCurrentlyActiveClassLoader() with nullptr, I can load the plugin also in the component container

@liarokapisv
Copy link

liarokapisv commented Nov 2, 2024

@mbeutelspacher

Did you have any progress on this?

@liarokapisv
Copy link

After looking into this, it seems this may be an instance of an issue with dynamic linking that the class-loader wiki page warns against:

2.8 Caution of Linking Directly Against Plugin Libraries

pluginlib as of version 1.9 and class_loader HIGHLY discourage linking applications directly against libraries containing plugins. Often times users will place plugins into libraries along side code intended to directly be linked. Other times they want to be able to use classes as plugins as well as directly use them without a ClassLoader. This was fine in previous versions of pluginlib, but as version 1.9, pluginlib sits on top of class_loader for plugin loading which cannot handle this.

The Problem - Orphan Class Factories.

The issue is that the way class_loader implements plugin introspection is by having plugin class factories automatically register themselves when the library is opened. This is not how pluginlib prior to version 1.9 operated. However, the problem is is that when you directly link an executable against a library with plugins, when that program starts up, all the plugin factories will be created outside the scope of a class_loader::ClassLoader. See class_loader/Design for more details.

When building with nix, it is easy for a library containing a plugin to be hard-linked to the runpath of a dependent package.
I managed to solve a few instances of this issue while packaging some missing packages by directly removing the dependencies through patchelf --remove-needed calls in the postPatch phase.

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

No branches or pull requests

3 participants