Files
sergioandClaude Opus 5 2c2ee951d6 licencias: resolver -only vs -or-later CON LA CITA — y tres «pruebas» que no probaban nada
Los identificadores obsoletos (`GPL-2.0`, `LGPL-2.1`, `AGPL-3.0`) no dicen si el proyecto
concede «sólo esta versión» o «ésta o cualquier posterior», y eso decide con qué se puede
combinar el paquete y bajo qué términos puede redistribuirlo quien lo reciba.

NO SE PUEDE MIRAR EL COPYING, que es la trampa evidente: el texto de la GPL es IDÉNTICO en
los dos casos —es la licencia, no la concesión— y encima su apéndice «cómo aplicar la
licencia» contiene literalmente «or (at your option) any later version», así que buscarla
ahí da SIEMPRE positivo y parece evidencia siendo plantilla. Misma trampa que la regla del
`.a` no-PIC, donde grep contaba reubicaciones de `.debug_*`. La concesión vive en las
cabeceras de los fuentes y en el README; ahí se busca, excluyendo los ficheros de licencia.

SE GUARDA LA CITA, no sólo el veredicto: fichero + frase exacta que decidió. Una licencia es
una afirmación legal y quien la revise tiene que poder ver POR QUÉ dice lo que dice sin
repetir el trabajo.

Y eso pagó de inmediato: de las 12 primeras resoluciones, TRES eran evidencia inválida y
sólo se vieron porque estaba la cita. Cada una de una clase distinta:
 · caligula   — la frase salía de `checks/headless/expected.iso`, un FIXTURE DE TEST;
 · libnl      — de `include/linux-private/linux/seg6.h`, una cabecera del KERNEL vendorizada.
                La licencia del kernel no es la de libnl;
 · lm-sensors — declarado GPL-2.0 y la cita decía «version 2.1 of the License», que es la
                LGPL. La frase era real pero no sostenía lo que se le atribuía.

Las tres clases quedan filtradas en el script: ficheros de licencia, rutas de test/fixture, y
código vendorizado; más una comprobación nueva de que **la cita hable de la misma versión que
la licencia declarada**.

Sembradas las 9 auditadas (13 ficheros; algunas viven en varias colas). Ambiguas: 55 → 41.
Las 40 sin evidencia quedan listadas y siguen contadas — la mayoría son Go y la familia
cosmic, donde la frase no aparece fuera del COPYING.

Hashes verificados: 0 movidos.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 15:15:20 -04:00

87 lines
5.9 KiB
TOML

# libqalculate — la calculadora que le falta al lanzador. El plugin `calc` de pop-launcher no calcula
# nada por su cuenta: arma una línea y se la pasa al binario **`qalc`**, que es de este paquete. Sin
# él, tecleando `=2+2` el lanzador contesta —correctamente y sin fallar— «qalc command is not
# installed». Es el primer paquete del catálogo que existe para que una TECLA del escritorio dé un
# resultado, no para que otra librería enlace.
#
# ── LA CADENA QUE NADIE ADIVINA MIRANDO ARRIBA ──────────────────────────────────────────────────
# `Super` → cosmic-launcher → pop-launcher → plugin calc → qalc → libqalculate → **mpfr → gmp**.
# Seis saltos desde una tecla hasta la aritmética de precisión arbitraria, y los dos últimos son
# obligatorios: el configure corta con «libgmp not found» y «libmpfr not found or uses a different
# ABI». Por eso [[gmp]] y [[mpfr]] entraron primero.
#
# ── LO QUE SE APAGA, Y POR QUÉ CADA UNO ─────────────────────────────────────────────────────────
# · `--without-libcurl`: es para BAJARSE tipos de cambio de internet. Un paquete de una distro
# reproducible no tiene por qué traer un cliente HTTP para sumar; y la clausura se ahorra curl
# entero. Las tasas quedan las del fichero de definiciones, que es lo honesto: un dato con fecha.
# · `--without-icu`: sólo aporta comparación de cadenas Unicode insensible a mayúsculas. Traería
# ICU —decenas de MB de tablas— para que `SIN` funcione igual que `sin`.
# · `--disable-nls`: no hay locales en la imagen (los clientes ya avisan «failed to get system
# locale, falling back to en-US»), así que gettext sólo agregaría dependencia sin traducir nada.
#
# ── ⚠ READLINE NO ES OPCIONAL ACÁ, Y ESO SE MIDIÓ ───────────────────────────────────────────────
# Yo había razonado que era indiferente «porque el plugin usa qalc de forma no interactiva». **Es
# falso, y el código del plugin lo dice**: `Command::new("qalc")` sin expresión, con `stdin` en pipe,
# le ESCRIBE la expresión por stdin y descarta las dos primeras líneas de stdout. O sea que lo usa en
# modo INTERACTIVO con stdin redirigido — el modo en que `-t <expr>` no participa.
# Sin readline ese modo no funciona: el binario imprime el prompt `>` y no evalúa nada, así que la
# fila del lanzador sale VACÍA (no «no está instalado»: está, y no contesta). Con readline el bucle
# de entrada es el que espera el plugin.
# La lección es la de siempre en esta campaña, otra vez: **la dep no se deduce de para qué sirve el
# paquete, se lee de cómo lo INVOCA quien lo usa.** «Es una calculadora, la llamarán con la cuenta
# en argv» era una suposición, no una medición.
name = "libqalculate"
version = "5.12.0"
license = "GPL-2.0-or-later"
[source]
tarball = "https://github.com/Qalculate/libqalculate/releases/download/v5.12.0/libqalculate-5.12.0.tar.gz"
sha256 = "f3dfdcf97d5a9e3a5bc0ebe66afd184721b606276eee3ba0ada8c92a5e71d44c"
[build]
# C++ de verdad (la librería entera lo es), y con `compiler = "zig-cc"` el sandbox pone
# CXX=hammer-zig-cxx, o sea `zig c++` con la libc++ de LLVM enlazada ESTÁTICA. Eso es lo que evita
# que el artefacto pida `libstdc++.so.6`/`libgcc_s.so.1` de Alpine — la deuda que la campaña
# «matar gcc» viene pagando en el resto del árbol.
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
flags = []
[build.phases]
configure = '''
# ── ALIAS DE CURSES, PORQUE EL CORPUS SÓLO EMPAQUETA LA VARIANTE WIDE ───────────────────────────
# El configure de libqalculate busca readline probando `-lreadline` junto a `-lncurses`, `-lcurses`,
# `-ltermcap` y `-ltinfo`, en ese orden. Nuestro `ncurses` instala **sólo `libncursesw.a`** (la
# variante de caracteres anchos, que es la correcta y la única que hace falta), así que las cuatro
# pruebas fallan con «unable to find static system library» y el configure concluye —sin error— que
# no hay readline. Que el paquete se llame `ncurses` no significa que provea `-lncurses`.
# Los alias van en un directorio LOCAL y no tocando `/usr/lib`: la vista de deps del sandbox es la
# evidencia de qué se declaró, y ensuciarla para que un test pase deja mintiendo justo al mecanismo
# que existe para no mentir.
mkdir -p .curses-compat
for a in libncurses libcurses libtinfo libtermcap; do ln -sf /usr/lib/libncursesw.a ".curses-compat/$a.a"; done
./configure \
--build=$CBUILD --host=$CHOST \
--prefix=/usr \
--disable-shared --enable-static \
--without-libcurl \
--without-icu \
--disable-nls \
LDFLAGS="$LDFLAGS -L$PWD/.curses-compat"
'''
# `-all-static` NO ES REDUNDANTE con `link = "static"`, y esa confusión costó todo un frente.
# El harness inyecta `LDFLAGS=-static`, pero **libtool se lo come**: la línea de enlace real de `qalc`
# salía dinámica contra `libc.so`. Y un musl DINÁMICO acá no es sólo «pesa distinto»: `stdin`,
# `stdout` y `stderr` terminaron **en la misma dirección de BSS**, las tres compartiendo una única
# ranura de copy-relocation, así que el `stdin` del programa era en realidad el `stdout`
# (`fileno(stdin)` = 1). De ahí que `qalc` no leyera NADA de una tubería mientras `-f /dev/stdin`
# —que abre el descriptor por ruta, sin tocar el FILE* roto— funcionaba perfecto.
# `-all-static` es la forma de decírselo a libtool; `-no-pie` va con él (un estático PIE no tiene
# sentido). Mismo par que usa `libxml2` en el corpus, por la misma razón.
compile = 'make LDFLAGS="-all-static -no-pie -L$PWD/.curses-compat" -j"$(nproc)"'
install = 'make DESTDIR=/out install LDFLAGS="-all-static -no-pie -L$PWD/.curses-compat"'
[deps]
build = ["make", "gmp", "mpfr", "libxml2", "pkgconf", "readline", "ncurses"]