clion ros srv include CMakeList 的来龙去脉

版权声明:本文为博主夏日辉的原创文章,未经博主允许不得转载。 https://blog.csdn.net/shanpenghui/article/details/89955879

在开发ros的server时候,参考ros教程http://wiki.ros.org/ROS/Tutorials/WritingServiceClient%28c%2B%2B%29
客户端的源码文件中,存在:

#include "beginner_tutorials/AddTwoInts.h"

刚开始觉得很奇怪,实际上include头文件不存在,为什么可以放在这里,而且可以编译通过呢?

其实官方教程中以及说明了一些端倪:

beginner_tutorials/AddTwoInts.h is the header file generated from the srv file that we created earlier.

就是说这个头文件是由srv文件生成的!而srv文件是什么?在这个例子中,AddTwoInts.srv的文件内容不过4行:

int64 a
int64 b
---
int64 sum

其实这个要从服务文件定义说起,服务文件的描述分成2个部分:请求和响应,被"—"符号分隔开。
真实原因是.msg/.srv/.action文件在使用之前都需要一个特殊的预处理编译步骤。下面说明的就是这些宏的概念,以及如何让它正常工作的步骤。
这些宏的关键是生成特定于编程语言的文件,以便可以使用所选编程语言中的消息,服务和操作。构建系统将使用所有可用的生成器(例如gencpp,genpy,genlisp等)生成绑定。
在CMakeList中,这三个宏分别提供了3个消息句柄:

add_message_files

add_service_files

add_action_files

然后,必须在调用生成的宏之后调用这些宏:

 generate_messages()

注意,这里需要区别顺序!!
这些宏必须在catkin_package()宏之前,以便生成正常工作。

 find_package(catkin REQUIRED COMPONENTS ...)
 add_message_files(...)
 add_service_files(...)
 add_action_files(...)
 generate_messages(...)
 catkin_package(...)
 ...

而catkin_package()宏必须对message_runtime具有CATKIN_DEPENDS依赖项。

catkin_package(
 ...
 CATKIN_DEPENDS message_runtime ...
 ...)

而且必须将find_package()用于包messagesegeneration,可以单独使用,也可以作为catkin的一个组件使用:

find_package(catkin REQUIRED COMPONENTS message_generation)

而这个时候,也需要修改package.xml,因为需要添加运行时的依赖message_runtime。如果这个依赖是从其他包传递过来的就可以不用改,但大多数时候保险起见还是改一下吧。
最后一步分3种情况:

  1. 如果只有一个目标(甚至可以传递)依赖于需要构建msg/srv/action的其他目标,则需要在目标catkin_EXPORTED_TARGETS上添加显式依赖项,以便它们按照正确的顺序构建。除非你自己的package不包含任何ros部分,否则就必须添加该显式依赖项。当然,如果不添加的话,程序也不会自动添加。
add_dependencies(some_target ${catkin_EXPORTED_TARGETS})
  1. 如果你有一个构建msg和/或srv的package,以及使用它们的可执行文件,必须在自动生成的消息目标上创建一个显式的依赖,以便它们能以正确的顺序编译。
add_dependencies(some_target ${${PROJECT_NAME}_EXPORTED_TARGETS})
  1. 如果你的package满足以上2个条件,你必须同时添加两个依赖。
add_dependencies(some_target ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

综上所述,一个完整的CMakeList如下:

  # 获取pkg编译依赖的信息
  find_package(catkin REQUIRED
    COMPONENTS message_generation std_msgs sensor_msgs)

  # 声明需要编译的msg文件
  add_message_files(FILES
    MyMessage1.msg
    MyMessage2.msg
  )

  # 声明需要编译的srv文件
  add_service_files(FILES
    MyService.srv
  )

  # 实际上生成特定语言的消息和服务文件
  generate_messages(DEPENDENCIES std_msgs sensor_msgs)

  # 声明catkin包运行时依赖
  catkin_package(
   CATKIN_DEPENDS message_runtime std_msgs sensor_msgs
  )

  # 定义可执行文件的源代码
  add_executable(message_program src/main.cpp)
  add_dependencies(message_program ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
  # 或者
  add_dependencies(message_program {PROJECT_NAME}_generate_messages_cpp)

  # 定义不使用这个package中任何消息/服务的其他任意可执行文件
  add_executable(does_not_use_local_messages_program src/main.cpp)
  add_dependencies(does_not_use_local_messages_program ${catkin_EXPORTED_TARGETS})
  # 或者
  add_dependencies(message_program {PROJECT_NAME}_generate_messages_cpp)

其中,要说明的是catkin_EXPORTED_TARGETS和之间的主要区别在于${PROJECT_NAME}_EXPORTED_TARGETS前者包含所有构建依赖项的导出目标(即:消息,服务,操作生成目标dynamic_reconfig等),而后者包含仅当前包的目标。

最后,在实际开发过程中,假如遇到srv include头文件不存在无法编译的情况,找到你当前工作空间中的devel文件夹下的setup.bash:

source <you workspace path>/devel/setup.bash

然后在该终端里面运行clion就可以啦

. <clion installed path>/clion.sh

当然,因为是动态生成的,如果照搬代码肯定会提示beginner_tutorial错误,这是因为这个名称是由CMakeList里面的工程名字生成的,所以在开发过程中,需要把头文件的路径换成#include “(project_name/include_name)”,以及相关类名都要换成project_name。

如果有其他问题欢迎小伙伴们一起探讨。

猜你喜欢

转载自blog.csdn.net/shanpenghui/article/details/89955879