编译期
一个 tauri 应用在运行之前,已经有三段代码在 cargo build 里跑过了:应用的 build.rs(tauri-build)、generate_context!(tauri-macros 调 tauri-codegen)、#[command] 和 generate_handler!(tauri-macros)。源码在 crates/tauri-build/src(约 2 500 行)、crates/tauri-codegen/src(约 1 800 行)、crates/tauri-macros/src(约 1 600 行),以及它们共用的 tauri-utils 里的 config、acl/build.rs、assets.rs、html2.rs。
这三段代码之间靠文件和环境变量交接,不靠函数调用:build script 把权限清单和能力写进 OUT_DIR、用 cargo:rustc-env 留下目标三元组;generate_context! 展开时再按 OUT_DIR 环境变量找到这些文件。命令宏这一边和前两者无关,只在开了 build > removeUnusedCommands 时读一份 build script 写的允许列表。
- tauri-build:
try_build的每一步:读配置并合并TAURI_CONFIG、发desktop/mobile/dev三个 cfg、核对 Cargo feature 和配置(「does not match the allowlist」就从这里来)、通过links元数据收集 tauri 和插件的权限文件、读capabilities/并校验、把acl-manifests.json和capabilities.json写进OUT_DIR;项目里没有capabilities目录时,每次cargo build都会重跑。 - generate_context!:配置变成 Rust 字面量;
frontendDist逐个文件 brotli 压缩(debug 质量 2、release 质量 9),以内容哈希命名写进OUT_DIR再include_bytes!;配置了 CSP 时为内联脚本和.js文件算 sha256;ACL 在这里解析;整个Context在一个 8 MiB 栈的线程里构造。 - #[command] 与 generate_handler!:命令宏保留原函数,另生成一个
__cmd__包装宏,每个参数一次CommandArg::from_command;同步和 async 两种生成;async 命令借用参数为什么必须返回Result;rename_all和rename;generate_handler!展开成按命令名match的闭包。
flowchart TB tauribs["tauri 的 build.rs"] -->|"DEP_TAURI_*"| appbs["应用的 build.rs"] conf["tauri.conf.json"] --> appbs caps["capabilities 目录"] --> appbs appbs --> outdir["OUT_DIR 里的 JSON"] conf --> ctxmacro["generate_context!"] dist["frontendDist"] --> ctxmacro outdir --> ctxmacro ctxmacro --> ctx["Context"] cmd["#[command] fn"] --> wrapper["__cmd__ 包装宏"] wrapper --> handler["generate_handler! 闭包"] ctx --> run["Builder::run"] handler --> run
Context 交给 Builder 之后的事属于启动主线的运行时部分,见 Builder 与 App;generate_handler! 生成的闭包在运行时怎么被调用,见 on_message 与分发。ACL 的数据结构和解析规则属于 07 安全(权限、能力、作用域、编译期解析),这一部分只讲它们在编译期从哪里收集、写到哪里。
💬 关联讨论
发起讨论加载中...