-
Notifications
You must be signed in to change notification settings - Fork 19
/
build.rs
126 lines (103 loc) · 3.04 KB
/
build.rs
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
124
125
126
extern crate cc;
extern crate handlebars as hbs;
#[macro_use]
extern crate serde_derive;
use std::convert::From;
use std::fs::File;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::env;
fn main() {
let in_path = Path::new("src").join("constants.c.in");
let out_path = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("constants.c");
// Template the file.
if let Err(e) = template_file(&in_path, &out_path) {
println!("Error creating `constants.c` from template");
println!("-> {:?}", e);
exit(1);
}
// Build the final library
let mut cfg = cc::Build::new();
let helpers_path = Path::new("src").join("helpers.c");
let ifaddrs_path = Path::new("src").join("ifaddrs.c");
let cfg = cfg.file(&out_path).file(&helpers_path);
if env::var_os("CARGO_CFG_TARGET_OS")
.unwrap()
.to_str()
.unwrap()
== "android"
{
cfg.file(ifaddrs_path);
}
cfg.compile("libinterfaces.a");
}
fn template_file(in_path: &PathBuf, out_path: &PathBuf) -> Result<(), Error> {
// Open and read the file.
let mut f = File::open(in_path)?;
let mut s = String::new();
f.read_to_string(&mut s)?;
let mut handlebars = hbs::Handlebars::new();
handlebars.register_template_string("template", s)?;
let mut f = File::create(out_path)?;
let data = make_data();
handlebars.render_to_write("template", &data, &mut f)?;
Ok(())
}
fn make_data() -> Context {
// These constants are "dynamically" generated by compiling a C file that includes their value
// and then including that in the final build. See `constants.rs` for a function that can be
// used to retrieve them.
let names: &[&str] = &[
// IOCTLs
"SIOCGIFCONF",
"SIOCGIFHWADDR",
"SIOCGIFFLAGS",
"SIOCSIFFLAGS",
"SIOCGIFMTU",
"SIOCSIFMTU",
// Address families
"AF_LINK",
"AF_PACKET", // Only on Linux
];
// These constants are the same as above, but we don't test them for existence with #ifdef.
let anames: &[&str] = &["sizeof(struct ifreq)"];
let names = names
.into_iter()
.map(|x| String::from(*x))
.collect::<Vec<String>>();
let anames = anames
.into_iter()
.map(|x| String::from(*x))
.collect::<Vec<String>>();
Context {
test_constants: names,
always_constants: anames,
}
}
#[derive(Serialize, Deserialize)]
struct Context {
test_constants: Vec<String>,
always_constants: Vec<String>,
}
#[derive(Debug)]
enum Error {
IoError(io::Error),
TemplateError(hbs::TemplateError),
RenderError(hbs::RenderError),
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Error {
Error::IoError(e)
}
}
impl From<hbs::TemplateError> for Error {
fn from(e: hbs::TemplateError) -> Error {
Error::TemplateError(e)
}
}
impl From<hbs::RenderError> for Error {
fn from(e: hbs::RenderError) -> Error {
Error::RenderError(e)
}
}