use std::mem::take;
use std::process::{Command, Stdio};
#[cfg(not(any(feature = "Lua5_3", feature = "Lua5_4")))]
compile_error!("must specify feature \"Lua5_3\" or \"Lua5_4\"");
#[cfg(all(feature = "Lua5_3", feature = "Lua5_4"))]
compile_error!("features \"Lua5_3\" and \"Lua5_4\" are currently mutually exclusive and cannot be enabled at the same time");
fn main() {
let mut include_dirs: Vec<String> = Vec::new();
let mut lib_dirs: Vec<String> = Vec::new();
let mut lib_names: Vec<String> = Vec::new();
{
#[cfg(feature = "Lua5_3")]
const PKG_NAME: &'static str = "lua-5.3";
#[cfg(feature = "Lua5_4")]
const PKG_NAME: &'static str = "lua-5.4";
#[cfg(not(any(feature = "Lua5_3", feature = "Lua5_4")))]
const PKG_NAME: &'static str = unreachable!();
let mut pkgcnf_cmd = Command::new("pkg-config");
pkgcnf_cmd
.args(["--cflags", "--libs", PKG_NAME])
.stderr(Stdio::inherit());
eprintln!("using pkg-config command: {pkgcnf_cmd:?}");
let pkgcnf = pkgcnf_cmd.output().expect("could not execute pkg-config");
eprintln!("pkg-config status: {:?}", pkgcnf.status);
eprintln!(
"pkg-config stdout: {:?}",
String::from_utf8_lossy(&pkgcnf.stdout)
);
if !pkgcnf.status.success() {
panic!("pkg-config returned with failure");
}
let mut parse_element = |s: String| {
if s.len() >= 2 {
let prefix = &s[0..2];
let value = &s[2..];
match prefix {
"-I" => include_dirs.push(value.to_string()),
"-L" => lib_dirs.push(value.to_string()),
"-l" => lib_names.push(value.to_string()),
_ => (),
}
}
};
let mut element: String = Default::default();
let mut escape: bool = false;
for ch in String::from_utf8(pkgcnf.stdout)
.expect("invalid UTF-8 from pkg-config")
.chars()
{
if escape {
element.push(ch);
escape = false;
} else if ch == '\\' {
escape = true;
} else if ch.is_ascii_whitespace() {
parse_element(take(&mut element));
} else {
element.push(ch);
}
}
if escape {
panic!("unexpected EOF from pkg-config (escape character at end)");
}
parse_element(element);
if lib_names.is_empty() {
panic!("pkg-config did not return any library name");
}
}
{
let mut builder = bindgen::Builder::default();
for dir in &include_dirs {
builder = builder.clang_arg(format!("-I{dir}"));
}
builder = builder.header("src/cmach.c");
builder = builder.parse_callbacks(Box::new(bindgen::CargoCallbacks));
let bindings = builder.generate().expect("unable to generate bindings");
let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("ffi_cmach.rs"))
.expect("unable to write bindings");
}
{
println!("cargo:rerun-if-changed=src/cmach.c");
let mut config = cc::Build::new();
for dir in &include_dirs {
config.include(dir);
}
config.file("src/cmach.c");
config.compile("libffi_cmach.a");
}
for dir in &lib_dirs {
println!("cargo:rustc-link-search=native={}", dir);
}
for name in &lib_names {
println!("cargo:rustc-link-lib={}", name);
}
}