ax-ctor-bare-macros
路径:
components/ctor_bare/ctor_bare_macros类型:过程宏库 分层:组件层 / 构造函数注册编译期辅助 版本:0.2.1文档依据:当前仓库源码、components/ctor_bare/Cargo.toml、components/ctor_bare/README.md、components/ctor_bare/ctor_bare_macros/Cargo.toml、components/ctor_bare/ctor_bare_macros/src/lib.rs、components/ctor_bare/ctor_bare/tests/*
ax-ctor-bare-macros 是 ax-ctor-bare 的编译期搭档。它的职责只有一个:把一个普通 Rust 函数改写成“可被放进 .init_array 的构造函数入口”。它不是初始化运行时,也不负责遍历 .init_array,更不是完整的启动编排框架。
架构设计
设计定位
这个 crate 提供的公开接口只有一个属性宏:
#[register_ctor]
因此它的定位非常纯粹:
- 在编译期检查函数签名是否合法
- 生成放入
.init_array的静态函数指针 - 生成最终会被调用的
extern "C"函数实体
它只处理“登记”,不处理“执行”。
1.2 宏展开的真实内容
当 #[register_ctor] 应用到一个函数上时,宏会做三类事情:
- 校验属性参数必须为空
- 校验目标 item 必须是函数,且:
- 没有输入参数
- 没有返回值
- 生成两段代码:
- 一个放进
.init_array的静态函数指针 - 一个
pub extern "C" fn的真实函数定义
- 一个放进
生成出来的静态项形如:
_INIT_<函数名>
并带有:
#[unsafe(link_section = ".init_array")]#[used]
这表明它的本质是“把函数地址写进一个约定段”。
1.3 为什么要重新生成函数
宏不会直接把原始函数原封不动塞进 .init_array,而是会生成:
#[unsafe(no_mangle)] pub extern "C" fn name() { ... }
这么做有几个现实目的:
- 保证段里放的是统一 ABI 的函数指针
- 让符号名稳定
- 让构造函数调用约定尽可能简单
因此 ax-ctor-bare-macros 实际上还承担了一个“小型 ABI 规整器”的角色。
1.4 错误诊断策略
源码中可以看到,以下输入都会在编译期被拒绝:
- 给
#[register_ctor(...)]传参数 - 标注到非函数 item 上
- 函数有参数
- 函数有返回值
这些限制不是保守,而是为了保证 ax_ctor_bare::call_ctors() 能无条件把段里的项目当作 fn() 调用。
1.5 与 ax-ctor-bare 的真实关系
当前仓库中,测试代码和最终用户都通过:
ax_ctor_bare::register_ctor
来使用这个宏,而不是直接依赖 ax-ctor-bare-macros。这说明它是一个典型的“内部辅助宏 crate”:
ax-ctor-bare-macros负责登记ax-ctor-bare负责运行时遍历执行
核心功能
功能概览
- 提供
#[register_ctor] - 编译期校验构造函数签名
- 把函数指针写入
.init_array - 生成统一 ABI 的构造函数入口
- 为错误输入生成清晰的
compile_error
2.2 当前仓库中的真实调用链
当前真实链路是:
- 用户代码写
#[register_ctor] fn foo() { ... } ax-ctor-bare-macros生成.init_array静态项和extern "C"函数ax_ctor_bare::call_ctors()运行时遍历并执行这些函数
因此这个 crate 只参与第 1 到第 2 步,且完全属于编译期。
边界说明
ax-ctor-bare-macros 不负责:
- 何时调用构造函数
- 调用多少次
- 构造函数之间的顺序与依赖
- 链接脚本中
.init_array的布局
这些都属于 ax-ctor-bare 或更上层运行时/链接配置的职责。