Saltar al contenido

build.rs: lo que pasa antes de compilar

Tres líneas que hacen cuatro trabajos: leer la configuración, generar el manifiesto de permisos, incrustar los metadatos de la plataforma y decidir cuándo hay que recompilar. Y el gancho que permite restringir qué comandos existen.

Qué es un script de compilación

Es una convención de Cargo, no de Tauri: si un paquete tiene un fichero build.rs en su raíz, Cargo lo compila y lo ejecuta antes de compilar el paquete. Su salida estándar es un canal de instrucciones para Cargo, y lo que escriba en el directorio de salida queda disponible para el código que se compila después.

Rust
// src-tauri/build.rs — completofn main() {    tauri_build::build()}

Ese tauri_build es la dependencia de compilación del nivel anterior. Se compila para tu máquina, corre una vez, y desaparece: no viaja dentro del binario.

Los cuatro trabajos

Por qué tocar un JSON recompila Rust

Es la consecuencia del paso 4 y desconcierta a todo el mundo la primera semana: cambias una línea de tauri.conf.json, que es un fichero de datos, y el CLI se pone a compilar Rust.

La razón es el paso 2. El manifiesto de permisos no se lee en tiempo de ejecución: se genera al compilar y acaba dentro del binario. Igual la configuración. Si no se recompilara, el programa seguiría ejecutando la versión antigua de las dos cosas.

Eso tiene una lectura de seguridad que conviene apreciar: los permisos de tu aplicación no son un fichero que alguien pueda editar en la máquina del usuario. Están compilados dentro del ejecutable, y cambiarlos exige recompilar y volver a firmar. Un modelo de permisos que viviera en un JSON junto al binario sería decorativo.

TXT
tauri.conf.json  ─┐capabilities/*.json ─┼─→ build.rs ─→ manifiesto ─→ dentro del binario ─→ firmadopermisos de los plugins ─┘

El gancho que restringe los comandos

Hay una variante de la llamada que casi nadie usa y que merece conocerse desde ahora, porque cambia una propiedad importante del modelo de permisos.

Por defecto, cualquier función marcada como comando es invocable si la capability concede el permiso general del núcleo. Es decir: el fichero de capabilities gobierna lo que hacen los plugins, pero tus propios comandos entran en bloque.

La forma de acotarlos es declarar el manifiesto de la aplicación al compilar:

Rust
// src-tauri/build.rsuse tauri_build::{Attributes, AppManifest};fn main() {    tauri_build::try_build(        Attributes::new().app_manifest(            AppManifest::new().commands(&["cargar_proyecto", "guardar_proyecto"]),        ),    )    .expect("no se pudo construir el manifiesto de la aplicación");}

Con eso, cada comando de la lista pasa a tener su propio permiso, y una capability tiene que concederlo explícitamente. Un comando que no aparezca ahí deja de ser invocable aunque exista.

Es más ceremonia, y es la diferencia entre «el frontend puede llamar a todos mis comandos» y «el frontend puede llamar a estos tres». La fase V vuelve sobre ello con el detalle completo; aquí lo que importa es saber que la puerta se cierra en build.rs y no en el fichero de capabilities.

Cuándo se toca este fichero

Casi nunca, y por eso conviene tener escrito para qué:

  • Para declarar el manifiesto de la aplicación, como arriba.
  • Para añadir tus propias instrucciones a Cargo: una variable de entorno en tiempo de compilación, un fichero generado.
  • Para incrustar información del repositorio —el hash del commit, la fecha— y poder enseñarla en la aplicación.

Todo lo demás va en la configuración, no aquí.