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:

  1. Create a catkin workspace to hold your migrated projects
  2. Move any project to this catkin workspace once all its dependencies are catkinized
  3. 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)
    1. 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)
    2. Add all other packages of the old stack as run_depend tags of the metapackage in the package.xml
    3. Remove the stack.xml, the information from it moves into the package.xml of the metapackage

    4. What previously was your ‘stack’ folder should now contain only packages and at most one metapackage.
  4. For each folder containing a manifest.xml file:

    1. Rename the manifest.xml to package.xml

    2. Add a name tag with the name of the package, which should also be the folder name
    3. If missing, create a CMakeLists.txt file containing a catkin_package() invocation

    4. Remove the Makefile
  5. In each CMakeLists.txt:

    1. If rosbuild macros were used, switch from rosbuild macros to the underlying CMake commands
    2. Declare how your targets (C++ binaries) shall be installed
  6. For each C++ executable or library:
    1. 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

    2. Add an target_link_libraries()` call to ${catkin_LIBRARIES} if ros is not found.

  7. For each executable python script in your package
    1. install the script using cmake (not setup.py) so that they are installed under "lib/PKGNAME" instead of the global "bin" folder
    2. 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.

  8. 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])

catkin_download_test_data

rosbuild_download_test_data

catkin_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: http://ros.org/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.

  1. Make sure there is a valid maintainer in package.xml
  2. Uncomment dependencies as needed
  3. deal with all TODO comments
  4. Validate marked changes
  5. remove all commented blocks that should now be obsolete
  6. list message, service and action files in the add_message_files, add_service_files and add_action_files macro calls

  7. remove obsolete include calls

  8. 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
  9. adapt target and variable names in CMakeLists.txt to make them likely unique
  10. 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

  11. install any scripts (python) using cmake catkin_install_python() macro

  12. 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 http://ros.org/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

Wiki: catkin/migrating_from_rosbuild (last edited 2021-07-07 18:16:33 by GvdHoorn)