1. 环境准备:搭建Apollo编译的基础舞台
第一次接触Apollo源码编译时,环境配置往往是最大的拦路虎。我清楚地记得去年在团队新配的戴尔工作站上折腾了两天才让编译通过,期间经历了显卡驱动冲突、Bazel版本不兼容等典型问题。下面就把这些经验教训转化为可复用的操作指南。
硬件方面,建议至少准备16GB内存和100GB可用磁盘空间。虽然官方文档说8GB内存也能跑,但实际编译planning模块时内存峰值经常突破12GB。显卡不是必须的,但如果要启用GPU加速(比如做感知模块开发),建议使用NVIDIA Turing架构以上的显卡(如RTX 20/30系列),对CUDA的兼容性更好。
软件环境的关键在于Docker的配置。这里有个容易踩的坑:很多人直接安装最新版Docker,但其实Apollo对Docker版本有隐性要求。实测发现Docker 20.10.14是最稳定的版本,可以用以下命令安装:
sudo apt-get install docker-ce=5:20.10.14~3-0~ubuntu-focal docker-ce-cli=5:20.10.14~3-0~ubuntu-focal接着要处理显卡驱动这个"老大难"问题。在宿主机上安装驱动时,建议先用ubuntu-drivers devices查看推荐版本,然后使用apt安装而非NVIDIA官网的.run文件。比如我的RTX 3090环境是这样配置的:
sudo apt install nvidia-driver-515 nvidia-utils-515最后是磁盘空间管理的小技巧:把Docker的存储目录挂载到单独的分区。我在/var/lib/docker空间不足时,用以下命令迁移到新硬盘:
sudo systemctl stop docker sudo rsync -aXS /var/lib/docker/. /mnt/new_disk/ sudo mv /var/lib/docker /var/lib/docker.bak sudo ln -s /mnt/new_disk/docker /var/lib/docker2. 源码获取与容器部署
从GitHub克隆源码时,千万别直接用git clone默认分支。Apollo的主分支经常处于不稳定状态,应该切换到稳定版本分支。比如当前6.0.0版本的完整操作流程:
git clone https://github.com/ApolloAuto/apollo.git cd apollo git checkout v6.0.0启动容器时有几个关键参数容易被忽略。-C参数可以指定中国区的软件源加速下载,-g参数在GPU支持不明确时可以强制检测显卡。我常用的完整启动命令是:
bash docker/scripts/dev_start.sh -C -g --shm-size 2G进入容器后有个重要步骤:配置Bazel的并行编译参数。在/apollo/.bazelrc中添加这些配置能显著提升编译速度:
build --jobs=8 build --ram_utilization_factor=80 build --local_cpu_resources=HOST_CPUS*0.8这些数字要根据你的CPU核心数调整。比如16核机器可以设为--jobs=12,保留部分资源给系统其他进程。内存分配比例建议不超过80%,否则容易触发OOM(内存溢出)错误。
3. 编译模式深度解析
Apollo的编译模式组合就像乐高积木,不同组合会产生完全不同的二进制产物。fastbuild模式编译速度最快但生成的代码几乎没有优化,适合快速验证;dbg模式会保留所有调试符号,在GDB调试时特别有用;opt模式则是发布版本的首选。
实际项目中,planning模块的调试我常用这样的组合命令:
bash apollo.sh build_dbg planning --config=cpu这个命令等价于:
bazel build --config=dbg --config=cpu //modules/planning/...当需要发布版本时,GPU加速的优化编译应该这样操作:
bash apollo.sh build_opt_gpu perception这里有个性能对比数据:在RTX 3090环境下,planning模块不同编译模式的耗时差异明显:
| 编译模式 | 耗时(s) | 生成文件大小(MB) |
|---|---|---|
| fastbuild | 328 | 45 |
| dbg | 417 | 178 |
| opt+gpu | 512 | 62 |
4. 模块化编译实战技巧
Apollo 6.0+的模块化编译设计让开发者能精准控制编译范围。但要注意模块间的依赖关系,比如单独编译planning模块前,需要确保cyber模块已经构建完成。我推荐这样的分步编译策略:
# 先编译基础框架 bash apollo.sh build cyber # 再编译依赖项 bash apollo.sh build common third_party # 最后编译目标模块 bash apollo.sh build planning遇到编译失败时,Bazel的缓存机制有时会成为障碍。这时候需要清理特定模块的缓存:
bazel clean --expunge bazel query //modules/planning/... | xargs bazel build对于需要频繁修改的模块,可以启用Bazel的监视模式。这个技巧帮我节省了大量等待时间:
bazel build //modules/planning/... --watch5. 测试验证与性能调优
编译通过只是第一步,真正的考验在于测试验证。Apollo的测试体系分为单元测试和集成测试两个层级。以planning模块为例,完整的测试流程应该是:
# 运行所有单元测试 bash apollo.sh test --config=gpu planning # 执行特定测试用例 bazel test --config=dbg //modules/planning/test:lane_follow_test测试报告中要特别关注这些指标:
- 测试覆盖率(可以通过
--collect_code_coverage参数生成) - 内存泄漏检查(需要编译时加入
--config=asan配置) - 实时性指标(使用
cyber_recorder工具记录时序)
性能调优时,我习惯用Bazel的profile功能生成编译耗时报告:
bazel build //modules/planning/... --profile=planning_profile.log然后用chrome://tracing/工具分析这个日志文件,找出编译瓶颈。常见的问题包括:
- 过多的模板实例化(显示为频繁的clang++调用)
- 头文件依赖混乱(表现为重复预处理)
- 并行度不足(任务队列出现空闲)
6. 常见问题解决方案库
在实际项目部署中,这些问题出现的频率最高:
问题一:第三方依赖下载超时解决方法是在容器内设置代理镜像:
echo "build --repository_cache=/apollo/.bazel-cache" >> /apollo/.bazelrc问题二:GPU编译失败先用这个命令验证CUDA环境:
bazel test //modules/perception/test:cuda_util_test --config=gpu如果失败,检查容器内的CUDA版本是否与宿主机一致:
nvcc --version cat /usr/local/cuda/version.txt问题三:内存不足导致编译中断临时解决方案是限制Bazel的内存使用:
bash apollo.sh build --local_ram_resources=8192长期方案则是优化模块划分,或者增加swap空间:
sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile7. 生产环境部署建议
当需要将编译产物部署到实车环境时,这些经验可能会帮到你:
首先用bazel query分析目标依赖:
bazel query 'deps(//modules/planning:planning_component)' --output graph > planning.dot然后用graphviz工具生成依赖图,剔除不必要的依赖项。发布版本应该使用静态链接:
bazel build //modules/planning:planning_component --config=opt --config=static对于Docker镜像的优化,我总结出这几个关键点:
- 使用多阶段构建减少镜像体积
- 分离编译环境和运行环境
- 对二进制文件进行strip操作
最后提醒一个容易忽视的细节:不同硬件平台的ABI兼容性问题。在x86平台编译的代码部署到ARM架构的车载电脑时,记得添加--config=arm编译选项。