交叉编译

有关交叉编译的背景信息,请参阅 概念文章

本文档为您提供有关如何交叉编译ROS 2软件栈的详细信息,以及提供基于Arm核心的系统的交叉编译示例。

交叉编译工具

使用该工具的说明在 cross_compile package 中。

传统工具说明

注解

只有在使用旧版本(发布版 0.0.1)的交叉编译工具时才按照以下步骤操作。对于其他情况,请参考 cross_compile 包文档。

尽管ROS 2是一个具有多个依赖项的丰富软件堆栈,但它主要使用两种不同类型的软件包:
  • 基于Python的软件,不需要进行交叉编译。

  • 基于CMake的软件,提供了进行交叉编译的机制。

此外,ROS 2 软件栈使用 Colcon 构建,它提供了一种机制,可以将参数传递给用于构建 ROS 2 发行版中每个包/库的单独构建的 CMake 实例。

在本地构建 ROS 2 时,开发人员需要在编译 ROS 2 发行版中的包之前下载所有的依赖项(例如 Python 和其他库)。在交叉编译时,也需要相同的方法。开发人员必须首先拥有目标系统的文件系统,并已安装所有的依赖项。

本文档的后续部分详细说明了使用 cmake-toolchainsCMAKE_SYSROOT 功能进行 ROS 2 交叉编译的方法。

CMake 工具链文件

CMake工具链文件是用于配置CMake进行交叉编译的文件,它定义了变量。基本条目如下:

  • CMAKE_SYSTEM_NAME:目标平台,例如``linux``

  • CMAKE_SYSTEM_PROCESSOR:目标架构,例如``aarch64``或``arm``

  • CMAKE_SYSROOT:目标文件系统的路径

  • CMAKE_C_COMPILER:C交叉编译器,例如``aarch64-linux-gnu-gcc``

  • CMAKE_CXX_COMPILER:C++交叉编译器,例如``aarch64-linux-gnu-g++``

  • CMAKE_FIND_ROOT_PATH``find_*``命令用来查找文件系统的替代路径

在进行ROS 2交叉编译时,需要设置以下选项:

  • CMAKE_FIND_ROOT_PATH``find_*``命令使用的替代路径,用于指定ROS 2 ``/install``文件夹的路径

  • CMAKE_FIND_ROOT_PATH_MODE_*:程序、包、库和包含文件的搜索策略,通常有:``NEVER``(在主机文件系统上查找)、``ONLY``(在sysroot上查找)和``BOTH``(在sysroot和主机文件系统上都查找)

  • PYTHON_SOABI:由ROS 2生成的Python库的索引名称,例如``cpython-36m-aarch64-linux-gnu``

  • THREADS_PTHREAD_ARG "0" CACHE STRING "Result from TRY_RUN" FORCE:将``TRY_RUN``命令的结果强制为0(成功),因为二进制文件无法在主机系统上运行。

将工具链文件提供给CMake时,使用``-DCMAKE_TOOLCHAIN_FILE=path/to/file``参数。这还将把``CMAKE_CROSSCOMPILING``变量设置为``true``,软件构建时可以使用该变量。

对于ROS 2来说,``CMAKE_SYSROOT``非常重要,因为软件包需要许多依赖项(例如python、openssl、opencv、poco、eigen3等)。将``CMAKE_SYSROOT``设置为安装了所有依赖项的目标文件系统,将允许CMake在交叉编译过程中找到它们。

注解

您可以在CMake的 文档 页面上找到更多信息。

在下载ROS 2源代码时,存储库`ros-tooling/cross_compile/cmake-toolchains <https://github.com/ros-tooling/cross_compile>`__中提供了一个通用的工具链文件,可以单独下载。有关如何使用它的更多示例,请参阅`Cross-compiling examples for Arm`_部分。

目标文件系统

如前所述,ROS 2需要不同的库文件来进行交叉编译。

获取文件系统有多种方式:
  • 下载预构建的映像

  • 在目标设备上安装依赖项并导出文件系统(例如使用sshfs)

  • 使用qemu + docker(或chroot)在主机上生成文件系统。

注解

您可以在接下来的`Cross-compiling examples for Arm`_部分找到有关如何使用Docker + qemu的信息。

构建过程

构建过程类似于本地编译,唯一的区别是给 Colcon 添加了一个额外的参数来指定 toolchain-file

colcon build --merge-install \
    --cmake-force-configure \
    --cmake-args \
        -DCMAKE_TOOLCHAIN_FILE="<path_to_toolchain/toolchainfile.cmake>"

toolchain-file 提供给 CMake 有关 交叉编译器目标文件系统 的信息。Colcon 将在 ROS 2 的每个软件包上使用给定的 toolchain-file 来调用 CMake。

为 Arm 进行交叉编译示例

下载 ROS 2 源代码 后,您可以通过 git clone https://github.com/ros-tooling/cross_compile.git -b 0.0.1 src/ros2/cross_compile 将交叉编译资产添加到工作空间。这些是关于如何为 Arm 内核进行交叉编译的可行示例。

支持以下目标:
  • Ubuntu-arm64:适用于任何基于ARMv8-A的系统。

  • Ubuntu-armhf:适用于任何现代基于ARMv7-A的系统。

以下是主要步骤:
  • 安装开发工具

  • 下载 ROS 2 源代码

  • 下载 ROS 2 交叉编译资产

  • 准备 sysroot

  • 交叉编译ROS 2软件栈

下面的章节详细解释了每个步骤。如果需要快速设置,请参阅`Automated Cross-compilation`_。

注解

这些步骤在Ubuntu 18.04(Bionic)上进行了测试

1. 安装开发工具

这个步骤与本地构建类似。不同之处在于一些库和工具不需要,因为它们将在sysroot中。需要以下软件包:

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

注解

您可以使用pip安装vcstool和colcon-common-extensions。这意味着您不需要添加额外的apt仓库。

Docker用于构建目标环境。请按照官方 文档 进行安装。

2. 下载ROS 2源代码

然后创建一个工作空间并下载ROS 2源代码:

mkdir -p ~/cc_ws/ros2_ws/src
cd ~/cc_ws/ros2_ws
wget https://raw.githubusercontent.com/ros2/ros2/release-latest/ros2.repos
vcs-import src < ros2.repos
git clone https://github.com/ros-tooling/cross_compile.git -b 0.0.1 src/ros2/cross_compile
cd ..

3. 准备 sysroot

使用Docker和qemu构建带有所有ROS 2依赖项的arm Ubuntu镜像:将``qemu-static``二进制文件复制到工作空间。它将用于使用Docker在目标文件系统上安装ROS 2依赖项。

mkdir qemu-user-static
cp /usr/bin/qemu-*-static qemu-user-static

ROS 2的标准:doc:设置 <../Installation/Alternatives/Ubuntu-Development-Setup>`过程在arm docker内运行。这得益于``qemu-static`,它将模拟一个arm机器。使用的基础镜像是来自Docker Hub的Ubuntu Bionic。

docker build -t arm_ros2:latest -f ros2_ws/src/ros2/cross_compile/sysroot/Dockerfile_ubuntu_arm .
docker run --name arm_sysroot arm_ros2:latest

将生成的容器导出为tarball文件并解压缩:

docker container export -o sysroot_docker.tar arm_sysroot
mkdir sysroot_docker
tar -C sysroot_docker -xf sysroot_docker.tar lib usr opt etc
docker rm arm_sysroot

此容器稍后可用作虚拟目标,以运行创建的文件系统和运行演示代码。

4. 构建

设置通用工具链文件使用的变量

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 ROS2_INSTALL_PATH=~/cc_ws/ros2_ws/install
export PYTHON_SOABI=cpython-36m-$TARGET_TRIPLE

以下软件包在交叉编译过程中仍然导致错误(正在调查中),现在必须禁用它们。

touch \
    ros2_ws/src/ros2/rviz/COLCON_IGNORE \
    ros2_ws/src/ros-visualization/COLCON_IGNORE

预构建的 Poco 存在一个已知问题,它在主机系统上搜索 libzlibpcre 而不是 SYSROOT。暂时的解决方法是,请将这两个库链接到主机的文件系统中。

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

然后,使用 colcon 指定工具链文件启动构建:

cd ros2_ws

colcon build --merge-install \
    --cmake-force-configure \
    --cmake-args \
        -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
        -DCMAKE_TOOLCHAIN_FILE="$(pwd)/src/ros2/cross_compile/cmake-toolchains/generic_linux.cmake" \
        -DSECURITY=ON

完成!安装目录和构建目录将包含交叉编译的资源。

自动交叉编译

上述所有步骤也包含在一个Dockerfile中,可以用于自动化/持续集成。

首先,下载Dockerfile并构建镜像:

wget https://raw.githubusercontent.com/ros-tooling/cross_compile/master/Dockerfile_cc_for_arm
docker build -t ros2-crosscompiler:latest - < Dockerfile_cc_for_arm

现在运行镜像:(这将需要一些时间!)

docker run -it --name ros2_cc \
    -v /var/run/docker.sock:/var/run/docker.sock \
    ros2-crosscompiler:latest

..注意:: 使用 -v /var/run/docker.sock 允许我们在 Docker 中使用 Docker。

构建的结果将在 ros2_ws 目录中,可以使用以下命令导出:

docker cp ros2_cc:/root/cc_ws/ros2_ws .

针对预构建的 ROS 2 进行交叉编译

您可以将您的软件包与预构建的 ROS 2 进行交叉编译。步骤与之前的“为 ARM 进行交叉编译示例”_ 部分相似,只需进行以下修改:

不需要下载ROS 2堆栈,只需将您的软件包(在此示例中是ros2 examples)和交叉编译资产填充到您的工作空间中:

mkdir -p ~/cc_ws/ros2_ws/src
cd ~/cc_ws/ros2_ws/src
git clone https://github.com/ros2/examples.git
git clone https://github.com/ros-tooling/cross_compile.git -b 0.0.1
cd ..

按照`3. 准备sysroot`_中所述的方法生成和导出文件系统,但使用提供的``Dockerfile_ubuntu_arm64_prebuilt``。这些``_prebuilt`` Dockerfile将使用:doc:`二进制包 <../Installation/Ubuntu-Install-Debians>`来安装ROS 2,而不是从源代码构建。

修改环境变量``ROS2_INSTALL_PATH``,指向安装目录:

export ROS2_INSTALL_PATH=~/cc_ws/sysroot_docker/opt/ros/crystal

在目标文件系统上调用``setup.bash``脚本:

source $ROS2_INSTALL_PATH/setup.bash

然后,使用``Colcon``指定``toolchain-file``来开始构建:

colcon build \
    --merge-install \
    --cmake-force-configure \
    --cmake-args \
        -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
        -DCMAKE_TOOLCHAIN_FILE="$(pwd)/src/cross_compile/cmake-toolchains/generic_linux.cmake"

在目标设备上运行

将文件系统复制到目标设备上或使用先前构建的 Docker 镜像:

docker run -it --rm -v `pwd`/ros2_ws:/ros2_ws arm_ros2:latest

加载环境:

source /ros2_ws/install/local_setup.bash

运行一些C++或Python示例:

ros2 run demo_nodes_cpp listener &
ros2 run demo_nodes_py talker