1.背景
因为需要x86架构的电脑编译项目到arm64架构的域控制器上跑,故需要交叉编译。参考ros2官方的交叉编译进行自己项目的交叉编译尝试。
2.环境
ROS:foxy
系统:ubuntu20.04 focal
架构:x86到arm64
python:3.8.10
docker:25.0.1
3.步骤
1.安装开发工具
sudo apt update && sudo apt install -y \
cmake \
git \
wget \
python3-pip \
qemu-user-static \
g++-aarch64-linux-gnu \
g++-arm-linux-gnueabihf \
pkg-config-aarch64-linux-gnu
python3 -m pip install -U \
vcstool \
colcon-common-extensions
docker安装请自行搜索方法。
2.准备ROS2的系统根(sysroot)
这里有两种方法(只成功了使用预构建好的ros2的方法,建议使用第一种):
2.1 使用预构建好的ROS2
2.1.1 创建目录以及文件修改
mkdir -p ~/cc_ws/src
cd ~/cc_ws/src
git clone https://github.com/ros-tooling/cross_compile.git -b 0.0.1
cd ..
修改~/cc_ws/src/cross_compile/sysroot/Dockerfile_ubuntu_arm64_prebuilt文件中第4行:
# FROM arm64v8/ubuntu:bionic
FROM arm64v8/ubuntu:focal
第28行:
# ENV ROS_DISTRO crystal
ENV ROS_DISTRO foxy
因为是ubuntu20.04上的foxy,所以需要修改。
注意:
如果担心一次安装不完或者半途有可能中断(安装ros可能需要数小时),记得把文件最后一行:
rm -rf /var/lib/apt/lists/*
注释掉,因为如果半途报错这句会直接删除已经下载包的缓存,从头开始。
2.1.2 准备系统根(sysroot)
(当前目录为~/cc_ws)
mkdir qemu-user-static
cp /usr/bin/qemu-*-static qemu-user-static
docker build \
-t arm_ros2:latest \
-f src/cross_compile/sysroot/Dockerfile_ubuntu_arm_prebuilt .
运行刚刚创建的docker,并且将生成的容器导出为tar包后解压:
docker run --name arm_sysroot arm_ros2:latest
docker container export -o sysroot_docker.tar arm_sysroot
mkdir sysroot_docker
tar -C sysroot_docker -xvf sysroot_docker.tar lib usr opt etc
2.2 使用ros2源码
2.2.1 创建目录以及文件修改
mkdir -p ~/cc_ws/ros2_ws/src
cd ~/cc_ws/ros2_ws
wget https://raw.githubusercontent.com
vcs-import src < ros2.repos
git clone https://github.com/ros-tooling/cross_compile.git \
-b 0.0.1 src/ros2/cross_compile
cd ..
修改~/cc_ws/src/cross_compile/sysroot/Dockerfile_ubuntu_arm64文件第5行:
# FROM ${ARM_ARCH}/ubuntu:bionic
FROM ${ARM_ARCH}/ubuntu:focal
在所有pip install命令后面加上-i https://pypi.tuna.tsinghua.edu.cn/simple,并且添加一个安装包rosdepc,最后将所有rosdep命令改为rosdepc命令。
2.2.2 准备系统根(sysroot)
mkdir qemu-user-static
cp /usr/bin/qemu-*-static qemu-user-static
docker build \
-t arm_ros2:latest \
-f ros2_ws/src/ros2/cross_compile/sysroot/Dockerfile_ubuntu_arm .
运行刚刚创建的docker,并且将生成的容器导出为tar包后解压:
docker container export -o sysroot_docker.tar arm_sysroot
mkdir sysroot_docker
tar -C sysroot_docker -xvf sysroot_docker.tar lib usr opt etc
3. 环境变量以及其他准备
需要设置cmake工具链要使用的环境变量:
export TARGET_ARCH=aarch64
export TARGET_TRIPLE=aarch64-linux-gnu
export CC=/usr/bin/$TARGET_TRIPLE-gcc
export CXX=/usr/bin/$TARGET_TRIPLE-g++
export CROSS_COMPILE=/usr/bin/$TARGET_TRIPLE-
export SYSROOT=~/cc_ws/sysroot_docker
export ROOT_PATH=~/ros2_ws
export PYTHON_SOABI=cpython-38-$TARGET_TRIPLE
其中ROOT_PATH为自己需要交叉编译的项目根目录,PYTHON_SOABI改为自己的python版本。
每次切换终端都需要重新输入一遍环境变量,建议写成一个bash脚本,每次切换终端都运行一下。
Poco预构建软件包有一个已知问题,即它在主机系统而不是 SYSROOT上搜索libz和libpcre。作为目前的解决方法,请将这两个库链接到主机的文件系统中。命令如下:
mkdir -p /usr/lib/$TARGET_TRIPLE
ln -s $(pwd)/sysroot_docker/lib/$TARGET_TRIPLE/libz.so.1 \
/usr/lib/$TARGET_TRIPLE/libz.so
ln -s $(pwd)/sysroot_docker/lib/$TARGET_TRIPLE/libpcre.so.3 \
/usr/lib/$TARGET_TRIPLE/libpcre.so
4. 交叉编译
对目标文件系统上的setup.bash安装脚本进行source:
source ~/cc_ws/sysroot_docker/opt/ros/foxy/setup.bash
进入需要交叉编译的项目目录(如~/ros2_ws):
cd ~/ros2_ws
使用制定工具链文件的colcon开始构建:
colcon build \
--merge-install \
--cmake-force-configure \
--cmake-args \
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
-DCMAKE_TOOLCHAIN_FILE="~/cc_ws/src/cross_compile/cmake-toolchains/generic_linux.cmake"
其中-DCMAKE_TOOLCHAIN_FILE必须是绝对路径。
4.其他注意事项
因为项目中使用了一些第三方库,在编译时一直链接不到需要的第三方库,目前解决方案只能是把在arm镜像中安装的第三方库so文件直接放到本地的路径/usr/lib/aarch64-linux-gnu下,以yaml-cpp这个第三方库为例。
在步骤2.1.2中导出镜像为tar包之前先进入这个创建的镜像,在镜像中直接安装需要的第三方库,然后再导出解压。
镜像名字是arm_sysroot
docker exec -it arm_sysroot /bin/bash
进docker以后直接用apt安装第三方库:
apt install libyaml-cpp-dev
把在arm镜像中安装的第三方库so文件直接放到本地:
sudo cp "~/cc_ws/sysroot_docker/usr/lib/aarch64-linux-gnu/libyaml-cpp.so.0.6.2" \
"/usr/lib/aarch64-linux-gnu/"
然后再编译。
参考:https://link.zhihu.com/?target=https%3A//docs.ros.org/en/foxy/Guides/Cross-compilation.html