Rust 编译器中的 rustc_public:为第三方工具设计的 rustc 公共 API 层
Rust 编译器中的 rustc_public为第三方工具设计的 rustc 公共 API 层【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rustrustc_public是 Rust 编译器仓库内一个正在孵化中的公开接口 crate它的目标是让验证引擎、linter、代码生成器等第三方工具能够以稳定的方式查询和分析 Rust 程序的类型信息、MIR 与 ABI 细节。本文基于 compiler/rustc_public/README.md 的设计说明结合仓库源码逐层拆解其“双 crate”架构、内部标识符互译机制与run!会话入口帮助读者理解这一编译器公共 API 的设计思路与当前使用方式。一、开发状态与当前使用方式README 首先交代了这个 crate 所处的阶段rustc_public目前与编译器一起在内树in-tree中开发尚未发布到 crates.io目标是将其发布为 crates.io 上的正式 crate在发布之前用户需要像使用其他 rustc crate 一样使用它通过 rustup 安装rustc-dev组件并在代码中将rustc-public声明为外部 crate。这一点可以从 Cargo.toml 得到印证crate 版本为0.1.0-preview采用 2024 edition并且全部核心依赖都指向仓库内路径rustc_middle、rustc_hir、rustc_span、rustc_abi、rustc_target、rustc_crate_store以及 rustc_public_bridge这正是典型的 in-tree crate 形态。crate 的文档头注释src/lib.rs也明确了目标读者与愿景//! This crate provides a public API for querying and analyzing Rust programs through the //! compilers internal representations. It is designed for third-party tools such as //! verification engines, linters, and code generators that need access to type information, //! MIR bodies, monomorphized instances, and ABI details.需要注意的限制该 API 尚未发布且仍处于破坏性变更阶段“This API is not yet published and is still subject to breaking changes”任何基于它构建的工具都必须做好跟进内树演化的准备。crate 目录下的 rust-toolchain.toml 则固定了构建它所需的工具链。二、总体设计借鉴 proc-macro2 的双 crate 拆分README 的 Design 一节 给出了核心架构决策rustc_public采用与proc-macro2类似的思路把实现拆分为两个 craterustc_public对外发布的公共 crate包含“稳定”stable的数据结构以及对rustc_public_bridgeAPI 的调用。公共类型与编译器内部类型之间的翻译也发生在这个 crate 里rustc_public_bridge面向编译器一侧的 crate负责实现“对编译器的公开 API”收集所有被请求的信息并以不稳定的内部形态把数据提供给rustc_public。调用关系是单向的工具依赖rustc_publicrustc_public再通过rustc_public_bridge定义的 API 调用编译器。README 用一张 ASCII 图表达了这种隔离┌────────────────────────────┐ ┌───────────────────────────┐ │ External Tool │ │ Rust Compiler │ │ ┌────────────┐ │ │ ┌────────┐ │ │ │ │ │ │ │ │ │ │ │rustc_public│ │ │ │rustc │ │ │ │ │ ├──────────►| │public │ │ │ │ │ │◄──────────┤ │bridge │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └────────────┘ │ │ └────────┘ │ └────────────────────────────┘ └───────────────────────────┘这个拆分的意义在于未来要发布到 crates.io 的只有左侧的rustc_public而右侧rustc_public_bridge可以随编译器自由演化。桥的接口一旦稳定内部实现的重构就不会破坏对外契约。源码印证Bridge 类型映射“翻译”职责在源码中体现得非常具体。compiler_interface.rs 定义了一个BridgeTys结构并实现rustc_public_bridge::Bridgetrait把每一类编译器内部类型映射为一个公共稳定类型pub struct BridgeTys; impl Bridge for BridgeTys { type DefId crate::DefId; type AllocId crate::mir::alloc::AllocId; type Span crate::ty::Span; type Ty crate::ty::Ty; type InstanceDef crate::mir::mono::InstanceDef; type Layout crate::abi::Layout; // ... 还有 CrateItem、AdtDef、TraitDef、StaticDef 等 }而在 src/lib.rs 中bridge_impl!宏批量为CrateItem、AdtDef、ForeignModuleDef、FnDef、ClosureDef、TraitDef、ImplDef、StaticDef等二十余类稳定类型实现了桥的构造 traitrustc_public_bridge::bridge::*。也就是说README 中说的“公共与内部结构之间的翻译在rustc_public完成”落点就是这些impl ... for 稳定类型。反向的互转能力则由unstable特性门控的 rustc_internal 模块 提供stable()把内部项转成稳定项internal()把稳定项转回内部项需要TyCtxt且明确要求“并非所有稳定项都能转回去”。rustc_public_bridge收集信息的编译器侧代理rustc_public_bridge/src/lib.rs 的文档注释与 README 的描述一一对应Crate that implements what will become the rustc side of rustc_public. This crate serves as a proxy for making calls to rustc queries. This crate is not intended to be invoked directly by users.它依赖rustc_middle的TyCtxt、mir、ty等内部设施对外暴露 CompilerCtxt 作为查询入口。README 提到该 API “仍然完全不稳定still completely unstable and subject to change”源码注释同样如此声明。三、核心机制Tables 互译表与内部标识符两个 crate 之间传递的不是编译器内部的DefId、Ty、Span而是一组轻量级的“稳定句柄”。互译的枢纽是 rustc_public_bridge/src/lib.rs 中的Tablespub struct Tablestcx, B: Bridge { pub def_ids: IndexMapDefId, B::DefId, pub alloc_ids: IndexMapAllocId, B::AllocId, pub spans: IndexMaprustc_span::Span, B::Span, pub types: IndexMapTytcx, B::Ty, pub instances: IndexMapty::Instancetcx, B::InstanceDef, pub ty_consts: IndexMapty::Consttcx, B::TyConstId, pub mir_consts: IndexMapmir::Consttcx, B::MirConstId, pub layouts: IndexMaprustc_abi::Layouttcx, B::Layout, }其工作方式同文件 L241-L275是IndexedValtrait 让每个稳定句柄都可以与一个usize下标互转IndexMap::create_or_fetch在首次遇到某个内部值时用当前表长度生成新句柄并缓存重复遇到则直接返回已有句柄——即“interning驻留/索引化”反查时Index实现会断言句柄与表项一致assert_eq!(*v, index, Provided value doesnt match with indexed value)防止跨会话使用失效句柄。因此稳定类型本质上只是对一次编译会话内 Tables 下标的包装。这带来一个设计约束这些值只在run!回调的会话内有效。src/lib.rs 中的ThreadLocalIndex标记类型正是为此服务——它使CrateNum等带索引的类型变为!Send/!Sync从类型系统层面阻止用户把某次会话的句柄移动到没有或有另一个rustc_public上下文的线程里源码注释也坦承这不能杜绝“在两次不同run!之间混用DefId”这类误用。四、会话入口run! 宏与编译流程挂钩rustc_public的入口是run!宏它负责搭建编译器会话并在合适的时机执行用户回调。src/lib.rs 的文档注释给出了官方示例use rustc_public::*; use std::ops::ControlFlow; let result run!(args, || - ControlFlow() { // Find all crates with the same name (potential duplicates). for krate in external_crates() { let dupes find_crates(krate.name); if dupes.len() 1 { println!(Warning: multiple versions of {}, krate.name); } } ControlFlow::Continue(()) });宏的实际定义在 rustc_internal/mod.rsrun!($args, $callback)接受“编译参数 回调”回调可以是一个无参函数标识符也可以是一个闭包表达式两种形式都会归约到内部的run_driver!run_with_tcx!与run!类似但会把编译器的TyCtxt传入回调供需要直接调用内部 API 的场景使用宏文档明确说明回调在“编译器完成全部分析之后、代码生成之前”被调用invoked after the compiler ran all its analyses, but before code generation。这意味着工具拿到的是完成类型检查、MIR 构建等分析后的完整数据。从 run_driver! 的展开结构看它导入了rustc_driver::{Callbacks, Compilation, run_compiler}与rustc_interface::interface并定义一个RustcPublic会话结构体——从源码结构看宏是把用户的回调包装进rustc_driver的Callbacks机制由run_compiler驱动整条编译流水线在分析阶段末尾触发回调并以std::ops::ControlFlow决定是否跳过后续代码生成。线程局部上下文与嵌套防护回调执行期间会话状态保存在 compiler_interface.rs 的 scoped thread-local 变量中// A thread local variable that stores a pointer to [CompilerInterface]. scoped_tls::scoped_thread_local!(static TLV: Cell*const ());run()在进入时检查TLV.is_set()若已有会话则直接返回Err(rustc_public already running)禁止嵌套调用所有公开查询函数如local_crate()、entry_fn()内部都通过with(|cx| ...)从 TLS 取出当前的CompilerInterface再执行查询因此所有查询必须在run!回调内完成——这也正是 lib.rs 文档强调的原因“data structures are tied to the compilers thread-local state”。rustc_public通过scoped-tls依赖见 Cargo.toml实现这一机制同时用tracing输出调试日志例如 compiler_interface.rs 中smir_crate对每次 crate 转换的debug!记录。五、公开查询 API 面在会话内工具可用的顶层 API 由 src/lib.rs 提供可归纳为“crate 发现”和“条目遍历”两类API作用local_crate()获取当前正在编译的本地 crateexternal_crates()列出编译会话中所有外部依赖cratefind_crates(name)按名称查找 crate同一依赖的不同版本会返回多个同名 crateentry_fn()获取程序入口点库 crate 返回Noneno_stdcrate 可能解析到#[start]函数all_local_items()获取本地 crate 中所有带 MIR body 的条目函数、闭包、带初始化的 static、常量all_trait_decls()/all_trait_impls()获取本地 crate 及其全部依赖的 trait 声明与实现含私有 trait对单个 crateCrate结构体lib.rs 提供了foreign_modules()、trait_decls()、trait_impls()、fn_defs()、statics()、adts()六类查询。文档注释对本地 crate 与外部 crate 的可见性差异作了重要说明本地 crate 会包含私有项而外部 crate 只返回元数据中可用的项。CrateItemlib.rs则是条目级分析的主力body()/expect_body()取 MIR body外部项或编译器内建项可能没有 body、has_body()预判、kind()区分函数/static/const/构造器、requires_monomorphization()判断是否泛型、ty()取类型、is_foreign_item()判断是否声明于extern块emit_mir()可直接把 MIR 文本 dump 到任意io::Write。稳定 IR 的具体内容分布在 src/ty/、src/mir/、src/abi.rs、src/target.rs 与 src/visitor.rs 中对应类型系统、MIR、函数 ABI 与内存布局、目标机器信息字节序、指针宽度以及遍历器。六、rustc_internal 特性门通往编译器内部的“后门”Cargo.toml 声明了唯一的特性开关注释写得非常直白[features] # Provides access to APIs that expose internals of the rust compiler. # APIs enabled by this feature are unstable. They can be removed or modified # at any point and they are not included in the crates semantic versioning. rustc_internal []开启该特性后rustc_internal 模块 才会被编译进来它提供stable()/internal()稳定 IR 与 rustc 内部 IR 的双向转换run()给已经有TyCtxt的宿主即内树工具直接挂接rustc_public上下文pretty子模块MIR 的美化打印。仓库内树自己就是第一个用户rustc_driver_impl/Cargo.toml 以rustc_public { path ../rustc_public, features [rustc_internal] }依赖它并在 pretty.rs 中调用rustc_public::rustc_internal::pretty::write_smir_pretty。从源码结构看rustc的 MIR 打印路径已经部分改走rustc_public的稳定 MIR可以推断官方正在用内树消费来验证稳定 IR 的完备性。七、序列化稳定 IR 的 JSON 友好设计稳定句柄被刻意设计为可序列化类型lib.rs 引入了serde::SerializeCrateNum、DefId、Layout、Ty等通过serialize_index_impl!宏序列化为纯数字本质是 Tables 中的下标。src/tests.rs 用一组单元测试固化了这一约定#[test] fn serialize_cratenum() { check_serialize(CrateNum(1, ThreadLocalIndex), 1); } // serialize_defid - 2, serialize_layout - 3, serialize_ty - 5, // serialize_span - 8, serialize_instancedef - 10 ...这类设计让工具可以低成本地把查询结果落盘、传输或嵌入报告Crate等结构也都派生了Serialize同时以确定性下标保证同一会话内句柄的可复现性。八、小结与适用边界综合 README 与源码rustc_public的定位与机制可以概括为双 crate 架构rustc_public持有稳定数据结构与翻译逻辑rustc_public_bridge负责向编译器收集信息并以不稳定内部形态回传工具只依赖前者与 proc-macro2 式的“稳定外壳 实现内核”模式一致索引化互译Tables将DefId、Ty、Span、Instance、常量、布局等内部值驻留为数字句柄配合ThreadLocalIndex在类型层面约束其线程/会话作用域会话式使用一切查询必须发生在run!回调内回调在编译分析完成、代码生成之前执行TLS 上下文禁止嵌套渐进开放稳定 API 面向第三方工具rustc_internal特性门控的内核 API 供内树工具如 driver 的 MIR 打印直接互转。适用边界方面该 crate 目前版本为0.1.0-preview尚未发布到 crates.ioAPI 存在破坏性变更的可能使用前提是 rustup 的 nightly 工具链加rustc-dev组件并将rustc-public声明为外部 crate。对计划构建 MIR 级分析、验证或代码生成工具的同学而言现在跟踪 compiler/rustc_public 目录的演化、并以 rustc_public_bridge 的接口稳定性作为判断发布时机的信号是最务实的路径。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →