news 2026/9/13 2:29:33

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Rust 编译器测试指南:minicore 测试辅助库与 `core` 存根的使用方法

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 don't want nor need to-Zbuild-std).

也就是说,当测试需要验证的是「编译器在某个目标平台上生成的代码/汇编是否符合预期」,而不是「标准库在这个平台上的行为」时,直接搬出完整的core往往是杀鸡用牛刀——此时minicore提供了一个最小化的、足以让编译器完成语义检查与代码生成的存根集合。

适用范围的重要警告

官方文档特别强调了一条边界,这一点在源码中也以注释形式反复出现:

  • minicore仅用于core,明确用于stdalloc项;
  • 原因在于core项适用于更广泛的测试场景,而std/alloc依赖的运行时设施太多,不适合用存根替代。

如何在测试中使用minicore

使用minicore一共需要三步:

  1. 在测试文件头部的编译测试指令(directive)区声明//@ add-minicore
  2. 在 crate 属性区同时声明#![feature(no_core)]#![no_std]#![no_core]——这表示本测试既不链接标准库,也不需要core预置项;
  3. minicore引入测试作用域
    • 2015 edition 使用extern crate minicore;
    • 2018+ edition 使用use minicore;(或按需use minicore::*;)。

下面是一个最小可用的结构示例(来自 rustc-dev-guide 文档原文):

//@ add-minicore //@ revisions: meow bark //@[meow] compile-flags: --target=x86_64-unknown-linux-gnu //@[meow] needs-llvm-components: x86 //@[bark] compile-flags: --target=wasm32-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_std+no_core构建,不支持展开式(unwinding)panic,因此//@ add-minicore会隐式地(也要求)为测试构建加上如下两个标志:

  1. -C panic=abort
  2. -C force-unwind-tables=yes

其中force-unwind-tables=yes的目的是在汇编(assembly)测试中保留 CFI(Call Frame Information)指令,使生成的汇编符合预期输出。

源码层面的实现佐证

这两条隐含标志并非文档空谈,在 runtest.rs 中可以找到确切的落地代码,并附有注释解释其设计意图:

// `minicore` requires `#![no_std]` and `#![no_core]`, which means no unwinding panics. if self.props.add_minicore { compiler.arg("-Cpanic=abort"); compiler.arg("-Cforce-unwind-tables=yes"); }

值得留意的是,这段代码是在「添加用户自定义编译标志」之前执行,也就是说先改变默认值,再叠加用户 flags。源码注释(runtest.rs)同时指出一个已知的改进空间(FIXME):目前如果用户在测试里显式写了非abort-Cpanic=或非yes-Cforce-unwind-tables=,compiletest 并不会报错或警告——部分测试恰恰需要「以特定方式混合 panic 模式被拒绝」的行为,所以只是先改变默认值而不强制覆盖。

此外,minicore自身作为辅助库被编译时也会携带-Cpanic=abort,见 runtest.rs 中的rustc.arg("-Cpanic=abort")

支持与不支持的模式

//@ add-minicore并非在所有测试模式下都可用。在 directives.rs 的update_add_minicore处理逻辑中,compiletest 会做两层校验:

  • 仅支持四种测试模式uicodegenassemblymir-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 中可以分为三步:

  1. 预编译辅助库build_minicore()(runtest.rs)使用测试输出目录下的libminicore.rlib作为产物路径,以--crate-type rlib-Cpanic=abort以及minicore_compile_flags编译tests/auxiliary/minicore.rs(路径来自config.minicore_path)。若编译失败,会以「auxiliary build of ... failed to compile」终止测试。
  2. 通过--extern注入compose_and_run_compiler()(runtest.rs)在真正编译测试文件前,检查self.props.add_minicore,若为真则追加--extern minicore=<rlib路径>
  3. 辅助文件同样生效:当被测文件依赖其他 auxiliary 文件时,runtest.rs 也会为 auxiliary 构建注入等价的--extern minicore=...参数。

也就是说,minicore在 compiletest 眼中是一个「按需预编译、按需注入」的普通外部 crate,只是它的内容恰好是core的存根。

minicore源码结构深度解析

tests/auxiliary/minicore.rs本身就是一个完整的#![no_std] #![no_core]crate,其源码本身就是一份绝佳的「最小core骨架」教材。它启用了no_coreintrinsicslang_itemsauto_traitsnegative_implsrepr_simdf16/f128asm_experimental_arch等一长串 feature,并整体#![allow(unused, improper_ctypes_definitions, internal_features, non_camel_case_types)]以保持整洁。

标记 trait 与语言项(lang item)

minicore#[lang = "..."]属性声明了大量编译器必需的内部语言项,例如:

语言项存根内容
pointee_sized/meta_sized/sizedPointeeSizedMetaSizedSized三层 trait 继承关系
destructDestruct,用于 drop 检查
copyCopy: Sized,并为其实现了基本类型与数组等实例
freeze/unpin/unsafe_unpinFreezeUnpinUnsafeUnpin自动 trait
unsafe_cellUnsafeCell<T>,并实现!Freeze负 impl
manually_drop/maybe_uninitManuallyDrop<T>MaybeUninit<T>(含const fn uninit()new()
add/neg算术 trait 及isizei8i32的最小实现
fn_once/fn_mut/fn闭包调用三件套,带extern "rust-call"ABI
drop_glue/drop析构相关语言项
syncextern "C"/unsafe函数指针的最小Sync实例集
dispatch_from_dyn/unsize/coerce_unsized动态分发与 unsize 强转支持
c_void/Ordering/const_param_tyFFI 与 const 泛型相关项
tuple_traitTupletrait,供闭包参数使用
legacy_receiver接收者 trait

CopySync的实现借助了文件内自带的impl_marker_trait!宏批量生成,覆盖charbool、全部整数/浮点类型(含f16/f128)等基础类型;Copy还覆盖了引用、裸指针、定长数组与PhantomData。注释说明:Sync只提供测试所需的最小 impl 集合(比如fn() -> Rextern "C" fn(A) -> R等),不必穷尽所有函数指针签名,按需添加即可

内建宏与内建函数(intrinsics)

minicore#[rustc_builtin_macro]声明了asm!naked_asm!global_asm!cfg_select以及concat!stringify!compile_error!pattern_type!等内建宏;同时用#[rustc_intrinsic]声明了copy_nonoverlappingmem::transmutemem::size_ofmem::align_of等内建函数,并在ptr::write_volatilehint::black_box中给出了带#[inline]的薄封装。

通用类型与 SIMD 存根

文件还提供了Option<T>Result<T, E>NonZero<T>(借助pattern_type!表达非零区间)与NonNull<T>(带#[rustc_nonnull_optimization_guaranteed]),以及num::Complex<T>。最值得一提的当属simd模块:它用#[repr(simd)]定义了Simd<T, N>结构体,并预置了f16x2f32x4i8x16u8x16等一大批 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中原样复制

这一点在文件中体现得淋漓尽致:SizedUnpinTupleConstParamTy_PointeeSizedMetaSizedDestruct等 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-tables=yes的配合下保留 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 2:29:27

考虑电动汽车V2G的配电网无功优化(电压控制)Matlab实现

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、算法改进、程序设计科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;完整代码获取 定制创新 论文复现私信&#x1f34a;个人信条&#xff1a;做科研&#xff0c…

作者头像 李华
网站建设 2026/9/13 2:25:26

数据结构与算法面试速通指南:高频考点与备考策略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 2:22:46

kohya_ss LoRA 训练完整指南:从零安装到练出第一个角色模型

kohya_ss LoRA 训练完整指南&#xff1a;从零安装到练出第一个角色模型 【免费下载链接】kohya_ss 项目地址: https://gitcode.com/GitHub_Trending/ko/kohya_ss kohya_ss 解决一件事&#xff1a;不碰命令行&#xff0c;也能给 Stable Diffusion 训练自己的 LoRA 和自定…

作者头像 李华
网站建设 2026/9/13 2:16:22

深入理解HOOK机制:从消息钩子到API Hook的底层原理与实战

HOOK这个词&#xff0c;搞Windows开发的人天天挂嘴边&#xff0c;做Web开发的人也经常听到&#xff0c;可你真要让人一句话说清楚它是什么、能干什么&#xff0c;能一口气讲明白的人真不多。我直接上两段能跑的代码&#xff0c;带你把HOOK的底层逻辑、实现方式和坑点一次性捋顺…

作者头像 李华