前言
最近公司升級交叉編譯環境,需要配置的目標機為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的交叉編譯全家桶!