news 2026/9/5 20:54:25

llama.cpp 外部安装与 CMake 包消费验证:详解 examples/test-cmake 的最小可运行示例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
llama.cpp 外部安装与 CMake 包消费验证:详解 examples/test-cmake 的最小可运行示例

llama.cpp 外部安装与 CMake 包消费验证:详解 examples/test-cmake 的最小可运行示例

【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp

examples/test-cmake是 llama.cpp 仓库中一个专门用于手动验证本机安装结果的最小工程:先把 llama.cpp 本身配置、构建并安装到一个本地目录,再把这个目录当作一个标准的 CMake 依赖包,用find_package(llama)的方式编译并链接一个独立的 C++ 程序。读完后,你将掌握如何把一个已安装的 llama.cpp 作为第三方库接入自己的项目,并能通过两个脚本build-install.sh/build.sh快速排查安装配置(install layout、共享库、动态后端加载)是否正确。

这个示例解决什么问题

README 对它的定位非常明确:

This is just for manually testing/developing of a llama.cpp installation to enable troubleshooting issues and exploration. The idea is that this can be used after making changes to llama.cpp installation cmake configuration and then verify it locally.

也就是说,当你修改了 llama.cpp 的安装相关 CMake 配置(例如库安装目录、共享/静态库开关、后端动态加载方式)之后,可以用这个工程在本地“自测”:安装产物是否完整、CMake config 文件是否能被下游find_package正确找到、运行期能否从自定义目录加载动态后端。整个示例由 5 个文件组成:

  • README.md:用法说明;
  • build-install.sh:以“被依赖库”的身份构建并安装 llama.cpp;
  • build.sh:以“下游消费者”的身份配置、编译、运行 test-cmake;
  • CMakeLists.txt:消费者工程的最小 CMake 脚本;
  • test-cmake.cpp:只做版本打印与后端初始化的最小 C++ 程序;
  • .gitignore:忽略installbuildllama-build-install三个本地产物目录。

第一步:构建并安装 llama.cpp 到本地目录

build-install.sh 的完整内容只有三行核心逻辑(清目录、配置、构建、安装):

#!/bin/bash set -e rm -rf llama-build-install install cmake --fresh -S ../../. -B llama-build-install -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=ON \ -DGGML_BACKEND_DL=ON \ -DGGML_CPU_ALL_VARIANTS=ON \ -DLLAMA_TESTS_INSTALL=OFF \ -DCMAKE_INSTALL_PREFIX="${PWD}/install" \ -DGGML_BACKEND_DIR="${PWD}/install/lib/llama.cpp" \ -DGGML_LIB_INSTALL_DIR="${PWD}/install/lib/llama.cpp" \ -DLLAMA_LIB_INSTALL_DIR="${PWD}/install/lib/llama.cpp" \ -DLLAMA_TOOLS_INSTALL=OFF cmake --build llama-build-install --parallel 12 cmake --install llama-build-install

注意它的-S ../../.指向的是 llama.cpp 仓库根目录,即“先把自己安装成一个库”。逐个参数解释如下,这些开关在仓库的 CMake 源码中都可以找到定义:

参数作用源码依据
CMAKE_BUILD_TYPE=Release以 Release 模式构建被安装的主库CMake 常规
BUILD_SHARED_LIBS=ON构建共享库(.so/.dylib/.dll),是下游动态链接的前提cmake/llama-config.cmake.inLLAMA_SHARED_LIB即取自该开关
GGML_BACKEND_DL=ON将 ggml 各计算后端(CPU、CUDA、Metal 等)构建成可动态加载的.so,运行期再加载,而非静态编入主库ggml/CMakeLists.txt:option(GGML_BACKEND_DL "ggml: build backends as dynamic libraries (requires BUILD_SHARED_LIBS)" OFF),且 ggml/src/CMakeLists.txt 明确GGML_BACKEND_DL依赖BUILD_SHARED_LIBS
GGML_CPU_ALL_VARIANTS=ON一次构建所有 CPU 微架构变体(如libggml-cpu-alderlake.sohaswell等),运行期按机器能力挑选加载ggml/CMakeLists.txt:option(GGML_CPU_ALL_VARIANTS "ggml: build all variants of the CPU backend (requires GGML_BACKEND_DL)" OFF)
GGML_BACKEND_DIR指定动态后端.so的安装目标目录ggml/CMakeLists.txt 定义为CACHE PATH;ggml/src/CMakeLists.txt 会在GGML_BACKEND_DL开启时把它编进ggml的宏定义GGML_BACKEND_DIR="...",并在 ggml/src/CMakeLists.txt 把各后端install(TARGETS ... LIBRARY DESTINATION ${GGML_BACKEND_DIR})
GGML_LIB_INSTALL_DIR/LLAMA_LIB_INSTALL_DIRggml 与 llama 两层库的安装目录ggml/CMakeLists.txt 与 CMakeLists.txt 中均定义为CACHE PATH
CMAKE_INSTALL_PREFIX整个安装的根前缀,这里落到当前目录下的install/CMake 常规
LLAMA_TESTS_INSTALL=OFF/LLAMA_TOOLS_INSTALL=OFF只安装库与头文件,不安装测试程序和 CLI 工具,缩小安装产物CMakeLists.txt 中两个option(...)的定义

安装完成后,install/lib/下的产物在 README 中给出了一个真实示例(不同平台文件名会不同):

(venv) $ ls install/lib/ cmake libggml.so libllama-common.so.0 libllama.so.0.1.0 llama.cpp libggml-base.so libggml.so.0 libllama-common.so.0.1.0 libmtmd.so pkgconfig libggml-base.so.0 libggml.so.0.19.0 libllama.so libmtmd.so.0 libggml-base.so.0.19.0 libllama-common.so libllama.so.0 libmtmd.so.0.1.0

可以观察到三个关键点:

  1. 出现了libggmllibggml-baselibllamalibllama-commonlibmtmd多组“无版本主链 + 带版本实体 + 带版本符号链接”的组合,说明主库确实按共享库方式安装,且 soname 机制完整;
  2. cmake/子目录存放的是供下游find_package使用的 CMake package config 文件(即由 cmake/llama-config.cmake.in 生成的产物);
  3. llama.cpp/子目录是GGML_BACKEND_DIR/GGML_LIB_INSTALL_DIR/LLAMA_LIB_INSTALL_DIR指向的目标位置,动态后端.so会落在里面——这解释了为什么运行期需要把install/lib/llama.cpp加进LD_LIBRARY_PATH

第二步:把安装目录当作 CMake 包来消费

build.sh 只有三行,但完整演示了“下游消费者”的标准流程:

#!/bin/bash set -e cmake -S . -B build -DCMAKE_PREFIX_PATH="${PWD}/install" cmake --build build LD_LIBRARY_PATH="${PWD}/install/lib/llama.cpp:${PWD}/install/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" ./build/test-cmake

三步分别对应:

  1. 配置-DCMAKE_PREFIX_PATH="${PWD}/install"告诉 CMake 到本地安装前缀里找find_package需要的 config 文件;
  2. 构建:正常cmake --build
  3. 运行:把install/lib/llama.cpp(动态后端目录)与install/lib(共享库目录)前置注入LD_LIBRARY_PATH,保证动态链接器能在运行期找到libllama.solibggml.so以及libggml-cpu-*.so等动态后端。

消费者工程 examples/test-cmake/CMakeLists.txt 是接入 llama.cpp 安装的最小模板,全文如下:

cmake_minimum_required(VERSION 3.14) project(llama-simple) set(CMAKE_CXX_STANDARD 17) find_package(llama 0.1.0 REQUIRED) add_executable(test-cmake test-cmake.cpp) target_link_libraries(test-cmake PRIVATE llama) target_compile_definitions(test-cmake PRIVATE LLAMA_BUILD_NUMBER=${LLAMA_BUILD_NUMBER} LLAMA_BUILD_COMMIT="${LLAMA_BUILD_COMMIT}" )

这里有两点值得展开。

find_package(llama)背后发生了什么

llama.cpp 通过 cmake/llama-config.cmake.in 提供标准 CMake package config,其关键片段是:

set(LLAMA_VERSION @LLAMA_VERSION@) set(LLAMA_BUILD_COMMIT @LLAMA_BUILD_COMMIT@) set(LLAMA_BUILD_NUMBER @LLAMA_BUILD_NUMBER@) set(LLAMA_SHARED_LIB @BUILD_SHARED_LIBS@) @PACKAGE_INIT@ set_and_check(LLAMA_INCLUDE_DIR "@PACKAGE_LLAMA_INCLUDE_INSTALL_DIR@") set_and_check(LLAMA_LIB_DIR "@PACKAGE_LLAMA_LIB_INSTALL_DIR@") find_package(ggml REQUIRED HINTS ${LLAMA_LIB_DIR}/cmake) find_library(llama_LIBRARY llama REQUIRED HINTS ${LLAMA_LIB_DIR} NO_CMAKE_FIND_ROOT_PATH) add_library(llama UNKNOWN IMPORTED) set_target_properties(llama PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LLAMA_INCLUDE_DIR}" INTERFACE_LINK_LIBRARIES "ggml::ggml;ggml::ggml-base;" IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${llama_LIBRARY}" INTERFACE_COMPILE_FEATURES c_std_90 POSITION_INDEPENDENT_CODE ON)

由此可以确认:

  • config 文件本身把LLAMA_VERSIONLLAMA_BUILD_COMMITLLAMA_BUILD_NUMBER暴露为普通 CMake 变量——这就是 examples/test-cmake/CMakeLists.txt 里能直接引用${LLAMA_BUILD_NUMBER}/${LLAMA_BUILD_COMMIT}的原因,它们并不是find_package自动生成的,而是llama-config.cmake显式set出来的;
  • 该 config 又通过find_package(ggml REQUIRED HINTS ${LLAMA_LIB_DIR}/cmake)级联找到 ggml 的 package config,并把导入目标llamaINTERFACE_LINK_LIBRARIES指向ggml::ggml;ggml::ggml-base,所以下游只需要target_link_libraries(... PRIVATE llama)就能同时拿到 llama 与 ggml 两套符号;
  • INTERFACE_INCLUDE_DIRECTORIES指向安装前缀里的头文件目录,因此消费者不需要再手工include_directories

这也解释了为什么build-install.sh中必须显式指定GGML_LIB_INSTALL_DIRLLAMA_LIB_INSTALL_DIR:config 文件里HINTS ${LLAMA_LIB_DIR}/cmakeHINTS ${LLAMA_LIB_DIR}都依赖这个路径才能找到 ggml 的 cmake 子目录和libllama.so实体。

test-cmake.cpp:只做“初始化即成功”

test-cmake.cpp 的完整源码:

#include "llama.h" #include <cstdio> int main(void) { printf("[test-cmake] version: %s, build: %d (%s)\n", llama_version(), LLAMA_BUILD_NUMBER, LLAMA_BUILD_COMMIT); printf("[test-cmake] Initializing backend...\n"); llama_backend_init(); printf("[test-cmake] Backend initialized.\n"); llama_backend_free(); return 0; }

它只验证四件事:

  1. 头文件llama.h能被编译器找到(include 目录配置正确);
  2. llama_version()LLAMA_BUILD_NUMBERLLAMA_BUILD_COMMIT这些运行期/编译期版本信息可读(config 文件变量传递正确);
  3. llama_backend_init()能成功加载后端——在GGML_BACKEND_DL=ON+GGML_CPU_ALL_VARIANTS=ON下,这一步会真正从GGML_BACKEND_DIR指向的目录 dlopen 具体的libggml-cpu-<variant>.so
  4. llama_backend_free()能正常释放,无运行期崩溃。

完整流程与预期输出

examples/test-cmake/目录内按 README 顺序执行:

./build-install.sh

会创建install/目录,并在其lib/下生成上节列出的共享库与cmake/pkgconfig/子目录。然后:

./build.sh

README 给出的实际运行输出是:

-- Configuring done (0.0s) -- Generating done (0.0s) -- Build files have been written to: /path/to/llama.cpp/examples/test-cmake/build [100%] Built target test-cmake [test-cmake] Using llama.cpp version 0.1.0-dev-b10335 [test-cmake] Initializing backend... load_backend: loaded CPU backend from /path/to/llama.cpp/examples/test-cmake/install/lib/llama.cpp/libggml-cpu-alderlake.so [test-cmake] Backend initialized.

其中load_backend: loaded CPU backend from .../install/lib/llama.cpp/libggml-cpu-alderlake.so这一行是判断GGML_BACKEND_DLGGML_BACKEND_DIR是否配置成功的直接证据:它明确说明运行期是动态加载了位于install/lib/llama.cpp/的 alderlake 变体 CPU 后端,而不是静态链接进libggml.so

适用前提与排查要点

在使用这个示例前需要明确的限制:

  • 依赖平台:示例脚本使用LD_LIBRARY_PATH注入动态库路径,属于 Linux/macOS 风格;Windows 用户需要改用 PATH 或将.dll放入可执行文件目录,脚本需自行调整。
  • 依赖共享库GGML_BACKEND_DL=ON在 ggml/src/CMakeLists.txt 中要求BUILD_SHARED_LIBS=ON,两者必须同时开启;
  • CPU 变体与 native 互斥:ggml/src/ggml-cpu/CMakeLists.txt 明确GGML_NATIVEGGML_BACKEND_DL不兼容,需要改用GGML_CPU_ALL_VARIANTS,这也正是build-install.sh的选法;
  • 安装前缀CMAKE_INSTALL_PREFIX硬编码为${PWD}/install,若仓库不允许写入(如根目录只读),需先修改脚本里的路径;
  • 产物目录install/build/llama-build-install/均已被 .gitignore 忽略,可放心在本地重复执行。

当你的项目修改了安装相关 CMake 配置(例如调整LLAMA_LIB_INSTALL_DIR、切换GGML_BACKEND_DL)后,最直接的验证路径就是本示例的“安装 →find_packagellama_backend_init”闭环:build-install.sh验证安装 layout,build.sh验证下游可发现性与运行期后端加载,两者合起来即等价于一次轻量化的集成回归。

【免费下载链接】llama.cppLLM inference in C/C++项目地址: https://gitcode.com/GitHub_Trending/ll/llama.cpp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 20:52:43

Scrapling 自适应 Web 抓取框架指南:Fetcher、Spider 与 CLI 全解析

Scrapling 自适应 Web 抓取框架指南&#xff1a;Fetcher、Spider 与 CLI 全解析 【免费下载链接】Scrapling &#x1f577;️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! 项目地址: https://gitcode.com/Git…

作者头像 李华
网站建设 2026/9/5 20:51:35

毕业论文修改全攻略:从查重到降AI的完整方法论

1. 引言&#xff1a;论文修改为何如此重要&#xff1f; 在撰写毕业论文的过程中&#xff0c;文本修改是一个不可避免的环节。面对不同的修改方式&#xff0c;我常常感到困惑&#xff1a;是使用传统的同义词替换&#xff0c;还是借助通用大模型辅助改写&#xff0c;或者使用专门…

作者头像 李华
网站建设 2026/9/5 20:46:33

Agent画图为何需要编译器?Archify与typed JSON IR设计解析

为什么 Agent 画图需要编译器&#xff1f;先说结论&#xff1a;现在的 LLM 直接输出像素图&#xff0c;基本是一条死路。你让 GPT-4o 画一张带渐变、投影、文字排版的界面稿&#xff0c;它画出来的东西 99% 的情况下不能直接用。坐标偏移、颜色串色、字体变形、图层覆盖顺序错乱…

作者头像 李华
网站建设 2026/9/5 20:39:20

基于MADDPG的多无人机协同围捕:从算法原理到PyTorch实战

简介&#xff1a;本资源是一个面向人工智能与机器人方向研究者、高校师生及强化学习实践者的多无人机协同围捕仿真项目&#xff0c;聚焦于解决多智能体在动态环境中协同决策与目标围捕的核心挑战。项目基于MADDPG算法&#xff0c;在自定义Gymnasium仿真环境上训练3架无人机智能…

作者头像 李华