gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1534Shell 199Rust 109Markdown 993713 Sutichaykuna

⎇ 36152da9284ad15039abe44e3cb91ef42aa43bb7 recipes/llama-cpp.toml TOML · 166 siq'ikuna · 10.0 KB Ñawpa willay ch'uya

busybox sale de las 24 build-deps: ya no viaja en NINGUNA imagen b53d91edf · Sergio ·

1# llama.cpp b10901 — el MOTOR DE INFERENCIA LOCAL del corpus. Es la pieza que destraba el §6.7 del
2# SDD 26 (IA local en la barra lateral de `atuq`) y la mitad semántica del §6.3 (preguntarle al
3# archivo personal en lenguaje natural).
4#
5# ══ POR QUÉ ESTA RECETA, Y NO «ENCHUFAR LO QUE YA HAY» ═════════════════════════════════════════
6# El §6.7 figuraba como costo «bajo» porque las piezas parecían estar escritas en tawasuyu. Se fue
7# a mirar y NO alcanzan, por dos razones independientes:
8#   1. `pluma-llm` tiene backends `anthropic`, `cohere`, `claude-cli` y `mock` — TODOS de nube o de
9#      juguete. Ninguno corre un modelo en la máquina;
10#   2. `rimay-verbo-fastembed` —el daemon de embeddings que `rag-motor` exige— trae `fastembed`
11#      con la feature `ort-download-binaries`: **baja onnxruntime precompilado (glibc) y el modelo
12#      de HuggingFace en el primer arranque**. En un build hermético y en una distro musl eso no es
13#      «lento», es imposible.
14# O sea que los dos pendientes comparten UN muro y el muro tiene forma de receta. llama.cpp lo
15# derriba entero: el mismo binario sirve `/v1/chat/completions` (el LLM del §6.7) y `/v1/embeddings`
16# (lo que `rag-motor` necesita para la mitad semántica del §6.3), sin ONNX, sin Python y sin red.
17#
18# ⚠ ESTA RECETA ES EL MOTOR, NO LA FUNCIÓN. Un motor sin modelo no responde nada. El modelo es una
19# FUENTE PINEADA aparte —igual que el perfil de PGO de firefox—, y es su propia unidad de trabajo.
20# Nadie debería leer «IA local» y esperar que esto conteste algo todavía.
21#
22# ══ LA VERSIÓN ES UN COMMIT, NO UNA SERIE ═════════════════════════════════════════════════════
23# llama.cpp no publica versiones semánticas: sus releases son `bNNNN`, una por commit de `master`
24# (b10901 = 2026-09-10). El `LLAMA_VERSION` interno dice `0.4.0-dev` y no identifica nada. Se pinea
25# el tag, que es lo único que nombra un árbol concreto, y subirlo es su propia unidad de trabajo.
26#
27# ══ LAS CUATRO PERILLAS QUE NO SON GUSTO ══════════════════════════════════════════════════════
28#
29# 1. **`-DLLAMA_USE_PREBUILT_UI=OFF` — viene ON DE FÁBRICA Y DESCARGA EN TIEMPO DE BUILD.**
30#    `tools/ui/CMakeLists.txt` cuelga un `add_custom_target` que corre `scripts/ui-assets.cmake`, y
31#    ése hace `file(DOWNLOAD …)` contra un bucket de HuggingFace para hornear la web UI dentro de
32#    `llama-server`. Leído en la fuente del tarball pineado, no supuesto. Hoy el sandbox no tiene
33#    red y el guión sólo avisa y sigue — pero apagarlo por AUSENCIA DE RED es exactamente la
34#    protección que funciona por accidente: el día que el sandbox tenga red, entraría un blob que no
35#    está en `hash_inputs` y el artefacto dejaría de reproducir sin que nadie tocara la receta. Se
36#    apaga por declaración. La web UI no se pierde: no la queríamos — acá el cliente es el host de
37#    native messaging del §7, que habla HTTP, no un navegador mirando el puerto.
38#
39# 2. **LAS SEIS PERILLAS DE ISA VAN UNA POR UNA, Y LA RAZÓN SE MIDIÓ ACÁ.**
40#    El primer sello de esta receta llevaba sólo `-DGGML_NATIVE=OFF`, apoyado en leer
41#    `ggml/CMakeLists.txt:141` — `if (GGML_NATIVE OR NOT GGML_NATIVE_DEFAULT) set(INS_ENB OFF)`—,
42#    o sea: con NATIVE=OFF, ggml debería ENCENDER las perillas explícitas (SSE4.2/AVX/AVX2/BMI2/
43#    FMA/F16C) en vez de apoyarse en `-march=native`. **Y es falso en ESTE sandbox**, por una línea
44#    50 renglones más arriba (`ggml/CMakeLists.txt:105`):
45#
46#        if (CMAKE_CROSSCOMPILING OR DEFINED ENV{SOURCE_DATE_EPOCH})
47#            set(GGML_NATIVE_DEFAULT OFF)
48#
49#    El sandbox de takana exporta `SOURCE_DATE_EPOCH=1` (`sandbox.rs:453`) — que es lo que nos da
50#    binarios reproducibles. Con eso `GGML_NATIVE_DEFAULT` queda OFF, `NOT GGML_NATIVE_DEFAULT` es
51#    verdadero, e `INS_ENB` termina en **OFF**: las seis perillas apagadas. O sea que
52#    **la variable que existe para que el build reproduzca apagó todas las instrucciones
53#    vectoriales del motor de inferencia.**
54#
55#    ⚠ Y no falló nada. El artefacto selló, `llama-cli --version` contesta, y el binario es x86-64
56#    pelado: **cero `%ymm`, cero `vfmadd`, cero `roundps`** en 1.634.770 líneas de `objdump -d`,
57#    contadas sobre el artefacto sellado. Un motor de inferencia sin AVX2 no está roto: está varias
58#    veces más lento, y ninguna métrica del repo lo dice. Es la figura de siempre — un ausente falla
59#    ruidosamente; un desviado llega hasta el final diciendo que todo fue bien.
60#
61#    Por eso las seis van declaradas y NO se confía en el default de nadie. Y por eso el `install`
62#    las COMPRUEBA en el binario: es el único punto donde este modo de fallar se puede ver.
63#
64#    ⚠ Eso fija un PISO declarado: x86-64-v3. Un CPU sin AVX2 (pre-2013) muere con SIGILL, no con un
65#    mensaje. Medido antes de elegirlo, no deducido: `momento`/gioser y el worker `dev.gioser.net`
66#    traen los seis flags, y el objetivo de metal (TigerLake, ver [[etapa-metal-usb]]) también.
67#    Bajar el piso o publicar variantes es `docs/plan-variantes-cpu.md`, no esta receta.
68#    `-DGGML_NATIVE=OFF` se queda igual, pero por lo que de verdad hace acá: prohibir `-march=native`,
69#    que sería un artefacto distinto por máquina — la familia del `MAKE_STAMP` de nftables.
70#
71# 3. **`-DGGML_CCACHE=OFF` — viene ON de fábrica y se autodetecta.** Si algún día el lab trae
72#    `ccache`, el build cambia de forma sin que el corpus haya cambiado en nada, y el lab NO entra
73#    en `hash_inputs` (ver [[lab-fuera-de-hash-inputs]]): dos labs sellarían bytes distintos en la
74#    misma dirección. Misma familia que el `CONFIG_SHELL=bash` que se rechazó en nftables.
75#
76# 4. **`-DGGML_OPENMP=OFF` — no es recorte, es evitar una dep invisible.** Con OpenMP encendido el
77#    binario arrastra la runtime de OpenMP del compilador. ggml trae su PROPIO pool de hilos y lo usa
78#    cuando OpenMP no está; el corpus prefiere no meterse la runtime de otro toolchain adentro
79#    (ver el `-static-libstdc++` de cmake.toml, misma lección).
80#
81# `-DLLAMA_OPENSSL=OFF`: su único uso es HTTPS para BAJAR modelos de HuggingFace desde el propio
82# binario. Acá un modelo entra como entra cualquier fuente —pineado por sha256— así que esa función
83# no sólo no hace falta: no queremos que exista. `-DLLAMA_BUILD_APP=OFF` por lo mismo (`app/` es el
84# binario unificado con `download.cpp` adentro).
85#
86# ⚠ `LLAMA_BUILD_TOOLS=ON` NO es un extra: `llama-server` vive en `tools/server`, y `tools/CMakeLists.txt`
87# sólo entra a `server/` (y a `cli/`) si `LLAMA_BUILD_SERVER` está encendido DENTRO de TOOLS. Con
88# TOOLS=OFF no hay servidor. De yapa vienen `llama-quantize`, `llama-bench` y `llama-perplexity`,
89# que son las tres herramientas con las que se mide un modelo antes de pinearlo.
90#
91# El wrapper `.zwrap` es el mismo de `poppler-glib` y por lo mismo: cmake le pasa
92# `-Wl,--fatal-warnings` al linker y zig cc convierte avisos benignos en errores.
93#
94# El `install` comprueba que `llama-server` EXISTA. No es paranoia: si `LLAMA_BUILD_TOOLS` o
95# `LLAMA_BUILD_SERVER` se apagan solos —que es lo que hizo `ENABLE_GLIB` en poppler—, el build sale
96# 0 y sella un artefacto sin la única pieza por la que esta receta existe.
97name    = "llama-cpp"
98version = "b10901"
99license = "MIT"
100
101[source]
102tarball = "https://github.com/ggml-org/llama.cpp/archive/refs/tags/b10901.tar.gz"
103sha256  = "2cf2d648c6a8ee94f67a94d8c70479620ba481e01a1d930a9075bc7780ff4f9f"
104
105[build]
106compiler = "zig-cc"
107target   = "x86_64-linux-musl"
108link     = "static"
109flags    = []
110# Sin esto el artefacto pesa 1,8 G: zig cc emite debug_info por defecto y acá son 16 binarios
111# ESTÁTICOS, o sea 16 copias de los símbolos de libllama+libggml+libc++. Medido: `llama-server`
112# pasa de 133 M a una fracción. Entra en el hash (`recipe.rs:574`), como tiene que ser.
113strip_debug = true
114
115[build.phases]
116configure = '''
117ZW="$PWD/.zwrap"; mkdir -p "$ZW"
118cat > "$ZW/cc"  <<'W'
119#!/bin/sh
120a=""; for x in "$@"; do [ "$x" = "-Wl,--fatal-warnings" ] && continue; a="$a $x"; done
121exec /opt/zig/zig cc -mcpu=baseline $a
122W
123cat > "$ZW/cxx" <<'W'
124#!/bin/sh
125a=""; for x in "$@"; do [ "$x" = "-Wl,--fatal-warnings" ] && continue; a="$a $x"; done
126exec /opt/zig/zig c++ -mcpu=baseline $a
127W
128chmod +x "$ZW/cc" "$ZW/cxx"
129cmake -B build -G Ninja -Wno-dev \
130  -DCMAKE_C_COMPILER="$ZW/cc" -DCMAKE_CXX_COMPILER="$ZW/cxx" \
131  -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \
132  -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF -DBUILD_SHARED_LIBS=OFF \
133  -DGGML_NATIVE=OFF -DGGML_CCACHE=OFF -DGGML_OPENMP=OFF -DGGML_BLAS=OFF \
134  -DGGML_SSE42=ON -DGGML_AVX=ON -DGGML_AVX2=ON -DGGML_BMI2=ON -DGGML_FMA=ON -DGGML_F16C=ON \
135  -DGGML_RPC=OFF -DGGML_BACKEND_DL=OFF \
136  -DLLAMA_OPENSSL=OFF -DLLAMA_BUILD_UI=OFF -DLLAMA_USE_PREBUILT_UI=OFF \
137  -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_EXAMPLES=OFF -DLLAMA_BUILD_APP=OFF \
138  -DLLAMA_BUILD_TOOLS=ON -DLLAMA_BUILD_SERVER=ON
139'''
140compile = 'cmake --build build -j"$(nproc)"'
141install = '''
142set -e
143DESTDIR=/out cmake --install build
144# Ver la cabecera: si TOOLS o SERVER se apagan solos, esto sella sin la pieza que justifica la receta.
145test -x /out/usr/bin/llama-server || {
146  echo "ERROR: no se instaló llama-server — ¿LLAMA_BUILD_TOOLS/LLAMA_BUILD_SERVER apagados?" >&2
147  exit 1
148}
149test -x /out/usr/bin/llama-cli || {
150  echo "ERROR: no se instaló llama-cli" >&2
151  exit 1
152}
153# Ver la perilla 2 de la cabecera: SOURCE_DATE_EPOCH apaga INS_ENB y el binario sale sin una sola
154# instrucción vectorial, sellando igual y corriendo igual. Esto es lo único que lo ve.
155objdump -d build/ggml/src/libggml-cpu.a 2>/dev/null | grep -q '%ymm' || {
156  echo "ERROR: libggml-cpu.a NO tiene registros %ymm — AVX2 quedó apagado (¿INS_ENB=OFF?)" >&2
157  exit 1
158}
159objdump -d build/ggml/src/libggml-cpu.a 2>/dev/null | grep -q 'vfmadd' || {
160  echo "ERROR: libggml-cpu.a NO tiene vfmadd — FMA quedó apagado" >&2
161  exit 1
162}
163'''
164
165[deps]
166build = ["cmake", "samurai", "binutils", "pkgconf"]