1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#![feature(proc_macro)]
extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
#[macro_use]
extern crate lazy_static;
use std::env;
use syn::{Ident, ItemKind};
use std::sync::RwLock;
use proc_macro::TokenStream;
lazy_static! {
static ref CRATES: RwLock<Vec<String>> = Default::default();
}
#[proc_macro_attribute]
pub fn init(_: TokenStream, target: TokenStream) -> TokenStream {
let s = target.to_string();
match syn::parse_item(&s) {
Ok(item) => {
match item.node {
ItemKind::Fn(..) => {
let package_name = env::var("CARGO_PKG_NAME").unwrap().replace('-', "_");
let self_abi_name = Ident::new(format!("_rust_init_{}", package_name));
let mut crate_abi_names = Vec::new();
for crate_name in &*CRATES.read().unwrap() {
crate_abi_names.push(Ident::new(format!("_rust_init_{}", crate_name)));
}
let crate_abi_names_2 = crate_abi_names.clone();
let item_name = &item.ident;
let gen = quote! {
#[inline(always)]
#item
extern "Rust" {
#(fn #crate_abi_names() -> ();)*
}
#[no_mangle]
#[allow(unused_unsafe)]
pub extern "C" fn #self_abi_name() {
unsafe { #(#crate_abi_names_2();)* }
#item_name();
}
};
return gen.parse().unwrap();
}
ItemKind::ExternCrate(name) => {
let item_name = name.unwrap_or(item.ident);
CRATES.write().unwrap().push(item_name.to_string());
}
_ => {
}
}
}
_ => {
}
}
target
}