Contents
-
Overview
- Prerequisites
- Package Layout in Workspace
- Converting a rosbuild (Dry) Package to a catkin (Wet) Package
- Difference in rosbuild manifest.xml from catkin package.xml
- Differences in CMakeLists.txt for rosbuild and catkin
- Python
- dynamic_reconfigure
- Migration Help - "Catkinize" Scripts
- Overlaying Dry and Wet Workspaces
- Changes in Tooling
- Updating References
Overview
Here we describe how to migrate rosbuild package to catkin, in general.
Prerequisites
Catkin packages cannot depend on rosbuild packages. Therefore before migrating a package from rosbuild to catkin make sure that all package dependencies have already been migrated to catkin.
For more information about catkin workspaces please see the REP 128.
Package Layout in Workspace
The layout of workspaces is not very different between rosbuild and catkin packages. A few keys things to notice:
Packages no longer contain a manifest.xml file -- this has been superseded by package.xml
my_package/ --> my_package/ manifest.xml --> package.xml
Packages are no longer organized within stacks. Instead, they are grouped into collections of packages called metapackages. The stack.xml file is replaced with a package.xml file which internally indicates it is a metapackage. This meta package.xml is moved into a folder on the same level as the other packages, from my_stack/stack.xml to my_stack/my_stack/package.xml.
my_stack/ --> my_metapackage/ my_package_1/ --> my_package_1/ manifest.xml --> package.xml ... my_package_n/ --> my_package_n/ manifest.xml --> package.xml stack.xml --> my_metapackage package.xml (Internally, a tag indicates it's a metapackage)
Packages still contain a CMakeLists.txt file, but the content and format of this file has changed drastically.
Packages no longer contain a Makefile.
Converting a rosbuild (Dry) Package to a catkin (Wet) Package
At a high level, the key steps to convert a ROS stack from rosbuild to catkin packages are:
- Create a catkin workspace to hold your migrated projects
- Move any project to this catkin workspace once all its dependencies are catkinized
- Convert your stack into a metapackage, unless it was a unary rosbuild stack (Unary rosbuild stacks are stacks with just one package, those will become one catkin package)
- Create a catkin package in your old stack folder and name it like the stack, this is going to be the metapackage (as an example, see ros_comm/ros_comm)
- Add all other packages of the old stack as run_depend tags of the metapackage in the package.xml
Remove the stack.xml, the information from it moves into the package.xml of the metapackage
- What previously was your ‘stack’ folder should now contain only packages and at most one metapackage.
For each folder containing a manifest.xml file:
Rename the manifest.xml to package.xml
- Add a name tag with the name of the package, which should also be the folder name
If missing, create a CMakeLists.txt file containing a catkin_package() invocation
- Remove the Makefile
In each CMakeLists.txt:
- If rosbuild macros were used, switch from rosbuild macros to the underlying CMake commands
- Declare how your targets (C++ binaries) shall be installed
- For each C++ executable or library:
Add an add_dependencies() call to the targets generating the message headers, e.g. geometry_msgs_generate_messages_cpp or using ${catkin_EXPORTED_TARGETS}.
For example, if your foo package that builds a foo_node executable depends on foo_msgs, then add add_dependencies(foo_node foo_msgs_gencpp) at the end of foo's CMakeLists.txt file
Add an target_link_libraries()` call to ${catkin_LIBRARIES} if ros is not found.
- For each executable python script in your package
- install the script using cmake (not setup.py) so that they are installed under "lib/PKGNAME" instead of the global "bin" folder
if the script is not only used by rosrun but also within launch files and there being found using "$(find pkgname)path/to/script": install the script for backward compatibility into share (within the same folder hierarchy as it is in source). (See this issue with xacro) You should also create a differently named script which will be used going forward. Such as change xacro.py to xacro and install it into the standard package local path. This will prevent collisions when using rosrun when using the backwards compatible executable.
If your package contains python packages, create a setup.py declaring the packages and invoke catkin_python_setup() in your CMakeLists.txt
One confusing aspect of catkin is the multiple source directories and what they hold. The layout of your catkin workspace if you have multiple packages is:
my_workspace/ build/ <-- created by catkin_make devel/ <-- created by catkin_make src/ package_1/ package.xml CMakeLists.txt src/ code.cpp ... package_2/ package.xml CMakeLists.txt src/ code.cpp ... ...
Now when you run catkin_make inside my_workspace, cmake will build your packages and drop the binaries inside of the build directory.
Note that catkin_make will create the build and devel directories and all of the files inside of those two directories. If you want to completely rebuild all of the catkin created files and directories, you can safely delete the build and devel directories. Another call of catkin_make will recreate those.
Difference in rosbuild manifest.xml from catkin package.xml
The manifest.xml and package.xml files serve almost the same role between rosbuild and catkin - providing information about the package and its dependencies. The difference is that some of the information that traditionally went into the manifest.xml file such as export information (e.g. compiler cflags) is now explicit in CMakeLists.txt and handled by CMake rather than by the ROS build system. See catkin/package.xml for more details.
Differences in CMakeLists.txt for rosbuild and catkin
The most significant change between rosbuild and catkin is the differences in the contents of the CMakeLists.txt file that must be provided with each package. The biggest difference is the elimination of rosbuild macros such as rosbuild_add_library which have been replaced by standard CMake functions or by catkin-specific macros. See catkin/CMakeLists.txt for details about the structure and contents of this file.
Below is a quick guide to showing the mapping between rosbuild CMake macros and catkin CMake macros.
Build Macros
rosbuild |
catkin |
rosbuild_init() |
remove |
rosbuild_add_library(...) |
add_library(...) |
rosbuild_add_executable(...) |
add_executable(...) |
rosbuild_add_compile_flags(...) |
set_target_properties(target PROPERTIES COMPILE_FLAGS new_flags) |
rosbuild_remove_compile_flags(...) |
set_target_properties(target PROPERTIES COMPILE_FLAGS new_flags) |
rosbuild_add_link_flags(...) |
set_target_properties(target PROPERTIES LINK_FLAGS new_flags |
rosbuild_remove_link_flags(...) |
set_target_properties(target PROPERTIES LINK_FLAGS new_flags) |
rosbuild_add_boost_directories(...); rosbuild_link_boost(target components) |
find_package(Boost REQUIRED COMPONENTS components); include_directories(${Boost_INCLUDE_DIRS}); target_link_libraries(target ${Boost_LIBRARIES}) |
rosbuild_add_openmp_flags(...) |
find_package(OpenMP), then do other stuff (an example is displayed below the table) |
rosbuild_invoke_rospack(...) |
DO NOT DO THIS |
rosbuild_find_ros_package(...) |
DO NOT DO THIS |
rosbuild_find_ros_stack() |
DO NOT DO THIS |
rosbuild_check_for_sse(...) |
look around online and find an example of how to find SSE |
rosbuild_include(package module) |
include(module) (might require some initial work to find the path to the module) |
rosbuild_add_lisp_executable() |
no support for this currently |
rosbuild_add_swigpy_library(target lib src1 src2) |
- |
OpenMP
Example usage for OpenMP with catkin:
# let cmake find OpenMP and set some variables find_package(OpenMP REQUIRED) if(OPENMP_FOUND) message(STATUS "OPENMP FOUND") set(OpenMP_FLAGS ${OpenMP_CXX_FLAGS}) # or if you use C: ${OpenMP_C_FLAGS} set(OpenMP_LIBS gomp) endif() ... # the entry in catkin_package could be optional (I am not fully sure about this) catkin_package( DEPENDS OpenMP ) ... # exemplary executable foo using OpenMP add_executable(foo ros/src/foo_node.cpp ) target_compile_options(foo PRIVATE ${OpenMP_FLAGS}) add_dependencies(foo ${catkin_EXPORTED_TARGETS}) target_link_libraries(foo ${catkin_LIBRARIES} ${OpenMP_LIBS} )
Test Macros
rosbuild |
catkin |
rosbuild_add_gtest(...) |
catkin_add_gtest(...) |
rosbuild_add_gtest_labeled |
if (${LABEL}) |
|
catkin_add_gtest(...) |
|
endif() |
rosbuild_add_gtest_future |
# comment it out |
rosbuild_add_gtest_build_flags |
use set_target_properties on test target |
rosbuild_add_pyunit |
migrate to catkin_add_nosetests(...) |
rosbuild_add_pyunit_labeled |
similar to rosbuild_add_gtest_labeled |
rosbuild_add_pyunit_future |
# comment it out |
rosbuild_add_rostest(...) |
add_rostest(...) |
rosbuild_add_rostest_labeled |
similar to rosbuild_add_gtest_labeled |
rosbuild_add_rostest_future |
# comment it out |
rosbuild_add_roslaunch_check |
roslaunch_add_file_check (as of roslaunch 1.9.46, requires to find package roslaunch before) |
rosbuild_declare_test |
add_dependencies(tests <test-target>) |
rosbuild_count_cores |
- |
rosbuild_check_for_display |
- |
rosbuild_check_for_vm |
- |
Note that the "add_rostest" macro is defined in the rostest package.
Message/Service Macros
rosbuild |
catkin |
rosbuild_add_generated_msgs(...) |
add_message_files(DIRECTORY msg FILES ...) |
rosbuild_add_generated_srvs(...) |
add_service_files(DIRECTORY srv FILES ...) |
rosbuild_genmsg() |
generate_messages() (once per CMakeLists.txt) |
rosbuild_gensrv() |
generate_messages() (once per CMakeLists.txt) |
Listing the message files is useful as adding removing files will trigger an automatic reconfigure by cmake.
Version Macros
rosbuild |
catkin |
rosbuild_get_stack_version |
obsolete |
rosbuild_get_package_version |
obsolete |
Data Macros
rosbuild |
catkin |
rosbuild_download_data(url filename [md5sum]) |
|
rosbuild_download_test_data |
|
rosbuild_untar_file |
- |
Special Targets
rosbuild |
catkin |
rosbuild_premsgsrvgen |
- |
rosbuild_precompile |
- |
rosbuild_make_distribution |
- |
Actionlib
rosbuild |
catkin |
include(${actionlib_msgs_PACKAGE_PATH}/cmake/actionbuild.cmake) |
Remove this, Add actionlib_msgs to find_package call |
genaction() |
add_action_files(DIRECTORY msg FILES ...) |
Python
Catkin leverages Python distutils. If you have python packages or scripts in your catkin package you will need to add a setup.py:
For a standard layout with the python module in the src subdirectory of your catkin package:
1 #!/usr/bin/env python
2
3 from distutils.core import setup
4 from catkin_pkg.python_setup import generate_distutils_setup
5
6 d = generate_distutils_setup(
7 # # don't do this unless you want a globally visible script
8 # scripts=['bin/myscript'],
9 packages=['PYTHON_PACKAGE_NAME'],
10 package_dir={'': 'src'}
11 )
12
13 setup(**d)
and in your CMakeLists.txt call:
catkin_python_setup()
and
catkin_install_python( PROGRAMS scripts/foo_script DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} )
For more details see: doc/groovy/api/catkin/html/user_guide/setup_dot_py.html and http://docs.ros.org/indigo/api/catkin/html/howto/format1/installing_python.html
dynamic_reconfigure
For each .cfg file:
Remove "import roslib;roslib.load_manifest(PACKAGE)".
Change "from dynamic_reconfigure.parameter_generator import *" to "from dynamic_reconfigure.parameter_generator_catkin import *"
In CMakeLists.txt, add the following before the call to catkin_package() to generate code for the dynamic reconfigure files:
generate_dynamic_reconfigure_options(cfg/DynFile1.cfg cfg/DynFile2.cfg ...)
Additionally in the CMakeLists.txt, add the following dependency for each target which uses the generated code:
# make sure configure headers are built before any node using them add_dependencies(example_node ${${PROJECT_NAME}_EXPORTED_TARGETS})
For more details see: the catkin dynamic reconfigure how-to and dynamic_reconfigure tutorial
Migration Help - "Catkinize" Scripts
There is a Python project available that can help you:
- Convert your manifest.xml files to package.xml files
- Convert your rosbuild-based CMakeLists.txt files to use the updated catkin macros
Here is an example of how to use them.
First, install the scripts:
$ git clone https://github.com/ros-infrastructure/catkinize $ cd catkinize $ sudo python setup.py install
Next, set up a catkin workspace in which to do the migration:
$ mkdir filter_ws $ mkdir filter_ws/src $ cd filter_ws $ catkin_make $ source devel/setup.bash
Check out a ROS stack that hasn't yet been converted to catkin into workspace src folder:
$ cd filter_ws/src $ hg clone https://kforge.ros.org/common/filters $ catkinize_stack filters 1.0.0
to catkinize single packages only, call:
$ catkinize filters 1.0.0
As an alternative to the catkinize scripts, use catkin_create_pkg to create a new package, and copy & paste or adapt the contents manually.
Migration checks
Now check and adapt the CMakeLists.txt and package.xml with any text editor.
- Make sure there is a valid maintainer in package.xml
- Uncomment dependencies as needed
- deal with all TODO comments
- Validate marked changes
- remove all commented blocks that should now be obsolete
list message, service and action files in the add_message_files, add_service_files and add_action_files macro calls
remove obsolete include calls
- In the catkin_package macro, export those dependencies required to build against your package, i.e. all that your API header files use, so that client packages do not have to speciy those redundantly
- adapt target and variable names in CMakeLists.txt to make them likely unique
for C++ libraries or executable targets that depend on (custom) ROS messages, add the add_dependencies() call
For example, if your foo package that builds a foo_node executable depends on foo_msgs, then add add_dependencies(foo_node foo_msgs_gencpp) at the end of foo's CMakeLists.txt file
install any scripts (python) using cmake catkin_install_python() macro
- create a setup.py for your own python modules
The last point is of particular importance. With catkin, projects are commonly build as one project, meaning cmake target names and global (cached) variables can conflict with each other between projects. See doc/groovy/api/catkin/html/user_guide/standards.html for details on recommended standards for CMakeLists.txt. So pay particular attention to any items like:
catkin_add_gtest(targetname ...) add_executable(targetname ...) set(varname CACHED ...) option(varname...)
and be sure that targetname and varname are likely to be unique among plenty of projects in the ROS ecosystem.
Check the results
$ cd ~/groovy_overlay/build $ cmake ../src $ make
Overlaying Dry and Wet Workspaces
A common problem you will likely run into is having to mix wet packages and dry packages. This is possible with the following constraints:
- catkin and rosbuild workspaces need to be in different, isolated directories
- Dry packages can depend on wet packages, but wet packages cannot depend on dry
That being said, things work in the same way through the use of environment setup files (i.e. setup.* scripts). Both catkin and rosbuild workspaces have this concept; in rosbuild these files are located in the workspace root, in catkin they are located in the devel and install spaces. Here is an example showing the difference between the layouts.
rosbuild_ws/ .rosinstall setup.bash setup.sh setup.py catkin_ws/ devel/ setup.bash setup.sh setup.py install/ setup.bash setup.sh setup.py
To overlay a rosbuild workspace on top of a catkin workspace, the rosbuild workspace has to reference the setup.sh file as setup-file of either the devel or the install space in the .rosinstall file (not both). Which one is up to you, the catkin way would be to use the devel space setup.sh.
When not using rosws/rosinstall, just make sure your ROS_PACKAGE_PATH includes the src folder of your catkin workspace.
A tutorial exists for this here
Changes in Tooling
The rosws tool was commonly used to setup and manage rosbuild workspaces, but now the wstool command line tool should be used with catkin packages. The commands and interfaces are very similar.
Updating References
rosbuild packages which are released are indexed in the release repo on code.ros.org while catkin packages are indexed in the git rosdistro repo. When you convert a released package from rosbuild to catkin you need to remove the old indexing entries and add them to the new location.
Remove Old Reference
To remove the old entry you will need to remove your repository from the appropriate rosdistro file in the release repo. All maintainers have access to this repo to be able to update their packages on release. [release/Setup/Repository|Reverse These Setup Instructions]
Add new entry in new rosdistro repo
After converting your package to catkin. If you would like it to be released you will need to follow the new releasing instructions. Instructions for releasing you will need to add it to the releases folder in the rosdistro repo