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
102res
105}
106
107pub fn write_common_mk() {
108 static COMMON_MK: &[u8] = include_bytes!("../mk/common.mk");
109 let makedir = makedir();
110
111 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}