前言
最近公司升级交叉编译环境,需要配置的目标机为Nvidia AGX xavier with Jetpack 4.5这里记录一些坑。
正文
总体概要
所谓cross-compile其实就是在amd64(下称host)上生成arm64(下称target)的binary
明确一点,所有与编译相关的工具都是运行在本地,比如cmake比如aarch64-gcc比如tclsh版本为host
而对应的rootfs可以简单理解为库,所有编译过程中需要的.so .a都会在rootfs里面找,版本为target
至于cuda这种比较特殊的交叉编译,就需要host_bin(例如nvcc)+ target_lib(例如libcublas.so)进行配合
莫慌,上述这些Nvidia SDK manager会提供下载。
前期准备
从SDKmanager下载到的sample rootfs里面不含任何nv三方库,需要自己安装deb
通过SDK manager可以下载对应型号的rootfs+三方库以及CUDA交叉环境,其中的json文件将指导每个deb的具体安装
host这边安装好cmake, autoconf, automake, libtool, m4 and tclsh这些编译相关工具,准备好与target一致的aarch64-gcc-7.5
仿真环境
使用qemu对target环境进行模拟,对应命令sudo apt install qemu-user-static
注意不要装错了
至此host已经具备执行target bin的能力,直接chroot
将报错failed to run command ‘/bin/bash’: No such file or directory
复制对应的文件sudo cp /usr/bin/qemu-aarch64-static <rootfs>/usr/bin/
有了这两步就可以chroot到target rootfs进行操作sudo chroot <rootfs> /bin/bash
成功后使用uname -a
检查架构是否为aarch64
装依赖库
理论上我们可以通过chroot + qemu的方式进入target rootfs进行包管理apt install ...
但这样比较费时费力
更糟糕的是,现阶段SDK manager刷机后半段会通过ssh访问Xavier安装一些在线内容,如此一来本地deb安装可能不全
我个人建议使用sample_rootfs作为底包并从刷好的Xavier迁移/usr /lib /opt /etc进行覆盖升级
完成后更新整个rootfs的符号链接为相对路径symlinks -cr /
此举可避免编译过程中rootfs中的文件链接到host 效果如下:
更新前<rootfs>/etc/resolv.conf -> /run/resolvconf/resolv.conf
更新后<rootfs>/etc/resolv.conf -> ../run/resolvconf/resolv.conf
打包技巧
可以使用fakeroot
替代sudo
实现对rootfs的去权限打包,解压也不再需要root权限。
交叉编译
这里提供两种思路:
- 编写交叉编译专用CMakeists参考cmake-toolchains(7)
- 编写通用CMakeLists通过传入外置
-DCMAKE_TOOLCHAIN_FILE=xxx.cmake
参数控制platform类型,使得多种架构复用同一套native CMakeLists变为可能
个人倾向第二种,典型的Linux交叉编译toolchain.cmake
包含如下信息:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_SYSROOT /home/devel/rasp-pi-rootfs)
set(CMAKE_STAGING_PREFIX /home/devel/stage)
set(tools /home/devel/gcc-4.7-linaro-rpi-gnueabihf)
set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
奇技淫巧
对于编译过程中可能遇到的三方依赖,尽量使用cmake官方find_package
提供的Modules如FindCUDA.cmake
官方版本经过迭代能很好的适应三方库因更新引入的文件结构变化,不用自己费心处理
而对于某些没有官方实现的package则需要自己编写,例如FindTensorRT.cmake
其中就有不小的坑
原先trt5中nvonnxparser_runtime
在trt7中已经弃用,比较简单的方法是强制版本>=7
若希望保留向前兼容能力,需要通过正则表达式提取NvInfer.h
或NvInferVersion.h
中的版本号进行区别处理
展望
本质上只要是ubuntu-18.04-aarch64的平台可以复用一套basic rootfs节省硬盘空间
特化项目所需lib与gcc全部外置,通过cmake参数传入搜索路径,实现模块化管理!
最后,期待有朝一日Nvidia放出一套类似MDC的交叉编译全家桶!