Catkin是基于CMake的编译构建系统,具有以下特点:
Catkin沿用了包管理的传统像 find_package()基础结构,pkg-config扩展了CMake,例如
软件包编译后无需安装就可使用,自动生成find_package()代码,pkg-config文件,解决了多个软件包构建顺序问题
一个Catkin的软件包(package)必须要包括两个文件:
package.xml:
包括了package的描述信息name, description, version, maintainer(s), license,opt. authors, url’s,dependencies, plugins, etc…
CMakeLists.txt:
构建package所需的CMake文件
调用Catkin的函数/宏
解析package.xml
找到其他依赖的catkin软件包
将本软件包添加到环境变量
package.xml
< name>-包的名字
< version>-包的版本号(格式:xxx.xxx.xxx)
< description>-包的内容描述
< maintainer>-维护包的人员的名字
< license>-软件许可证 (例如GPL,BSD,ASL,TODO)
< author> - 原作者名
< url> - 介绍本package的网站链接
< package format=“2”> 格式2
< buildtool_depend>编译构建工具,构建工具依赖关系指定此软件包需要构建自身的构建系统工具。通常只有catkin;
< build_depend>编译依赖项,构建依赖关系指定构建此包所需的包,如果你只使用一些特定的依赖来构建你的包, 而不是在执行时,你可以使用 <build_depend>标签;
< build_export_depend>指定包构需要哪些包用来build;
< package format=“2”> 格式2
< exec_depend>
运行依赖项,指定运行此包中的代码需要哪些包,或针对此包构建库;
< doc_depend>
文档依赖项;
< depend>
指定依赖项为编译、导出、运行需要的依赖,最常用,可以涵盖上面的
< build_depend>,< build_export_depend>和< exec_depend>;
顺序
- 所需的 CMake 版本 (cmake_minimum_required)
- 包名 (project())
- 将普通、缓存或环境变量设置为定值set(CMAKE_CXX_STANDARD 14)
- 查找构建所需的其他 CMake/Catkin 包 (find_package())
- 启用 Python 模块支持 (catkin_python_setup())
- 消息/服务/动作生成器(add_message_files(), add_service_files(), add_action_files())
- 调用消息/服务/操作生成 (generate_messages())
- 指定包构建信息导出 (catkin_package())
- 指定目标编译时需要的头文件路径 include_directories(< dir1 >, < dir2 >, …, < dirN >)
- 要构建的库/可执行文件(add_library()/add_executable()/target_link_libraries())
- 要构建的测试 (catkin_add_gtest())
- 安装规则(install())
cmake_minimum_required(VERSION 3.10)
定义CMake 版本 (固定要写)
每个 catkin CMakeLists.txt 文件都必须以所需的 CMake 版本开头。
Catkin 需要 2.8.3 或更高版本。现在已经有3.10了
cmake_minimum_required(VERSION 3.10)
project()
CMake项目函数指定包的名称(固定要写)。比如我们正在制作一个名为robots_brain的包
project(robot_brain)
在 CMake 中,可以再CMake 脚本中任何需要的地方使用变量${PROJECT_NAME }引用项目名称。
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 14)
通过为CMAKE_CXX_STANDAND赋值,指定要使用 C/C++ 的什么版本;
set(CMAKE_CXX_STANDARD_REQUIRED ON)
通过为CMAKE_CXX_STANDARD_REQUIRED赋值,设置指定的C++编译器版本是
必须的,如果不设置,或者为OFF,则指定版本不可用时,会使用上一版本;
find_package()
编译一个项目,需要使用CMake 的 find_package函数确定依赖的其他CMake包并找到它们,一般情况下至少会有一个catkin依赖:
find_package(catkin REQUIRED)
除此之外,项目依赖的其他软件包,都会自动成为catkin的组件(components)(就CMake而言)。如果将它们指定为组件,而不是在这些包上使用find_package,它将更简单。例如,如果使用包nodelet
find_package(catkin REQUIRED COMPONENTS nodelet)
如果使用 C++ 和 Boost,需要在 Boost 上调用find_package()并指定您使用 Boost 的哪些部分作为组件。
例如,如果想使用 Boost 线程,便这样写:
find_package(Boost REQUIRED COMPONENTS thread)
1. find_package()做了什么?
如果CMake通过 find_package()查找到一个软件包,它就会创建几个CMake环境变量,以提供有关已查找到的软件包的信息。这些环境变量可以在后面的CMake脚本中使用,它们表示软件包导出的头文件所在的位置、源文件所在的位置、软件包依赖的库以及这些库的查找路径,环境变量的名字遵循_,即包名-属性:
_FOUND:当库被查找到时置为true,否则为false
_INCLUDE_DIRS或_INCLUDES:软件包导出的头文件路径
_LIBRARIES或_LIBS:软件包导出的库的路径
_DEFINITIONS:?
2. 为何将Catkin软件包指定为组件?
Catkin软件包(指的是外部软件包等等)严格意义上并不是catkin的组件,而且,CMake的功能组件功能被用于catkin的设计,以节省大量的打字时间。
对于catkin软件包,以catkin的组件的方式 find_package它们是有好处的,因为这个过程以catkin_prefix的形式创建了一组环境变量。例如,在程序中要使用nodelet软件包,推荐查找软件包的方式是:
find_package(catkin REQUIRED COMPONENTS nodelet)
这就意味着nodelet导出的头文件路径、库等都会附加到 catkin_variables上,比如,catkin_INCLUDE_DIRS不仅包含catkin的头文件路径,也包含了nodelet软件包的头文件路径,这在后面会派上用场。
含有message\service\action的
记住要在catkin_package()前面,cmakelists的注释为#号
- find_package()两种写法:
set(ROS_DEPENDENCIES
roscpp std_msgs
behaviortree_cpp_v3
actionlib_msgs
actionlib
message_generation
genmsg
)
//包含行为树库的路径,同时还包含了创建action 和 service 相关的库
find_package(catkin REQUIRED COMPONENTS
${ROS_DEPENDENCIES})
----------------------------------------------------------
find_package(catkin REQUIRED
COMPONENTS
//含有msg的要添加以下包依赖生成信息
message_generation
//以下包属于信息的类型,看需要获取
//http://wiki.ros.org/genmsg?distro=noetic
genmsg
std_msgs
//含有action要添加以下两个包依赖
actionlib_msgs
actionlib
)
- add_xxx_files(),generation_message()添加相关文件
add_message_files(
FILES
BehaviorTree.msg
NodeParameter.msg
NodeStatus.msg
StatusChange.msg
StatusChangeLog.msg
TreeNode.msg
)
add_service_files(
FILES
do_what.srv
)
add_action_files(
DIRECTORY action//找不到路径则详细说明存放的目录
FILES Shoot.action
)
generate_messages(
DEPENDENCIES
std_msgs # Or other packages containing msgs
genmsg//也可
actionlib_msgs
)
- package.xml文件必须包含一个在message_generation上的编译依赖和一个在message_runtime上的运行时依赖,如果从其他包中传递依赖关系,则这不是必需的。
<depend>message_generation</depend>
<depend>std_msgs</depend>
<depend>geometry_msgs</depend>
<depend>actionlib</depend>
<depend>actionlib_msgs</depend>
<exec_depend>message_runtime</exec_depend>
- add_dependencies()
- 如果有一个目标(甚至是过渡性的)依赖于需要建立消息/服务/动作的其他目标,需要在目标catkin_EXPORTED_TARGETS上添加显式依赖项,以使它们按照正确的顺序编译。这种情况几乎总是适用,除非你的软件包真的不使用ROS的任何部分。不幸的是,这种依赖不能自动传播。(some_target是由add_executable()设置的目标的名字)
add_dependencies(some_target ${catkin_EXPORTED_TARGETS})
- 如果有编译消息和/或服务的软件包以及使用这些软件的可执行文件,则需要在自动生成的消息目标上创建明确的依赖关系,以便它们按正确的顺序编译。
add_dependencies(some_target ${${PROJECT_NAME}_EXPORTED_TARGETS})
- 如果都满足,则
add_dependencies(shoot_action_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} ros_behaviortree_demo_gencpp)
catkin_package()
catkin_package()是一个由catkin提供的CMake宏。需要指定特定的catkin信息到编译系统,而这些信息又会被为find_package和pkg-config生成代码和其他CMake文件, 以便其他包可以获取有关此包的信息。
可以说catkin_package()是作用在find_package()中的,它安装 package.xml 文件。
必须在使用add_library()或add_executable()声明任何目标之前调用此函数。该函数有 5 个可选参数:
- INCLUDE_DIRS (list of strings) : CMAKE_CURRENT_SOURCE_DIR - C/C++ 的相对路径。软件包导出的头文件路径(例如cflags)
- LIBRARIES(list of strings) : 从项目导出的库 如果逻辑目标名称与安装的名称不同,则会中断此操作。
- CATKIN_DEPENDS(list of strings) : 当前项目依赖的其他catkin项目,DEPENDS以及CATKIN_DEPEND 告诉 catkin 您的包的哪些依赖项应该传递给find_package
- DEPENDS(list of strings) : 当前项目依赖的非catkin CMake项目,但为该项目所依赖的 CMake 项目列表。由于它们可能不是find_packagable或缺少 pkg-config 文件,因此它们INCLUDE_DIRS和LIBRARIES被直接传递。这要求它之前已经被find_package -ed。(ROS packages有时会需要操作系统提供一些外部函数库,这些函数库就是所谓的“系统依赖项”)
- CFG_EXTRAS(strings) : 附加配置选项
catkin_package( INCLUDE_DIRS include
LIBRARIES ${PROJECT_NAME}
CATKIN_DEPENDS roscpp nodelet
DEPENDS eigen opencv)
catkin_package(
INCLUDE_DIRS include
LIBRARIES ros_behaviortree_demo
CATKIN_DEPENDS ${ROS_DEPENDENCIES}//find_package已经定义的
# DEPENDS system_lib
)
include_directories(< dir1>, < dir2>, …, < dirN>)
include_directories的参数应该是由调用find_package生成的* _INCLUDE_DIRS变量以及需要包含的任何其他目录。如果使用catkin和Boost,include_directories()的调用为:
include_directories(include {Boost_INCLUDE_DIRS} {catkin_INCLUDE_DIRS})
第一个参数“include”表示包中的include/目录也是路径的一部分。
add_library()/add_executable()/target_link_libraries()
- 要指定必须编译的可执行目标,必须使用CMake函数 add_executable()。声明想要的可执行文件的文件名,以此生成此可执行文件所需的源文件列表,如果有多个源文件,用空格区分开。例如:
add_executable(myProgram src/main.cpp src/some_file.cpp src/another_file.cpp)
- 该命令会编译名为 myProgram的可执行文件,它是由后面的三个源文件共同编译生成的。
CMake函数 add_library()指定用于编译的库文件,默认情况下,catkin编译共享库。
add_library({PROJECT_NAME} {${PROJECT_NAME}_SRCS})
- 使用 target_link_libraries()函数指定可执行目标所要链接的库,即告诉CMake当链接此可执行文件时需要链接哪些库(这些库在上面的find_package中定义),通常在调用完add_executable()后被调用。如果出现ros未定义的引用错误,则添加** ${catkin_LIBRARIES}**。
语法:
target_link_libraries(, , , … ) - 例子:
//将 foo与libmoo.so链接起来
add_executable(foo src/foo.cpp)
add_library(moo src/moo.cpp)
target_link_libraries(foo moo)
//else
add_library(rm_common SHARED ${sources} include/rm_common/referee/data.h)
add_executable(test_kalman test/test_kalman_filter.cpp)
target_link_libraries(rm_common ${catkin_LIBRARIES})
target_link_libraries(test_kalman rm_common ${catkin_LIBRARIES})
注意,在大多数使用情况下,没有必要使用link_directories(),因为该信息通过find_package()已经自动提取到了。
install()
编译完成后,目标被放入catkin工作空间下的devel目录。一般希望将目标安装到系统上,以使其他用户使用,或者安装到本地目录来测试系统级别的安装。也就是说,如果希望能够对代码进行make install,就需要明确目标结束的位置。
上述过程可以使用CMake的 install()函数实现,该函数的参数有:
TARGETS:要安装的目标
ARCHIVE DESTINATION:静态库和动态链接库DLL(Windows).lib存根
LIBRARY DESTINATION:非DLL共享库和模块
RUNTIME DESTINATION:可执行目标和DLL(Windows)模式共享库
例子:
install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
除了这些标准的目标,还要安装一些文件到特定的目录下,即一个包含Python绑定的库必须要安装到另外的不同的目录下,这对Python是重要的:
install(TARGETS python_module_library
ARCHIVE DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_PYTHON_DESTINATION})
- 安装Python可执行脚本
Python代码的安装规则有些不同,它不需要使用 add_library()和add_executable()函数来告知CMake哪个文件是目标文件、目标文件是什么类型的。而是使用如下的CMakeList.txt文件:
catkin_install_python(PROGRAMS scripts/myscript
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
如果只是安装了Python的脚本,不提供任何模块的话,就不用创建上文提到的 setup.py文件,也不用调用catkin_python_setup()。
- 安装头文件
头文件必须安装到include目录下,这通常通过安装整个文件夹的文件来完成(可以根据文件名模式进行过滤,并排除SVN子文件夹)。可以通过一下安装规则实现:
install(DIRECTORY include/${PROJECT_NAME}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
PATTERN ".svn" EXCLUDE)
或者如果include目录下的子文件夹无法和软件包名匹配时:
install(DIRECTORY include/
DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION}
PATTERN ".svn" EXCLUDE)
- 安装roslaunch文件或其他源
其他像launchfiles的资源可以安装到 ${CATKIN_PACKAGE_SHARE_DESTINATION}:
install(DIRECTORY launch/
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
PATTERN ".svn" EXCLUDE)
参考连接:
来自知乎
来自廖总
优秀的相关文章
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)