I have been facing linking issues when including various ROS packages and Drake as libraries, and have narrowed the issue down to VTK.
It seems that ROS(noetic) PCL depends on VTK 7.1.0
whereas Drake depends on VTK 9.1.0
after running ldd
:
linux-vdso.so.1 (0x00007fffa88ea000)
libdrake.so => /opt/drake/lib/libdrake.so (0x00007f644589d000)
libpcl_io.so.1.10 => /lib/x86_64-linux-gnu/libpcl_io.so.1.10 (0x00007f64455d7000)
libvtkCommonCore-7.1.so.7.1p => /lib/x86_64-linux-gnu/libvtkCommonCore-7.1.so.7.1p (0x00007f644528b000)
libvtkFiltersGeneral-7.1.so.7.1p => /lib/x86_64-linux-gnu/libvtkFiltersGeneral-7.1.so.7.1p (0x00007f6444f41000)
libvtkRenderingCore-7.1.so.7.1p => /lib/x86_64-linux-gnu/libvtkRenderingCore-7.1.so.7.1p (0x00007f6444c30000)
libvtkRenderingOpenGL2-7.1.so.7.1p => /lib/x86_64-linux-gnu/libvtkRenderingOpenGL2-7.1.so.7.1p (0x00007f6444907000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f6444725000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6444533000)
libdrake_lcm.so => /opt/drake/lib/libdrake_lcm.so (0x00007f644451a000)
libdrake_marker.so => /opt/drake/lib/libdrake_marker.so (0x00007f6444517000)
libvtksys-9.1.so.1 => /opt/drake/lib/libvtksys-9.1.so.1 (0x00007f64444c2000)
libvtkfmt-9.1.so.1 => /opt/drake/lib/libvtkfmt-9.1.so.1 (0x00007f644449b000)
libvtkkissfft-9.1.so.1 => /opt/drake/lib/libvtkkissfft-9.1.so.1 (0x00007f6444493000)
libvtkloguru-9.1.so.1 => /opt/drake/lib/libvtkloguru-9.1.so.1 (0x00007f6444459000)
...
My CMakeLists.txt
is defined as:
cmake_minimum_required(VERSION 3.10)
project(my_project)
find_package(catkin REQUIRED COMPONENTS
roscpp
pcl_ros
)
find_package(drake CONFIG REQUIRED PATHS /opt/drake)
catkin_package(
CATKIN_DEPENDS roscpp pcl_ros
DEPENDS drake
)
include_directories(${catkin_INCLUDE_DIRS})
add_executable(my_test test.cpp)
target_link_libraries(my_test drake::drake ${catkin_LIBRARIES})
and package.xml
as
....
<buildtool_depend>catkin</buildtool_depend>
<depend>roscpp</depend>
<depend>pcl_ros</depend>
</package>
Simply including vtk
headers causes immediate an segmentation fault:
#include "drake/systems/framework/diagram_builder.h"
#include <vtkPolyData.h>
int main() {
drake::systems::DiagramBuilder<double> builder;
return 0;
}
That's correct -- VTK's library symbols are not version-namespaced, so you cannot load two different VTK versions into the same process, even for two completely independent uses. This is not unique to Drake; it's generally true about VTK.
The only challenge with Drake is that (1) Drake's pre-compiled binaries are built against a specific version of VTK that differs from ROS PCL's VTK, and (2) even for a Drake source build, Drake doesn't make it very easy to change which version of VTK will be linked. Unlike Eigen or spdlog or fmt, Drake's VTK dependency is not designed to be end-user-serviceable.
To avoid problems like this, Drake is actively working on linking VTK privately. Follow #16502 for updates. ETA for the fix should be within the next month or two.
In the meantime, there are not many good work-arounds.
The only easy one is to carefully link to only the parts of PCL that do not depend on VTK. For example, the PCL KDTree does not use VTK (should be safe), but the PCL IO does use VTK (will segfault). If your problem is only over-linking, then fixing your build to link fewer unnecessary things might resolve it.
The other work-around is to put a process boundary between your Drake-using code and PCL-with-VTK-using-code, with some kind of a message channel inbetween. That is, rework your code to only ever load Drake in some programs, and PCL in others, and never the two shall meet.
Hopefully, the Drake feature 16502 will be resolved soon, making this all moot.