use std::{io::Write, path::PathBuf};
trait TrimmedRead {
fn read_line_trimmed(&mut self, buf: &mut String) -> std::io::Result<bool>;
}
impl<R: std::io::Read> TrimmedRead for std::io::BufReader<R> {
fn read_line_trimmed(&mut self, buf: &mut String) -> std::io::Result<bool>
{
use std::io::BufRead;
match self.read_line(buf)? {
0 => Ok(false),
_ => {
*buf = buf.trim().into();
Ok(true)
}
}
}
}
pub struct LineIterator<R: std::io::Read> {
reader: std::io::BufReader<R>,
}
impl <R: std::io::Read> LineIterator<R> {
pub fn new(r: R) -> Self {
Self {
reader: std::io::BufReader::new(r),
}
}
}
pub trait ToLineIterator<R>
where
R: std::io::Read,
{
fn to_line_iterator(&mut self) -> LineIterator<R>;
}
impl <R> ToLineIterator<R> for Option<R>
where
R: std::io::Read,
{
fn to_line_iterator(&mut self) -> LineIterator<R>
{
LineIterator::new(self.take().unwrap())
}
}
impl <R: std::io::Read> From<R> for LineIterator<R> {
fn from(value: R) -> Self {
LineIterator::new(value)
}
}
impl <R: std::io::Read> std::iter::Iterator for LineIterator<R> {
type Item = std::io::Result<String>;
fn next(&mut self) -> Option<Self::Item> {
let mut line = String::new();
match self.reader.read_line_trimmed(&mut line) {
Ok(true) => Some(Ok(line)),
Ok(false) => None,
Err(e) => Some(Err(e)),
}
}
}
pub fn finish_cmd<E>(st: Result<std::process::ExitStatus,E>)
where
E: std::fmt::Debug
{
match st {
Err(e) => {
panic!("make aborted with {:?}", e);
}
Ok(s) => {
if !s.success() {
panic!("make failed with {:?}", s);
}
}
}
}
fn makedir() -> PathBuf {
let outdir: PathBuf = std::env::var("OUT_DIR").unwrap().into();
outdir.join("ensc-build-rs")
}
pub fn run_make() -> std::process::Command {
let mut res = std::process::Command::new("make");
res.args(["-s", "--no-print-directory"])
.arg("--include-dir")
.arg(std::env::var("OUT_DIR").unwrap())
.arg("IN_ENSC_BUILD_RS=1");
res
}
pub fn write_common_mk() {
static COMMON_MK: &[u8] = include_bytes!("../mk/common.mk");
let makedir = makedir();
let _ = std::fs::create_dir(&makedir);
let mut file = std::fs::File::create(makedir.join("common.mk")).unwrap();
file.write_all(COMMON_MK).unwrap();
file.flush().unwrap();
}
pub fn emit_libs() {
let mut cmd = run_make()
.arg("emit-libs")
.stdout(std::process::Stdio::piped())
.spawn()
.unwrap();
cmd.stdout
.to_line_iterator()
.map(|v| v.unwrap())
.filter(|l| !l.is_empty())
.for_each(|l| println!("cargo:rustc-flags={l}"));
finish_cmd(cmd.wait());
}
pub fn get_cflags() -> Vec<String> {
let mut cmd = run_make()
.arg("emit-cflags")
.stdout(std::process::Stdio::piped())
.spawn()
.unwrap();
let res = cmd.stdout
.to_line_iterator()
.map(|v| v.unwrap())
.filter(|l| !l.is_empty())
.collect();
finish_cmd(cmd.wait());
res
}