ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Short answer is no.

catkin workspaces do not support multiple inheritance of workspaces. For example:

Consider that you have some binary debians installed, and you want to build workspace A, you would do so like this:

  • source /opt/ros/groovy/setup.bash
  • catkin_make # In A_ws

Then you separately build B (in a new terminal):

  • source /opt/ros/groovy/setup.bash
  • catkin_make # In B_ws

Now you have a workspace C which you want to use A and B, so you try:

  • source /opt/ros/groovy/setup.bash
  • source A_ws/devel/setup.bash
  • source B_ws/devel/setup.bash
  • catkin_make # In C_ws

The C_ws will likely fail to build if it relies on packages which only exist in workspace A. Why? because the setup.bash files overwrite each other. In fact when if I build workspace A like this:

  • ./src/catkin/bin/catkin_make # In A_ws (assuming catkin is in that workspace)

And then do this:

  • source /opt/ros/groovy/setup.bash
  • source A_ws/devel/setup.bash

Then you will not find the /opt/ros/groovy/ install space in your environment.

This is the rule you have to remember:

The setup.bash/zsh/sh file generated by catkin has the current environment plus the workspace which was just built.

That means that each time you source a setup.bash file which was generated by catkin it is reconstructing the environment in which it was created. The reason for this is to provide a consistent build and run environment for your packages. It in fact does not make sense to build packages in one environment and run them in another.

If you want to build workspace C on top of A and B, then you should follow this pattern:

  • source /opt/ros/groovy/setup.bash
  • catkin_make # In A_ws
  • # open a new terminal (this isn't required, but it is good to keep a clean environment)
  • source A_ws/devel/setup.bash # This contains /opt/ros/groovy AND A_ws's packages
  • catkin_make # In B_ws
  • # open a new terminal
  • source B_ws/devel/setup.bash # This contains /opt/ros/groovy, A_ws, and B_ws
  • catkin_make # In C_ws

In this way you are always building your current workspace on top of exactly one other workspace.

This is a necessary constraint to prevent other less obvious errors from arising. For example, consider this:

You build a workspace A which contains a library foo.

Next you build a workspace B, after sourcing A, which contains a library bar which is linked against foo from A.

But then you have a modified version of foo in a workspace C which you build after source A. You source A first to get the dependencies of foo from workspace A, but now the version of foo from workspace C is overlaying the version from A.

Next you want to build a package in workspace D which uses bar and foo, but you want to test your changes to foo from C. So you do this:

  • Source A
  • Source B
  • Source C
  • Build D

But workspace D fails because it cannot find bar. So you try sourcing B again:

  • Source B
  • Build D

Now D builds, finding bar in B and foo from A, but you do not get your modified version of foo from C.

Lets assume for a second that you could add the environment from C onto the environment from B. Now D builds and finds foo from C and bar from B. But there is still a problem, because bar from B is compiled against foo from A, so your package in D is now linking against foo from C AND foo from A via bar from B. This problem is not easy to catch and not all changes to foo would actually cause a problem. But to prevent this from occurring catkin enforces no multiple workspace inheritance. Because any time you do this multiple workspace inheritance you will be using a product from one workspace which was built without influence from the other, e.g. bar from B was not built in the presence of foo from C.

Now if you take the recommendation from above, you would do this:

  • Build A
  • Source A
  • Build C
  • Source C
  • Build B
  • Source B
  • Build D

Now D builds against a bar from B which linked against a foo from C which is overlaying the foo from A. By enforcing this single workspace inheritance model, catkin tries to prevent inconsistent build/run environments.

Hopefully this helps a little bit to explain why this is and why catkin workspaces have this limitation, and I would like to hear feedback on ways to improve this use case, because I cannot think of any.

Short answer is no."yes", longer answer is "it can be dangerous".

You can call any setup.bash/zsh/sh with the --extend option which will "extend" your current environment. If you do not do this then the setup.bash/zsh/sh will overwrite your current environment to restore the environment which existed when it was generated (the setup.bash/zsh/sh).

So you can do something like this:

  • source /opt/ros/groovy/setup.bash
  • catkin_make # In A_ws
  • # open a new terminal
  • source /opt/ros/groovy/setup.bash
  • catkin_make # In B_ws
  • # open a new terminal
  • source A_ws/devel/setup.bash
  • source B_ws/devel/setup.bash --extend
  • catkin_make # In C_ws (this builds on both A and B and /opt/ros/groovy)

BUT this can be dangerous, read on if you care:

catkin workspaces do not support multiple inheritance of workspaces. workspaces by default in order to prevent inconsistent build and run environments. For example:

Consider that you have some binary debians installed, and you want to build workspace A, you would do so like this:

  • source /opt/ros/groovy/setup.bash
  • catkin_make # In A_ws

Then you separately build B (in a new terminal):

  • source /opt/ros/groovy/setup.bash
  • catkin_make # In B_ws

Now you have a workspace C which you want to use A and B, so you try:

  • source /opt/ros/groovy/setup.bash
  • source A_ws/devel/setup.bash
  • source B_ws/devel/setup.bash
  • catkin_make # In C_ws

The C_ws will likely fail to build if it relies on packages which only exist in workspace A. Why? because the setup.bash files overwrite each other. In fact when if I build workspace A like this:

  • ./src/catkin/bin/catkin_make # In A_ws (assuming catkin is in that workspace)

And then do this:

  • source /opt/ros/groovy/setup.bash
  • source A_ws/devel/setup.bash

Then you will not find the /opt/ros/groovy/ install space in your environment.

This is the rule you have to remember:

The setup.bash/zsh/sh file generated by catkin has the current environment plus the workspace which was just built.

That means that each time you source a setup.bash file which was generated by catkin it is reconstructing the environment in which it was created. The reason for this is to provide a consistent build and run environment for your packages. It in fact does not make sense to build packages in one environment and run them in another.

If you want to build workspace C on top of A and B, then you should follow this pattern:

  • source /opt/ros/groovy/setup.bash
  • catkin_make # In A_ws
  • # open a new terminal (this isn't required, but it is good to keep a clean environment)
  • source A_ws/devel/setup.bash # This contains /opt/ros/groovy AND A_ws's packages
  • catkin_make # In B_ws
  • # open a new terminal
  • source B_ws/devel/setup.bash # This contains /opt/ros/groovy, A_ws, and B_ws
  • catkin_make # In C_ws

In this way you are always building your current workspace on top of exactly one other workspace.

This is a necessary constraint to prevent other less obvious errors from arising. For example, consider this:

You build a workspace A which contains a library foo.

Next you build a workspace B, after sourcing A, which contains a library bar which is linked against foo from A.

But then you have a modified version of foo in a workspace C which you build after source A. You source A first to get the dependencies of foo from workspace A, but now the version of foo from workspace C is overlaying the version from A.

Next you want to build a package in workspace D which uses bar and foo, but you want to test your changes to foo from C. So you do this:

  • Source A
  • Source B
  • Source C
  • Build D

But workspace D fails because it cannot find bar. So you try sourcing B again:

  • Source B
  • Build D

Now D builds, finding bar in B and foo from A, but you do not get your modified version of foo from C.

Lets assume for a second that you could used the --extend option to add the environment from C onto the environment from B. Now D builds and finds foo from C and bar from B. But there is still a problem, because bar from B is compiled against foo from A, so your package in D is now linking against foo from C AND foo from A via bar from B. This problem is not easy to catch and not all changes to foo would actually cause a problem. But to prevent this from occurring catkin enforces no multiple workspace inheritance. Because any time you do this multiple workspace inheritance you will be using a product from one workspace which was built without influence from the other, e.g. bar from B was not built in the presence of foo from C.

Now if you take the recommendation from above, you would do this:

  • Build A
  • Source A
  • Build C
  • Source C
  • Build B
  • Source B
  • Build D

Now D builds against a bar from B which linked against a foo from C which is overlaying the foo from A. By enforcing this single workspace inheritance model, catkin tries to prevent inconsistent build/run environments.

Hopefully this helps a little bit to explain why this is and why catkin workspaces have this limitation, and I would like to hear feedback on ways to improve this use case, because I cannot think of any.