# yoga — el motor de maquetación flexbox de Meta. Entra como DEP OBLIGATORIA de fcitx5 ≥5.1.20. # # ══ POR QUÉ ESTA RECETA EXISTE: ES UN SUBMÓDULO Y EL TARBALL VIENE VACÍO ═══════════════════════ # `fcitx5` usa yoga para maquetar la ventana de candidatos de su UI clásica (`src/ui/classic`), y lo # trae como **submódulo git** (`third_party/yoga` → `https://github.com/facebook/yoga`). Un archive # de GitHub NO materializa submódulos: medido, `third_party/yoga` es el **único** directorio vacío # del tarball de fcitx5 5.1.21. Y su CMakeLists no tiene salida por red: # # if (USE_SYSTEM_YOGA) find_package(yoga REQUIRED); set(YOGA_TARGET yoga::yogacore) # else() add_subdirectory(third_party/yoga/yoga) ← directorio VACÍO acá # # ⇒ `USE_SYSTEM_YOGA=On` + esta receta es el único camino. Es la misma figura que `sonic` con # espeak-ng, con una diferencia que importa: allá el fallback era un `git clone` en tiempo de build; # acá es un `add_subdirectory` de algo que no existe, así que falla al CONFIGURAR y no al enlazar. # # ══ EL COMMIT ES EL QUE FCITX5 PINEA ═══════════════════════════════════════════════════════════ # `042f5013…` es exactamente el gitlink que `fcitx5` 5.1.21 declara para su submódulo (leído por la # API de GitHub, no adivinado). Se pinea ese y no el último tag de yoga porque es el emparejamiento # que upstream prueba — mismo criterio que `sonic`. Si fcitx5 mueve su submódulo, esta receta lo # sigue y el `git log` dirá por qué. # # La versión de upstream es literalmente `0.0.0` en su `package.json`: yoga no versiona el paquete # nativo, versiona los bindings. El sufijo del commit es lo único que identifica este artefacto. # # ══ ⚠ DOS PARCHES AL ÁRBOL, Y LOS DOS SON OBLIGATORIOS ═════════════════════════════════════════ # 1. **`add_subdirectory(tests)` baja googletest POR RED.** El CMakeLists raíz lo añade **sin # condición** (no hay perilla `BUILD_TESTING` que lo cubra), y `tests/CMakeLists.txt` hace # `FetchContent_Declare(googletest URL https://github.com/google/googletest/…zip)`. El sandbox de # takana no tiene red a propósito, así que eso mata el configure. # # ⚠ Y NO se puede esquivar configurando `-S yoga` (el subdirectorio de la biblioteca): **las # reglas de `install` y el `export` del paquete cmake viven en el CMakeLists RAÍZ**, no en # `yoga/`. Construir sólo el subdirectorio daría la `.a` sin `yogaConfig.cmake`, y entonces el # `find_package(yoga REQUIRED)` de fcitx5 no la encontraría: artefacto sellado, con contenido, y # sin lo único que el consumidor busca. ⇒ se conserva la raíz y se le quita la línea. # # 2. **`-Werror` está en `cmake/project-defaults.cmake`** (con `-Wall`), y está calibrado contra los # compiladores de Meta. El clang de zig es otra versión y avisa de otras cosas; un aviso nuevo # cualquiera convertiría el build en un fallo que no dice nada de yoga. No vale pasar # `-Wno-error` por `CMAKE_CXX_FLAGS`: esos van ANTES de los `add_compile_options`, y en clang # gana el último. ⇒ se quita de la fuente, que es determinista y se ve en el diff. # # Los dos parches se comprueban: si el `sed` no cambia nada —porque upstream movió la línea— el # configure falla ruidosamente en vez de volver a bajar googletest por una red que no hay. # # ══ LO QUE NO HACE FALTA TOCAR ═════════════════════════════════════════════════════════════════ # · `add_library(yogacore STATIC …)` está codificado, y `project-defaults.cmake` ya pone # `CMAKE_POSITION_INDEPENDENT_CODE ON`. O sea que la `.a` es PIC y **puede entrar en un `.so`**, # que es justo lo que hace falta: la UI clásica de fcitx5 es un addon que el daemon abre con # `dlopen`. Sin ese PIC estaríamos en el muro del 19-oct otra vez. # · El `check_ipo_supported` de upstream escribe la propiedad con el nombre equivocado # (`CMAKE_INTERPROCEDURAL_OPTIMIZATION` en vez de `INTERPROCEDURAL_OPTIMIZATION`), así que es un # no-op y **no hay LTO**. Conviene que siga así: una `.a` con LTO entrando en un `.so` es un # problema que no queremos buscar. # · fcitx5 incluye `` y el `install(DIRECTORY)` deja las cabeceras exactamente en # `/usr/include/yoga/`, así que resuelve por la ruta de sistema. # # ⚠ `CMAKE_INSTALL_LIBDIR=lib` EXPLÍCITO: el CMakeLists raíz hace `include(GNUInstallDirs)`, que en # algunas distros de 64 bits elige `lib64`. Todo este corpus vive en `/usr/lib`, y un artefacto que # caiga en `/usr/lib64` se sella igual y no lo encuentra nadie. name = "yoga" version = "0.0.0-042f501" license = "MIT" [source] tarball = "https://github.com/facebook/yoga/archive/042f5013152eb81c1552dec945b88f7b95ca350f/yoga.tar.gz" sha256 = "4742f41722a16f181e3da37abf943390db1e928f00f26402cb154662ae7f110f" [build] compiler = "zig-cc" target = "x86_64-linux-musl" link = "static" flags = [] [build.phases] configure = ''' set -e ZW="$PWD/.zwrap"; mkdir -p "$ZW" printf '#!/bin/sh\nexec /opt/zig/zig cc -mcpu=baseline "$@"\n' > "$ZW/cc" printf '#!/bin/sh\nexec /opt/zig/zig c++ -mcpu=baseline "$@"\n' > "$ZW/cxx" chmod +x "$ZW/cc" "$ZW/cxx" # Parche 1: fuera los tests, que bajan googletest por red. Se COMPRUEBA que la línea existía. grep -q '^add_subdirectory(tests)' CMakeLists.txt || { echo "yoga: no encuentro 'add_subdirectory(tests)' en el CMakeLists raíz — upstream lo movió." >&2 echo " Sin ese parche el configure intenta bajar googletest por red y muere sin decir por qué." >&2 exit 1 } sed -i '/^add_subdirectory(tests)$/d' CMakeLists.txt # Parche 2: fuera el -Werror de upstream. También se comprueba. grep -q -- '-Werror' cmake/project-defaults.cmake || { echo "yoga: no encuentro '-Werror' en cmake/project-defaults.cmake — upstream lo movió." >&2 exit 1 } sed -i '/^\s*-Werror$/d' cmake/project-defaults.cmake rm -rf build cmake -B build -G Ninja -Wno-dev \ -DCMAKE_C_COMPILER="$ZW/cc" -DCMAKE_CXX_COMPILER="$ZW/cxx" \ -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_LIBDIR=lib \ -DBUILD_FUZZ_TESTS=OFF ''' compile = "cmake --build build" # Guardián escrito contra las reglas de `install` del CMakeLists raíz, que es la fuente que decide # qué queda — y contra lo que el consumidor busca de verdad: `find_package(yoga REQUIRED)` más el # target `yoga::yogacore`. Las tres piezas cubren fallos distintos: # · la `.a` sin el config ⇒ find_package no la ve: sellaría un paquete invisible # · el config sin targets ⇒ find_package pasa y `yoga::yogacore` no existe, y el error sale # DENTRO de fcitx5, culpando a fcitx5 de algo que es de acá # · sin cabeceras ⇒ compila fcitx5 y no encuentra install = ''' set -e DESTDIR=/out cmake --install build [ -f /out/usr/lib/libyogacore.a ] || { echo "yoga: no quedó /usr/lib/libyogacore.a — NO sello" >&2; find /out -name 'libyoga*' 2>/dev/null >&2; exit 1; } for f in yogaConfig.cmake yogaTargets.cmake; do [ -f "/out/usr/lib/cmake/yoga/$f" ] || { echo "yoga: falta lib/cmake/yoga/$f — el find_package(yoga REQUIRED) de fcitx5 no encontraría nada" >&2; ls -R /out/usr/lib/cmake 2>/dev/null >&2; exit 1; } done # El namespace importa: fcitx5 enlaza contra `yoga::yogacore`, y ese nombre lo fija el # `NAMESPACE yoga::` del install(EXPORT). Si upstream lo cambiara, el config existiría y el target no. grep -q 'yoga::yogacore' /out/usr/lib/cmake/yoga/yogaTargets.cmake || { echo "yoga: yogaTargets.cmake no define el target yoga::yogacore — es el nombre exacto que fcitx5 enlaza" >&2; exit 1; } [ -f /out/usr/include/yoga/Yoga.h ] || { echo "yoga: falta include/yoga/Yoga.h — fcitx5 incluye " >&2; exit 1; } h=$(find /out/usr/include/yoga -name '*.h' | wc -l) echo "yoga: libyogacore.a + yogaConfig/yogaTargets + $h cabecera(s)" ''' [deps] build = ["cmake", "samurai"]