When trying to build my ROS2 project, I get a ModuleNotFoundError
when compiling one of the C modules, due to a missing dependency called em
:
% colcon build --cmake-clean-cache
Starting >>> r1_messages
--- stderr: r1_messages
CMake Error at /Users/mryall/src/mawson/ros2-iron-build/install/share/rosidl_adapter/cmake/rosidl_adapt_interfaces.cmake:57 (message):
execute_process(/opt/homebrew/Frameworks/Python.framework/Versions/3.12/bin/python3.12
-m rosidl_adapter --package-name r1_messages --arguments-file
/Users/mryall/src/mawson/r1-ros/build/r1_messages/rosidl_adapter__arguments__r1_messages.json
--output-dir
/Users/mryall/src/mawson/r1-ros/build/r1_messages/rosidl_adapter/r1_messages
--output-file
/Users/mryall/src/mawson/r1-ros/build/r1_messages/rosidl_adapter/r1_messages.idls)
returned error code 1:
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/Users/mryall/src/mawson/ros2-iron-build/install/lib/python3.11/site-packages/rosidl_adapter/__main__.py", line 19, in <module>
sys.exit(main())
^^^^^^
File "/Users/mryall/src/mawson/ros2-iron-build/install/lib/python3.11/site-packages/rosidl_adapter/main.py", line 53, in main
abs_idl_file = convert_to_idl(
^^^^^^^^^^^^^^^
File "/Users/mryall/src/mawson/ros2-iron-build/install/lib/python3.11/site-packages/rosidl_adapter/__init__.py", line 18, in convert_to_idl
from rosidl_adapter.msg import convert_msg_to_idl
File "/Users/mryall/src/mawson/ros2-iron-build/install/lib/python3.11/site-packages/rosidl_adapter/msg/__init__.py", line 16, in <module>
from rosidl_adapter.resource import expand_template
File "/Users/mryall/src/mawson/ros2-iron-build/install/lib/python3.11/site-packages/rosidl_adapter/resource/__init__.py", line 19, in <module>
import em
ModuleNotFoundError: No module named 'em'
Call Stack (most recent call first):
/Users/mryall/src/mawson/ros2-iron-build/install/share/rosidl_cmake/cmake/rosidl_generate_interfaces.cmake:132 (rosidl_adapt_interfaces)
CMakeLists.txt:14 (rosidl_generate_interfaces)
---
Failed <<< r1_messages [4.13s, exited with code 1]
My ROS2 installation was built with a Python virtual environment, which I have activated. But even though the virtual-env is activated and all the required libraries are installed with pip
, the ROS modules built with CMake don't seem to be able to find it.
I tried to check that the em
library was installed. Running pip install empy
confirms that it is already installed:
% pip install empy
Requirement already satisfied: empy in /Users/mryall/src/mawson/ros2-iron/iron_venv/lib/python3.11/site-packages (3.3.4)
CMake modules in ROS2 do not automatically pick up the virtual environment used by the shell which calls colcon
. (This is apparently an intentional decision by the ROS2 maintainers, who don't seem to understand the purpose or operation of virtual environments very well.)
You can fix this by asking colcon
to pass the Python3_EXECUTABLE
parameter to CMake, using the $VIRTUAL_ENV
environment variable from your shell with the active virtualenv:
% colcon build --cmake-args -DPython3_EXECUTABLE="$VIRTUAL_ENV/bin/python"
Fortunately, once the right binary is known, Python is smart enough to find the libraries which are installed in the virtualenv.
This enables C++/CMake modules in your ROS2 code to find all their Python dependencies.