Build Tool
A build tool operates on a set of packages
- determines the dependency graph
- invokes the specific build system for each package in topological order.
- for a specific package, knows how to setup the environment for it, invokes the build, and sets up the environment to use the built package.
The build system operates on a single package: CMake
, Make
, Python setuptools
. catkin
and ament_cmake
are based on CMake
Dependency Graph
find_package
helps the graph.FindFoo.cmake
orFindFoo.cmake
for the dependency must be in a prefix that CMake searches implicitly, like/usr
, or a location provided through env varsCMAKE_PREFIX_PATH
, orCMAKE_MODULE_PATHCMAKE_MODULE_PATH
- Install a shared_lib in a non-default location, that location needs to be in
LD_LIBRARY_PATH
.
ROS 2 Cpp And Python Package
-
We’ll create a ROS2 Cpp package, which contains a package.xml and CMakeLists.txt.
1 2
$ cd ~/ros2_ws/src/ $ ros2 pkg create my_cpp_py_pkg --build-type ament_cmake
-
See:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
my_cpp_py_pkg/ # --> package info, configuration, and compilation ├── CMakeLists.txt ├── package.xml # --> Python stuff ├── my_cpp_py_pkg │ ├── __init__.py │ └── module_to_import.py ├── scripts │ └── py_node.py # --> Cpp stuff ├── include │ └── my_cpp_py_pkg │ └── cpp_header.hpp └── src └── cpp_node.cpp
-
- For Python, no more setup.py and setup.cfg, everything will be done in the CMakeLists.txt.
- Note that we have a sub directory called
"my_cpp_py_pkg"
. Inside, the python code lives there. Like ROS1, they are executableschmod +x
. - The module is visible to other packages:
from my_cpp_py_pkg.module_to_import import ...
- Note that we have a sub directory called
-
package.xml
:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
<?xml version="1.0"?> <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> <package format="3"> <name>my_cpp_py_pkg</name> <version>0.0.0</version> <description>TODO: Package description</description> <maintainer email="your@email.com">Name</maintainer> <license>TODO: License declaration</license> <buildtool_depend>ament_cmake</buildtool_depend> <buildtool_depend>ament_cmake_python</buildtool_depend> <depend>rclcpp</depend> <depend>rclpy</depend> <test_depend>ament_lint_auto</test_depend> <test_depend>ament_lint_common</test_depend> <export> <build_type>ament_cmake</build_type> </export> </package>
-
CMakeLists.txt
:cmake_minimum_required(VERSION 3.5) project(my_cpp_py_pkg) # Default to C++14 if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 14) endif() if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic) endif() # Find dependencies find_package(ament_cmake REQUIRED) find_package(ament_cmake_python REQUIRED) find_package(rclcpp REQUIRED) find_package(rclpy REQUIRED) # Include Cpp "include" directory include_directories(include) # Create Cpp executable add_executable(cpp_executable src/cpp_node.cpp) ament_target_dependencies(cpp_executable rclcpp) # Install Cpp executables install(TARGETS cpp_executable DESTINATION lib/${PROJECT_NAME} ) # Install Python modules ament_python_install_package(${PROJECT_NAME}) # Install Python executables install(PROGRAMS scripts/py_node.py DESTINATION lib/${PROJECT_NAME} ) ament_package()
C++ & Python Interface Packages
An interface package defines ROS2 messages, services, and common utilities for other ROS2 packages. To create Python utilities, once a Python package is built and installed, and the workspace is sourced, its Python modules in install/MY_INTERFACE/local/lib/python3.10/dist-packages/MY_INTERFACE
are automatically added to the Python path. What we need are as follow:
- Make sure the python package files are here:
- Empty
MY_INTERFACE/MY_INTERFACE/__init__.py
- Module file:
MY_INTERFACE/MY_INTERFACE/My_Module
- Empty
- Add
MY_INTERFACE/setup.py
:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
from setuptools import setup, find_packages package_name = "MY_PACKAGE" setup( name=package_name, version="0.0.1", packages=find_packages(include=[package_name, f"{package_name}.*"]), install_requires=["setuptools"], zip_safe=True, maintainer="TODO", maintainer_email="your_email@example.com", description="TODO", license="Apache-2.0", tests_require=["pytest"], entry_points={ "console_scripts": [], }, )
CMakeLists.txt
1 2 3 4 5 6
install( DIRECTORY mumble_interfaces/ DESTINATION local/lib/python3.10/dist-packages/mumble_interfaces FILES_MATCHING PATTERN "*.py") ament_package()
- The destination
install/MY_INTERFACE/local/lib/python3.10/dist-packages/MY_INTERFACE
is carefully chosen, because that’s where generated srv, msg files go. Why? Because when there are packages with the same name at two different locations, Python will look into one, and throw afile-not-found
error if files are not there. - We are NOT using
ament_python_install_package
because it’s meant for pure Python packages. We need to manually installMY_INTERFACE
ininstall/MY_INTERFACE/lib/python3.10/site-packages
- The destination
- User Code:
1
from MY_INTERFACE import MyFunc
1
2
- Or one can use: `python3 -c import MY_INTERFACE.My_Module` in the same console, because after sourcing `install/setup.bash`, the installed file is added to the Python Path.
- One can check the python path with: `python3 -c "import sys; print(sys.path)"` or `echo $PYTHONPATH`