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

How to specify dependencies with "foo_msgs" catkin packages

asked 2013-01-18 05:14:23 -0600

cdellin gravatar image

updated 2013-02-07 07:04:27 -0600

Say I have two catkin packages, foo and foo_msgs, in my workspace. Here's how I currently have them set up:

project(foo_msgs)
find_package(catkin REQUIRED COMPONENTS message_generation)
add_message_files(
  DIRECTORY msg
  FILES foomsg.msg
)
generate_messages()
catkin_package(CATKIN_DEPENDS message_runtime)
project(foo)
find_package(catkin REQUIRED COMPONENTS foo_msgs)
catkin_package()
include_directories(include ${catkin_INCLUDE_DIRS})
add_executable(foo foo.cpp)

I find that if I catkin_make foo, the message isn't generated. Indeed, catkin_make foo_msgs is a no-op. catkin_make foo_msgs_gencpp works, however. In order to get foo to build correctly, I must add the following line to its CMakeLists.txt:

add_dependencies(foo foo_msgs_gencpp)

Is this by design? I'd expect that building the package foo_msgs would automatically generate all its messages. Is there a way to make that happen?

Edit: I've approved WilliamWoodall's answer, although KruseT's was just as useful. (I also added the include_directories() line to foo's CMakeLists.txt, which I initially forgot.)

It turns out my solution is correct; the foo_msgs_gencpp auto-target should be added as a dependency of the foo target. Note that there is some disagreement about whether a different solution should be supported by catkin; KruseT started a discussion on the topic here.

Since this type of explicit dependency auto-target (_gencpp and _genpy) is necessary for using ROS messages/actions/services in any executable, library, or script, I think it should be better documented (I found no reference to it in catkin/migrating_from_rosbuild). KruseT opened a related rosdistro issue here.

edit retag flag offensive close merge delete

4 Answers

Sort by ยป oldest newest most voted
18

answered 2013-02-05 12:46:54 -0600

WilliamWoodall gravatar image

updated 2014-02-28 07:59:06 -0600

William gravatar image

Your projects are setup correctly (mostly), you just need to run catkin_make with no arguments.

First update foo:

cmake_minimum_required(VERSION 2.8.3)
project(foo)

find_package(catkin REQUIRED COMPONENTS foo_msgs)

catkin_package()

include_directories(include ${catkin_INCLUDE_DIRS})

add_executable(foo_node src/foo_node.cpp)
add_dependencies(foo_node foo_msgs_generate_messages_cpp)

Using add_dependencies(...) is by design or necessity, however you look at it, because we cannot know or assume that foo's targets (executables or libraries) use and therefore depend on the messages which are getting generated by foo_msgs.

Then just execute catkin_make with no arguments.

If you want to build foo_msgs explicitly (not the whole workspace) then as of pull request ros/catkin#352 you can do catkin_make --pkg foo_msgs.

Calling catkin_make foo_msgs is not sufficient because that is instructing catkin_make to invoke the foo_msgs make target which does not exist. tkruse's solution simply adds a foo_msgs target which depends on the foo_msgs_generate_messages_cpp target, allowing it to be callable and causing the foo_msgs_generate_messages_cpp target to be generated. This is not something we do by default because packages often define targets with the same name as the project which would immediately cause a conflict.

The only reliable way to build an entire package (including all of its targets) is to go to the package's build space and invoke make [all], which is what catkin_make --pkg does.

I setup an example repository here:

https://github.com/wjwwood/catkin_dem...

edit flag offensive delete link more

Comments

1

Hi WilliamWoodall, this is very helpful! Clearly the _gencpp dependency needs to go somewhere explicitly. You list it in foo's CMakeLists file. In that case, if foo_msgs is already installed (so catkin is only building foo), will the foo_msgs_gencpp dependency be correctly resolved by catkin?

cdellin gravatar image cdellin  ( 2013-02-06 10:12:17 -0600 )edit
1

Yes, CMake will ignore targets which are not defined, you could add add_dependencies(foo_node bar_does_not_exist) and it will build with no warnings.

WilliamWoodall gravatar image WilliamWoodall  ( 2013-02-06 10:40:51 -0600 )edit

Great! This is my favorite solution, since it doesn't introduce new targets (foo_msgs), and explicitly encodes the dependency between the foo (binary) target and the generated cpp messages.

cdellin gravatar image cdellin  ( 2013-02-06 12:21:46 -0600 )edit

Also, I want to stress about catkin_make arguments: (a) sometimes it is useful to build only particular targets (yes, targets, not packages), and (b) running catkin_make with no arguments doesn't help here; the _gencpp target is still required to ensure targets are built in the correct order.

cdellin gravatar image cdellin  ( 2013-02-06 12:43:29 -0600 )edit

(a) building specific target is already supported by "catkin_make", any argument without a special meaning is passed straight forward to "make", see "catkin_make --help" for details.

Dirk Thomas gravatar image Dirk Thomas  ( 2013-02-06 20:45:18 -0600 )edit

Hi Dirk! I understand this, I just wanted to correct the answer. I believe that WilliamWoodall's assertion that "running catkin_make with no arguments" would somehow fix my problem is incorrect.

cdellin gravatar image cdellin  ( 2013-02-07 04:48:01 -0600 )edit
1

It looks like the version of CMake on Ubuntu Xenial and newer now complains of non-existent targets. Switching to ${catkin_EXPORTED_TARGETS} seems to make it more happy.

ahendrix gravatar image ahendrix  ( 2017-04-25 01:47:10 -0600 )edit
17

answered 2013-08-28 11:33:35 -0600

updated 2019-08-16 18:19:04 -0600

lucasw gravatar image

I believe the modern way of doing this is to add a dependency on ${catkin_EXPORTED_TARGETS}, as specified on this documentation page. It should look something like this:

find_package(catkin REQUIRED COMPONENTS foo_msgs)

add_dependencies(your_program ${catkin_EXPORTED_TARGETS})
add_dependencies(your_library ${catkin_EXPORTED_TARGETS})
edit flag offensive delete link more

Comments

You should check that `${catkin_EXPORTED_TARGETS}` is set to something before passing it to `add_dependencies(...)`.

William gravatar image William  ( 2013-08-28 12:12:53 -0600 )edit

https://gist.github.com/wjwwood-snippets/5979727

William gravatar image William  ( 2013-08-28 12:13:25 -0600 )edit

Doesn't the fix for this issue make this check redundant? https://github.com/ros/catkin/issues/453

kalakris gravatar image kalakris  ( 2013-08-28 12:17:42 -0600 )edit

Ah yes, I forgot we added that.

William gravatar image William  ( 2013-08-28 12:19:17 -0600 )edit
3

The documentation link above is broken. The page can be found here.

Neil Traft gravatar image Neil Traft  ( 2014-08-07 21:35:53 -0600 )edit
4

answered 2013-01-18 09:40:55 -0600

KruseT gravatar image

updated 2013-02-07 03:39:17 -0600

catkin_make with an argument just passes that argument to make. That a make target for the package exists is more by chance than design, I'd guess it is added by cmake for each subfolder (but not with nested folders). Maybe you can open a ticket on github to add the feature of a dedicated target to make. However a small problem exists, frequently a package named foo defines an executable named foo, so the target names overlap each other. Not sure whether any clean solution is possible. At least it wont be straightforward.

What you can do to cause "make foo_msgs" not be a noop is in package foo_msg, add a dependency like this:

add_custom_target(${PROJECT_NAME} DEPENDS ${PROJECT_NAME}_gencpp)

which is equivalent to

# add_custom_target(foo_msgs DEPENDS foo_msgs_gencpp)

but easier for copy&paste

[Update3: this is wrong:

Update: add_dependencies is definitely the wrong way to go, the way you use it (in foo, add dependency to foomsg). add_dependency should never cross catkin project boundaries. For you it only works coincidentally (because catkin cheats cmake conventions), it will break build in other cases or when building the projects in isolation.]

Update3: So it seems that indeed currently, calling add_dependencies accross package boundaries it currently the only recommendable way to achieve that the headers generated by foo_msg exist before they are being consumed by a target in foo.

We'll discuss this in the buildsystem SIG and maybe there will be a cleaner solution in the future.Discussion here: https://groups.google.com/d/topic/ros-sig-buildsystem/dvVO5QCHBLM/discussion

edit flag offensive delete link more

Comments

Ok, so the add_dependencies(foo foo_msgs_gencpp) solution is the right way to go?

cdellin gravatar image cdellin  ( 2013-01-18 10:58:52 -0600 )edit

Apologies kruset, I'm still confused. What exactly should I add to my CMakeLists file(s) for this example? I haven't found anything but the _gencpp dependency (across catkin project boundaries) to work.

cdellin gravatar image cdellin  ( 2013-02-05 11:59:46 -0600 )edit

There is no reason to call catkin_make with arguments... You are not telling catkin_make what packages you want to build you are just passing targets to make, and the project target and executable/library targets can overlap. It is better to just invoke catkin_make with no arguments.

WilliamWoodall gravatar image WilliamWoodall  ( 2013-02-06 06:21:47 -0600 )edit

I partially agree and partiall disagree, WilliamWoodall. Yes, clearly the user of catkin should be aware that catkin_make targets correspond directly with executable/library targets. I've found it very useful to only make/remake particular targets during development for compilation time purposes.

cdellin gravatar image cdellin  ( 2013-02-06 10:07:21 -0600 )edit
1

kruset, thanks for the clarification; this appears to be the best solution I've found. Perhaps it should go in a tutorial? Setting up this type of package structure (foo and foo_msgs) seems to be a very standard practice, and that I had such a hard time getting it to work properly is unfortunate.

cdellin gravatar image cdellin  ( 2013-02-06 10:09:05 -0600 )edit

The reason caktin_make foo_msgs is a no-op is that there is no make target for a package by default. In stead there is a Makefile for each time project(...) is called in CMake. The correct thing to do in order to build a package is to go to its location in the build folder and invoke make.

WilliamWoodall gravatar image WilliamWoodall  ( 2013-02-06 10:23:00 -0600 )edit

In my example, if I run: cd build/catkin_demos/foo_msgs && make all of the messages are generated. This is basically what catkin_make --pkg foo_msgs will do: https://github.com/ros/catkin/pull/352

WilliamWoodall gravatar image WilliamWoodall  ( 2013-02-06 10:24:36 -0600 )edit

Regarding documentation, I opened https://github.com/ros/rosdistro/issues/439.

KruseT gravatar image KruseT  ( 2013-02-06 11:19:12 -0600 )edit
0

answered 2021-10-06 02:42:15 -0600

Micha Sende gravatar image

As the other answers already state, you need to add the correct dependencies in the CMakeLists.txt. However, I found I also have to correctly specify the dependencies in the package.xml, otherwise the packages would not build in the correct order (i.e., first foo_msgs then foo).

I am using the catkin tools for building. Not sure if it is strictly necessary for caktin_make.

A minimal package.xml could look like this:

<?xml version="1.0"?>
<package format="2">
  <name>foo</name>
  <version>1.0.0</version>
  <description>Package foo depends on foo_msgs</description>
  <maintainer email="foo@bar.com">Foo Bar<maintainer>
  <license>Foo Bar</license>
  <buildtool_depend>catkin</buildtool_depend>
  <depend>roscpp</depend>
  <depend>foo_msgs</depend>
</package>
edit flag offensive delete link more

Question Tools

7 followers

Stats

Asked: 2013-01-18 05:14:23 -0600

Seen: 22,897 times

Last updated: Oct 06 '21