tf2::fromMsg / tf2::toMsg can compile with undefined symbols
Operating System:
Ubuntu 22.04
ROS version or commit hash:
Jazzy
Steps to reproduce issue
- Use tf2::toMsg with a
geometry_msgs::msg::PoseStampedas first parameter andtf2::Transformor the oposite (Pose and tf2::Stampedtf2::Transform), which are not defined templates intf2_geometry_msgs/tf2_geometry_msgs.hpp
Expected behavior
The compiler should complain but doesn't, probably due to the declaration of a template for tf2::fromMsg but I am missing background on this library to be sure :)
Actual behavior
The compiler doesn't complain. Got:
undefined symbol: _ZN3tf27fromMsgIN13geometry_msgs3msg10Transform_ISaIvEEEKNS_9TransformEEEvRKT_RT0_
[ros2run]: Process exited with failure 127
Additional information
Maybe this is a problem with my specific compiler or system but, in case that another user experiences this issue, make sure you are using a specialized template inside tf2_geometry_msgs/tf2_geometry_msgs.hpp
🧇 @alsora might more info
These functions are implemented as template functions. It's expected that users would include headers with template specializations for the conversions.
https://github.com/ros2/geometry2/blob/906b659ebb9d4a22cd43433bcc5a21c8da145b0d/tf2/include/tf2/convert.hpp#L122-L138
It might be worth rethinking if these are APIs even belong in the tf2 package. It seems like conversion functions for ROS types should live in tf2_ros instead. Maybe there's a different way to offer conversion functions that fails at compile time.
Correct.
Unfortunately I stumbled on this problem several times myself. You need to make sure that the file where the explicit template specialization that you need is included.
And unfortunately, as you pointed out, compilers will not notice the problem but they app will fail to start.
The reason is that although tf2::toMsg is a template, there's not a "generic" definition for it, but only explicit specializations.
You MUST include the file with the explicit specialization that you need, otherwise you'll get a linker error.
To make things more complex, you are likely dealing with a shared library (tf2 and similar). The necessary symbol is not automatically exported, and that's why you need to "include it" in your application.
It might be worth rethinking if these are APIs even belong in the tf2 package. It seems like conversion functions for ROS types should live in tf2_ros instead. Maybe there's a different way to offer conversion functions that fails at compile time.
I think that the current location is ok-ish.. Moving it somewhere else won't really change anything and in theory it allows to have also non-ros explicit instantiations.
But I definitely agree that a different implementation that fails at compile time would be a lot better! Maybe using function overloads?