3. 开发环境搭建

Cyber RT 是 Apollo 自动驾驶平台中的高性能运行时框架,其数据通道(Channel)与组件(Component)机制都建立在统一的构建与运行环境之上。若环境搭建不完整,后续的通道通信、组件加载、DAG 调度都会出现难以定位的编译或运行错误。本节从源码获取、依赖安装、Bazel 构建、编译运行到最小可运行示例,完整走通一次环境搭建流程,为后续章节的通道与组件开发打下可复现的基础。

一、核心原理:Cyber RT 的构建与运行依赖链

Cyber RT 采用 Bazel 作为主构建系统,源码以 WORKSPACE 为根,通过 BUILD 文件描述目标。其运行依赖可分为四层:系统层(Ubuntu、内核、编译工具链)、第三方库层(Protobuf、gflags、glog、Fast DDS、Boost 等)、Apollo 基础层(cyber、common、proto 等模块)以及应用层(用户组件与通道定义)。理解这条依赖链,才能判断构建失败发生在哪一层。

Cyber RT 的编译产物主要包括动态库(如 libcyber.so)、可执行程序(如 cyber_node、cyber_channel)以及用户组件生成的 .so 插件。运行时通过 DAG 文件与 launch 文件加载组件,通道则通过共享内存或 Fast DDS 完成进程间通信。因此,环境搭建的目标不是“能编译”,而是“能编译且能运行一个最小通道与组件”。

Cyber RT 环境搭建:依赖链与构建运行流程 系统层 Ubuntu 20.04 / 22.04 GCC / G++ / CMake 第三方库层 Protobuf / gflags / glog Fast DDS / Boost / Eigen Apollo 基础层 cyber / common / proto BUILD / WORKSPACE 应用层 用户 Component Channel / DAG / Launch 源码获取 git clone 依赖安装 install_deps.sh Bazel 构建 bazel build 编译运行 cyber_launch 最小示例 Talker/Listener 运行态:通道与组件协作 Talker 组件 Writer / Channel Channel 通道 共享内存 / DDS Listener 组件 Reader / Callback 构建成功 ≠ 运行成功:还需 DAG 配置、通道注册与组件加载

二、方法流程:从源码到可运行的五步操作

以下流程以 Ubuntu 20.04 为例,假设工作目录为 ~/apollo。每一步都建议在干净终端中执行,并保留日志以便排障。

  1. 源码获取:克隆 Apollo 仓库并切换到稳定分支。Cyber RT 位于 cyber/ 目录下。
  2. 依赖安装:执行官方依赖脚本,安装系统包与第三方库。
  3. Bazel 构建:使用 Bazel 编译 cyber 核心库与工具。
  4. 编译运行:通过 cyber_launch 启动 DAG,验证通道与组件是否正常。
  5. 最小示例:编写 Talker/Listener 组件,完成一次端到端通信。
# 1. 源码获取
git clone https://github.com/ApolloAuto/apollo.git
cd apollo
git checkout v9.0.0

# 2. 依赖安装
bash docker/setup_host/install_docker.sh   # 如使用容器
bash apollo.sh build cyber                 # 或使用官方依赖脚本

# 3. Bazel 构建(在 apollo 根目录)
bazel build //cyber:cyber
bazel build //cyber/tools/cyber_monitor:cyber_monitor

# 4. 编译运行
source cyber/setup.bash
cyber_launch start cyber/examples/talker_listener.launch

# 5. 查看通道
cyber_channel list
cyber_channel echo /apollo/test
若使用 Docker 开发,推荐直接使用 Apollo 官方镜像,可跳过大部分系统依赖安装,但需注意容器内外的文件挂载与网络配置。

三、案例/场景:最小可运行示例 Talker/Listener

最小示例是验证环境是否真正可用的关键。它包含三个文件:消息定义 test.proto、发送组件 talker.cc、接收组件 listener.cc,以及一个 DAG 文件。Talker 周期性写入通道,Listener 订阅并打印消息。

// test.proto
syntax = "proto2";
package apollo.cyber.example;
message Test {
  optional string content = 1;
}

// talker.cc 核心逻辑
bool Talker::Init() {
  writer_ = node_->CreateWriter<Test>("/apollo/test");
  return true;
}
bool Talker::Proc() {
  auto msg = std::make_shared<Test>();
  msg->set_content("hello cyber");
  writer_->Write(msg);
  return true;
}

// listener.cc 核心逻辑
bool Listener::Init() {
  reader_ = node_->CreateReader<Test>(
      "/apollo/test",
      [this](const std::shared_ptr<Test>& msg) {
        AINFO << "Received: " << msg->content();
      });
  return true;
}

DAG 文件负责把组件、通道和调度配置绑定在一起。启动后,若 cyber_channel echo /apollo/test 能持续输出 hello cyber,说明源码、依赖、构建、运行四个环节全部打通。

环节 关键命令/文件 成功标志 常见失败原因
源码获取 git clone / checkout cyber 目录存在 网络超时、分支错误
依赖安装 install_deps.sh 无缺失库报错 apt 源、权限、版本冲突
Bazel 构建 bazel build //cyber:cyber BUILD SUCCESSFUL Bazel 版本、缓存污染
编译运行 cyber_launch start 进程常驻、无崩溃 DAG 路径、库路径未 source
最小示例 talker_listener.launch echo 有数据输出 通道名不一致、组件未注册

四、误区与复盘:环境搭建中最容易踩的坑

  • 只编译不运行:Bazel 构建成功不代表运行成功。DAG 文件、通道名、组件注册宏(CYBER_REGISTER_COMPONENT)任一缺失都会导致静默失败。
  • 忽略 setup.bash:Cyber RT 的动态库与工具依赖环境变量,未 source cyber/setup.bash 时会出现找不到 libcyber.so 或 cyber_launch 命令。
  • Bazel 缓存污染:切换分支或修改依赖后,建议 bazel clean --expunge 后重新构建,避免旧缓存导致链接错误。
  • 通道名不一致:Talker 写 /apollo/test,Listener 读 /apollo/test,大小写、斜杠、命名空间必须完全一致。
  • 容器内外路径混淆:Docker 中挂载的源码路径与宿主机不同,DAG 中的相对路径需以容器内工作目录为基准。
若 cyber_channel list 为空,优先检查组件是否真正启动、DAG 是否加载成功,而不是反复重装依赖。多数“环境问题”实际是配置问题。

完成本节后,你应拥有一个可编译、可运行、可观测的 Cyber RT 环境,并能通过 Talker/Listener 示例验证通道通信。后续的组件开发、通道参数配置与 DAG 调度,都将在这个最小闭环之上逐步展开。