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
use std::io::Write;
use anyhow::Context;
use cfg_expr::targets::get_builtin_target_by_triple;
use rusty_bind_parser::binding_module::CargoFeature;
use rusty_bind_parser::BindingModule;
use syn::{File, Item};
pub fn parse_ffi_module(input_rust_file_path: &str, output_dir: &str) -> anyhow::Result<()> {
let file = std::fs::read_to_string(input_rust_file_path)
.with_context(|| format!("Could not read a file `{input_rust_file_path}`"))?;
if !std::path::Path::new(output_dir).exists() {
std::fs::create_dir(output_dir)
.with_context(|| format!("Could not create a directory `{output_dir}`"))?;
}
let context = build_context().context("Failed to build context")?;
if let Ok(file) = syn::parse_str(&file) as Result<File, _> {
for item in file.items.iter() {
if let Item::Mod(module) = item {
let parsed = BindingModule::translate_module(module.clone(), &context)?;
let rust_code = parsed.get_tokens().to_string();
let generated_code = parsed.generate_binding_files();
let mut output_interface = std::fs::File::create(format!(
"{output_dir}/interface.rs"
))
.with_context(|| format!("Could not create a file `{output_dir}/interface.rs`"))?;
output_interface
.write_all(rust_code.as_bytes())
.with_context(|| format!("Could not write file `{output_dir}/interface.rs`"))?;
let mut output_interface = std::fs::File::create(format!("{output_dir}/ffi_cxx.h"))
.with_context(|| format!("Could not create a file `{output_dir}/ffi_cxx.h`"))?;
output_interface
.write_all(generated_code.cpp_header.as_bytes())
.with_context(|| format!("Could not write file `{output_dir}/ffi_cxx.h`"))?;
let mut output_interface =
std::fs::File::create(format!("{output_dir}/ffi_swift.swift")).with_context(
|| format!("Could not create a file `{output_dir}/ffi_swift.swift`"),
)?;
output_interface
.write_all(generated_code.swift_header.as_bytes())
.with_context(|| {
format!("Could not write file `{output_dir}/ffi_swift.swift`")
})?;
let mut output_interface = std::fs::File::create(format!(
"{output_dir}/ffi_swift.h"
))
.with_context(|| format!("Could not create a file `{output_dir}/ffi_swift.h`"))?;
output_interface
.write_all(generated_code.cpp_externs.as_bytes())
.with_context(|| format!("Could not write file `{output_dir}/ffi_swift.h`"))?;
let mut output_interface = std::fs::File::create(format!(
"{output_dir}/ffi_swig.i"
))
.with_context(|| format!("Could not create a file `{output_dir}/ffi_swig.i`"))?;
output_interface
.write_all(generated_code.swig_interface.as_bytes())
.with_context(|| {
format!("Could not write to file `{output_dir}/ffi_swig.i`")
})?;
}
}
}
Ok(())
}
fn build_context() -> anyhow::Result<rusty_bind_parser::BuildContext> {
let target = std::env::var("TARGET").context("TARGET env variable is not present")?;
let current_target_info =
get_builtin_target_by_triple(&target).context("Fail to parse TARGET env")?;
let features = std::env::vars()
.map(|kv| kv.0)
.filter(|key| key.starts_with("CARGO_FEATURE_"))
.map(|key| CargoFeature::new(&key["CARGO_FEATURE_".len()..]))
.collect();
let target_features = std::env::var("CARGO_CFG_TARGET_FEATURE")
.unwrap_or_default()
.split(',')
.map(Into::into)
.collect();
Ok(rusty_bind_parser::BuildContext {
current_target_info,
features,
target_features,
})
}