gnome: los 7 typelibs CERRADOS — librsvg y ibus, y dos deudas viejas pagadas de paso

Rsvg-2.0   librsvg b3:351f4658
  IBus-1.0   ibus    b3:d4d3750a

**1. PERILLA NUEVA DEL LAB: `[source] cargo_vendor`.** `detect_build_system` asume UN
sistema de build por árbol, y librsvg genuinamente tiene dos: `configure.ac` gana por
precedencia pero su Makefile llama a `cargo build`, que dentro del sandbox hermético
no tiene red. La perilla fuerza el vendoreo (que ocurre en el fetch, donde sí hay red)
sin tocar la detección. **No entra al ArtifactHash** —decide de dónde salen las deps,
no cuáles: eso lo fija el Cargo.lock, ya bajo el sha256 de la fuente— así que se puede
prender en una receta ya sellada sin re-hashear nada. Con test, y verificado en vivo:
libelogind no movió su hash tras el cambio.

**2. LA DEUDA DEL UNWINDER, PAGADA.** librsvg moría en
`undefined reference: _Unwind_DeleteException`. No es de librsvg: es de la `std` de
rustc, que trae landing pads y espera el runtime que en glibc vive en libgcc_s. Es la
deuda que el corpus arrastra desde matar-gcc —«las 12 recetas Rust son UN problema, no
12»— y el remedio estaba a mano: **zig empaqueta la libunwind de LLVM** y exporta los
`_Unwind_*` (verificado con nm). Alcanza `LIBS=-lunwind`. Va por LIBS y no por LDFLAGS
porque autotools pone LIBS al FINAL de la línea de enlace, que es donde tiene que ir
una librería que resuelve símbolos indefinidos.

librsvg va en 2.58.5 y no 2.59+: en 2.59 cambió a meson + cargo-c, y cargo-cbuild
enlaza el crate `cargo` entero (libgit2, libssh2, libcurl, openssl) — una campaña
propia por un binario que sólo corre en el constructor. 2.58.5 produce el mismo
Rsvg-2.0. Mismo criterio que gnome-desktop 44.5.

**3. `x11-compose-data`, y es una tensión que vale la pena tener escrita.** ibus COMPILA
la tabla de teclas muertas de X11 dentro de libibus (Makefile.am:310, incondicional, sin
`--disable-`). Sin datos no construye. Los datos viven en el tarball de libX11 por
historia, no por necesidad técnica: son 5192 líneas de reglas. La receta extrae SÓLO los
ficheros de locale reproduciendo la regla de upstream (`cpprules.in`: cpp crudo +
CPP_SED_MAGIC literal) y no compila una línea de X11. Un escritorio Wayland-only sigue
necesitando la tabla de composición del mundo Unix.

Gotchas de ibus, los tres medidos: su ayuda MIENTE (`--enable-gtk4`/`--enable-wayland`
sugieren default apagado; el default es `yes`); `--disable-emoji-dict` NO apaga
`--disable-unicode-dict`; y con `--disable-wayland` el build muere igual porque
`tools/main.c` llama wl_display_* sin `#ifdef` mientras WAYLAND_LIBS sólo se agrega si
la opción está prendida — bug de upstream en su propia configuración sin Wayland.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-29 14:28:50 -04:00
co-authored by Claude Opus 5
parent 0a76ead129
commit bc4d0c8aea
6 changed files with 324 additions and 3 deletions
+14 -2
View File
@@ -220,7 +220,13 @@ pub fn build(
// Recetas Cargo: vendoreamos las deps (red permitida en el fetch) para que el build sea
// hermético `--offline` dentro del sandbox. Tras los patches, por si tocaron Cargo.toml/lock.
if matches!(detect_build_system(&src_tree), BuildSys::Cargo) {
// `cargo_vendor = true` fuerza esta rama en árboles POLÍGLOTAS, donde `detect_build_system`
// —que asume un sistema por árbol— eligió el de C. librsvg es el arquetipo: `configure.ac` gana
// por precedencia, pero su Makefile llama a `cargo build`, y sin vendoreo ese cargo sale a la
// red dentro del sandbox hermético. Ver `Source::cargo_vendor`.
if matches!(detect_build_system(&src_tree), BuildSys::Cargo)
|| eff_recipe.source.cargo_vendor == Some(true)
{
// El source se copia DENTRO del repo hammer (que es un workspace Cargo) ⇒ si el Cargo.toml
// de la fuente NO declara su propio `[workspace]`, cargo cree que pertenece al workspace de
// hammer y `cargo vendor` aborta. Inyectamos un `[workspace]` vacío para aislarla. SÓLO si
@@ -229,7 +235,13 @@ pub fn build(
// por receta. Ver memoria 'cargo-recipe crate suelto'.
ensure_cargo_workspace_isolation(&src_tree)?;
// Extractor de workspaces (Etapa G): si el root es virtual, resuelve `-p <pkg>` del bin.
inject_cargo_package_selector(&mut eff_recipe, &src_tree);
// SÓLO cuando el árbol ES una receta Cargo. En un políglota (`cargo_vendor = true`) el
// producto lo arma el sistema de build de C —que llama a cargo con sus propios argumentos—
// y meterle un `-p` a los flags de la receta sería inyectar una opción de Cargo en un
// `./configure`. Acá el forzado pide vendoreo, nada más.
if matches!(detect_build_system(&src_tree), BuildSys::Cargo) {
inject_cargo_package_selector(&mut eff_recipe, &src_tree);
}
tracing::info!("cargo: vendoreando deps para build offline");
fetch::vendor_cargo_deps(
&src_tree,
+41
View File
@@ -66,6 +66,19 @@ pub struct Source {
/// `.cargo/config.toml` que emite `cargo vendor` ya apunta al dir que se le pasa.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cargo_vendor_dir: Option<String>,
/// Fuerza el vendoreo cargo aunque el árbol NO se detecte como `BuildSys::Cargo`.
///
/// Existe porque `detect_build_system` asume **un** sistema de build por árbol, y hay proyectos
/// que genuinamente tienen dos: C por fuera, Rust por dentro. El arquetipo es librsvg —trae
/// `configure.ac` Y `Cargo.toml`, y autotools gana por precedencia—, pero su `Makefile` invoca
/// `cargo build`. Sin vendoreo ese cargo intenta salir a la red DENTRO del sandbox hermético y
/// el build muere. Es un patrón, no una excepción: cada vez hay más GNOME así.
///
/// No cambia qué se construye, sólo de dónde salen las deps —el `Cargo.lock` del source es el
/// que fija las versiones— así que **no entra al ArtifactHash**, igual que `cargo_vendor_dir`.
/// Es lo que permite prenderla en una receta ya sellada sin re-hashearla.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cargo_vendor: Option<bool>,
#[serde(default)]
pub patches: Vec<String>,
}
@@ -732,6 +745,34 @@ expected_output = "b3:deadbeef"
);
}
#[test]
fn cargo_vendor_roundtripea_y_no_afecta_el_hash() {
// `cargo_vendor` decide DE DÓNDE salen las deps de Cargo (registro vs. `vendor/` local), no
// CUÁLES: eso lo fija el `Cargo.lock` del source, que ya está bajo el hash de la fuente. Por
// eso no entra a `hash_inputs`, igual que `cargo_vendor_dir` — y por eso se puede prender en
// una receta YA SELLADA para destrabar su build offline sin re-hashear nada aguas abajo.
let sin = Recipe::from_toml(SAMPLE).unwrap();
let mut con = sin.clone();
con.source.cargo_vendor = Some(true);
assert_eq!(
sin.hash_inputs(&[]).unwrap(),
con.hash_inputs(&[]).unwrap(),
"cargo_vendor NO debe entrar en hash_inputs"
);
// Y roundtripea por TOML: si se perdiera al serializar, el forzado se apagaría solo en
// cualquier flujo que reescriba la receta.
let r = Recipe::from_toml(&con.to_toml().unwrap()).unwrap();
assert_eq!(r.source.cargo_vendor, Some(true));
// Ausente sigue siendo ausente (no `Some(false)`), que es lo que mantiene el TOML limpio.
assert_eq!(
Recipe::from_toml(&sin.to_toml().unwrap())
.unwrap()
.source
.cargo_vendor,
None
);
}
#[test]
fn slots_round_trip_y_no_afectan_el_hash() {
// H4b: el bloque `slots` declara TOPOLOGÍA (qué toca / de qué depende), no identidad ⇒