尧图精选

Rust 编译器测试指南:minicore 测试辅助库与 `core` 存根的使用方法

🕒 发布时间:2026/9/13 2:29:51 📁 来源:尧图网络
Rust 编译器测试指南minicore 测试辅助库与core存根的使用方法【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust导读minicore是 Rust 编译器rustc测试套件中一个特殊的测试辅助库test auxiliary它以#![no_core]的方式从零存根stub出core中与编译器测试相关的核心语言项lang item、标记 trait、内建宏与内建函数让需要交叉编译目标、但又不依赖完整core预编译库的 ui / codegen / assembly / mir-opt 测试能够快速构建。读完本文你将掌握通过// add-minicore指令启用该辅助库的完整姿势、其隐含的编译器标志、如何在测试中引入minicore存根以及如何结合仓库源码理解其底层实现与维护约定。minicore是什么tests/auxiliary/minicore.rs是专门服务于 ui、codegen、assembly、mir-opt 这四类测试套件的辅助文件。它的核心定位是为那些需要面向交叉编译目标构建、但既不需要也不希望真正运行也不愿意用-Zbuild-std拉取完整标准库的测试提供core的存根实现。从源码文件头部注释可以看到它的设计动机Auxiliaryminicoreprelude which stubs outcoreitems forno_coretests that need to work in cross-compilation scenarios where nocoreis available (that dont want nor need to-Zbuild-std).也就是说当测试需要验证的是「编译器在某个目标平台上生成的代码/汇编是否符合预期」而不是「标准库在这个平台上的行为」时直接搬出完整的core往往是杀鸡用牛刀——此时minicore提供了一个最小化的、足以让编译器完成语义检查与代码生成的存根集合。适用范围的重要警告官方文档特别强调了一条边界这一点在源码中也以注释形式反复出现minicore仅用于core项明确不用于std或alloc项原因在于core项适用于更广泛的测试场景而std/alloc依赖的运行时设施太多不适合用存根替代。如何在测试中使用minicore使用minicore一共需要三步在测试文件头部的编译测试指令directive区声明// add-minicore在 crate 属性区同时声明#![feature(no_core)]、#![no_std]与#![no_core]——这表示本测试既不链接标准库也不需要core预置项将minicore引入测试作用域2015 edition 使用extern crate minicore;2018 edition 使用use minicore;或按需use minicore::*;。下面是一个最小可用的结构示例来自 rustc-dev-guide 文档原文// add-minicore // revisions: meow bark //[meow] compile-flags: --targetx86_64-unknown-linux-gnu //[meow] needs-llvm-components: x86 //[bark] compile-flags: --targetwasm32-unknown-unknown //[bark] needs-llvm-components: webassembly #![crate_type lib] #![feature(no_core)] #![no_std] #![no_core] extern crate minicore; use minicore::*; struct Meow; impl Copy for Meow {} // Copy here is provided by minicore // CHECK-LABEL: meow #[unsafe(no_mangle)] fn meow() {}注意其中impl Copy for Meow {}的Copy并非来自真实core而是由minicore提供的存根——这正是它在no_core环境下发挥作用的关键。隐含的编译器标志由于使用minicore的测试本质上是no_stdno_core构建不支持展开式unwindingpanic因此// add-minicore会隐式地也要求为测试构建加上如下两个标志-C panicabort-C force-unwind-tablesyes其中force-unwind-tablesyes的目的是在汇编assembly测试中保留 CFICall Frame Information指令使生成的汇编符合预期输出。源码层面的实现佐证这两条隐含标志并非文档空谈在 runtest.rs 中可以找到确切的落地代码并附有注释解释其设计意图// minicore requires #![no_std] and #![no_core], which means no unwinding panics. if self.props.add_minicore { compiler.arg(-Cpanicabort); compiler.arg(-Cforce-unwind-tablesyes); }值得留意的是这段代码是在「添加用户自定义编译标志」之前执行也就是说先改变默认值再叠加用户 flags。源码注释runtest.rs同时指出一个已知的改进空间FIXME目前如果用户在测试里显式写了非abort的-Cpanic或非yes的-Cforce-unwind-tablescompiletest 并不会报错或警告——部分测试恰恰需要「以特定方式混合 panic 模式被拒绝」的行为所以只是先改变默认值而不强制覆盖。此外minicore自身作为辅助库被编译时也会携带-Cpanicabort见 runtest.rs 中的rustc.arg(-Cpanicabort)。支持与不支持的模式// add-minicore并非在所有测试模式下都可用。在 directives.rs 的update_add_minicore处理逻辑中compiletest 会做两层校验仅支持四种测试模式ui、codegen、assembly、mir-opt其他模式例如 run-make会直接panic!报错add-minicore is currently only supported for ui, codegen, assembly and mir-opt test modes不能与 run-pass 类模式组合如果测试声明了PassFailMode::RunPass同样会panic!add-minicore cannot be used to run the test binary原因很直接——minicore只是core的存根产物并不能真正运行。这也解释了为什么minicore面向的始终是「只编译、不运行」的测试类别。另外在 handlers.rs 与 directive_names.rs 中可以确认add-minicore是 compiletest 内置的命名指令known directive之一早期指令检查do_early_directives_check会校验其书写规范。minicore的构建与注入流程minicore是如何进入每个测试的编译命令的整个流程在 compiletest 中可以分为三步预编译辅助库build_minicore()runtest.rs使用测试输出目录下的libminicore.rlib作为产物路径以--crate-type rlib、-Cpanicabort以及minicore_compile_flags编译tests/auxiliary/minicore.rs路径来自config.minicore_path。若编译失败会以「auxiliary build of ... failed to compile」终止测试。通过--extern注入compose_and_run_compiler()runtest.rs在真正编译测试文件前检查self.props.add_minicore若为真则追加--extern minicorerlib路径。辅助文件同样生效当被测文件依赖其他 auxiliary 文件时runtest.rs 也会为 auxiliary 构建注入等价的--extern minicore...参数。也就是说minicore在 compiletest 眼中是一个「按需预编译、按需注入」的普通外部 crate只是它的内容恰好是core的存根。minicore源码结构深度解析tests/auxiliary/minicore.rs本身就是一个完整的#![no_std] #![no_core]crate其源码本身就是一份绝佳的「最小core骨架」教材。它启用了no_core、intrinsics、lang_items、auto_traits、negative_impls、repr_simd、f16/f128、asm_experimental_arch等一长串 feature并整体#![allow(unused, improper_ctypes_definitions, internal_features, non_camel_case_types)]以保持整洁。标记 trait 与语言项lang itemminicore用#[lang ...]属性声明了大量编译器必需的内部语言项例如语言项存根内容pointee_sized/meta_sized/sizedPointeeSized、MetaSized、Sized三层 trait 继承关系destructDestruct用于 drop 检查copyCopy: Sized并为其实现了基本类型与数组等实例freeze/unpin/unsafe_unpinFreeze、Unpin、UnsafeUnpin自动 traitunsafe_cellUnsafeCellT并实现!Freeze负 implmanually_drop/maybe_uninitManuallyDropT、MaybeUninitT含const fn uninit()与new()add/neg算术 trait 及isize、i8、i32的最小实现fn_once/fn_mut/fn闭包调用三件套带extern rust-callABIdrop_glue/drop析构相关语言项sync带extern C/unsafe函数指针的最小Sync实例集dispatch_from_dyn/unsize/coerce_unsized动态分发与 unsize 强转支持c_void/Ordering/const_param_tyFFI 与 const 泛型相关项tuple_traitTupletrait供闭包参数使用legacy_receiver接收者 traitCopy与Sync的实现借助了文件内自带的impl_marker_trait!宏批量生成覆盖char、bool、全部整数/浮点类型含f16/f128等基础类型Copy还覆盖了引用、裸指针、定长数组与PhantomData。注释说明Sync只提供测试所需的最小 impl 集合比如fn() - R、extern C fn(A) - R等不必穷尽所有函数指针签名按需添加即可。内建宏与内建函数intrinsicsminicore用#[rustc_builtin_macro]声明了asm!、naked_asm!、global_asm!、cfg_select以及concat!、stringify!、compile_error!、pattern_type!等内建宏同时用#[rustc_intrinsic]声明了copy_nonoverlapping、mem::transmute、mem::size_of、mem::align_of等内建函数并在ptr::write_volatile、hint::black_box中给出了带#[inline]的薄封装。通用类型与 SIMD 存根文件还提供了OptionT、ResultT, E、NonZeroT借助pattern_type!表达非零区间与NonNullT带#[rustc_nonnull_optimization_guaranteed]以及num::ComplexT。最值得一提的当属simd模块它用#[repr(simd)]定义了SimdT, N结构体并预置了f16x2、f32x4、i8x16、u8x16等一大批 SIMD 类型别名——这正是大量 codegen 测试如 homogeneous-aggregate.rs能够用use minicore::simd::*;直接写 SIMD ABI 测试的原因。SimdAlign枚举的注释还特别提醒其取值必须与编译器内部rustc_middle/src/ty/consts/int.rs中的定义保持一致。添加更多core存根的约定当你在编写测试时发现某个core项在minicore中缺失文档给出的建议是如果该存根很可能被用到、或者已经被多个测试共同需要就考虑把它加进tests/auxiliary/minicore.rs。同时源码头部的「Important notes」给出了两条硬性约束存根必须与真实core的对应项保持一致为了在不同测试之间得到一致的诊断输出任何diagnostic属性例如on_unimplemented都必须在minicore中原样复制。这一点在文件中体现得淋漓尽致Sized、Unpin、Tuple、ConstParamTy_、PointeeSized、MetaSized、Destruct等 trait 上都完整复刻了与core一致的#[diagnostic::on_unimplemented(...)]消息与 label——否则用minicore与用真实core编译同一段非法代码时输出会不一致进而破坏 ui 测试的.stderr快照比对。另外还有一个容易被忽略的注意点源码注释第 10 行添加新 feature 时要小心那些只对部分目标可用的内容避免让minicore无法在某些交叉编译目标上构建。与core保持同步的维护要求minicore中的每一项都必须与core保持同步更新。这在实践中意味着当core中某个被minicore覆盖的 item 发生变化签名、属性、语言项归属时需要同步修改 tests/auxiliary/minicore.rs任何会影响诊断输出的diagnostic属性如on_unimplemented都要精确复刻以保证「用core和用minicore的诊断输出一致」这一目标。顺带一提minicore并非完全原创——源码第 15-18 行的注释标明它部分改编自rustc_codegen_cranelift示例中的mini_core.rs这也解释了为什么文件结构带有明显的「最小可编译内核」风格。仓库中 rustc_codegen_cranelift/example 目录保留了同源思路的示例可供对照阅读。真实仓库中的使用案例// add-minicore在仓库测试中有着广泛的应用以下选取几个典型代表codegen ABI 测试homogeneous-aggregate.rs 在第 1 行声明// add-minicore随后use minicore::simd::*;用f64x2等 SIMD 类型测试 AArch64 同构聚合体HFA的传参/返回 ABI并通过// CHECK:断言期望的 LLVM IR 签名汇编assembly测试tests/assembly-llvm 下有大量asm/测试如各架构的*-types.rs、*-modifiers.rs通过add-minicore获得asm!等内建宏的存根支持从而在-C force-unwind-tablesyes的配合下保留 CFI 指令并做汇编级断言mir-opt 与 ui 测试同样可以在 tests/mir-opt 与 tests/ui 中检索到大量add-minicore用例。这些用例的共同特征正如文档总结面向交叉编译目标、只编译不运行、关注编译产物本身。当你需要为某个目标平台编写这类测试时优先考虑复用minicore而非引入完整core既能大幅缩短构建链路也避免标准库行为干扰对编译器行为的验证。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →