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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#![feature(proc_macro_expand)]
#![feature(proc_macro_span)]
use std::{io::Read, path::Path, process::Command};
use proc_macro::Literal;
use quote::quote;
use syn::{parse_macro_input, LitStr};
use tempfile::NamedTempFile;
fn simulate_inclusion(file: &LitStr) -> Result<(), proc_macro::ExpandError> {
let src = quote! {
include_bytes!(#file)
};
let _ = proc_macro::TokenStream::from(src).expand_expr()?;
Ok(())
}
macro_rules! expand_macro_input {
($tokenstream:ident) => {
match $tokenstream.expand_expr() {
Ok(tokenstream) => tokenstream,
Err(err) => {
let tokenstream = proc_macro2::TokenStream::from($tokenstream);
let error = syn::Error::new_spanned(tokenstream, err);
return proc_macro::TokenStream::from(error.into_compile_error());
}
}
};
}
fn include_transformed(
input: proc_macro::TokenStream,
transform: impl FnOnce(&Path, &Path) -> Command,
) -> proc_macro::TokenStream {
let input = expand_macro_input!(input);
let file = parse_macro_input!(input as LitStr);
simulate_inclusion(&file).unwrap();
let mut src = proc_macro::Span::call_site().source_file().path();
src.set_file_name(file.value());
let mut dst = NamedTempFile::new().unwrap();
let status = transform(src.as_path(), dst.path()).status().unwrap();
assert!(status.success());
let output = {
let mut buf = Vec::new();
dst.read_to_end(&mut buf).unwrap();
Literal::byte_string(&buf)
};
proc_macro::TokenStream::from(proc_macro::TokenTree::from(output))
}
#[proc_macro]
pub fn include_nasm_bin(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
include_transformed(input, |src_path, dst_path| {
let mut nasm = Command::new("nasm");
nasm.arg("-f")
.arg("bin")
.arg(src_path)
.arg("-o")
.arg(dst_path);
nasm
})
}