在 x86_64 的 EndeavourOS 上临时编译和验证 arm64/aarch64 的 ROS 1 工程时,直接维护一套实体 Ubuntu 20.04 ARM 环境比较麻烦。这里使用 Podman + Distrobox + qemu-user-static,在本机运行 Ubuntu 20.04 arm64 容器,再安装 ROS Noetic 和 GCC 13,最后把结果提交成 localhost/noetic:aarch64 镜像,方便重复创建开发容器。
这套流程延续了我之前用 Distrobox 搭 ROS Melodic 的思路,相关背景可以看这篇:https://www.helywin.com/posts/20260605124741/。本文把 aarch64、Ubuntu 20.04、ROS Noetic、华为云 ubuntu-ports、GCC 13 PPA 和 qemu binfmt 的注意点合在一起,按完整过程记录。
当前完成状态:
- 容器名:
noetic-aarch64 - 容器 home:
~/distrobox-homes/noetic-aarch64 - 本地镜像:
localhost/noetic:aarch64 - 基础镜像:
localhost/ubuntu:20.04-arm64-huaweicloud - 架构:
aarch64/arm64 - ROS:
ros-noetic-desktop-full - 默认编译器:
gcc/g++13.1.0
镜像源原则:
- Ubuntu apt 使用华为云
ubuntu-ports - ROS apt 使用华为云 ROS 镜像
- GCC 13 使用 Ubuntu Toolchain PPA;focal arm64 官方源没有
gcc-13 - 包管理只用
apt,不在安装流程里运行rosdep
一、宿主机准备
1.1 安装 Podman、Distrobox 和 qemu
sudo pacman -S --needed podman distrobox
sudo pacman -S --needed qemu-user-static qemu-user-static-binfmt验证:
podman --version
distrobox --version
cat /proc/sys/fs/binfmt_misc/qemu-aarch641.2 修复 aarch64 setuid 支持
如果 aarch64 容器内执行 sudo 报 effective uid 相关错误,需要把 qemu aarch64 binfmt flags 调整为 FPC:
sudo tee /etc/binfmt.d/qemu-aarch64-static.conf << 'EOF'
:qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64-static:FPC
EOF
sudo systemctl restart systemd-binfmt.service验证 flags 应包含 C:
cat /proc/sys/fs/binfmt_misc/qemu-aarch64
# flags: POCF二、准备 Ubuntu 20.04 arm64 基础镜像
如果已经存在 localhost/ubuntu:20.04-arm64-huaweicloud,可以跳过本节。
mkdir -p ~/distrobox-homes/images
curl -L --retry 3 --continue-at - \
-o ~/distrobox-homes/images/focal-server-cloudimg-arm64-root.tar.xz \
https://mirrors.huaweicloud.com/ubuntu-cloud-images/focal/current/focal-server-cloudimg-arm64-root.tar.xz
podman import --arch arm64 --os linux \
--change 'CMD ["/bin/bash"]' \
--change 'ENV LANG=C.UTF-8' \
~/distrobox-homes/images/focal-server-cloudimg-arm64-root.tar.xz \
localhost/ubuntu:20.04-arm64配置华为云 apt 源并提交基础镜像:
podman rm -f ubuntu2004-aarch64-seed 2>/dev/null || true
podman run --name ubuntu2004-aarch64-seed \
--platform linux/arm64 \
localhost/ubuntu:20.04-arm64 \
/bin/bash -lc '
set -euo pipefail
cat > /etc/apt/sources.list << "EOF"
deb https://mirrors.huaweicloud.com/ubuntu-ports/ focal main restricted universe multiverse
deb https://mirrors.huaweicloud.com/ubuntu-ports/ focal-updates main restricted universe multiverse
deb https://mirrors.huaweicloud.com/ubuntu-ports/ focal-backports main restricted universe multiverse
deb https://mirrors.huaweicloud.com/ubuntu-ports/ focal-security main restricted universe multiverse
EOF
cat > /etc/apt/apt.conf.d/99huaweicloud-direct << "EOF"
Acquire::http::Proxy::mirrors.huaweicloud.com "DIRECT";
Acquire::https::Proxy::mirrors.huaweicloud.com "DIRECT";
EOF
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
apt-utils bash-completion build-essential ca-certificates curl git gnupg \
iproute2 iputils-ping less locales lsb-release passwd procps \
software-properties-common sudo tzdata vim-tiny wget xz-utils
apt-get clean
rm -rf /var/lib/apt/lists/*
'
podman commit \
--change 'CMD ["/bin/bash"]' \
--change 'ENV LANG=C.UTF-8' \
ubuntu2004-aarch64-seed \
localhost/ubuntu:20.04-arm64-huaweicloud
podman rm ubuntu2004-aarch64-seed三、构建 Noetic aarch64 镜像
podman rm -f noetic-aarch64-seed 2>/dev/null || true
podman run --name noetic-aarch64-seed \
--platform linux/arm64 \
localhost/ubuntu:20.04-arm64-huaweicloud \
/bin/bash -lc '
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
cat > /etc/apt/sources.list << "EOF"
deb https://mirrors.huaweicloud.com/ubuntu-ports/ focal main restricted universe multiverse
deb https://mirrors.huaweicloud.com/ubuntu-ports/ focal-updates main restricted universe multiverse
deb https://mirrors.huaweicloud.com/ubuntu-ports/ focal-backports main restricted universe multiverse
deb https://mirrors.huaweicloud.com/ubuntu-ports/ focal-security main restricted universe multiverse
EOF
cat > /etc/apt/apt.conf.d/99huaweicloud-direct << "EOF"
Acquire::http::Proxy::mirrors.huaweicloud.com "DIRECT";
Acquire::https::Proxy::mirrors.huaweicloud.com "DIRECT";
EOF
apt-get update
apt-get install -y ca-certificates curl gnupg lsb-release
install -d -m 0755 /usr/share/keyrings
curl -fsSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc \
| gpg --dearmor -o /usr/share/keyrings/ros-archive-keyring.gpg
cat > /etc/apt/sources.list.d/ros-latest.list << "EOF"
deb [signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] https://mirrors.huaweicloud.com/ros/ubuntu/ focal main
EOF
gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys \
C8EC952E2A0E1FBDC5090F6A2C277A0A352154E5 \
60C317803A41BA51845E371A1E9377A2BA9EF27F
gpg --batch --export \
C8EC952E2A0E1FBDC5090F6A2C277A0A352154E5 \
60C317803A41BA51845E371A1E9377A2BA9EF27F \
| gpg --dearmor -o /usr/share/keyrings/ubuntu-toolchain-r-test.gpg
rm -rf /root/.gnupg
cat > /etc/apt/sources.list.d/ubuntu-toolchain-r-test.list << "EOF"
deb [signed-by=/usr/share/keyrings/ubuntu-toolchain-r-test.gpg] https://ppa.launchpadcontent.net/ubuntu-toolchain-r/test/ubuntu focal main
EOF
apt-get update
apt-get install -y \
curl gnupg lsb-release software-properties-common \
git build-essential cmake pkg-config \
python3-rosdep python3-rosinstall python3-rosinstall-generator \
python3-wstool python3-vcstool python3-catkin-tools \
mesa-utils \
gcc-13 g++-13 \
ros-noetic-desktop-full
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 130
update-alternatives --set gcc /usr/bin/gcc-13
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 90
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 130
update-alternatives --set g++ /usr/bin/g++-13
grep -qxF "source /opt/ros/noetic/setup.bash" /etc/bash.bashrc \
|| echo "source /opt/ros/noetic/setup.bash" >> /etc/bash.bashrc
cat > /etc/profile.d/ros-noetic.sh << "EOF"
[ -f /opt/ros/noetic/setup.bash ] && . /opt/ros/noetic/setup.bash
EOF
apt-get clean
rm -rf /var/lib/apt/lists/*
'如果手头已有 aarch64 的 host-spawn 二进制,可以在提交前预置进去:
podman cp /path/to/host-spawn-aarch64 noetic-aarch64-seed:/usr/bin/host-spawn提交为带架构标签的镜像:
podman commit \
--change 'CMD ["/bin/bash"]' \
--change 'ENV LANG=C.UTF-8' \
noetic-aarch64-seed \
localhost/noetic:aarch64
podman rm noetic-aarch64-seed验证镜像架构:
podman image inspect localhost/noetic:aarch64 \
--format '{{.Architecture}} {{.Os}} {{.Id}} {{.Size}}'四、创建 Distrobox 容器
mkdir -p ~/distrobox-homes/noetic-aarch64
distrobox create \
--image localhost/noetic:aarch64 \
--name noetic-aarch64 \
--home ~/distrobox-homes/noetic-aarch64 \
--platform linux/arm64 \
--yes首次进入会安装 Distrobox 基础整合包,aarch64 用户态模拟下会比原生容器慢:
distrobox enter noetic-aarch64首次进入后,把默认 shell 固定为 bash,并把 ROS 环境写入 bash 启动文件:
sudo usermod -s /bin/bash "$USER"
touch "$HOME/.bash_profile" "$HOME/.bashrc"
grep -qxF "source ~/.bashrc" "$HOME/.bash_profile" \
|| printf '\nsource ~/.bashrc\n' >> "$HOME/.bash_profile"
grep -qxF "source /opt/ros/noetic/setup.bash" "$HOME/.bashrc" \
|| printf '\nsource /opt/ros/noetic/setup.bash\n' >> "$HOME/.bashrc"五、验证结果
distrobox enter noetic-aarch64 -- bash -lc '
set -e
echo arch=$(uname -m)
echo dpkg_arch=$(dpkg --print-architecture)
source /opt/ros/noetic/setup.bash
echo ros=$(rosversion -d)
gcc --version | sed -n "1p"
g++ --version | sed -n "1p"
sudo -n true && echo sudo_ok
'当前验证输出:
arch=aarch64
dpkg_arch=arm64
ros=noetic
gcc (Ubuntu 13.1.0-8ubuntu1~20.04.2) 13.1.0
g++ (Ubuntu 13.1.0-8ubuntu1~20.04.2) 13.1.0
sudo_okROS Master 烟测:
distrobox enter noetic-aarch64 -- bash -lc '
set -e
source /opt/ros/noetic/setup.bash
roscore >/tmp/roscore-noetic-smoke.log 2>&1 &
pid=$!
trap "kill $pid 2>/dev/null || true" EXIT
sleep 6
rostopic list
kill $pid 2>/dev/null || true
wait $pid 2>/dev/null || true
trap - EXIT
'预期输出:
/rosout
/rosout_agg六、日常使用
进入容器:
distrobox enter noetic-aarch64宿主机直接执行容器内 ROS 命令:
distrobox enter noetic-aarch64 -- bash -lc 'source /opt/ros/noetic/setup.bash && rosversion -d'创建 catkin 工作空间:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws
catkin_make停止容器:
distrobox stop noetic-aarch64删除容器:
distrobox rm noetic-aarch64