In a project where we need to softlink some messages from a different folder in a repository into a new ROS2 messages package
(to only use a subset of them, and have them be the real definition of them) I ran into the following error when running:
ros2 interface show my_pkg_msgs/msg/MyMessage
Error processing '// generated from rosidl_adapter/resource/msg.idl.em' of 'my_pkg_msgs/MyMessage': '//'
Traceback (most recent call last):
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/bin/ros2", line 10, in <module>
sys.exit(main())
^^^^^^
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/ros2cli/cli.py", line 91, in main
rc = extension.main(parser=parser, args=args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/ros2interface/command/interface.py", line 35, in main
return extension.main(args=args)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/ros2interface/verb/show.py", line 196, in main
_show_interface(
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/ros2interface/verb/show.py", line 144, in _show_interface
for line in _get_interface_lines(interface_identifier):
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/ros2interface/verb/show.py", line 116, in _get_interface_lines
yield InterfaceTextLine(
^^^^^^^^^^^^^^^^^^
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/ros2interface/verb/show.py", line 47, in __init__
msg_spec = parse_message_string(
^^^^^^^^^^^^^^^^^^^^^
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/rosidl_adapter/parser.py", line 516, in parse_message_string
fields.append(Field(Type(type_string, context_package_name=pkg_name), field_name, default_value_string))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/rosidl_adapter/parser.py", line 280, in __init__
super(Type, self).__init__(type_string, context_package_name=context_package_name)
File "/home/user/CompanyCode/company/pixi_ros2_ws/.pixi/envs/default/lib/python3.11/site-packages/rosidl_adapter/parser.py", line 188, in __init__
raise InvalidResourceName(type_string)
rosidl_adapter.parser.InvalidResourceName: //
Another symptom of this was trying to record a rosbag would output:
[WARN] [1747297617.019685024] [rosbag2_storage_mcap]: no .msg definition for my_pkg_msgs/msg/MyMessage, falling back to IDL
The tree of my my_pkg_msgs
looks like:
├── CMakeLists.txt
├── msg
│ ├── MyMessage.msg -> ../../../../../ros2/msg/MyMessage.msg
The issue was that my install folder install/my_pkg_msgs/share/wayve_interfaces/msg
, by default, would make softlinks to my softlinks, which would looke like:
MyMessage.msg -> ../../../../../ros2/msg/MyMessage.msg
And be pointing to the wrong place (given the different path of the install folder), in my case to the root of the workspace.
Add a cmake rule to install the actual files instead of softlinking them as it's done by default (at least in ROS2 humble).
# This is needed to avoid a symlink to symlink issue in install/my_pkg_msgs/share/my_pkg_msgs/
file(GLOB MSG_LINKS "${CMAKE_CURRENT_SOURCE_DIR}/msg/*.msg")
foreach(_link ${MSG_LINKS})
# 2) Figure out its real path (dereference all symlinks)
get_filename_component(_real_file "${_link}" REALPATH)
# 3) Extract just the filename (so we can install it under that name)
get_filename_component(_base_name "${_link}" NAME)
# 4) Install the real file, but rename it back to the original .msg name
install(
FILES "${_real_file}"
DESTINATION share/${PROJECT_NAME}/msg
RENAME "${_base_name}"
)
endforeach()
file(GLOB SRV_LINKS "${CMAKE_CURRENT_SOURCE_DIR}/srv/*.srv")
foreach(_link ${SRV_LINKS})
get_filename_component(_real_file "${_link}" REALPATH)
get_filename_component(_base_name "${_link}" NAME)
install(
FILES "${_real_file}"
DESTINATION share/${PROJECT_NAME}/srv
RENAME "${_base_name}"
)
endforeach()