rust打印闭包的插件实现

背景

“调试”编译器的某些行为时,可以通过编译器错误输出来判断
比如想知道一个类型是否实现了某个trait

fn main() {
   
    use std::fmt::Debug;
    struct A;
    fn foo<T: Debug>(t: T) {
   }

    let a = A;
    foo(A);
}

提示:required by this bound in foo
意思就是:结构体A没有实现Debug trait

解决方式

有些涉及编译器内部处理的逻辑并不会通过编译提示输出,但研究某段代码时想看看rustc怎么编译
比较暴力的方法就是直接修改编译器源代码插入日志
但是由于编译器项目巨大,想拿到结果会耗时耗力

所幸rustc项目优秀的架构设计和API文档使得程序化调用rustc内部逻辑非常方便
下文写一个编译器插件,输出Rust闭包的内部结构

Rustc Driver 和 Rustc Interface

https://rustcrustc.github.io/rustc-dev-guide-zh/rustc-driver.html

介绍

【大概解释】
rustc_driver 本质上是 rustc 的 main() 函数,它使用 rustc_interface crate 中定义的接口,按正确顺序执行编译器各个阶段

rustc_interface crate 为外部用户提供了一个(不稳定的)API,用于在编译过程中的特定时间运行代码
从而允许第三方有效地使用 rustc 的内部代码作为库来分析 crate 或在进程中模拟编译器(例如 RLS 或 rustdoc )

对于那些将 rustc 作为库使用的用户,rustc_driver工作如下:

  • rustc_interface::run_compiler() 函数是编译器的主要入口点
  • 它接受一个编译器配置参数,以及一个接受 Compiler 参数的闭包
  • run_compiler 从配置中创建一个 Compiler 并将其传递给闭包
  • 在闭包内部,使用 Compiler 来驱动查询以编译 crate 并获取结果

【更详细的解释】
rustc_driver是Rust编译器自带的一个Crate,它提供了一个用于驱动Rust编译过程的接口
具体来说,rustc_driver Crate 提供了使用 Rust 编译器进行编译的功能
可以处理编译相关的任务,包括读取源码、解析语法、类型检查、生成中间代码等
它是 Rust 编译器的核心部分之一,可以作为开发者构建自定义编译工具或进行编译相关操作的重要工具。

将rustc_driver Crate 导入到当前的 Rust 代码文件中,以便使用其中定义的类型和函数来执行与编译器相关的任务
这样,开发者可以利用rustc_driver Crate 提供的功能来扩展和自定义 Rust 编译器的行为

rustc_interface是一个Rust的内置Crate,它提供了与Rust编译器接口交互的能力
它是Rust编译器在编译过程中不可或缺的部分,可以用于将源代码编译为可执行文件或库
具体而言,rustc_interface Crate 包含了一系列类型和函数,用于读取、解析、转译和执行Rust代码

【用法】
通过 rustdocs 查看 Compiler 当前可用的查询

通过查看 rustc_driver 的实现,特别是 rustc_driver::run_compiler 函数(不要与 rustc_interface::run_compiler 混淆)
来查看如何使用它们

rustc_driver::run_compiler 接受一堆命令行参数和一些其他配置,并指定相关的编译参数和源代码,推动编译完成
rustc_driver::run_compiler 接受一个 Callbacks,它是一个允许自定义编译器配置以及允许一些自定义代码在编译的不同阶段之后运行的 trait

【注意】
本质来说,编译器内部 API 总是不稳定的,但是会尽力避免不必要的破坏

方法

rustc_driver::init_rustc_env_logger

pub fn init_rustc_env_logger(handler: &EarlyErrorHandler)

without having to magically match rustc’s tracing crate version
工具可以在不必像魔术般匹配 rustc 的 tracing crate 版本的情况下,启用 Rust 的日志记录(enable rust logging)

rustc_driver::catch_with_exit_code

pub fn catch_with_exit_code(
    f: impl FnOnce() -> Result<(), ErrorGuaranteed>
) -> i32

Variant of catch_fatal_errors for the interface::Result return type that also computes the exit code
针对 interface::Result 返回类型的 catch_fatal_errors 变种,同时计算退出码
退出码通常用于表示程序在结束时返回给操作系统的状态指示

rustc_driver::catch_fatal_errors

pub fn catch_fatal_errors<F, R>(f: F) -> Result<R, ErrorGuaranteed>
where
    F: FnOnce() -> R,

Runs a closure and catches unwinds triggered by fatal errors.
该代码运行一个闭包(closure)并捕获由致命错误引起的异常取消(catches unwinds triggered by fatal errors)

The compiler currently unwinds with a special sentinel value to abort compilation on fatal errors.
This function catches that sentinel and turns the panic into a Result instead.
编译器当前在致命错误发生时会使用特殊的标记值(哨兵值)(a special sentinel value)来取消编译。
该函数捕获该标记值,然后将 panic 转换成一个 Result 类型的返回值。

这段代码用于处理编译器在遇到致命错误时可能引发的 panic。
它将该 panic 转换成一个 Result 类型的返回值,能够以更优雅的方式处理异常状况,而不是直接终止程序的执行。

步骤

安装rustup

在macOS上需要提前安装xcode命令行 xcode-select --install

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none --profile minimal -y

创建插件项目

cargo new --bin rustc-plugin
cd rustc-plugin

// 从界面输入中重定向到输出
cat <<EOF > rust-toolchain
[toolchain]
channel = "nightly"
components = [ "rustc-dev", "llvm-tools-preview", "rust-src" ]
EOF

编写插件

// 打开rustc_privatefeature,能够直接调用rust编译器的内置函数和注入回调获取想要的信息
#![feature(rustc_private)]

// extern crate语法来导入外部的Crate
// 在之前初始化环境步骤里通过rustup(components = [ "rustc-dev" ])自动安装到本地的
// 相当于rustc编译器的入口函数,通过它们可以程序式地唤起编译流程,比如设置自定义编译配置
// 在最新版本的Rust中,extern crate已被弃用,不再需要显式导入Crate
// 可以使用use语句来引入Rust的内置Crate
extern crate rustc_driver;
extern crate rustc_interface;
extern crate rustc_session;
use rustc_session::config::ErrorOutputType;
use rustc_session::{
   EarlyErrorHandler};

struct MyCallback;

fn fatal_deal_function() -> i32 {
   
    42 // 在这个例子中,只是返回一个简单的整数
}

fn main() {
   
    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
    rustc_driver::init_rustc_env_logger(&handler);

    let result = rustc_driver::catch_fatal_errors(|| fatal_deal_function());
    match result {
   
        Ok(value) => {
   
            println!("Function executed successfully: {}", value);
        }
        Err(_) => {
   
            println!("Function encountered a fatal error.");
        }
    }
}

声明回调类型

rustc的Callbacks trait如下:

pub trait Callbacks {
   
    // Provided methods
    fn config(&mut self, _config: &mut Config) {
    ... }
    fn after_crate_root_parsing<'tcx>(
        &mut self,
        _compiler: &Compiler,
        _queries: &'tcx Queries<'tcx>
    ) -> Compilation {
    ... }
    fn after_expansion<'tcx>(
        &mut self,
        _compiler: &Compiler,
        _queries: &'tcx Queries<'tcx>
    ) -> Compilation {
    ... }
    fn after_analysis<'tcx>(
        &mut self,
        _compiler: &Compiler,
        _queries: &

你可能感兴趣的:(rust,rust,开发语言,后端)