ROS Resources: Documentation | Support | Discussion Forum | Service Status | Q&A answers.ros.org

Migrating ROS/ROS2 off of catkin/colcon (towards pure CMake)

One of the biggest difficulties I had when I started working with ROS and ROS2 this year was learning how to deal with catkin and colcon. The documentation for these tools is absolutely terrible*, they make bizarre choices for options (colcon’s idea of “–verbose” is “–event-handlers=console_cohesion+”. The prosecution rests), and I’ve found that they really get in the way of managing a large codebase. For example, if I want all my code to build with warnings as errors, I need to set -Werror in each package’s CMakeLists.txt, and if a new package is added I need to make sure to set it there as well. Compare this with a project defined with CMake at the top level, I just need to set CMAKE_C_FLAGS in the root CMakeLists.txt and that’s it.

When I finally understood how catkin/colcon look through the folder hierarchy for package.xml files and use those to build a dependency tree and then parallelize builds I started to appreciate that. I guess that this package based architecture is also supposed to be useful to multi-language builds? I haven’t tried that myself, but I’m guessing it still needs to go through CMake?

What I’d really like to see is support from OSRF for building ROS code in a pure CMake way, in addition to the catkin/colcon package.xml way. I tried to do this and got pretty close, but ran into some roadblocks. For a ROS1 project, I managed to get everything to build the standard CMake way (mkdir build, cd build, cmake …, make) but it took 1-2 minutes for CMake itself to run (this was for a couple dozen packages). It was mostly really sluggish on various catkin macros. For ROS2, I tried to clone the demos repo (https://github.com/ros2/demos) and build the pendulum_msgs package with CMake. It didn’t produce the setup.bash file. Running make install produced a local_setup.bash file, but not the setup.bash file. Apparently that’s done through a colcon extension.

So to reiterate the question, would OSRF be interested in supporting a pure CMake build of ROS or ROS2? I think it could really benefit the ROS community to at least have this option alongside the catkin/colcon build system. It gives a better onramp experience for those familiar with those tools, and gives more debugging options for those who already use catkin/colcon.

* If you look up catkin documentation, you’ll probably land on this page http://wiki.ros.org/catkin which describes catkin as “Low-level build system macros and infrastructure for ROS.”. This tells me virtually nothing about what it is or what it does. The page proceeds to jump into how to install catkin and points the user to another documentation page for a user guide, which just jumps into the package format without explaining what it is. The conceptual overview page is not much better, it is similarly too vague and high level to be useful (“catkin was designed to be more conventional than rosbuild” <- what’s rosbuild? why is it unconventional?)

2 Likes

These?

They look pretty good to me.

I’m not a build system expert, but how would you achieve this with pure CMake? ROS systems are very modular/package-oriented. Seems like this is a pretty good argument in favour of catkin & colcon.

You can pass CMake arguments through catkin & colcon (--cmake-args, see the documentation above). With colcon you can even move that to a defaults.yaml file so that you don’t need to include it in your command every time (see documentation).

Again, I’m not an expert, so I’ll let other people chime in, but I kind of fail to see the point.

Please, also note that there is “catkin” (which provides “catkin_make” and “catkin_make_isolated” binaries), and then there are “catkin_tools” (which provide the “catkin” binary). These are two distinct tools which both utilize the python/CMake Catkin library inside, but expose a different CLI. The docs referenced by @actinium226 refer to “catkin” package and the CMake library (and these really are a bit messy), whereas @christophebedard refers to “catkin_tools” (whose docs are great).

One more question to make this thread more focused - are you interested in building the whole ROS system from scratch with pure CMake, or is it enough for you to build a few packages that depend on system-installed ROS packages? I think it makes a big difference whether you want the core packages to be buildable by plain CMake or not…

Also note that there might (should) be other tools involved in the build process. E.g. rosdep for installing dependencies. Would you like to get rid of that, too? It seems like a step back to me…

@christophebedard I hadn’t seen those links. They echo my existing complaints about the documentation, which is essentially that it’s written for audience that already knows how the tool works. For example, the docs don’t mention that you need a directory called src in the same directory in which you invoke catkin, or that it’s making a separate CMake project for each package.xml it finds. But the documentation is more of an annoyance rather than my main point.

@peci1 Thanks for your points. I think your discussion about catkin helps to paint just how confusing it is, but again I digress :slight_smile:

I think it would be really cool to be able to build the whole ROS system from scratch with CMake, but to start out with it probably makes more sense to start with individual packages, like I mentioned in the example I gave with ros2 demos pendulum_msgs, and then move on to larger groups of packages, like the whole ros2 demos repo.

Imagine a model like python, where there’s lot of packages, but there’s freedom as to whether you want to package your code or not. With ROS, if you just want to use the C/C++ libraries and headers, you can, but you have to sort of bend over backwards to do it (I tried).

The whole reason ROS is package oriented is because the build tools won’t allow you to create ROS code any other way. Again going back to the python example, there’s some tooling to help you make a package, but it’s entirely optional.

As with the python example, they have pip and so I think tools like rosdep would remain necessary, although I haven’t used rosdep very heavily myself so I’m not sure if pip is a good analogy?

And could you describe your idea of the toplevel CMakeLists.txt? Would you order the packages to satisfy dependencies in your head and then “add_subdirectory” each of them?

Single packages can be built using plain CMake pretty well. I do it all the time within CLion. Dependencies and inclusion of 3rd-party libs not installed in the system is where it gets tough.

Otherwise, the analogy between rosdep and pip is quite good :wink:

Sorry you didn’t find what you were looking for right off the bat, but maybe my answers can help clear some things up for you.

There are a lot of reasons this will be difficult. I’ll comment on that below.

For ROS 1, if you want to build individual packages with cmake, you can. Just do the normal mkdir build && cd build && cmake .. && make. The catch is that you need to make sure that all of the dependencies of that package are installed and on the CMAKE_PREFIX_PATH and that any other necessary environment variables are set, e.g. LIBARARY_PATH or ROS_DISTRO. This is part of what the setup.bash does. This should work for any ROS 1 package, as they are all catkin and based on CMake or even are pure CMake.

If you want to build a library or executable with C++ and do not want to use catkin or catkin_tools, you can do that too, with some exceptions. @gerkey made examples of this a long time ago:

Notably, you cannot generate messages with just CMake, as we need a bunch of functionality provided by CMake macros in catkin to make that work easily. It would be possible to make that easier to do from “pure” CMake, but no one has had the need.

For ROS 2, you can still build any individual package without colcon or any special tools. Some of the packages are CMake but use ament_cmake (equivalent to catkin from ROS 1) CMake macros, some are pure CMake, but others are something else, e.g. pure Python packages which use setup.py or pure Java packages that don’t use CMake at all. For the first two cases you can again use mkdir build && cd build && cmake .. && make, so long as the dependencies are installed and all the environment variables are setup.

Again, if you want to make executables or libraries using C++ that depend on ROS, you can do that with pure CMake if you want using the ros2 branch on @gerkey’s repository:


As for why we don’t build multiple packages at once in a single CMake invocation… there are a lot of reasons, but first I’ll say you can do this in ROS 1.

We started out with catkin_make which does exactly this, it adds a group of packages you have locally to a single cmake project using add_subdirectory(). In ROS 2, with ament_cmake, we explicitly decided to no longer do that. See:

https://design.ros2.org/articles/ament.html#building-within-a-single-cmake-context

One common technical hurdle, just to give one example, is that if two packages define the same target name, e.g. my_test_executable, then adding them to the same CMake context will cause a failure during configuration.

For the core ROS 1 packages we made sure this wasn’t an issue (we regularly built everything with catkin_make all at once and fixed any issues), but we found that for users it didn’t scale. Because they would take packages which were developed separately, and try to add them together where before that never happened, then they’d run into issues, an error if they’re lucky or cross-talk from global state in CMake if they’re not lucky…

Also, since in ROS 2 we don’t have all CMake based packages (we have pure Python and others like Java or Rust), it’s not always convenient to include them into a CMake project. We could use add_command or ExternalProject_Add, but we feel that this is much more difficult to implement and maintain than doing the same thing essentially except in Python as an extension to catkin_tools or colcon.


Now for some random comments.

I don’t think that’s ergonomic either…

These tools are for handling highly federated packages, it doesn’t impact large code bases in my opinion. You may have a single package for yourself which contains as much as you want, in a single CMake project, modularized how ever you like…

How does it get in the way?

If you just do CXXFLAGS=-Werror colcon ... it will have the same effect… I use it all the time. You shouldn’t need to edit other peoples code in order to turn on warnings or configure them as errors. I personally use export CXXFLAGS=-Werror so I don’t have to specify it each time.

In the case that you set the CMAKE_C_FLAGS in the “root” CMakeLists.txt, what happens if one of the sub projects (that you didn’t write) also sets it and wasn’t expecting it to be set already?

Yes, sorry if I reiterated that above without acknowledging it until now.

For ROS 1, everything is CMake based, so yes. But for ROS 2 and with colcon, no, something things do not use CMake at all.

If you mean, “building more than one package at a time in a single CMake invocation”, then I’d say not really. In ROS 1 you can do this for many packages, this is exactly what catkin_make does. In ROS 2, it may or may not work, but since there’s non-CMake stuff in the dependency tree then I’d say it’s unlikely to be easy.

I don’t think that’s right. The reason it’s package based (federated) is that otherwise anyone wanting to contribute something to the ecosystem would need to get us to accept the change.

Take OpenCV as a counter example, they have a single CMake project, so if you want to add a new feature, it either has to be a separate CMake project (in a different repository) or you have to get a merge request through their process. Now, the former is fine at first, your README will be like “install or build OpenCV, then cmake/make my project”. But at scale this falls apart, it becomes, “install or build OpenCV, some other persons addition, and then some other addition that uses that, and …, then my project”. For robotics it becomes even more complicated as instead of chains you end up with graphs of dependencies due to there being multiple sources of information and separate systems working in parallel.

pip performs many similar functions, but importantly it only works for Python, if you mix languages, as we do, then you need tools that are broader. Our pure Python packages in ROS 2 use setuptools (which is what pip uses) and rosdep will call pip to install dependencies for you. So we’re not reinventing the wheel in that case.

True! Honestly I thought everything (e.g. tutorials and all) had moved to catkin_tools.

Fair point. Perhaps that could be revisited.

I like the pip vs. single package analogy as well. However, like @peci1 mentions there’s a few other things/layers to consider!

@wjwwood Thank you for the detailed reply!

I think I gave a bad example. Here’s another one: Let’s say I want to run something before my build, maybe a script to install dependencies or create a timestamp file or something. With CMake I could add an execute_process in the toplevel CMakeLists.txt, but with colcon I can’t do anything of the sort. I could wrap the command I want to run alongside the colcon call in a build script and make that my build command, but I don’t like the path this goes down. Custom build scripts have a tendency towards becoming dumping grounds, and it’s hard to keep the documentation up to date with the functionality. I really value having an easy onramp experience for a project, so the idea of being able to use the standard mkdir build && cd build && cmake .. && make is really appealing.

Here’s another one: I wanted to add static analysis to my project, but the tool I was using, cppcheck, expects one project. I ended up exporting compile_commands.json for each package and calling cppcheck for each one individually.

Here’s another one: CLion is designed to work with a single CMake project, so I can’t use it for my overall project, or rather I can, but I have to give up some features of its CMake integration.

The point is, if I could structure my project with a toplevel CMake build, it would make certain tools and integrations much easier, not to mention onboarding.

No, definitely not. There’s definitely not a need to require all contributions to the ecosystem to be approved by OSRF. I think we’re conflating package management with building here, and again pip provides a good model with requirements.txt. Of course, as you point out, a pip package only needs to specify compatibility with a limited set python versions, whereas system managing Python/C/C++/Rust/Java packages needs to keep track of Python version, gcc version, architecture, rustc version, javac version, etc.

The current model is clearly working, as there is a large and thriving ecosystem around ROS, but I think there are ways to improve while keeping the aspects of it that work. Some concrete suggestions:

  • Performance: It takes about a second for the catkin_package macro to run. For a couple packages this is fine, but for our ROS1 system we had about 60+ packages, which meant every call to cmake .. takes 60+ seconds when we configured it to use a toplevel CMakeLists.txt. A single character changed in a single CMakeLists.txt meant 60 seconds of reconfiguring. When I did some profiling it looked like a lot of time was going to regenerating files from templates using empy
  • One of: Documentation/CMake macros/consolidation of requirements, in the context of being able to use ROS CLI tools like rosmsg/rosrun/roslaunch with non-catkin packages. For example, for rosmsg show to work, the environment variable ROS_PACKAGE_PATH needs to contain a directory that has a msg folder with the messages and a package.xml with a valid <name> tag. Having that documented somewhere, or having the generate_messages macro look for a valid package.xml and warn the user if it’s not found (and what the consequences are) would help with decoupling ROS functionality from the build system. Arguably the package name could be taken from ROS_PACKAGE_PATH. I can provide additional notes on roslaunch/rosrun if you like. Edit: I see that gerkey’s repo has the info for roslaunch/rosrun, about having a valid package.xml, having a .catkin file and having the path appear in CMAKE_PREFIX_PATHS.
  • For the ROS2 side, similar documentation for the CLI tools would be great. Overall ROS documentation tends to be too high level and abstract (and spread out) to be useful. More details that are grounded in how things really work would be helpful, for example “catkin crawls your src directory for package.xml files, and reads them in order to create a directed acyclic graph of package dependencies, and then builds each package as a separate CMake project starting with the leaves of the tree and working upwards”

To your point about how a single-context build leads to issues like name collision on targets, you’re right. I would argue that the end-user should choose whether or not they want to deal with those issues and accept the tradeoff in order to have a single context build that can more easily integrate with various tools. Right now the user is effectively being blocked from doing so. I doubt this was intentional, but with the number of things that are needlessly coupled with the build system in an undocumented fashion (see the rosmsg example), this is effectively the result. While for ROS1, and even ROS2 to some degree, one can claim that it’s possible to build without catkin/colcon, this is true only in a very technical and academic sense and I think it would be great if this were more of a first class feature of ROS.

1 Like

The OP of @actinium226 brought up some interesting points, but the later comments seem to go more into the direction of “we need better documentation” and “my use-case/preferred use of a build tool isn’t sufficiently being covered by catkin_make/catkin_tools/colcon”. Those are valid concerns, but the thread started with “how about doing all of this with pure CMake?” and I’d like to hear more about that part specifically.

Over the years there have been quite a few comments about “why a custom build system/tool?”. I expect @dirk-thomas may have some comments on the rationale for Colcon fi, but as @christophebedard mentioned, some of it has to do with managing sets of packages with (inter)dependencies (and their dependencies, and their dependencies, and so on).

@actinium226: could you comment on how you’d approach this with pure CMake projects? Especially also with multiple different types of projects and many of which may not use CMake or a language that needs to be compiled or needs special setup of the (build) environment for other projects to be able to find them?

This is a strong statement which I doubt is true (Python nodes don’t need to be Catkin / ROS packages at all fi). The most you could say (and based on my understanding) is that the build tools we have work in a certain way because ROS uses a package based approach to distribution of code. Not the other way around.

I’m not sure it was completely intentional, but freedom-from-choice is a very valuable thing for many users. Especially those not up-to-speed on how build tools work but “just want their packages built”.

This invariably means that more advanced (or involved) use-cases are going to be slightly less supported (or somewhat more involved to get working), but it doesn’t mean that everything is horrible. Just that different choices were made.

Being able to “choose whether or not they want to deal with those issues and accept the tradeoff in order to have a single context build that can more easily integrate with various tools” is valuable, but it would also mean the (average?) user would have to know when to make that choice, which is not apparent and would make it even harder to get started.

I would also add that you have to remember that quite a bit of what you might see as duplication or unnecessary has only become unnecessary because modern CMake started doing many of the same things over the past few years (exporting target dependencies, interface only libraries, transitive dependency resolution, federated builds, etc).

Admittedly I’m very familiar with the way Catkin & Colcon work (so I’m biased), but really, this (ie: the emphasised part) is one of the things I like about the tools we use. It’s very, very frustrating to deal with projects that don’t use something similar and require me to follow 18+ steps in a readme with every step running autotools, cmake, ninja or other tools manually (and 18+ points at which I could make a mistake, something doesn’t work, or I used an incorrect or unexpected way of specifying flags, build options or other configuration).

True, but it would also complicate quite a few other use-cases (if not done carefully), many of which are part of the core development workflow of many of us, such as building packages from others without having to deal with their dependencies, not having to care about which package(s) to build first, etc. Granted, this is not all perfect, but I would not like to start doing that manually again.

This reads as if you have a particular target audience in mind for which this would be true. Could you elaborate?

Personally, for a few of my target audiences (students fi), it’s been a blessing to be able to summarise the entire build process as:

First, run rosdep install -y --from-paths /path/to/your/catkin_ws --ignore-src and then run catkin build in the root of the workspace and wait for it to finish

instead of:

For every project, please mkdir build, then cd build, then cmake ... Do not run this in the src directory (or wherever the project stores its source files). Solve any problems it notifies you of, then run make and then make install. Be sure to specify a suitable DESTDIR and/or other way of specifying where the installable artefacts should go, and please make sure to not try and run sudo make install. Also please do not do any of this for non-CMake projects (which don’t have CMakeLists.txt). Use the regular python setup.py install for Python (add --user for a non-system-wide install, you should know when you’d want that). If you are trying to build a Java based package, then do whatever you’d do with those. For other languages / build systems: please follow the readme, but make sure to maintain a sane build environment at all times.

And above all, please make sure you figure out the proper build order across all packages (both your own and those you downloaded earlier from others), and make sure to have all dependencies installed first.

This is of course exaggerated but helps get the point across.

In my experience, one of the best ways of seeing these suggestions implemented would be to show that they work. Show an example CMake-only build of a workspace with a representative set of packages (ie: containing .msg, .srv (or ROS 2 .idl), multiple different languages, specific environment setup hooks, etc). Show how you’d deal with dependency management and how you’d support the federated workflow.

I’m not saying “you get something for free so you cannot complain”, but with the community as it is right now, code is king and is how you get things changed.

1 Like

If I wanted to make a PR I’d do it. In fact I’ve made several PRs against ROS2 documentation. However the issue I’m trying to bring to light is not one that’s solvable in a single PR, or even a couple. And any change I make could easily be reversed by a future PR that perpetuates the existing model in which ‘catkin/colcon is king’.

That’s why I’m raising this in a thread, because I want to see if there’s any sympathy or currency to these ideas and if so, to try to gather some resources to move things in a direction in which catkin/colcon is not the only game in town.

I agree, but freedom-of-choice and freedom-from-choice do not have to be in opposition. The way to structure a system to have both is to build it on simpler underlying ideas that can be combined in multiple ways, and provide a canonical implementation(s) that combine those ideas in a particular way. The first part gives freedom-of-choice, the second provides a freedom-from-choice.

To give an example, consider the organization of code in C/C++. Most of the time it is organized in header and source files, but this is not strictly necessary. #include is simply copy paste, so if you want to #include a source file, you can. I think I did that once in order to test a static function in a source file (I suppose maybe I could’ve used a prototype but I digress).

To give a bad example, consider CMake. Currently it’s possible to use both old-style and Modern CMake in the same project, and I would say there isn’t enough reference documentation using Modern CMake to make it clear which version one should use. Slowly, more and more Stack Overflow answers are getting comments like “prefer target_include_directories over include_directories”, but overall I’d agree with you that the multitude of options provided by CMake is confusing and makes it a difficult tool to pick up for both students and professionals alike.

To return to the main point, I think the ROS ecosystem would benefit a lot from this approach of having a canonical way of doing things, but providing enough support and documentation for those who want to try something on their own to be able to do so. Right now it’s either catkin’s way or the highway.

To help motivate the discussion, I’ve modified the geometry2 package to build with pure CMake here. This is meant for discussion purposes as opposed to an actual proposal against geometry2, so please don’t bash it too much, but if you clone the repo at that commit you’ll be able to mkdir build && cd build && cmake .. && make. You’ll notice that the CMake step takes 10 seconds. Normally I’m not one to complain about 10 seconds, but you’ll notice this scales with the number of packages (try commenting out the last 5 add_subdirectory commands and time it again. Hint: time in front of a command will time it, i.e. time cmake ..). For a project with 60 packages, this means 60 seconds for every change in a cmake file, even just a comment change. The extra time is coming from the catkin_package call. In order to make it practical for people to use plain CMake in their projects, I think this has to be addressed, does that seem reasonable? Obviously catkin projects would benefit as well, but with the distributed nature of the catkin build I think it would be less noticeable.

Of course, the overall trajectory I’m proposing would require many more steps beyond optimizing catkin_package, in particular colcon might have to take a few steps back as it relies on a non-CMake extension to generate setup.bash, but how do people feel about moving towards a model where BYO-Tool is supported, but there’s a canonical path for those just want to use ROS and don’t want to be bothered with getting up to speed on build tools?

It’s not a complete solution, but I do builds through a single top-level CMakeLists to play nice with a CMake-based IDE (CLion).

Here’s my top-level CMakeLists.txt file, which uses Colcon to gather packages and build them. It can’t successfully build the entire ROS2 C++ stack for various reasons:

  1. Unlike variables, functions have global scope, so two packages declaring the same function name can interfere in weird ways.
  2. Some packages declare the same target name (e.g. the way osrf testing tools pulls in GTest causes build problems for me).

Still, it’s good enough to do multi-package development on C++ stacks. It could probably also be extended by using ExternalProject_Add commands instead of add_subdirectory.

3 Likes

@peci1 +1 for CLion. Have you discovered setting up remote build/run/debugging using ssh yet? :slight_smile: I just got it working so I can build and debug ROS2 modules on my RPI from my desktop computer.

I am a big fan of cmake and the more we can lean on cmake vs colcon I am in favor of. There are some weaknesses in cmake where colcon fits in, so I am not sure it can completely go away.

To add a note about the geometry2 example above, the overall goal would be to get it to compile without the catkin_package macro, instead using cmake’s target_add_dependency. As it is in the commit I linked, it relies on catkin_package generating the cmake files used by find_package, and the order of the add_subdirectory commands reflects the dependency tree. Other steps that would be required to achieve this would be modifying generate_messages to produce a target, and either documenting rosmsg/roslaunch well enough that anyone could add what’s necessary to their project in order to use those tools, or making some new CMake macros that can automatically add what’s necessary to use those tools (or both). I think it would also be necessary to add documentation/macros for setup.bash. Hopefully this helps clear up the picture of what I’m talking about for those who were asking what a pure CMake build would look like.

I can’t speak to handling dependencies for languages other than C/C++ here, but in all of my ROS/ROS2/DDS projects, I have used Conan for both build tool dependencies and library dependencies with fairly great success. Conan has come a long way and I’ve used it in production for a couple of projects, one of which had support for multi-arch builds as well. It has excellent integration support with CMake and overall helps to create highly reproducible builds. This matters a LOT in production environments. I really hate to rely on system dependencies in any of my production software, as you can very easily end up with non-reproducible builds if you don’t take a ton of precautions to lock system dependencies down, which can often be complicated by things like automatic upgrades of packages, optional dependencies, etc. Conan does have support for system dependencies if you absolutely must rely on them (generally because some dependency has not been packaged for Conan yet). Additionally, many of the most popular C/C++ libraries are available as Conan packages already.

I’ve fantasized about the ability to simply include ROS2 and the various components as a Conan dependency, and target_link_libraries( ros2:: ) in my CMakeLists.txt, and just ‘cmake … && make’ without the need to install anything as a system dependency or go through the colcon workflow. Additionally, the IDL generation tools can be included as a build dependency, much the same way you might use <build_depends> in package.xml.

I’ve gone through most of this workflow for pure DDS systems (RTI and FastRTPS) but haven’t dug nearly deep enough into all of the various components and tools necessary to achieve this for ROS2. If there is interest in this, I’d be happy to help in the effort and provide support on the Conan packaging front.

2 Likes

@actinium226, thanks for raising this important topic! We’re always open to suggestions on how to improve the user and developer experience.

@wjwwood and others already covered much of what I would have said, so I’ll just add a few thoughts:

Building ROS vs. using ROS

I don’t see this goal as an end in itself, but rather an approach to addressing some underlying shortcomings in the current workflow.

If I’m a user of a project, then so long as I have a reliable way to install it and then a well-documented way to use it in a manner that’s familiar to me, then I’m satisfied and I don’t worry about how the developers of the project make the sausage. If I want to start contributing to the project as a developer, then I expect that I’ll have to adopt the conventions (code style, file organization) and workflows (CI, code review, test running, build procedures) that the project uses. Eventually, once I’ve established myself among that developer community, I might propose changes to those conventions and workflows, but I’ll assume that the status quo is likely to be preferred so long as it’s working well for the project.

So, rather than saying that ROS should be built using pure CMake, can we figure out what the underlying problems are? I’ve seen two issues raised here so far:

  1. As a ROS user I want to build my ROS-dependent code without using ROS-specific tools.
  2. As a {ROS developer or ROS user who frequently builds ROS from source}, I want my builds of ROS to go faster.

I’ll address each in turn below:

Ease of use of ROS software from outside ROS

That’s a clear, concise, and desirable design goal. To my knowledge, we are achieving it, albeit with areas for improvement.

In creating the examples of using ROS 1 packages without catkin or other ROS-specific tools, I repeatedly experienced two alternating feelings:

  1. Hey, we really can do everything build-related outside of our usual workflow. That’s great!
  2. Holy cow, making that work was not intuitive. We should improve our documentation and maybe also modify how some of the underlying tools work!

This back-and-forth is perhaps best embodied by the example of doing ROS 1 message-generation directly from make and bash. I’m happy that it works, but it was hard to figure out and the resulting workflow is not especially pretty.

Personally, I’d be happy to see improved support for these “external” use cases. When they’re difficult, it’s not because we intend them to be or because we want to force ROS users to use the workflows we use when developing ROS. It’s just that we don’t regularly exercise those external use cases and as a result they suffer. I’d welcome PRs (to code and docs) that make the underlying tools easier to invoke directly.

(Lack of) Efficiency in ROS builds

We build ROS from source in a package-by-package process. As others have noted, there are important advantages to this approach, including inter-package isolation of CMake targets and variables, and support for non-CMake packages.

But as many of us have experienced, a big cost to this approach is that it’s slow. The constant overhead of invoking cmake (or python setup.py..., or another tool) once per package adds up quickly. There’s clearly a lot of redundant work happening over repeated builds and it costs time to developers and CI systems.

I don’t have a particular solution to suggest here. It would be great to see proposals for how to improve the speed of a ROS build without sacrificing the established advantages of the per-package build approach.

CMake macros vs. build tools

Finally: others have pointed it out, but I want to emphasize that there’s a distinction between two things:

  1. A library of CMake macros such as catkin or ament. In my experience, every substantial project that uses CMake ends up having a library of CMake macros that are reused throughout the project. We’ve just been more explicit than most projects by externalizing that library into a separately named entity. And while we find those macros to be useful and convenient, we don’t force anyone else to use them. In any case, using macros like we do is still, in my opinion, pure CMake.

  2. An executable tool used to build a bunch of packages, such as catkin_make (packaged with the catkin CMake macros), catkin (distributed separately in catkin_tools), or colcon. (You’d be forgiven for confusion over the naming for the catkin-related software. That confusion is one reason that ament and colcon are named differently.) This one is potentially more controversial, as we’re recommending that you run our tool to build (potentially) your code. It should always be possible (and ideally easy) to build your code using whatever tool you prefer. Wherever that’s not the case, we should fix it!

3 Likes

@spiderkeys: I would be glad if you could share your insights and experiences with ROS2 and conan.

This is exactly a use case I’m dealing with: a rather simple (from build perspective) single executable, which interacts with ROS/Ignition simulation. I don’t care about how ROS itself is built, but I do care how my simple application is built.

Here are the problems I’ve run into. Firstly, I’m a beginner ROS user and on top of that, I was just thrown from Windows to Linux, Visual Studio to VS Code with CMake, naked executable to Docker image, etc. In general, I’m dealing with completely new development environment and a lot of confusion. Understandably, confusion minimization is my goal, at least in initial stages. My project requires a single executable, but catkin forces me into a workspace configured for potentially multiple packages. Visual Studio Code has multiple CMake extensions and a ROS extension, each with somewhat different ideas about project configuration. It took me a while sifting through documentation to find out relationships between catkin workspace, catkin make, catkin_make, VS Code autoconfigure mess, ROS packages, roslaunch, rosrun, etc. Part of it is a necessary learning curve, but a lot of it was not needed for my simple roscpp scenario. Sorry for ranting, but I thought a new user experience may add some value to this discussion.

1 Like

@pauljurczak Would it have helped if you’d encountered a tutorial that shows you how to use plain CMake to build your roscpp application, without any mention of catkin? That would be easy to do (or promote more heavily, if it already exists somewhere).

The catkin workflow is important if you’re developing multiple ROS packages that need to depend on each other, and/or you want others to be able to easily consume your ROS package(s). But if you’re just building a leaf application that uses ROS, and you’ve installed ROS from binaries (e.g., on Linux via apt), you shouldn’t need to know about catkin.

2 Likes

@gerkey Thanks for the reply. I’m glad to see this topic generating some interesting discussion :slight_smile:

That’s fair, but it’s very possible for a project to have conventions that are, well, conventional, as opposed to internal only. Take Linux or git for example. They can be built with just make.

From a robotics perspective, perhaps, but from a programming perspective I disagree. There is only one way to build software, and this is to go through catkin/cmake. Trying to cut through that complexity and just get to the headers and libraries is an exercise in frustration, as you pointed out shortly after that quote.

Overall you’re right to point out that building with pure CMake isn’t the right goal, I think the goal is better support for non-catkin/colcon (or even non-cmake) workflows. And I think it’s achieved by the development process of ROS being more conscious of this as a goal. Otherwise, what ends up happening is that some documentation is created, never advertised properly, and effectively lost (i.e your example repo, which I duplicated at one point because I was unaware of it).

One other thing I’d like to point out re:documentation, because I think better documentation is a big part of this, OSRF is much better positioned to consolidate and create effective documentation than a contributor. There are 4 separate pages that claim to be documentation for catkin. As a user, I have no access to user stats to see which of those sites is getting visited, and from where. And if I want to contribute to documentation, am I supposed to do it in 4 places? f that, seriously. There are good models to follow here, i.e. Eigen, CMake (they could have more examples, but at least it’s all in one place). Also, there are certain undocumented decisions that inhibit the kind of development we’re talking about. It’s one thing to build an executable that can use ROS message bus, but it’s another to build one that can take advantage of rosrun/roslaunch/rosmsg, mostly because catkin is taking care of the installation step for you and hiding all the details. I’m totally fine with abstracting away details in a friendly interface, but I’d love it much more if I could look up documentation about that interface and get some information as to what’s going on.