llama.cpp 在 Snapdragon Linux 设备上的实战:Docker 交叉编译、build.py 自动化部署与多 NPU 推理
本文围绕 Snapdragon Linux 设备构建指南 展开,完整覆盖 llama.cpp 在骁龙 Linux 平台上的交叉编译、部署与运行流程。读完本篇,你将掌握:使用 ghcr.io/snapdragon-toolchain/arm64-linux:v0.7 工具链容器完成 arm64 目标编译、通过 build.py / run.py 脚本实现"一条命令构建并推送到设备、一条命令远程执行推理"的完整工作流,以及多 NPU(Hexagon HTP)张量切分推理的配置方法。
为什么需要交叉编译:Snapdragon 的后端与工具链
在 Snapdragon 平台上,llama.cpp 支持三类后端:CPU、Adreno GPU(OpenCL)和 Hexagon NPU(即 HTP 设备)。其中 Hexagon NPU 在 -ngl 等卸载参数的语义上被当作"GPU"设备处理。骁龙 Linux 设备(例如某些开发板、车载或嵌入式形态的 x86 之外的 arm64 主机)与桌面 Linux x86 主机构型不同,因此需要在开发机上交叉编译出 arm64 目标代码,并生成 NPU 端需要的骨架库(skel)。
交叉编译由 Snapdragon Linux Docker 工具链镜像完成,镜像中内置了 Hexagon SDK、交叉编译器与 CMake。Snapdragon 系列的构建文档入口见 Snapdragon 总览,Windows 平台的对应流程见 windows.md。
Linux 工具链镜像为:
ghcr.io/snapdragon-toolchain/arm64-linux:v0.7
统一构建脚本 scripts/snapdragon/build.py 会自动拉取该容器并编排整个编译过程,你只需确保宿主机上 Docker 处于运行状态。
从 ggml/src/ggml-hexagon/CMakeLists.txt 可以看出,Hexagon 后端构建依赖 HEXAGON_SDK_ROOT 与 HEXAGON_TOOLS_ROOT 两个路径,工具链镜像正是把这两个变量预置好的环境,这也是"手动裸机交叉编译很难走通、而容器方式开箱即用"的根本原因。
构建方式一:build.py 脚本(推荐)
scripts/snapdragon/build.py 是最省心的构建方式。它自动完成四件事:复制 CMake presets、启动正确的编译容器、构建并安装库与工具、可选地推送到目标设备。
构建并部署到 Linux 目标(--target 接受 lnx 或 linux 别名,后面跟 user@host):
$ ./scripts/snapdragon/build.py --target lnx:user@host --push
build.py 关键参数
| 参数 | 说明 |
|---|---|
--target |
目标与部署定义。Linux 可写 lnx:user@host、linux:user@host 或 ubuntu:user@host(见 build.py 的 parse_target) |
--push |
构建完成后通过 SSH/SCP 把产物推送到设备,Linux 默认落到 ~/llama.cpp |
--target-dir |
指定设备端部署目录(Linux 默认 ~/llama.cpp) |
--build-dir |
构建目录名,默认 build-<target>(如 build-lnx) |
--install-dir |
安装目录名,默认 pkg-<target> |
-j / --jobs |
并行编译任务数,默认取宿主机 CPU 核数 |
--preset |
覆盖使用的 CMake preset |
--debug |
使用 -debug 而非 -release preset,产物目录带 -dbg 后缀 |
--no-docker |
不在容器中执行,而是在宿主机原生编译 |
--toolchain-version |
工具链镜像 tag,默认 v0.7 |
--toolchain-url |
镜像仓库地址,默认 ghcr.io/snapdragon-toolchain |
脚本内部做了什么
结合 build.py 源码,脚本的实际行为是:
- 同步 preset 文件:把 docs/backend/snapdragon/CMakeUserPresets.json 复制到仓库根目录(若 docs 版本更新,会先备份旧文件为
.bak再覆盖); - 选择 preset:Linux 目标默认使用
arm64-linux-snapdragon-release(--debug时切换为-debug); - 启动 Docker 容器:等价于执行
docker run --rm --volume <repo>:/workspace --workdir /workspace --platform linux/amd64 [-u uid:gid] <镜像> bash -c "cmake --preset ... && cmake --build ... -j N && cmake --install ...",即把仓库挂载为/workspace后依次完成 configure、build、install 三步; - 推送部署:
--push时通过ssh清理远端~/llama.cpp下过期文件,再用scp -r把pkg-*/llama.cpp目录整体拷贝到设备(见 build.py 的部署段)。
arm64-linux-snapdragon preset 的配置细节
CMakeUserPresets.json 中 Linux preset 的关键缓存变量:
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "cmake/arm64-linux-clang.cmake",
"CMAKE_C_FLAGS": "-march=armv8.2a+fp16+dotprod -fvectorize -fno-finite-math-only -flto -D_GNU_SOURCE",
"CMAKE_PREFIX_PATH": "$env{OPENCL_SDK_ROOT}",
"HEXAGON_SDK_ROOT": "$env{HEXAGON_SDK_ROOT}",
"HEXAGON_TOOLS_ROOT": "$env{HEXAGON_TOOLS_ROOT}",
"PREBUILT_LIB_DIR": "linux_aarch64",
"GGML_OPENMP": "OFF",
"GGML_LLAMAFILE": "OFF",
"GGML_OPENCL": "OFF",
"GGML_HEXAGON": "ON",
"LLAMA_OPENSSL": "OFF"
}
几个值得注意的点:
- 交叉工具链文件为 cmake/arm64-linux-clang.cmake;
- 与 Android preset 不同,Linux preset 中
GGML_OPENCL为OFF、GGML_HEXAGON为ON——即 Snapdragon Linux 路径默认只启用 Hexagon NPU 后端(加上 CPU),不编 Adreno OpenCL 后端; PREBUILT_LIB_DIR设为linux_aarch64,对应工具链中该平台的 Hexagon 预编译库;- 该 preset 标记为
hidden,对外暴露的是继承它的arm64-linux-snapdragon-release与arm64-linux-snapdragon-debug两个 preset。
构建方式二:手动 CMake 构建
如果不使用脚本,也可以手动进入交叉编译容器执行 CMake 命令:
# 手动启动交叉编译容器:
~/src/llama.cpp$ docker run -it --rm -u $(id -u):$(id -g) --volume $(pwd):/workspace --platform linux/amd64 ghcr.io/snapdragon-toolchain/arm64-linux:v0.7
# 在容器内,使用 preset 构建项目:
[d]/workspace> cp docs/backend/snapdragon/CMakeUserPresets.json .
[d]/workspace> cmake --preset arm64-linux-snapdragon-release -B build-snapdragon
[d]/workspace> cmake --build build-snapdragon -j $(nproc)
生成可安装的"包"只需执行 cmake --install 再打包:
[d]/workspace> cmake --install build-snapdragon --prefix pkg-linux
[d]/workspace> zip -r pkg-linux.zip pkg-linux
安装阶段会输出各库的安装路径,其中 lib/libggml-hexagon.so 是宿主侧 Hexagon 后端运行时,lib/libggml-htp-v73.so、libggml-htp-v75.so、libggml-htp-v79.so、libggml-htp-v81.so 是面向不同 Hexagon 架构版本的 NPU 端 skel 库(可对照 ggml/src/ggml-hexagon 目录结构)。运行时设备会按实际 NPU 架构选择加载对应的 v7x 库。
部署安装:传输产物、配置环境变量、下载模型
将 pkg-linux.zip 传到目标 Linux 设备后解压,并设置两个必需的环境变量:
$ unzip pkg-linux.zip
$ cd pkg-linux
$ export LD_LIBRARY_PATH=./lib
$ export ADSP_LIBRARY_PATH=./lib
其中 LD_LIBRARY_PATH 让动态链接器找到 lib/ 下的 ggml 系列库;ADSP_LIBRARY_PATH 是 Hexagon 平台加载 DSP 侧 skel 库(libggml-htp-vXX.so)所依赖的路径,二者缺一不可。
随后在设备上准备好模型文件,例如:
$ wget https://huggingface.co/bartowski/Llama-3.2-3B-Instruct-GGUF/resolve/main/Llama-3.2-3B-Instruct-Q4_0.gguf
运行推理:run.py 统一入口
本地运行
在 Snapdragon Linux 设备上可以直接用 scripts/snapdragon/run.py 运行:
$ ./scripts/snapdragon/run.py --devices HTP0 -- llama-cli -m Llama-3.2-3B-Instruct-Q4_0.gguf -ngl 99 -p "what is the most popular cookie in the world?"
从开发机远程运行
通过 --target 指定 SSH 目标,即可从宿主机远程驱动设备上的推理:
$ ./scripts/snapdragon/run.py --target lnx:user@host --devices HTP0 -- llama-cli -m Llama-3.2-3B-Instruct-Q4_0.gguf -ngl 99 -p "what is the most popular cookie in the world?"
run.py 对 Linux 目标的执行逻辑在 run.py 的 SSH 分支:它把 cd ~/llama.cpp && ulimit -c unlimited && LD_LIBRARY_PATH=./lib ADSP_LIBRARY_PATH=./lib <其余环境变量> <命令> 组装成一条远端 shell 命令,经 ssh 下发执行。ulimit -c unlimited 用于在 NPU 崩溃时生成 core dump 便于调试。
多 NPU 系统的张量切分示例
在多 NPU 机器上,可以指定两个 HTP 做张量切分(tensor split)的远程补全:
$ ./scripts/snapdragon/run.py --target ubuntu:maxk@192.168.1.87 --device HTP0:0,HTP1:0 -- llama-completion -m models/gemma-2b-it-Q4_0.gguf -f prompts/sample_prompt_1024.txt --jinja -st --split-mode tensor --ctx-size 8192
从 run.py 的设备解析逻辑 看,--devices/--device 参数中凡是含 htp(不区分大小写)的条目会被收集进 GGML_HEXAGON_DEVICES,其余条目则映射为 GGML_OPENCL_DEVICE,从而实现 NPU 与 GPU 的混合指定。上例最终在远端实际执行的是:
+ ssh maxk@192.168.1.87 "cd ~/llama.cpp && ulimit -c unlimited && LD_LIBRARY_PATH=./lib ADSP_LIBRARY_PATH=./lib GGML_HEXAGON_DEVICES=HTP0:0,HTP1:0 GGML_HEXAGON_OPPOLL=1 ./bin/llama-completion -m models/gemma-2b-it-Q4_0.gguf -f prompts/sample_prompt_1024.txt --jinja -st --split-mode tensor --ctx-size 8192 -v -n 16 --device HTP0:0,HTP1:0 -ngl 99 --ubatch-size 1024 -fa on -t 6"
对比这条展开命令可以发现 run.py 自动注入的默认项(见 run.py 的默认参数注入):
-ngl 99:把尽可能多的层卸载到 NPU(用户未显式指定时注入);--ubatch-size 1024:加大微批处理尺寸;-fa on:默认开启 Flash Attention;-t 6:默认 6 个 CPU 线程;GGML_HEXAGON_OPPOLL=1:--hex-oppoll的默认值,开启 NPU opbatch 完成轮询。
直接在设备上运行二进制
不用脚本包装时,也可以直接进入包目录执行二进制(前提是 LD_LIBRARY_PATH 已设置好):
$ ./bin/llama-cli -m Llama-3.2-3B-Instruct-Q4_0.gguf --device HTP0 -ngl 99 -p "what is the most popular cookie in the world?"
run.py 中 Hexagon 相关参数的补充说明
除设备选择外,run.py 还暴露了一组 --hex-* 参数,全部映射为 GGML_HEXAGON_* 环境变量,便于在 Linux 设备上做 NPU 调优与诊断:
| 参数 | 对应环境变量 | 作用 |
|---|---|---|
--hex-verbose |
GGML_HEXAGON_VERBOSE |
后端算子级详细日志 |
--hex-profile |
GGML_HEXAGON_PROFILE |
NPU 算子性能剖析 |
--hex-nhvx |
GGML_HEXAGON_NHVX |
HVX 单元数量 |
--hex-nhmx |
GGML_HEXAGON_NHMX |
HMX 单元数量,0 表示不启用 HMX |
--hex-opbatch |
GGML_HEXAGON_OPBATCH |
单次 HTP 执行打包的最大算子数 |
--hex-oppoll |
GGML_HEXAGON_OPPOLL |
是否轮询 opbatch 完成,默认 1 |
--hex-opfilter |
GGML_HEXAGON_OPFILTER |
正则过滤哪些算子卸载到 NPU(可让个别算子回退 CPU) |
--hex-arch |
GGML_HEXAGON_ARCH |
覆盖目标 Hexagon 架构版本(v73/v75/v79/v81 等) |
更多环境变量的完整说明(含 GGML_HEXAGON_DEVICES 的 HTP<phys>:<virt> 会话格式、GGML_HEXAGON_PROFILE 的分级剖析、opfilter 回退策略等),可参考 Snapdragon 总览文档的 Environment variables 一节。
小结
针对 Snapdragon Linux 设备,llama.cpp 的完整链路是:arm64-linux:v0.7 工具链容器交叉编译(preset arm64-linux-snapdragon-release,启用 GGML_HEXAGON)→ cmake --install 生成 pkg-linux 包 → SCP/手动传输到设备并设置 LD_LIBRARY_PATH 与 ADSP_LIBRARY_PATH → 用 run.py 以 HTP0(或多 NPU HTP0:0,HTP1:0 张量切分)驱动 llama-cli / llama-completion 推理。build.py --push 与 run.py --target 两个脚本把这条链路压缩成了两条命令,是当前仓库中面向骁龙 Linux 平台最推荐的工程化实践。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00