ros里Catkin的CMakelists/package.xml

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_export_depend>指定包构需要哪些包用来build;
< package format=“2”> 格式2
< exec_depend>
运行依赖项,指定运行此包中的代码需要哪些包,或针对此包构建库;
< doc_depend>
文档依赖项;
< depend>
指定依赖项为编译、导出、运行需要的依赖,最常用,可以涵盖上面的
< build_depend>,< build_export_depend>和< exec_depend>;

顺序

  1. 所需的 CMake 版本 (cmake_minimum_required)
  2. 包名 (project())
  3. 将普通、缓存或环境变量设置为定值set(CMAKE_CXX_STANDARD 14)
  4. 查找构建所需的其他 CMake/Catkin 包 (find_package())
  5. 启用 Python 模块支持 (catkin_python_setup())
  6. 消息/服务/动作生成器(add_message_files(), add_service_files(), add_action_files())
  7. 调用消息/服务/操作生成 (generate_messages())
  8. 指定包构建信息导出 (catkin_package())
  9. 指定目标编译时需要的头文件路径 include_directories(< dir1 >, < dir2 >, …, < dirN >)
  10. 要构建的库/可执行文件(add_library()/add_executable()/target_link_libraries())
  11. 要构建的测试 (catkin_add_gtest())
  12. 安装规则(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的注释为#号

  1. 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
 			)
  1. 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
)
  1. package.xml文件必须包含一个在message_generation上的编译依赖和一个在message_runtime上的运行时依赖,如果从其他包中传递依赖关系,则这不是必需的。
    <depend>message_generationdepend>
    <depend>std_msgsdepend>
    <depend>geometry_msgsdepend>
    <depend>actionlibdepend>
    <depend>actionlib_msgsdepend>
    <exec_depend>message_runtimeexec_depend>
  1. 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)

参考连接:
来自知乎
来自廖总
优秀的相关文章

你可能感兴趣的:(C++,ROS,c++)