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

Refactor moveit_core package to export a single library #1801

Closed
wants to merge 10 commits into from
Closed

Refactor moveit_core package to export a single library #1801

wants to merge 10 commits into from

Conversation

ChrisThrasher
Copy link
Contributor

Description

moveit_core is currently comprised of a few dozen, small libraries. Some of these libraries are small as a single .cpp/.h pair. Some libraries have circular dependencies with others which mean they're difficult if not impossible to use in isolation.

This PR consolidates those libraries into a single moveit::core target which better expresses the fact that moveit_core is intended to be used as one library, not a collection of them. Along the way I was able to make some satisfying simplifications like how many dozens of target_link_libraries, target_include_directories, and install commands were collapsed into just a small few. There's a certain amount of CMake overhead related to each sub-library which is now gone. This will make it easier for others to understand how moveit_core is built and understand how to modify it as needed as requirements change in the future.

This change also required no modification to downstream packages which continue to use moveit_core exactly as they have before.

I'm submitting this PR with the full, verbose commit history so reviewers can see the incremental steps I took, but I plan on squashing this into a single commit before merging since these individual commits are not particularly valuable.

@codecov
Copy link

codecov bot commented Dec 12, 2022

Codecov Report

Base: 50.24% // Head: 49.59% // Decreases project coverage by -0.65% ⚠️

Coverage data is based on head (289bd02) compared to base (e23fb8f).
Patch coverage: 100.00% of modified lines in pull request are covered.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1801      +/-   ##
==========================================
- Coverage   50.24%   49.59%   -0.64%     
==========================================
  Files         374      381       +7     
  Lines       31277    31667     +390     
==========================================
- Hits        15712    15703       -9     
- Misses      15565    15964     +399     
Impacted Files Coverage Δ
...lision_detection/allvalid/collision_env_allvalid.h 100.00% <ø> (ø)
...lude/moveit/collision_detection/collision_common.h 83.88% <ø> (ø)
...collision_detection/collision_detector_allocator.h 84.62% <ø> (ø)
...include/moveit/collision_detection/collision_env.h 100.00% <ø> (ø)
...lude/moveit/collision_detection/collision_matrix.h 100.00% <ø> (ø)
...lude/moveit/collision_detection/collision_plugin.h 100.00% <ø> (ø)
...include/moveit/collision_detection/occupancy_map.h 0.00% <ø> (ø)
.../collision_detection/test_collision_common_panda.h 98.73% <ø> (ø)
...it/collision_detection/test_collision_common_pr2.h 100.00% <ø> (ø)
...it_core/include/moveit/collision_detection/world.h 100.00% <ø> (ø)
... and 125 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@mergify
Copy link

mergify bot commented Dec 13, 2022

This pull request is in conflict. Could you fix it @ChrisThrasher?

@@ -0,0 +1,22 @@
add_subdirectory(collision_detection_bullet)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file really necessary? Having the content in the main file means less searching around and I don't see any additional complexity that is worth hiding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it's not strictly necessary. My thought was that it was nice to bury some of this code to avoid having to relocate and change the path to many dozens of source files. I could be convinced to move all those target_sources call up the main CMakeLists.txt thus eliding them.

My bigger holdup was whether it was worth reorganizing all the tests. Currently I'm keeping them in place but I'm on the fence about whether they should get moved out into their own tests directory alongside include and src. If we do this, then we can delete all these extra CMakeLists.txt in src/. That would be more consistent with how else I've reorganized things but I'd like someone else's input.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was more thinking about using add_subdirectory(src/...). The separate target sources make sense to me, and would even make more sense if we could group all of these targets into fewer but more meaningful namespaces/contexts. Until then, I think it's ok to leave tests where they are for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was more thinking about using add_subdirectory(src/...).

That sounds slightly better to me as well.

whether they should get moved out into their own tests directory alongside include and src

I do think it makes much more sense to keep the tests in the individual source folders.
moveit_core might become one library now, conceptually, but it's still pretty big and the separate folders help to show what component has how many tests.

@@ -40,7 +40,7 @@
#include <rclcpp/logging.hpp>

// Logger
static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_collision_detection.collision_world_allvalid");
static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_core.collision_world_allvalid");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the logger names should be revised, but setting them all to moveit_core doesn't really make them better. Let's omit these changes for now and first discuss how we want to log MoveIt in general.
My thought is that some context is still needed (here maybe collision_detection) and that this context should be reflected by file structure and namespace. Ideally we should define a pattern that we could use everywhere, something like moveit.<package>.<context>.<optional detail> -> moveit.core.collision_detection. (copied to #1614 (comment))

Curiously, this file is *_env_allvalid and the logger says _world_allvalid...

Copy link
Member

@tylerjw tylerjw Dec 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest we change the logger names to just:

<package_name>.<source_file_name>

There are two uses of these identifiers I know of:

  1. Enabling DEBUG level on a small amount of code to get the debug output.
  2. Searching through the code for an ERROR log to figure out where it came from.

I believe the format above would be effective for both of these use cases.

In the code this comment is on it would be changed to moveit_core.collision_world_allvalid

Copy link
Member

@henningkayser henningkayser Dec 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

third use case is setting up logger filters for debugging of packages/contexts/detail, and with detail I mean plugin or class instance. Actually, adding file would be redundant because that's already reported by the logger. (see https://docs.ros2.org/latest/api/rcutils/logging_8h.html#a27340ac73188b1cf8d9cb96d86c76694)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, I can revert these logger name changes. I was even 100% they were worthwhile changes to begin with but I was just doing pattern matching.

endif()

ament_add_gtest(test_fcl_collision_env test/test_fcl_env.cpp)
target_link_libraries(test_fcl_collision_env moveit::core)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this change the behavior of the test? The old cmake didn't link against the plugin code so it implicitly tested for valid plugin registration and loading. This version might omit this step, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I think it's reasonable to keep the plugins as separate targets. I'll have to think about that more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about this in the MoveIt standup this morning. It came up that there is a technical reason for this. Something to do with how classloader works. You can't load a plugin from the same library that the base class of the plugin is in because of how ClassLoader uses RTTI. The plugins will need to be separate targets.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is best practice to keep plugin lib instantiations in a separate standalone library and I would strongly propose you keep it that way. We had a similar case in MTC last year (that I brought up because of the infamous memory leaks) and ended up splitting the plugins off again.

Personally my main argument is that unless strictly necessary, libraries should not execute code on so-load, unless strictly needed for every use of the library. But that's exactly what the PLUGINLIB/CLASSLOADER macros do and not every use of moveit::core requires plugins. You have no idea how often boost libraries broke my neck as a linux distribution maintainer because of some random unnecessary initialization it does on load.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Viable options I see to move the plugins out:

  • new moveit_plugins subfolders (actually new packages) for all
  • a separate moveit::core_plugins library for the three of them
  • add moveit::collision_plugins and split the butterworth filter out into moveit_plugins. fcl/bullet are definitely close to moveit::core, but the signal smoother is only used in moveit_servo. On the other hand moveit_core does not use the plugins but directly relies on the classes in most cases.

I slightly prefer the last option.

Copy link
Member

@henningkayser henningkayser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great simplification, I really appreciate this effort! Some notes from my end:

  • Should we maybe keep separate plugin libraries? I think it would make sense to eventually separate out plugin implementations along with their dependencies (e.g. Bullet/FCL). That would cleanly delineate what core really does (feature integration+abstraction), and the feature implementation itself (collision checking, smoothing, etc). This is already the case for IK and planners.
  • Let's split out the logger name changes (see comment)
  • Could you add an entry to the migration notes for those depending on modules?
  • There is still a moveit_core/dummy.cpp

@lilustga would you have some time to review and test the export header for Windows?

@sjahr
Copy link
Contributor

sjahr commented Feb 9, 2023

@ChrisThrasher Can you rebase this PR so we can consider merging it?

@ChrisThrasher
Copy link
Contributor Author

ChrisThrasher commented Feb 9, 2023

@ChrisThrasher Can you rebase this PR so we can consider merging it?

I wish I could. At a minimum, we need to find a home for plugins in moveit_core that need to be removed before we can start consolidating targets and get that merged. After that I plan on rebasing as much of this PR as I can then reimplementing the rest as needed. The list of conflicts is pretty big so I'm not sure how much of this PR can be rebased without having to basically rewrite it all.

If anyone still has lingering issues with this PR, please share them now before I put any more work into reimplementing this.

@ChrisThrasher ChrisThrasher changed the title Rewrite moveit_core build scripts to build as a single library Refactor moveit_core package to export a single library Feb 9, 2023
@@ -0,0 +1,22 @@
add_subdirectory(collision_detection_bullet)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was more thinking about using add_subdirectory(src/...).

That sounds slightly better to me as well.

whether they should get moved out into their own tests directory alongside include and src

I do think it makes much more sense to keep the tests in the individual source folders.
moveit_core might become one library now, conceptually, but it's still pretty big and the separate folders help to show what component has how many tests.

add_library(moveit::core ALIAS moveit_core)
generate_export_header(moveit_core EXPORT_FILE_NAME include/moveit/export.h)
target_include_directories(moveit_core PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced we gain anything from splitting sources and headers for the different components. I'll not block the decision though if you think it more convenient.

The decision to split the headers of is fully independent of whether or not there should be one libmoveit_core.so and it's definitely not considered separately in this discussion so far.
Yes, it consolidates paths a bit. But it also adds three subdirectory changes to go from a component's sources to the respective headers...

endif()

ament_add_gtest(test_fcl_collision_env test/test_fcl_env.cpp)
target_link_libraries(test_fcl_collision_env moveit::core)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Viable options I see to move the plugins out:

  • new moveit_plugins subfolders (actually new packages) for all
  • a separate moveit::core_plugins library for the three of them
  • add moveit::collision_plugins and split the butterworth filter out into moveit_plugins. fcl/bullet are definitely close to moveit::core, but the signal smoother is only used in moveit_servo. On the other hand moveit_core does not use the plugins but directly relies on the classes in most cases.

I slightly prefer the last option.

@ChrisThrasher
Copy link
Contributor Author

ChrisThrasher commented Feb 10, 2023

I spent yesterday trying to split out the three plugins in moveit_core and it was awful.

  • collision_detector_bullet
  • collision_detector_fcl
  • filter_plugin_butterworth

I didn't even get to the last one. I started with the two collision_detector plugins which I tried to move to a new package within the moveit_plugins meta package. The major issue is that there are parts of moveit_core than depend heavily on collision_detector_fcl so extracting that whole directory is very messy. I tried to move all the dependent code out of that collision_detector_fcl into the collision_detection package but I think I ended up created a cyclic dependency in the #include graph forcing me to forward declare many types. I can try to keep pushing on that until it finally builds but the solution will be very gross and perhaps not good enough to merge.

Does anyone have other ideas for extracting collision_detector_fcl when parts of moveit_core are already depending on it? I might change focus to instead extract the other two plugins which will hopefully put up less of a fight then we can get a clearer picture of how to handle collision_detector_fcl.

@mergify
Copy link

mergify bot commented May 8, 2023

This pull request is in conflict. Could you fix it @ChrisThrasher?

@ChrisThrasher
Copy link
Contributor Author

Could you fix it @ChrisThrasher?

No I cannot.

@mergify
Copy link

mergify bot commented Aug 11, 2023

This pull request is in conflict. Could you fix it @ChrisThrasher?

@sjahr sjahr mentioned this pull request Mar 1, 2024
6 tasks
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.

5 participants