3. 环境搭建:交叉编译工具链、嵌入式Linux系统配置、TensorRT-LLM依赖库安装
3.1 核心原理:为什么不能直接在目标板上编译?
嵌入式设备(如 Jetson Orin、Xavier NX 或自定义 ARM 板卡)的算力、内存和存储资源通常远小于 x86 开发工作站。若直接在目标板上执行 TensorRT-LLM 的完整编译流程,会遇到三个致命瓶颈:CPU 核数少导致编译耗时数小时、内存不足导致 OOM 崩溃、文件系统空间不足以容纳中间产物。因此,业界标准做法是采用交叉编译:在 x86_64 主机上使用目标架构的交叉工具链,生成 ARM64(aarch64)架构的可执行文件与共享库,再通过 SSH/ADB 或 U 盘部署到嵌入式 Linux 系统上运行。
交叉编译的核心在于三套分离的环境:构建环境(x86_64 主机)、目标环境(aarch64 嵌入式 Linux)、sysroot(目标板的根文件系统镜像,包含头文件与预编译库)。TensorRT-LLM 依赖 CUDA、cuDNN、TensorRT 等 NVIDIA 闭源库,这些库必须从 NVIDIA 官网下载对应 aarch64 版本并放入 sysroot,而不能直接使用主机上的 x86_64 版本。
3.2 方法流程:交叉编译工具链与 sysroot 准备
首先确认目标板架构与系统版本。以 Jetson Orin NX 16GB 为例,其 CPU 为 Arm Cortex-A78AE(aarch64),推荐使用 JetPack 5.1.2(对应 Ubuntu 22.04)。主机侧安装交叉工具链:
# 主机 (x86_64 Ubuntu 22.04)
sudo apt update
sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
# 验证版本
aarch64-linux-gnu-g++ --version # 应显示 11.4 或更高
# 创建 sysroot 目录结构
mkdir -p ~/tllm_sysroot/{usr/include,usr/lib/aarch64-linux-gnu,lib}
cd ~/tllm_sysroot
# 从目标板同步系统头文件与基础库(需在目标板上执行 rsync)
# 目标板执行:
# rsync -avz /usr/include/ user@host:~/tllm_sysroot/usr/include/
# rsync -avz /usr/lib/aarch64-linux-gnu/ user@host:~/tllm_sysroot/usr/lib/aarch64-linux-gnu/
# rsync -avz /lib/aarch64-linux-gnu/ user@host:~/tllm_sysroot/lib/
接下来下载 NVIDIA 官方 aarch64 依赖库。注意:不能从 pip 或 apt 直接安装 x86 版本,必须从 NVIDIA 官网 选择 Linux aarch64 的 CUDA Toolkit、cuDNN 和 TensorRT 的 .deb 或 .tar.gz 包。解压后,将 lib 目录下的 .so 文件复制到 sysroot 的 usr/lib/aarch64-linux-gnu/ 下,头文件复制到 usr/include/ 对应位置。
| 依赖库 | 版本要求 | 关键文件 | 放置位置 (sysroot) |
|---|---|---|---|
| CUDA Toolkit | ≥ 12.2 | libcudart.so, libcuda.so | usr/lib/aarch64-linux-gnu/ |
| cuDNN | ≥ 8.9 | libcudnn.so.8 | usr/lib/aarch64-linux-gnu/ |
| TensorRT | ≥ 8.6 | libnvinfer.so, libnvinfer_plugin.so | usr/lib/aarch64-linux-gnu/ |
| OpenMP | 随 GCC 提供 | libgomp.so.1 | usr/lib/aarch64-linux-gnu/ |
3.3 案例:TensorRT-LLM 的 CMake 交叉编译配置
TensorRT-LLM 官方支持交叉编译,但需要显式指定工具链文件。以下是一个经过验证的 toolchain.cmake 示例:
# toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_SYSROOT $ENV{HOME}/tllm_sysroot)
set(CMAKE_FIND_ROOT_PATH $ENV{HOME}/tllm_sysroot)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# 强制使用静态链接 libstdc++ 避免目标板缺库
set(CMAKE_EXE_LINKER_FLAGS "-static-libstdc++ -static-libgcc")
然后执行编译(以 TensorRT-LLM v0.10.0 为例):
cd ~/TensorRT-LLM
mkdir build && cd build
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DTRT_LIB_DIR=$HOME/tllm_sysroot/usr/lib/aarch64-linux-gnu \
-DTRT_INCLUDE_DIR=$HOME/tllm_sysroot/usr/include \
-DCUDNN_LIB_DIR=$HOME/tllm_sysroot/usr/lib/aarch64-linux-gnu \
-DCUDNN_INCLUDE_DIR=$HOME/tllm_sysroot/usr/include \
-DCUDA_TOOLKIT_ROOT_DIR=$HOME/tllm_sysroot/usr/local/cuda
make -j$(nproc) trtllm-build
cannot find -lcuda,说明 CUDA 的 .so 文件未正确放入 sysroot。请检查 libcuda.so 是否为符号链接且指向真实存在的 libcuda.so.1。另外,TensorRT-LLM 部分组件(如 pybind11)需要 Python 头文件,若不需要 Python 绑定,务必添加 -DBUILD_PYTHON_BINDINGS=OFF 以缩短编译时间。
3.4 嵌入式 Linux 系统配置与依赖安装
编译完成后,将产物部署到目标板。目标板需要预先安装以下运行时库(注意是 aarch64 版本):
# 在目标板上执行
sudo apt update
sudo apt install -y libgomp1 libpython3.10 libssl3 libcurl4
# 创建部署目录并拷贝文件(从主机执行)
scp -r ~/TensorRT-LLM/build/lib/*.so user@target:/opt/tensorrt-llm/lib/
scp ~/TensorRT-LLM/build/trtllm-build user@target:/opt/tensorrt-llm/bin/
# 在目标板上设置环境变量
echo 'export LD_LIBRARY_PATH=/opt/tensorrt-llm/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
echo 'export PATH=/opt/tensorrt-llm/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
验证部署是否成功:
# 目标板上执行
ldd /opt/tensorrt-llm/bin/trtllm-build | grep "not found"
# 若无输出,说明所有依赖已满足
file /opt/tensorrt-llm/lib/libtensorrt_llm.so
# 应输出: ELF 64-bit LSB shared object, ARM aarch64
# 运行冒烟测试
trtllm-build --help | head -5
3.5 误区与复盘:交叉编译中的典型陷阱
- 误区一:使用 pip 安装 TensorRT-LLM 的 x86 版本后直接拷贝 .so 到目标板。 这会导致
Exec format error,因为 x86 与 ARM 的 ELF 格式不兼容。复盘:必须从源码交叉编译,或使用 NVIDIA 官方提供的aarch64wheel 包(若有)。 - 误区二:忘记同步 sysroot 中的 libstdc++。 主机 GCC 12 的 libstdc++ 版本高于目标板 GCC 11,导致
GLIBCXX_3.4.30 not found。复盘:在 toolchain.cmake 中增加-static-libstdc++,或同步目标板的 libstdc++.so.6 到 sysroot。 - 误区三:CUDA 库版本不匹配。 TensorRT-LLM 编译时链接 CUDA 12.2,但目标板 JetPack 自带 CUDA 11.4,导致运行时
libcudart.so.12 not found。复盘:务必确认目标板的 CUDA 版本与编译时一致,必要时在目标板安装 CUDA 12.2 的 runfile(仅安装 toolkit,不覆盖驱动)。 - 误区四:忽略 OpenMP 线程数设置。 嵌入式 CPU 核数少,默认线程数可能过高导致上下文切换开销。复盘:在推理脚本中设置
OMP_NUM_THREADS=4(根据实际核数调整),并观察nvidia-smi的 GPU 利用率与 CPU 负载平衡。
CMakeCache.txt 中的关键路径变量,便于回溯。