参考:
https://answers.ros.org/question/58498/what-is-the-purpose-of-catkin_depends/
https://docs.ros.org/en/api/catkin/html/dev_guide/generated_cmake_api.html#catkin-package
我们在一些ros功能包的CMakeLists文件中经常可以看见catkin_package
catkin_package(
CATKIN_DEPENDS
diagnostic_updater
dynamic_reconfigure
geometry_msgs
nav_msgs
rosbag
roscpp
sensor_msgs
std_srvs
tf2
tf2_msgs
tf2_ros
INCLUDE_DIRS include
LIBRARIES amcl_sensors amcl_map amcl_pf
)
catkin_package是给下游(使用该包的包)使用的,它用于向其他包导出依赖,这些依赖可能是本包给其他包提供的公共头文件、库,或者是本包依赖的其他包。
它有5个选项:
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if you package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
## CFG_EXTRAS: Additional configuration options
catkin_package(...
DEPENDS
和 CATKIN_DEPENDS
用来告诉 catkin 需要将你程序包的哪些依赖项,传递给使用 find_package(...)
查找你的程序包的程序包。
例如,假设你调用 find_package(Boost REQUIRED)
,并在你的安装的头文件中 #include
。为使一个依赖于你的程序包的程序包能构建和连接你的头文件,它们需要在自己的 include 路径中包含 Boost 的 include 目录,还需要连接 Boost 的库。
由于你已经在头文件中导出了该依赖,它们应该能从你那里获得依赖。也就是它们不再需要 find_package(Boost REQUIRED)
,因为它们是使用你的包构建的,而不是直接使用 Boost。
你的程序包依赖于 Boost 这一事实是一个实现细节,因此当一些包通过 find_package(...)
查找你的包时,它们能间接获得对 Boost 的依赖。让这种机制起作用方法是在你的 catkin_package(...)
调用中加入 DEPENDS Boost
。在内部,catkin 将 find_package(Boost)
,并向 ${your_pkg_LIBRARIES}
添加 ${Boost_LIBRARIES}
,向 ${your_pkg_INCLUDE_DIRS}
添加 ${Boost_INCLUDE_DIRS}
。因此其他包,只需要链接${your_pkg_INCLUDE_DIRS}
、${your_pkg_LIBRARIES}
即可获取传递的依赖。
我们应该注意,catkin 将你告诉它的确切的程序包名传递给find_package()
来查找该包, 然后尝试使用该包的 _LIBRARIES
和 _INCLUDE_DIRS
变量。但是 find_package(...)
得到的结果变量的形式并不总是这样,因为 CMake 没有强制执行此 *** 作。例如当 find_package(...)
Python 时,find_package(PythonLibs REQUIRED)
的结果变量的形式为 PYTHON_INCLUDE_PATH
,find_package(OpenGL REQUIRED)
的结果变量为 OPENGL_INCLUDE_DIR
。除了变量前缀变得不一样(PythonLibs
-> PYTHON
),后缀也变得不标准(PYTHON_INCLUDE_PATH
and OPENGL_INCLUDE_DIR
vs *_INCLUDE_DIRS
)。在这种情况下你就需要使用 INCLUDE_DIRS
选项和 LIBRARIES
选项了。另外,自己对外暴露的头文件、库也要通过选项INCLUDE_DIRS、LIBRARIES 传递出去(见下面的例子foo)。
CATKIN_DEPENDS
选项和 DEPENDS
选项十分相似,但是你只能在其列表中放置 catkin 程序包。将 catkin 依赖设置为一个单独的选项的好处是可以让 catkin 执行一些额外的检查,然后警告你有什么不妥的做法。
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
)
...
此例中你可以看到我 find_package(Boost...)
并将它传递给 catkin_package()
的 DEPENDS
部分,因为它生成的是兼容 CMake 的变量。我 find_package(PythonLibs...)
并在内部使用它,但是不用将它传递给 catkin_package()
,因为我没有在我任何导出的头文件中包含它。我 find_package(OpenGL...)
,由于它不是兼容 CMake 的变量,所以我将其显示地传递给 catkin_package()
的 NCLUDE_DIRS
和 LIBRARIES
部分。最后,我 find_package(catkin ... rosconsole roscpp
,并在内部使用,但是我可能只在 .c* 文件中使用了 rosconsole,因此我不用传递它,所以 catkin_package()
的 CATKIN_DEPENDS
部分我只需放入 roscpp。
最后要说明但是,如果一个程序包有直接使用像 Boost 这样的依赖项,那么它们应该确保用 find_package(...)
显示地查找它,而不是通过其他包隐式地依赖于它。举个这样的例子,如果程序包 foo 将 Boost 作为依赖项导出,又有程序包 bar 依赖于 foo,但也在内部使用 Boost,那么 bar 即使在没有显示依赖 Boost 的情况下也能编译正常。 但后来 foo 可能决定重构并删除了它对 Boost 的依赖,那么现在 bar 将无法编译,因为它不再具有通过 foo 传递来的对 Boost 的隐式依赖。
我们上面只是讨论了catkin_package的用途,并没有详细讲述它是如何起作用的。catkin_package调用之后会在安装目录/share/
目录下生成cmake config模式的查找文件:
生成的xxConfig.cmake文件主要是处理上面的几个选项,库、头文件,依赖,将搜索结果追加到
附录一个xxConfig.cmake文件的例子,它是根据catkin/cmake/template/pkgConfig.cmake.in模板生成的。我的包名叫test。
# generated from catkin/cmake/template/pkgConfig.cmake.in
# append elements to a list and remove existing duplicates from the list
# copied from catkin/cmake/list_append_deduplicate.cmake to keep pkgConfig
# self contained
macro(_list_append_deduplicate listname)
if(NOT "${ARGN}" STREQUAL "")
if(${listname})
list(REMOVE_ITEM ${listname} ${ARGN})
endif()
list(APPEND ${listname} ${ARGN})
endif()
endmacro()
# append elements to a list if they are not already in the list
# copied from catkin/cmake/list_append_unique.cmake to keep pkgConfig
# self contained
macro(_list_append_unique listname)
foreach(_item ${ARGN})
list(FIND ${listname} ${_item} _index)
if(_index EQUAL -1)
list(APPEND ${listname} ${_item})
endif()
endforeach()
endmacro()
# pack a list of libraries with optional build configuration keywords
# copied from catkin/cmake/catkin_libraries.cmake to keep pkgConfig
# self contained
macro(_pack_libraries_with_build_configuration VAR)
set(${VAR} "")
set(_argn ${ARGN})
list(LENGTH _argn _count)
set(_index 0)
while(${_index} LESS ${_count})
list(GET _argn ${_index} lib)
if("${lib}" MATCHES "^(debug|optimized|general)$")
math(EXPR _index "${_index} + 1")
if(${_index} EQUAL ${_count})
message(FATAL_ERROR "_pack_libraries_with_build_configuration() the list of libraries '${ARGN}' ends with '${lib}' which is a build configuration keyword and must be followed by a library")
endif()
list(GET _argn ${_index} library)
list(APPEND ${VAR} "${lib}${CATKIN_BUILD_CONFIGURATION_KEYWORD_SEPARATOR}${library}")
else()
list(APPEND ${VAR} "${lib}")
endif()
math(EXPR _index "${_index} + 1")
endwhile()
endmacro()
# unpack a list of libraries with optional build configuration keyword prefixes
# copied from catkin/cmake/catkin_libraries.cmake to keep pkgConfig
# self contained
macro(_unpack_libraries_with_build_configuration VAR)
set(${VAR} "")
foreach(lib ${ARGN})
string(REGEX REPLACE "^(debug|optimized|general)${CATKIN_BUILD_CONFIGURATION_KEYWORD_SEPARATOR}(.+)$" "\\1;\\2" lib "${lib}")
list(APPEND ${VAR} "${lib}")
endforeach()
endmacro()
if(test_CONFIG_INCLUDED)
return()
endif()
set(test_CONFIG_INCLUDED TRUE)
# set variables for source/devel/install prefixes
if("FALSE" STREQUAL "TRUE")
set(test_SOURCE_PREFIX /data/src/utils/test)
set(test_DEVEL_PREFIX /data/devel_buzzard_isolated/test)
set(test_INSTALL_PREFIX "")
set(test_PREFIX ${test_DEVEL_PREFIX})
else()
set(test_SOURCE_PREFIX "")
set(test_DEVEL_PREFIX "")
set(test_INSTALL_PREFIX /data/install_buzzard_isolated)
set(test_PREFIX ${test_INSTALL_PREFIX})
endif()
# warn when using a deprecated package
if(NOT "" STREQUAL "")
set(_msg "WARNING: package 'test' is deprecated")
# append custom deprecation text if available
if(NOT "" STREQUAL "TRUE")
set(_msg "${_msg} ()")
endif()
message("${_msg}")
endif()
# flag project as catkin-based to distinguish if a find_package()-ed project is a catkin project
set(test_FOUND_CATKIN_PROJECT TRUE)
if(NOT "include " STREQUAL " ")
set(test_INCLUDE_DIRS "")
set(_include_dirs "include")
if(NOT " " STREQUAL " ")
set(_report "Check the issue tracker '' and consider creating a ticket if the problem has not been reported yet.")
elseif(NOT " " STREQUAL " ")
set(_report "Check the website '' for information and consider reporting the problem.")
else()
set(_report "Report the problem to the maintainer 'Jiaheng Hong ' and request to fix the problem.")
endif()
foreach(idir ${_include_dirs})
if(IS_ABSOLUTE ${idir} AND IS_DIRECTORY ${idir})
set(include ${idir})
elseif("${idir} " STREQUAL "include ")
get_filename_component(include "${test_DIR}/../../../include" ABSOLUTE)
if(NOT IS_DIRECTORY ${include})
message(FATAL_ERROR "Project 'test' specifies '${idir}' as an include dir, which is not found. It does not exist in '${include}'. ${_report}")
endif()
else()
message(FATAL_ERROR "Project 'test' specifies '${idir}' as an include dir, which is not found. It does neither exist as an absolute directory nor in '/data/install_buzzard_isolated/${idir}'. ${_report}")
endif()
_list_append_unique(test_INCLUDE_DIRS ${include})
endforeach()
endif()
set(libraries "")
foreach(library ${libraries})
# keep build configuration keywords, target names and absolute libraries as-is
if("${library}" MATCHES "^(debug|optimized|general)$")
list(APPEND test_LIBRARIES ${library})
elseif(TARGET ${library})
list(APPEND test_LIBRARIES ${library})
elseif(IS_ABSOLUTE ${library})
list(APPEND test_LIBRARIES ${library})
else()
set(lib_path "")
set(lib "${library}-NOTFOUND")
# since the path where the library is found is returned we have to iterate over the paths manually
foreach(path /data/install_buzzard_isolated/lib;/data/install_buzzard_isolated/lib)
find_library(lib ${library}
PATHS ${path}
NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
if(lib)
set(lib_path ${path})
break()
endif()
endforeach()
if(lib)
_list_append_unique(test_LIBRARY_DIRS ${lib_path})
list(APPEND test_LIBRARIES ${lib})
else()
# as a fall back for non-catkin libraries try to search globally
find_library(lib ${library})
if(NOT lib)
message(FATAL_ERROR "Project '${PROJECT_NAME}' tried to find library '${library}'. The library is neither a target nor built/installed properly. Did you compile project 'test'? Did you find_package() it before the subdirectory containing its code is included?")
endif()
list(APPEND test_LIBRARIES ${lib})
endif()
endif()
endforeach()
set(test_EXPORTED_TARGETS "")
# create dummy targets for exported code generation targets to make life of users easier
foreach(t ${test_EXPORTED_TARGETS})
if(NOT TARGET ${t})
add_custom_target(${t})
endif()
endforeach()
set(depends "glog_vendor;grpc_vendor")
foreach(depend ${depends})
string(REPLACE " " ";" depend_list ${depend})
# the package name of the dependency must be kept in a unique variable so that it is not overwritten in recursive calls
list(GET depend_list 0 test_dep)
list(LENGTH depend_list count)
if(${count} EQUAL 1)
# simple dependencies must only be find_package()-ed once
if(NOT ${test_dep}_FOUND)
find_package(${test_dep} REQUIRED NO_MODULE)
endif()
else()
# dependencies with components must be find_package()-ed again
list(REMOVE_AT depend_list 0)
find_package(${test_dep} REQUIRED NO_MODULE ${depend_list})
endif()
_list_append_unique(test_INCLUDE_DIRS ${${test_dep}_INCLUDE_DIRS})
# merge build configuration keywords with library names to correctly deduplicate
_pack_libraries_with_build_configuration(test_LIBRARIES ${test_LIBRARIES})
_pack_libraries_with_build_configuration(_libraries ${${test_dep}_LIBRARIES})
_list_append_deduplicate(test_LIBRARIES ${_libraries})
# undo build configuration keyword merging after deduplication
_unpack_libraries_with_build_configuration(test_LIBRARIES ${test_LIBRARIES})
_list_append_unique(test_LIBRARY_DIRS ${${test_dep}_LIBRARY_DIRS})
list(APPEND test_EXPORTED_TARGETS ${${test_dep}_EXPORTED_TARGETS})
endforeach()
set(pkg_cfg_extras "")
foreach(extra ${pkg_cfg_extras})
if(NOT IS_ABSOLUTE ${extra})
set(extra ${test_DIR}/${extra})
endif()
include(${extra})
endforeach()
xxConfig-version.cmake文件:
# generated from catkin/cmake/template/pkgConfig-version.cmake.in
set(PACKAGE_VERSION "1.0.0")
set(PACKAGE_VERSION_EXACT False)
set(PACKAGE_VERSION_COMPATIBLE False)
if("${PACKAGE_FIND_VERSION}" VERSION_EQUAL "${PACKAGE_VERSION}")
set(PACKAGE_VERSION_EXACT True)
set(PACKAGE_VERSION_COMPATIBLE True)
endif()
if("${PACKAGE_FIND_VERSION}" VERSION_LESS "${PACKAGE_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE True)
endif()
注意:This function must be called before declaring any targets with add_library()
or add_executable()
上面遗漏了一个选项没有说明,CFG-EXTRAS,这里补充说明。
待写。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)