7 releases
0.1.6 | Nov 17, 2023 |
---|---|
0.1.5 | Nov 17, 2023 |
0.1.4 | Oct 15, 2023 |
#858 in Rust patterns
Used in 3 crates
13KB
159 lines
hictor
0.1.5
提供三个辅助函数获取命令行参数:
fn args() -> &'static [*const u8];
fn program_invocation_name() -> &'static str;
fn program_invocation_short_name() -> &'static str;
功能介绍
基于声明宏实现gcc支持的__attribute__((constructor))和__attribute__((destructor))的功能.
和ctor crate的差异在于:
- 声明宏; ctor是过程宏实现.
- 只支持函数; ctor还支持静态变量.
ctor_args, ctor_custom
支持获取命令行输入参数; ctor未支持.- dtor完全等同__attribute__((destructor)),windows等平台不支持; ctor封装了atexit.
无论如何,业务代码不能依赖多个初始化函数的调用顺序,其无法保证.
注:仅在linux平台下测试通过.
attribute((constructor))
不关心命令行输入参数,则可以采用无参数的函数实现. 类型必须是unsafe fn()
.
unsafe fn init() {
println!("init before main");
}
hictor::ctor!(init);
如果需要获取命令行输入,函数类型必须是unsafe extern "C" fn(i32, *const *const i8)
unsafe extern "C" fn init(argc: i32, argv: *const *const i8) {
println!("argc = {argc}, program = {:?}", std::ffi::CStr::from_ptr(*argv));
}
hictor::ctor_args!(init);
有的平台下支持更多的参数,比如linux平台下还可以获取环境变量,其函数类型为unsafe extern "C" fn(u32, *const *const u8, *const *const u8)
.
#[cfg(target_os = "linux")]
unsafe extern "C" fn init(argc: i32, argv: *const *const i8, envs: *const *const i8) {
println!("argc = {argc}, program = {:?} env.0 = {:?}", std::ffi::CStr::from_ptr(*argv), std::ffi::CStr::from_ptr(*envs));
}
#[cfg(target_os = "linux")]
hictor::ctor_custom!(init);
attribute((destructor))
函数类型必须是unsafe fn(). 注意业务不应该依赖这个机制,因为应用程序可能因多种未知因素异常退出,这些函数都不会被调用到. 一个高可用性的软件应该为这种无法绝对避免的场景做准备,比如启动时做恢复检查或者额外的监控和容错处理程序等.
unsafe fn fini() {
println!("fini after main");
}
hictor::dtor!(fini);
获取命令行输入
如果不在main函数中,可以获取当前应用程序的命令行输入参数.
fn foo() {
let args: &'static [*const i8] = hictor::args();
}
说明
其实现原理是定义一个全局变量,初始化为指定的函数指针,并指定在ELF的特殊段(linux下是.init_array
)中. 需要定义一个静态变量实现这个功能.
但声明宏中无法同C的宏,组合行号等其他信息来生成一个变量名(concat_idents
宏仅在nightly版本可用), 为了避免静态变量的重复定义,宏的实现中
利用函数名的唯一性定义了一个子模块,如果刚好有一个和函数同名的模块存在,则会存在冲突,这种情况下需要你指定一个唯一的模块名.
mod init {
pub(super) unsafe fn init() {
println!("init before main");
}
}
use init::init;
hictor::ctor!(init_mod, init);