ensc_build_rs/
lib.rs

1use std::{io::Write, path::PathBuf};
2
3trait TrimmedRead {
4    fn read_line_trimmed(&mut self, buf: &mut String) -> std::io::Result<bool>;
5}
6
7impl<R: std::io::Read> TrimmedRead for std::io::BufReader<R> {
8    fn read_line_trimmed(&mut self, buf: &mut String) -> std::io::Result<bool>
9    {
10	use std::io::BufRead;
11
12	match self.read_line(buf)? {
13	    0	=> Ok(false),
14	    _	=> {
15		*buf = buf.trim().into();
16		Ok(true)
17	    }
18	}
19    }
20}
21
22pub struct LineIterator<R: std::io::Read> {
23    reader:	std::io::BufReader<R>,
24}
25
26impl <R: std::io::Read> LineIterator<R> {
27    pub fn new(r: R) -> Self {
28	Self {
29	    reader: std::io::BufReader::new(r),
30	}
31    }
32}
33
34pub trait ToLineIterator<R>
35where
36    R: std::io::Read,
37{
38    fn to_line_iterator(&mut self) -> LineIterator<R>;
39}
40
41impl <R> ToLineIterator<R> for Option<R>
42where
43    R: std::io::Read,
44{
45    fn to_line_iterator(&mut self) -> LineIterator<R>
46    {
47	LineIterator::new(self.take().unwrap())
48    }
49}
50
51impl <R: std::io::Read> From<R> for LineIterator<R> {
52    fn from(value: R) -> Self {
53        LineIterator::new(value)
54    }
55}
56
57impl <R: std::io::Read> std::iter::Iterator for LineIterator<R> {
58    type Item	= std::io::Result<String>;
59
60    fn next(&mut self) -> Option<Self::Item> {
61	let mut line = String::new();
62
63	match self.reader.read_line_trimmed(&mut line) {
64	    Ok(true)	=> Some(Ok(line)),
65	    Ok(false)	=> None,
66	    Err(e)	=> Some(Err(e)),
67	}
68    }
69}
70
71pub fn finish_cmd<E>(st: Result<std::process::ExitStatus,E>)
72where
73    E: std::fmt::Debug
74{
75    match st {
76        Err(e) => {
77            panic!("make aborted with {:?}", e);
78        }
79
80        Ok(s) => {
81            if !s.success() {
82                panic!("make failed with {:?}", s);
83            }
84        }
85    }
86}
87
88fn makedir() -> PathBuf {
89    let outdir: PathBuf = std::env::var("OUT_DIR").unwrap().into();
90
91    outdir.join("ensc-build-rs")
92}
93
94pub fn run_make() -> std::process::Command {
95    let mut res = std::process::Command::new("make");
96
97    res.args(["-s", "--no-print-directory"])
98        .arg("--include-dir")
99        .arg(std::env::var("OUT_DIR").unwrap())
100        .arg("IN_ENSC_BUILD_RS=1");
101
102//    std::thread::sleep(std::time::Duration::from_secs(10));
103
104    res
105}
106
107pub fn write_common_mk() {
108    static COMMON_MK: &[u8] = include_bytes!("../mk/common.mk");
109    let makedir = makedir();
110
111    // ignore errors when creating the directory; it is very likely that we
112    // get EEXIST.  Other errors will be catched below when creating the file
113    let _ = std::fs::create_dir(&makedir);
114
115    let mut file = std::fs::File::create(makedir.join("common.mk")).unwrap();
116
117    file.write_all(COMMON_MK).unwrap();
118    file.flush().unwrap();
119}
120
121pub fn emit_libs() {
122    let mut cmd = run_make()
123	.arg("emit-libs")
124	.stdout(std::process::Stdio::piped())
125	.spawn()
126	.unwrap();
127
128    cmd.stdout
129	.to_line_iterator()
130	.map(|v| v.unwrap())
131	.filter(|l| !l.is_empty())
132        .for_each(|l| println!("cargo:rustc-flags={l}"));
133
134    finish_cmd(cmd.wait());
135}
136
137pub fn get_cflags() -> Vec<String> {
138    let mut cmd = run_make()
139	.arg("emit-cflags")
140	.stdout(std::process::Stdio::piped())
141	.spawn()
142	.unwrap();
143
144    let res = cmd.stdout
145	.to_line_iterator()
146	.map(|v| v.unwrap())
147	.filter(|l| !l.is_empty())
148	.collect();
149
150    finish_cmd(cmd.wait());
151
152    res
153}