从此篇开始,我们即将告别入门阶段,走上进阶之路,还是要照常hold住信心啊!作为进阶篇的开始,我们今天轻松点,只动眼不动手,周末了稍稍躺平一下。
rosdep是啥
还记得之前在构建一个包之前都被建议要检查下依赖项吗,rosdep install --from-paths src -y --ignore-src,就是这串有点脸熟的命令,这里面就出现了rosdep,那这个rosdep到底是个啥呢?其实大家应该也能七七八八猜个大谱,但更官方更专业的叫法,它被称之为依赖关系管理实用程序(dependency management utility),又被称之为元包管理器(meta-package manager),与通常意义上的软件包管理器可不一样(比如Ubuntu里面的apt就是一种软件包管理器),它只负责根据它对系统和依赖关系了解到的规则去寻找适合目标平台安装的包,真正的安装动作则是由真正的软件包管理器来实施。它不但能够应用于单个的包还能应用到包的目录上(如工作空间)。
虽然rosdep里面带了个ros,貌似专为ROS定制的,但是呢,它居然还能被用到非ROS的软件工程项目上,具体用法后面如果有幸碰到类似的案例,我们再来研究,这不是当前阶段的重点。
package.xml的一点内容
package.xml是rosdep查找依赖关系的文件,在我们构建包的过程中,该文件里面的依赖列表是需要我们手动添加的,而且可千万别发生遗漏或不正确的情况,否则种瓜得瓜种豆得豆,不但导致构建时出现问题,即使侥幸构建成功但别人也用不了你的包,更别提包的发布了。
package.xml文件中的依赖项通常被称为"rosdep-keys"。这些依赖项由包的创建者手动填充到package.xml文件中,并且应该是所需的任何非内置库和包的详尽列表。
下面列举出一些比较有代表性的标签(详细说明请参考REP-149):
<depend>
此标签内的依赖项是那些在包构建时和运行时都要用的,对于C++包来说,最保险的做法就是添加上这个标签(有钱没钱回家过年),而对于纯python写的包,因为python是解释型语言,没有编译构建这一步骤,所以只在运行时需要用到依赖,可以替代为<exec_depend>这个标签。
<build_depend>
如果运行时用不到依赖,只在编译构建时需要一个特别的依赖项,那我们就可以用这个标签。那么这样此包的二进制安装时就不需要再安装这个特别的包了(因为在构建时已经被包含编译进去了)。
然而,如果你的包导出了一个包含来自某个依赖项的头文件的头文件,这可能会引发一个问题。在这种情况下,我们还需要一个<build_export_depend>(构建导出依赖)标签来解决问题。
<build_export_depend>
如果你导出一个头文件,该头文件又包含了来自一个依赖项的头文件,那么其他<build_depend>(构建依赖)于你的包的包也将需要这个头文件。这主要适用于头文件和CMake配置文件。你所导出的库所引用的库包应该通常指定<depend>(依赖),因为它们也需要在执行时使用(是不是有点绕,后面具体使用时再加体会即可,此时不理解没关系)。
<exec_depend>
此标记声明了运行包时所需的共享库、可执行文件、Python模块、启动脚本和其他文件的依赖项。
<test_depend>
此标记声明仅测试所需的依赖项。此处的依赖项不应与<build_depend>、<exec_depend>或<dependent>指定的键重复。
rosdep如何工作
rosdep 会在其路径中或针对特定包检查 package.xml
文件,并查找其中存储的 rosdep 键。然后,这些键会与中央索引进行交叉引用,以在各种包管理器中找到适当的 ROS 包或软件库。最后,一旦找到这些包,它们就会被安装并准备就绪!
rosdep 的工作原理是通过将中央索引检索到本地机器上,这样它每次运行时就不必访问网络(在 Debian/Ubuntu 上,其配置存储在 /etc/ros/rosdep/sources.list.d/20-default.list
)。
这个中央索引被称为 rosdistro,可以在线找到。我们将在下一节更详细地探讨它。
简而言之,rosdep 是一个工具,它使用中央索引(rosdistro)来解析和安装 ROS 包的依赖项。它通过读取 package.xml
文件中的 rosdep 键,然后查找和安装相应的依赖包,使 ROS 开发者能够更方便地管理和构建他们的项目。通过将索引存储在本地,rosdep 可以在不依赖网络连接的情况下运行,提高了工作效率。
我如何知道我该添加什么键(依赖项)到package.xml
这个问题连官方原文的作者都报以慈祥的微笑(●'◡'●),官方是这么回答的:
- 如果你想在你的包中依赖一个基于ROS的包,并且这个包已经被发布到ROS生态系统中,例如nav2_bt_navigator,你可以直接使用该包的名称。你可以在https://github.com/ros/rosdistro(添加到浏览器收藏夹啊)上找到所有已发布的ROS包的列表的<distro>/distribution.yaml文件(例如humble/distribution.yaml)。
- 如果你想依赖一个非ROS的包,通常被称为"系统依赖",你需要找到特定库的键。一般来说,有两个文件值得关注:
rosdep/base.yaml包含了apt系统的依赖项
rosdep/python.yaml包含了python的依赖项
举个例子,方便理解。假设一个包依赖于doxygen,因为它是一个专注于高质量文档的优秀软件。我们会在rosdep/base.yaml中搜索doxygen,并找到以下内容:
doxygen:
arch: [doxygen]
debian: [doxygen]
fedora: [doxygen]
freebsd: [doxygen]
gentoo: [app-doc/doxygen]
macports: [doxygen]
nixos: [doxygen]
openembedded: [doxygen@meta-oe]
opensuse: [doxygen]
rhel: [doxygen]
ubuntu: [doxygen]
这意味着我们的rosdep键是doxygen。当使用这个键时,rosdep会根据不同的操作系统的包管理器将其解析为相应的安装名称。这样,无论是在Ubuntu、Debian还是其他支持的操作系统上,rosdep都能确保使用正确的包名来安装doxygen。这使得开发者可以更方便地跨平台管理依赖关系,而无需关心每个系统具体的包名差异。
如果rosdistro里面找不到我的库呢
那就手动添加到里面,贡献新键的方法大家可以看看,众人拾柴火焰高,这就是开源的魅力。如果出于某种原因,这些索引可能没有公开提供,则可以派生一个rosdistro并维护备用索引以供使用。
如何使用rosdep工具
安装rosdep
$apt-get install python3-rosdep
但是有点需要注意,在Debian/Ubuntu还有一个差不多名字的包,叫python3-rosdep2,如果我们之前已经安装了这个rosdep2,记得在安装rosdep之前将rosdep2卸载掉。
如果是在ROS之外的环境使用rosdep,那么像上面那种常规的方法安装的ROS包是不能使用的,我们得从https://pypi.org直接安装:
$pip install rosdep
rosdep的操作
行文至此,我们已经对rosdep、package.xml、rosdistro有了一点了解,我们现在可以开始介绍下rosdep的使用了。如果是第一次运行rosdep,我们得先初始化并刷新(保证有同步更新最新的内容索引)一下:
$sudo rosdep init
$rosdep update
还记得之前的一篇文章有介绍如何解决rosdep失败的问题吗(主要是国内网络环境问题引起)?如果你们在执行上面的命令出现超时等失败情况,记得翻回那篇文章参考解决一下。
最后我们就可以通过rosdep install命令安装针对很多包的所有依赖项了(在工作空间上执行)。如果我们需要针对工作空间根路径下的src路径进行依赖项检查安装(这里面一般包含了该工作空间所包含包的所有依赖项),我们一个经典的语法如下:
$rosdep install --from-paths src -y --ignore-src
从 src
目录中的 ROS 包中查找依赖(但忽略源代码中的依赖),然后自动安装这些依赖。
- --from-path src :依赖关系查找路径,指定检查package.xml文件以解析其键的路径(src);
- -y:依赖安装过程中的所有提示选项都选择yes,省的手动去选择确认的麻烦;
- --ignore-src:忽略安装依赖项,这个参数告诉
rosdep
在查找依赖时忽略src
目录中的源代码。这通常用于避免因为源代码的更改而引入不必要的依赖。
还有其他关于rosdep的用法,我们可以通过rosdep -h进行查找,也可以参考ROS packages --- rosdep 0.22.2 documentation这个文档学习到更多的操作。
今天内容虽然有些概念还是不那么清晰,但是随着后面学习的深入,接触的多了,便会柳暗花明啦。
本篇完。