第一章:开发环境搭建——工欲善其事,必先利其器

各位同学,咱们直接进入正题。做嵌入式开发,尤其是AMD平台,环境搭建是第一道坎。我见过太多人卡在这一步,折腾一整天连个Hello World都跑不起来。今天我就把15年踩过的坑,一次性给你讲透。

1.1 安装AMD官方工具链:ROCm与AOCC

先说ROCm。这是AMD的GPU计算平台,说白了就是让CPU和GPU能好好配合干活。我刚开始接触时,总觉得这东西跟CUDA差不多,结果发现坑不少。

核心要点:ROCm目前只支持Ubuntu 20.04/22.04 LTS,别用其他发行版折腾自己。

安装步骤其实不复杂,但顺序很重要。我个人习惯这样来:

  1. 添加AMD官方源
    wget -q -O - https://repo.radeon.com/rocm/rocm.gpg.key | sudo apt-key add -
    echo 'deb [arch=amd64] https://repo.radeon.com/rocm/apt/5.7.1 ubuntu main' | sudo tee /etc/apt/sources.list.d/rocm.list
  2. 安装核心组件
    sudo apt update
    sudo apt install rocm-dev rocm-libs rocm-dkms
  3. 验证安装
    rocminfo | grep "Name:"

嗯,这里要注意。安装完成后一定要重启,不然驱动加载不上。我曾经有一次急着演示,没重启就跑了测试程序,结果GPU死活不认,场面一度很尴尬。

再说AOCC——AMD的优化编译器。这东西比GCC快不少,尤其对Zen架构有专门优化。安装更简单:

wget https://developer.amd.com/wordpress/media/files/aocc-compiler-4.2.0.tar
tar -xf aocc-compiler-4.2.0.tar
cd aocc-compiler-4.2.0
./install.sh

我的小技巧:装完后把AOCC的bin目录加到PATH里,我一般写在~/.bashrc最后一行:export PATH=/opt/AMD/aocc-compiler-4.2.0/bin:$PATH

1.2 配置交叉编译环境

交叉编译,说白了就是在你的电脑上编译出能在目标板上跑的程序。为什么需要这个?因为嵌入式设备的性能通常不够跑编译器。

我建议用sysroot方式来管理。这样最干净,不会污染你的系统库。

具体步骤:

  1. 下载AMD提供的交叉编译工具链
    wget https://developer.amd.com/wordpress/media/files/x86_64-amd-linux-gnu.tar.xz
    tar -xf x86_64-amd-linux-gnu.tar.xz -C /opt/
  2. 设置环境变量
    export CROSS_COMPILE=/opt/x86_64-amd-linux-gnu/bin/x86_64-amd-linux-gnu-
    export CC=${CROSS_COMPILE}gcc
    export CXX=${CROSS_COMPILE}g++
  3. 测试编译
    $CC -o hello hello.c
    file hello
    # 输出应该显示:ELF 64-bit LSB executable, x86-64, version 1 (SYSV)

避坑指南:我曾经犯过一个低级错误——忘了设置--sysroot参数。结果编译出来的程序在目标板上运行时,报了一堆"cannot find shared library"的错误。折腾了两天才发现是库路径没指对。

正确的做法是加上这个参数:

export CFLAGS="--sysroot=/opt/x86_64-amd-linux-gnu/sysroot"

1.3 搭建QEMU模拟器调试环境

QEMU这东西,说白了就是个软件模拟器。你可以在上面跑完整的AMD系统,不用真硬件。我刚开始做开发时,团队就一块开发板,大家排队用。后来我搭了QEMU环境,效率直接翻倍。

安装QEMU:

sudo apt install qemu-system-x86 qemu-utils

然后你需要一个内核镜像和根文件系统。我一般用Buildroot来生成:

git clone https://github.com/buildroot/buildroot.git
cd buildroot
make qemu_x86_64_defconfig
make

编译大概要20分钟,正好可以去喝杯咖啡。完成后你会得到:

  • output/images/bzImage — 内核
  • output/images/rootfs.ext2 — 根文件系统

启动QEMU的命令:

qemu-system-x86_64 \
  -kernel output/images/bzImage \
  -drive file=output/images/rootfs.ext2,format=raw \
  -append "root=/dev/sda console=ttyS0" \
  -nographic

调试模式启动:加上-s -S参数,QEMU会等待GDB连接。这样你就可以在宿主机上用GDB调试目标程序了。

我个人习惯这样调试:

# 终端1:启动QEMU并等待调试器
qemu-system-x86_64 -kernel bzImage -drive file=rootfs.ext2,format=raw -append "root=/dev/sda" -s -S

# 终端2:连接GDB
gdb-multiarch vmlinux
(gdb) target remote :1234
(gdb) break start_kernel
(gdb) continue

你看,这样就能在代码里设断点、单步执行了。比用printk打印日志高效得多。

1.4 验证环境是否正常

环境搭好了,总得跑个程序验证一下。我习惯写个简单的矩阵乘法:

// test_roc.cpp
#include <hip/hip_runtime.h>
#include <iostream>

__global__ void vec_add(float* a, float* b, float* c, int n) {
    int idx = threadIdx.x + blockIdx.x * blockDim.x;
    if (idx < n) c[idx] = a[idx] + b[idx];
}

int main() {
    int n = 1024;
    float *a, *b, *c;
    hipMalloc(&a, n * sizeof(float));
    hipMalloc(&b, n * sizeof(float));
    hipMalloc(&c, n * sizeof(float));
    
    vec_add<<<1, 256>>>(a, b, c, n);
    hipDeviceSynchronize();
    
    std::cout << "ROCm works!" << std::endl;
    return 0;
}

用AOCC编译:

/opt/AMD/aocc-compiler-4.2.0/bin/clang++ -o test_roc test_roc.cpp -I/opt/rocm/include -L/opt/rocm/lib -lhip_hcc

检查结果:如果输出"ROCm works!",说明环境没问题。如果报错,八成是库路径没配好。检查一下LD_LIBRARY_PATH有没有包含/opt/rocm/lib

好了,环境搭建就这些。你想想看,其实步骤不多,但每一步都有讲究。我当年刚入行时,光装ROCm就折腾了一周,现在你照着这个流程,半天应该就能搞定。

下一章我们讲调试工具的使用,到时候我会分享一些实战中遇到的奇葩问题。嗯,先到这吧,有问题随时找我。