Rust 编译器(rustc)调试实战指南:bootstrap 配置、-Z 标志、tracing 日志与源码级排障 📅 发布时间:2026/9/11 12:16:40 👁 浏览次数: Rust 编译器rustc调试实战指南bootstrap 配置、-Z 标志、tracing 日志与源码级排障【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust本篇指南围绕 rustc 编译器本身的调试展开适用于任何在 rust-lang/rust 仓库中工作、需要定位编译器内部 bug 或理解编译行为的人。文章以 rustc-dev-guide 的《Debugging the compiler》章节为核心骨架结合本仓库bootstrap.example.toml、compiler/rustc_feature/src/builtin_attrs.rs、compiler/rustc_session/src/options.rs、compiler/rustc_driver_impl/src/lib.rs等源码与配置完整覆盖从构建期开启调试信息、触发 ICE 后获取回溯到利用-Z不稳定标志、RUSTC_LOG日志过滤、#[rustc_*]测试属性、Graphviz 可视化乃至 CodeLLDB 断点调试的全套排障手段。读完你将能够配置一个可单步调试的 rustc 构建、用一行命令定位错误/延迟 bug 的发射位置、快速二分回归引入的 PR并熟练使用编译器内部的转储与日志工具。配置编译器开启调试信息默认情况下rustc 在构建时不携带大部分调试信息。要在bootstrap.toml中开启调试能力核心开关只有一个rust.debug truerust.debug true会连带打开多项调试选项例如debug-assertions、debug-logging等这些选项之后都可以单独微调但对多数人而言直接设置rust.debug true就足够了。使用 GDB 调试 rustc如果希望用 GDB 调试 rustc请在bootstrap.toml中配置rust.debug true rust.debuginfo-level 2注意以下代价磁盘占用很大可达 35GB 以上此数字来自 rustc-dev-guide 2022 年 8 月的注释编译时间显著变长若使用debuginfo-level 1即rust.debug true时的默认值可以追踪执行路径但会失去可供调试的符号信息。符号名修饰symbol mangling与 GDB 版本默认配置会启用symbol-mangling-versionv0 方案这要求 GDB 至少为 v10.2如果你的 GDB 版本较低需要在bootstrap.toml中关闭新版符号修饰rust.new-symbol-mangling false本仓库 bootstrap.example.toml 对new-symbol-mangling有更详细的说明开启 v0 方案对 profiling rustc 很有帮助因为泛型信息会保留在符号中而不是被抹平成不透明的T不显式设置时编译器及其工具使用新方案、标准库使用旧方案一旦显式设置则全代码库统一采用该值。与调试相关的完整选项速查以下选项均来自 bootstrap.example.toml 的注释可作为精细调优参考选项默认值说明rust.debugfalse总开关开启后联动下方多个选项rust.debug-assertions跟随rust.debug为编译器与标准库开启 debug 断言帮助发现 bug代价是轻微运行时变慢rust.debug-assertions-std跟随debug-assertions仅针对标准库的覆盖项rust.debug-assertions-tools跟随debug-assertions仅针对 bootstrap 构建的工具rust.debug-logging跟随debug-assertions是否在 rust 二进制中保留debug!与trace!调用默认不保留详见后文 tracing 章节rust.overflow-checks跟随rust.debug是否为编译器与标准库启用溢出检查rust.debuginfo-level若rust.debug则为1否则为0对应-C debuginfoN2会生成数 GB 调试信息并显著拖慢链接rust.debuginfo-level-rustc/-std/-tools跟随debuginfo-level针对编译器、标准库、工具的单独覆盖rust.new-symbol-mangling见上是否启用 symbol-mangling v0另外值得注意的是bootstrap.example.toml提醒不要为了最大化可调试而关闭优化——未优化的 rustc 会变得不可用的慢注释中引用了 rust-lang/rust#24840 报告的 25 倍减速且引导构建 libstd 需要数小时实际中大家通常保持optimize true。任何配置改动后都需要重新构建编译器才会生效在仓库根目录执行./x.py build之类的构建命令具体流程参见 构建章节 相关文档。抑制 ICE 转储文件RUSTC_ICE当 rustc 遇到内部编译器错误Internal Compiler ErrorICE时默认会在当前工作目录下写出一个名为rustc-ice-时间戳-pid.txt的转储文件记录 ICE 现场内容。若不需要这个文件可以设置export RUSTC_ICE0该机制在源码中有清晰实现在 compiler/rustc_driver_impl/src/lib.rs 中rustc 先读取RUSTC_ICE环境变量作为 ICE 报告文件的输出目录若其值为0则禁止写出文件随后拼接rustc-ice-{file_now}-{pid}.txt作为文件名。相应的诊断提示the environment variableRUSTC_ICEis set to ...位于 compiler/rustc_driver_impl/src/diagnostics.rs。获取崩溃回溯RUST_BACKTRACE当编译器发生 panic即 ICE时可以像调试普通 Rust 程序一样用RUST_BACKTRACE1获取panic!的堆栈回溯RUST_BACKTRACE1 rustc stage1 your-file.rs注意回溯在 MinGWWindows GNU 工具链上不工作如果遇到问题或回溯结果全是unknown建议改用 Linux、macOS 或 Windows 上的 MSVC 工具链。不带调试信息时的回溯默认配置未开启debug true下没有行号回溯大致如下stack backtrace: 0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace 1: std::sys_common::backtrace::_print 2: std::panicking::default_hook::{{closure}} 3: std::panicking::default_hook 4: std::panicking::rust_panic_with_hook 5: std::panicking::begin_panic (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~) 32: rustc_typeck::check_crate 33: std::thread::local::LocalKeyT::with 34: std::thread::local::LocalKeyT::with 35: rustc::ty::context::TyCtxt::create_and_enter 36: rustc_driver::driver::compile_input 37: rustc_driver::run_compiler开启 debug 后的回溯设置debug true后回溯会带上源码行号定位问题容易得多stack backtrace: (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~) at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:110 7: rustc_typeck::check::cast::CastCheck::check at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:572 at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:460 at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:370 (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~) 33: rustc_driver::driver::compile_input at /home/user/rust/compiler/rustc_driver/src/driver.rs:1010 at /home/user/rust/compiler/rustc_driver/src/driver.rs:212 34: rustc_driver::run_compiler at /home/user/rust/compiler/rustc_driver/src/lib.rs:253-Z不稳定调试标志rustc 拥有一批仅 nightly 可用的-Z不稳定标志其中很多对调试极有价值。想查看完整清单运行rustc -Z help其中-Z verbose-internals会打印更多调试信息。下面详细介绍几个最常用的。为错误获取回溯-Z treat-err-as-bug想在编译器发射某条错误消息的位置拿到回溯可以传-Z treat-err-as-bugn让编译器在第n条错误处主动 panic省略n时默认n 1即在第一条错误处 panic。用一个触发类型错误的例子// error.rs fn main() { 1 (); }正常情况下编译输出$ rustc stage1 error.rs error[E0277]: cannot add () to {integer} -- error.rs:2:7 | 2 | 1 (); | ^ no implementation for {integer} () | help: the trait Add() is not implemented for {integer} error: aborting due to previous error加-Z treat-err-as-bug后rustc 会在发射该错误的同时 panic 并给出回溯$ RUST_BACKTRACE1 rustc stage1 error.rs -Z treat-err-as-bug error[E0277]: the trait bound {integer}: std::ops::Add() is not satisfied -- error.rs:2:7 | 2 | 1 (); | ^ no implementation for {integer} () | help: the trait std::ops::Add() is not implemented for {integer} error: internal compiler error: unexpected panic note: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report note: rustc 1.24.0-dev running on x86_64-unknown-linux-gnu note: run with RUST_BACKTRACE1 for a backtrace thread rustc panicked at encountered error with -Z treat_err_as_bug, /home/user/rust/compiler/rustc_errors/src/lib.rs:411:12 note: Some details are omitted, run with RUST_BACKTRACEfull for a verbose backtrace. stack backtrace: (~~~ IRRELEVANT PART OF BACKTRACE REMOVED BY ME ~~~) 7: rustc::traits::error_reporting::impl rustc::infer::InferCtxta, tcx ::report_selection_error at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:823 8: rustc::traits::error_reporting::impl rustc::infer::InferCtxta, tcx ::report_fulfillment_errors at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:160 at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:112 9: rustc_typeck::check::FnCtxt::select_obligations_where_possible at /home/user/rust/compiler/rustc_typeck/src/check/mod.rs:2192 (~~~ IRRELEVANT PART OF BACKTRACE REMOVED BY ME ~~~) 36: rustc_driver::run_compiler at /home/user/rust/compiler/rustc_driver/src/lib.rs:253这样一来错误从哪段代码发射出来一目了然。调试 delayed bugs-Z eagerly-emit-delayed-bugsrustc 的延迟 bugdelayed bug通常不会立即展示给用户。-Z eagerly-emit-delayed-bugs会把它们转成普通错误使其可见并且可以和-Z treat-err-as-bug组合使用——在某个特定延迟 bug 处停下并拿到回溯非常适合排查那些晚一步才暴露的 ICE。定位错误发射位置-Z track-diagnostics-Z track-diagnostics借助#[track_caller]在每条错误旁边打印其创建位置例如$ RUST_BACKTRACE1 rustc stage1 error.rs -Z track-diagnostics error[E0277]: cannot add () to {integer} -- src\error.rs:2:7 | 2 | 1 (); | ^ no implementation for {integer} () -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs:638:39 | help: the trait Add() is not implemented for {integer} help: the following other types implement trait AddRhs: a f32 as Addf32 a f64 as Addf64 a i128 as Addi128 a i32 as Addi32 a i64 as Addi64 a i8 as Addi8 a isize as Addisize and 48 others For more information about this error, try rustc --explain E0277.它与-Z treat-err-as-bug相似但不同它为所有发射的错误打印位置而非只停在第一条不需要用调试符号构建的编译器不必通读冗长的堆栈回溯。这三个标志的解析与默认值定义在 compiler/rustc_session/src/options.rstreat_err_as_bug是OptionNonZerousize类型默认Noneeagerly_emit_delayed_bugs与track_diagnostics均为布尔型默认false其中treat_err_as_bug是TRACKED标志其余为UNTRACKED它们随后在 compiler/rustc_session/src/config.rs 被组装进编译器配置。使用 tracing 日志RUSTC_LOGrustc 内部使用tracingcrate 打点遍布大量debug!、trace!、info!调用是缩小 bug 范围、理解编译流程的首选手段。完整用法见 tracing 章节这里给出最常用的几条命令# 打印 rustc_middle::traits 模块内的所有 debug 级别及以上日志 RUSTC_LOGrustc_middle::traitsdebug rustc stage1 my-file.rs # 重定向到文件避免刷屏 RUSTC_LOGrustc_middle::traitsdebug rustc stage1 my-file.rs 2traits-log # 按函数过滤配合 #[instrument] 注解只打印 borrowck 某函数的日志 RUSTC_LOGrustc_borrowck[do_mir_borrowck] rustc stage1 my-file.rs # 按 query 过滤例如只看 typeck 阶段 RUSTC_LOG[typeck] rustc stage1 my-file.rs # 查看 codegen 了哪些函数info! 级别在正式发布版也可用 RUSTC_LOGrustc_codegen_ssainfo rustc stage1 my-file.rs相关环境变量还包括RUSTC_LOG_COLORauto/always/never、RUSTC_LOG_ENTRY_EXIT、RUSTC_LOG_THREAD_IDS、RUSTC_LOG_BACKTRACE、RUSTC_LOG_LINES、RUSTC_LOG_FORMAT_JSON、RUSTC_LOG_OUTPUT_TARGET其定义集中在compiler/rustc_log/src/lib.rs。重要前提debug!和trace!调用默认在编译产物中被移除只有error!、warn!、info!始终保留。如果设置RUSTC_LOG后看不到DEBUG日志请确认bootstrap.toml中rust.debug-logging true已开启它默认跟随debug-assertions即默认关闭。二分定位回归cargo-bisect-rustccargo-bisect-rustc工具可以快速、自动地找出哪个 PR 改变了 rustc 行为。它会自动下载 rustc 的 PR 构建产物针对你提供的测试项目反复编译直到定位到引入回归的那次改动随后查看对应 PR 即可了解变更原因。使用教程见 rustc-dev-guide 的相关 tutorial 页面可通过 rustc-dev-guide 目录 索引查找。从 CI 下载构建产物rustup-toolchain-install-masterrustup-toolchain-install-master工具作者 kennytm可以根据某个 SHA1 直接下载 Rust CI 的构建产物——这基本对应某个 PR 成功合入的状态——并安装到本地使用。它也支持bors try产生的实验性产物。当你只想检查某个 PR 的构建结果、又不想自己完整构建一遍时这个工具非常省时。#[rustc_*]测试属性一键转储编译器内部信息编译器定义了大量内部perma-unstable属性可转储编译器内部信息统一以rustc_为前缀由内部 featurerustc_attrs门控通过#![feature(rustc_attrs)]开启。完整的、最新的清单可以在 compiler/rustc_feature/src/builtin_attrs.rs 中找到其中被标记为TEST的那批即调试用途。以下是值得关注的一部分属性说明rustc_dump_def_parents转储某个定义def的DefId父级链rustc_dump_def_path转储某个 item 的def_path_strrustc_dump_generics转储某个 item 的泛型rustc_dump_hidden_type_of_opaques转储 crate 中每个 opaque 类型的隐藏类型见 opaque types 章节rustc_dump_inferred_outlives转储 item 的隐含约束implied bounds即inferred_outlives_of的结果rustc_dump_item_bounds转储 item 的item_boundsrustc_dump_layout转储类型布局见下文调试类型布局rustc_dump_object_lifetime_defaults转储 item 的对象生命周期默认值rustc_dump_clauses转储 item 的clauses_ofrustc_dump_symbol_name转储 item 的修饰mangled与反修饰demangled符号名rustc_dump_variances转储 item 的型变variance见 variance 章节rustc_dump_vtable转储 impl 或 dyn 类型别名的 vtable 布局rustc_regions转储 NLL 闭包区域需求其中涉及def_path_str、inferred_outlives_of、item_bounds、clauses_of、symbol_name等都是TyCtxt上的查询方法可在compiler/rustc_middle/src/ty/context.rs中进一步查阅其实现。用rustc_dump_layout调试类型布局在类型上标注#[rustc_dump_layout(debug)]即可转储该类型的Layout。例如#![feature(rustc_attrs)] #[rustc_dump_layout(debug)] type Ta a u32;会输出error: layout_of(u32) Layout { size: Size(8 bytes), align: AbiAlign { abi: Align(8 bytes), }, backend_repr: Scalar( Initialized { value: Pointer( AddressSpace( 0, ), ), valid_range: 1..18446744073709551615, }, ), fields: Primitive, largest_niche: Some( Niche { offset: Size(0 bytes), value: Pointer( AddressSpace( 0, ), ), valid_range: 1..18446744073709551615, }, ), uninhabited: false, variants: Single { index: 0, }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847, } -- src/lib.rs:4:1 | 4 | type Ta a u32; | ^^^^^^^^^^^^^^^^^^^^^输出以error形式呈现这只是因为属性转储走了诊断通道实际展示了引用类型的大小、对齐、标量表示、有效值范围、niche 等信息——对研究内存布局、niche 优化如OptionT的优化极有帮助。Layout结构体定义于compiler/rustc_public/src/abi.rs中。格式化 Graphviz 输出.dot 文件部分调试选项会产出 Graphviz 图。例如在函数上标注#[rustc_mir(borrowck_graphviz_postflowsuffix.dot)]配合-Zdump-mir-dataflow会转储借用检查器borrowck的数据流图。这类选项都会生成.dot文件安装 graphviz如apt-get install graphviz后即可查看$ dot -T pdf maybe_init_suffix.dot maybe_init_suffix.pdf $ firefox maybe_init_suffix.pdf # 或任意 pdf 阅读器Graphviz 自带的预处理程序unflatten有时能让输出布局不那么松散。它读入一个 dot 文件、输出另一个 dot 文件因此可以直接放进管道$ unflatten mir_dump/*.foo.-------.nll.0.regioncx.all.dot | dot -Tpdf -o foo-outlives.pdf这对于查看借用检查器输出的复杂 region outlives 图尤其有用相关背景可参考 borrow check 调试章节。调试借用检查器借用检查器borrow checker的调试有专门的章节borrow-check/debugging.md其中涵盖了 MIR 转储、region 推断图等针对性内容。当问题出在借用检查阶段时请优先查阅该章节而非通用手段。在 VSCode 中用 CodeLLDB 调试 rustc如果你使用 VSCode并且已在bootstrap.toml中对感兴趣的代码部分请求了 debuginfo 级别 1 或 2就可以用 CodeLLDB 扩展直接调试它。下面是一个launch.json示例用于直接从构建目录运行 stage1 编译器无需安装// .vscode/launch.json { version: 0.2.0, configurations: [ { type: lldb, request: launch, name: Launch, args: [], // 传给编译器的命令行参数字符串数组 program: ${workspaceFolder}/build/host/stage1/bin/rustc, windows: { // 在 Windows 上适用 program: ${workspaceFolder}/build/host/stage1/bin/rustc.exe }, cwd: ${workspaceFolder}, // 程序启动时的工作目录 stopOnEntry: false, sourceLanguages: [rust] } ] }调试时只需在args中填入传给 rustc 的参数例如[-Ztreat-err-as-bug, error.rs]即可在任意 rustc 源码位置下断点、单步观察编译过程。若改用 GDB 命令行调试记得按前文配置rust.debug true与rust.debuginfo-level 2以获得完整符号与行号。小结调试 rustc 的核心思路是让编译器自证其行先通过bootstrap.toml打开调试信息与debug-logging再用RUST_BACKTRACE获取 ICE 回溯、用-Z treat-err-as-bug与-Z track-diagnostics定位错误发射点、用-Z eagerly-emit-delayed-bugs暴露延迟 bug、用RUSTC_LOG过滤追踪编译器内部流程最后辅以#[rustc_*]属性转储、Graphviz 可视化与 CodeLLDB/GDB 断点几乎可以系统性地攻克绝大多数编译器内部问题。相关调试手段的完整索引与更多专题增量编译调试、LLVM 后端调试等可参见 rustc-dev-guide 总目录。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考