ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange |
1 | initial version |
DEPENDS
and CATKIN_DEPENDS
are how you can tell catkin which of your package's dependencies should be passed along to packages which find_package(...)
your package.
For example, lets say you find_package(Boost REQUIRED)
and in one of your installed headers you #include <boost/function.hpp>
. In order for a dependent package to build and link your header they need to have Boost's include directory in the their include path and they need to link against Boost's libraries. They should get that dependency from you since you expose it in your header, i.e. they should not have to find_package(Boost REQUIRED)
just because they are building against your package, and do not otherwise use Boost.
The fact that your package depends on Boost is an implementation detail. Therefore when some find_package(...)
's your package they should get the dependency on Boost "for free". The way this works is that you put DEPENDS Boost
in your catkin_package(...)
call. Internally, catkin will find_package(Boost)
and add ${Boost_LIBRARIES}
to ${your_pkg_LIBRARIES}
and add ${Boost_INCLUDE_DIRS}
to ${your_pkg_INCLUDE_DIRS}
.
I should note that catkin will take the exact thing you give it and try to find_package(...)
it and then try to use the _LIBRARIES
and _INCLUDE_DIRS
variables for that package. This assumption about find_package(...)
layout does not always hold, as CMake does not enforce this. For example, when find_package(...)
ing Python: find_package(PythonLibs REQUIRED)
results in variables like PYTHON_INCLUDE_PATH
, and find_package(OpenGL REQUIRED)
results in OPENGL_INCLUDE_DIR
. Aside from case of the variable prefixes, the actual prefixes differ (PythonLibs
-> PYTHON
), and the suffixes are non-standard (PYTHON_INCLUDE_PATH
and OPENGL_INCLUDE_DIR
vs *_INCLUDE_DIRS
). In this case you need to pass the include dirs variable to catkin_package(...)
explicitly using the INCLUDE_DIRS
option and the libraries using the LIBRARIES
option.
The CATKIN_DEPENDS
option is exactly like that DEPENDS
option, but you must put catkin packages only in that list. The benefit for sorting your catkin depends into a separate option is that catkin can do additional checks and warn you of potentially incorrect practices.
Finally, a simple example CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.3)
project(foo)
find_package(Boost REQUIRED
COMPONENTS
system
thread
)
find_package(PythonLibs REQUIRED)
find_package(OpenGL REQUIRED)
find_package(catkin REQUIRED
COMPONENTS
rosconsole
roscpp
)
include_directories(
include
${catkin_INCLUDE_DIRS}
${OPENGL_INCLUDE_DIR}
${PYTHON_INCLUDE_PATH}
)
catkin_package(
INCLUDE_DIRS include ${OPENGL_INCLUDE_DIR}
LIBRARIES foo ${OPENGL_LIBRARIES}
CATKIN_DEPENDS roscpp
DEPENDS Boost
)
...
In this example you can see that I find_package(Boost...)
and pass it along in the DEPENDS
section because it generates compliant CMake variables. I find_package(PythonLibs...)
and use it internally but do not pass it along as it is not in any of my exposed headers. I find_package(OpenGL...)
but since it does not make compliant CMake variables I pass it along explicitly to INCLUDE_DIRS
and LIBRARIES
. Finally I find_package(catkin...rosconsole roscpp)
, I use both internally, but maybe I only use rosconsole in my .c* files and therefore I do not need to pass it along, so in the CATKIN_DEPENDS
variable I just put roscpp.
One final example, if a package uses a dependency like Boost directly they should make sure that they find_package(...)
it explicitly and that they do not just implicitly depend on it being there from another package. An example where this occurs is that if a package foo
exports Boost as a dependency and a package bar
depends on foo
, but also uses Boost internally then bar
will compile fine without an explicit dependency on Boost. But later foo
might decide to refactor and remove its dependency on Boost. Now bar
will fail to compile as it does not have the implicit dependency on Boost via foo
anymore.
2 | No.2 Revision |
To answer part A of your question...
DEPENDS
and CATKIN_DEPENDS
are how you can tell catkin which of your package's dependencies should be passed along to packages which find_package(...)
your package.
For example, lets say you find_package(Boost REQUIRED)
and in one of your installed headers you #include <boost/function.hpp>
. In order for a dependent package to build and link your header they need to have Boost's include directory in the their include path and they need to link against Boost's libraries. They should get that dependency from you since you expose it in your header, i.e. they should not have to find_package(Boost REQUIRED)
just because they are building against your package, and do not otherwise use Boost.
The fact that your package depends on Boost is an implementation detail. Therefore when some find_package(...)
's your package they should get the dependency on Boost "for free". The way this works is that you put DEPENDS Boost
in your catkin_package(...)
call. Internally, catkin will find_package(Boost)
and add ${Boost_LIBRARIES}
to ${your_pkg_LIBRARIES}
and add ${Boost_INCLUDE_DIRS}
to ${your_pkg_INCLUDE_DIRS}
.
I should note that catkin will take the exact thing you give it and try to find_package(...)
it and then try to use the _LIBRARIES
and _INCLUDE_DIRS
variables for that package. This assumption about find_package(...)
layout does not always hold, as CMake does not enforce this. For example, when find_package(...)
ing Python: find_package(PythonLibs REQUIRED)
results in variables like PYTHON_INCLUDE_PATH
, and find_package(OpenGL REQUIRED)
results in OPENGL_INCLUDE_DIR
. Aside from case of the variable prefixes, the actual prefixes differ (PythonLibs
-> PYTHON
), and the suffixes are non-standard (PYTHON_INCLUDE_PATH
and OPENGL_INCLUDE_DIR
vs *_INCLUDE_DIRS
). In this case you need to pass the include dirs variable to catkin_package(...)
explicitly using the INCLUDE_DIRS
option and the libraries using the LIBRARIES
option.
The CATKIN_DEPENDS
option is exactly like that DEPENDS
option, but you must put catkin packages only in that list. The benefit for sorting your catkin depends into a separate option is that catkin can do additional checks and warn you of potentially incorrect practices.
Finally, a simple example CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.3)
project(foo)
find_package(Boost REQUIRED
COMPONENTS
system
thread
)
find_package(PythonLibs REQUIRED)
find_package(OpenGL REQUIRED)
find_package(catkin REQUIRED
COMPONENTS
rosconsole
roscpp
)
include_directories(
include
${catkin_INCLUDE_DIRS}
${OPENGL_INCLUDE_DIR}
${PYTHON_INCLUDE_PATH}
)
catkin_package(
INCLUDE_DIRS include ${OPENGL_INCLUDE_DIR}
LIBRARIES foo ${OPENGL_LIBRARIES}
CATKIN_DEPENDS roscpp
DEPENDS Boost
)
...
In this example you can see that I find_package(Boost...)
and pass it along in the DEPENDS
section because it generates compliant CMake variables. I find_package(PythonLibs...)
and use it internally but do not pass it along as it is not in any of my exposed headers. I find_package(OpenGL...)
but since it does not make compliant CMake variables I pass it along explicitly to INCLUDE_DIRS
and LIBRARIES
. Finally I find_package(catkin...rosconsole roscpp)
, I use both internally, but maybe I only use rosconsole in my .c* files and therefore I do not need to pass it along, so in the CATKIN_DEPENDS
variable I just put roscpp.
One final example, if a package uses a dependency like Boost directly they should make sure that they find_package(...)
it explicitly and that they do not just implicitly depend on it being there from another package. An example where this occurs is that if a package foo
exports Boost as a dependency and a package bar
depends on foo
, but also uses Boost internally then bar
will compile fine without an explicit dependency on Boost. But later foo
might decide to refactor and remove its dependency on Boost. Now bar
will fail to compile as it does not have the implicit dependency on Boost via foo
anymore.