CMake、Ament 与 Catkin:ROS 构建系统的前世今生
如果你开发过 ROS(机器人操作系统)程序,一定对 CMakeLists.txt、package.xml 以及 catkin_make 或 colcon build 这些名词不陌生。但你真的清楚 CMake 、Ament (ROS 2)和 Catkin(ROS 1)之间的关系吗?它们有什么区别?为什么 ROS 2 要从 Catkin 迁移到 Ament?
本文将为你彻底讲清这三者的定位、联系与区别,帮助你更好地理解 ROS 的构建体系。
一、CMake:通用的构建引擎
CMake 是一个跨平台的开源构建系统生成器。它本身不直接编译代码,而是根据 CMakeLists.txt 生成原生构建工具(如 Makefile、Ninja、Visual Studio 工程)所需的文件,再由这些工具完成实际的编译链接。
CMake 的核心能力
- 检测编译器和系统环境
- 查找依赖库、头文件(
find_package、find_library) - 定义构建目标(可执行文件、静态/动态库)
- 管理编译选项、链接选项
- 支持测试(CTest)、打包(CPack)
适用范围
任何 C/C++ 项目(也支持 Fortran、CUDA 等),以及需要复杂构建配置的 Python 项目(通过 pybind11 等)。CMake 不包含任何机器人领域的概念。
典型用法
bash
mkdir build && cd build
cmake .. # 生成 Makefile
make # 实际编译
二、Catkin:ROS 1 的元构建系统
Catkin 是 ROS 1 官方采用的构建系统,它构建在 CMake 之上,为 ROS 1 包提供了额外的抽象和约定。
Catkin 解决了什么问题?
- 需要从
.msg/.srv文件自动生成代码 - 多个 ROS 包之间复杂的依赖关系
- 工作空间(workspace)环境变量自动设置(
setup.bash)
Catkin 的组成
package.xml:包的元信息(名称、版本、依赖)CMakeLists.txt:其中调用find_package(catkin REQUIRED ...)和catkin_package()- 构建工具:
catkin_make(官方简单工具)或catkin build(更强大的catkin_tools)
Catkin 典型用法
bash
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws
catkin_make # 一次性构建所有包
catkin_make --only-pkg-with-deps my_pkg # 只构建某个包
Catkin 的 CMakeLists.txt 片段
cmake
cmake_minimum_required(VERSION 2.8.3)
project(my_ros1_pkg)
find_package(catkin REQUIRED COMPONENTS roscpp std_msgs)
catkin_package(
INCLUDE_DIRS include
LIBRARIES ${PROJECT_NAME}
CATKIN_DEPENDS roscpp std_msgs
)
add_executable(my_node src/my_node.cpp)
target_link_libraries(my_node ${catkin_LIBRARIES})
三、Ament:ROS 2 的元构建系统
Ament 是 ROS 2 中取代 Catkin 的元构建系统。同样基于 CMake,但设计上更加现代化、模块化。
Ament 相比 Catkin 的改进
- 完全隔离的构建 :不再有
devel空间,所有产物直接安装到install空间,避免交叉污染。 - 一等 Python 支持 :提供
ament_python构建类型,原生支持纯 Python 包。 - 更清晰的依赖管理 :
ament_target_dependencies自动处理 include 路径、库、编译定义。 - 更模块化 :
ament_cmake由多个小组件(ament_cmake_core、ament_cmake_export_*等)组成,按需使用。 - 与 colcon 深度集成 :
colcon build统一构建 C++ 和 Python 包。
Ament 典型用法
bash
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
colcon build # 构建所有包
colcon build --packages-select my_pkg # 只构建指定包
Ament 的 CMakeLists.txt 片段
cmake
cmake_minimum_required(VERSION 3.8)
project(my_ros2_pkg)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
ament_target_dependencies(my_node rclcpp std_msgs)
# 生成消息/服务(ROS 2 使用 rosidl)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/MyMsg.msg"
"srv/MySrv.srv"
)
ament_package()
四、三者关系一图以蔽之
text
┌─────────────────────────────────────────────────────────┐
│ CMake │
│ (通用构建系统生成器) │
│ 提供:target, find_package, add_executable ... │
└─────────────────┬───────────────────┬───────────────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ Catkin │ │ Ament │
│ (ROS 1 元构建) │ │ (ROS 2 元构建) │
│ 扩展:catkin_package │ │ 扩展:ament_* 宏 │
│ 工具:catkin_make │ │ 工具:colcon │
└─────────────────────┘ └─────────────────────┘
- CMake 是"引擎",提供底层能力。
- Catkin 和 Ament 是"专用车身套件",基于 CMake 封装出 ROS 领域的高级功能。
五、核心功能对比表
| 功能点 | CMake | Catkin (ROS 1) | Ament (ROS 2) |
|---|---|---|---|
| 适用领域 | 任何 C/C++ 项目 | 仅 ROS 1 包 | 仅 ROS 2 包 |
| 包清单文件 | 无(或自定义) | package.xml |
package.xml |
| 查找 ROS 依赖 | 不支持 | find_package(catkin ...) |
find_package(rclcpp ...) |
| 添加 ROS 依赖 | 手动 target_link... |
${catkin_LIBRARIES} |
ament_target_dependencies |
| 生成消息/服务代码 | 需要手写生成器 | add_message_files + generate_messages |
rosidl_generate_interfaces |
| 环境脚本 | 无 | devel/setup.bash |
install/setup.bash |
| 构建命令 | cmake && make |
catkin_make 或 catkin build |
colcon build |
| 构建空间隔离 | 手动控制 | devel 与 build 混用 |
build + install 完全隔离 |
六、为什么 ROS 2 要从 Catkin 迁移到 Ament?
- 现代 CMake 需求 :Catkin 要求 CMake 2.8.3(2009 年标准),而 Ament 要求 3.8+,可利用现代 CMake 特性(如
target粒度控制、INTERFACE传播)。 - Python 包支持 :Catkin 对 Python 包的处理比较别扭(需要手动编写
setup.py),Ament 则原生支持ament_python构建类型。 - 隔离构建 :Catkin 的
devel空间容易导致环境污染和难以复现的问题;Ament 强制安装到install空间,每个包独立。 - 模块化与可维护性 :Ament 拆分为多个独立的 CMake 子包(如
ament_cmake_export_dependencies),更易于扩展和维护。 - 与 colcon 统一体验 :无论 C++ 还是 Python 包,都用
colcon build构建,开发者体验一致。
七、常见问题速查
Q1:我能在 ROS 2 中直接用 CMake 而不通过 Ament 吗?
技术上可以,但你会失去消息生成、环境脚本自动配置、依赖传播等 ROS 2 生态的关键功能。强烈不建议这么做。
Q2:Catkin 和 Ament 的 CMakeLists.txt 可以互相转换吗?
不能直接转换 ,但迁移思路是:将 catkin_package() 改为 ament_package(),将 find_package(catkin REQUIRED COMPONENTS ...) 拆成多个独立的 find_package,并替换依赖添加方式为 ament_target_dependencies。
Q3:Colcon 只能构建 Ament 包吗?
colcon 是构建工具,支持多种构建器(ament_cmake、ament_python、cmake、python 等)。你甚至可以用 colcon 构建非 ROS 的纯 CMake 包。
Q4:学习 ROS 构建系统,我应该重点掌握什么?
- 底层理解:CMake 的核心概念(目标、属性、查找包)。
- ROS 层面 :熟悉
package.xml的写法,以及对应的构建宏(catkin_*或ament_*)。 - 构建工具 :会用
catkin_make/colcon build以及常用选项(--symlink-install、--packages-select)。
八、总结
| 系统 | 本质 | 一句话总结 |
|---|---|---|
| CMake | 通用构建引擎 | 它什么都不懂,但什么都能造。 |
| Catkin | ROS 1 的 CMake 扩展 | 为 ROS 1 定制的"老爷车套件",功勋卓著但略显陈旧。 |
| Ament | ROS 2 的 CMake 扩展 | 为 ROS 2 全新设计的"现代套件",更干净、更灵活、更 Python 友好。 |