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
111
112
113
114
115
116
117
118
119
120
121
122
123
pub use autocxx_engine::Error as EngineError;
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use syn::Item;
use tempfile::{tempdir, TempDir};
#[derive(Debug)]
pub enum Error {
FileReadError(std::io::Error),
Syntax(syn::Error),
InvalidCxx(EngineError),
TempDirCreationFailed(std::io::Error),
FileWriteFail(std::io::Error),
NoIncludeCxxMacrosFound,
MacroParseFail(EngineError),
IncludeDirProblem(EngineError),
}
pub struct Builder {
build: cc::Build,
_tdir: TempDir,
}
impl Builder {
pub fn new<P1: AsRef<Path>>(rs_file: P1, autocxx_inc: &str) -> Result<Self, Error> {
let tdir = tempdir().map_err(Error::TempDirCreationFailed)?;
let mut builder = cc::Build::new();
builder.cpp(true);
let source = fs::read_to_string(rs_file).map_err(Error::FileReadError)?;
let source = syn::parse_file(&source).map_err(Error::Syntax)?;
let mut counter = 0;
for item in source.items {
if let Item::Macro(mac) = item {
if mac.mac.path.is_ident("include_cxx") {
let mut include_cpp = autocxx_engine::IncludeCpp::new_from_syn(mac.mac)
.map_err(Error::MacroParseFail)?;
include_cpp.set_include_dirs(autocxx_inc);
for inc_dir in include_cpp
.include_dirs()
.map_err(Error::IncludeDirProblem)?
{
builder.include(inc_dir);
}
let generated_code = include_cpp
.generate_h_and_cxx()
.map_err(Error::InvalidCxx)?;
let fname = format!("gen{}.cxx", counter);
counter += 1;
let gen_cxx_path =
Self::write_to_file(&tdir, &fname, &generated_code.implementation)
.map_err(Error::FileWriteFail)?;
builder.file(gen_cxx_path);
}
}
}
if counter == 0 {
Err(Error::NoIncludeCxxMacrosFound)
} else {
Ok(Builder {
build: builder,
_tdir: tdir,
})
}
}
pub fn builder(&mut self) -> &mut cc::Build {
&mut self.build
}
fn write_to_file(tdir: &TempDir, filename: &str, content: &[u8]) -> std::io::Result<PathBuf> {
let path = tdir.path().join(filename);
let mut f = File::create(&path)?;
f.write_all(content)?;
Ok(path)
}
}