use regex::Regex;
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::Path;
fn main() -> Result<(), Box<dyn Error>> {
let out_dir = env::var("OUT_DIR")?;
let out_dir = Path::new(&out_dir);
let gurobi_include = match env::var("GUROBI_HOME") {
Ok(grb) => {
println!("cargo:rustc-link-search={}/lib", grb);
Path::new(&grb).join("include")
}
Err(_) => {
if let Some(dir) = ["/usr/include", "/usr/local/include"].iter().find(|dir| {
let f = Path::new(dir).join("gurobi_c.h");
f.exists()
}) {
Path::new(dir).to_path_buf()
} else {
panic!("Can't find include file `gurobi_c.h` (maybe set GUROBI_HOME environment variable)");
}
}
};
let mut text = String::new();
File::open(gurobi_include.join("gurobi_c.h"))
.expect("Can't open header file 'gurobi_c.h'")
.read_to_string(&mut text)?;
let major: usize = Regex::new(r"#define\s+GRB_VERSION_MAJOR\s+(\d+)")?
.captures(&text)
.expect("Cannot find GRB_VERSION_MAJOR in gurobi_c.h")[1]
.parse()?;
let minor: usize = Regex::new(r"#define\s+GRB_VERSION_MINOR\s+(\d+)")?
.captures(&text)
.expect("Cannot find GRB_VERSION_MINOR in gurobi_c.h")[1]
.parse()?;
println!("cargo:rustc-link-lib=gurobi{}{}", major, minor);
let bindings = bindgen::Builder::default()
.header(gurobi_include.join("gurobi_c.h").to_str().unwrap())
.allowlist_function("GRB.*")
.allowlist_type("GRB.*")
.allowlist_var("GRB.*")
.blocklist_type("FILE")
.blocklist_type("_.*")
.opaque_type("GRBmodel")
.opaque_type("GRBenv")
.opaque_type("GRBsvec")
.opaque_type("GRBbatch")
.generate()
.map_err(|_| "Can't generate bindings".to_string())?;
let result = bindings.to_string();
let result = Regex::new(r#"pub const (.*) &(?:'static )?\[u8;.*?\](.*");"#)?.replace_all(
&result,
"pub const $1 *const ::std::os::raw::c_char $2 as *const u8 as *const ::std::os::raw::c_char;",
);
let result = Regex::new(r#": [ui]32 = (.*);"#)?.replace_all(&result, ": ::std::os::raw::c_int = $1;");
let result = Regex::new(r#": [ui]8 = (.*)([ui]8)?;"#)?
.replace_all(&result, ": ::std::os::raw::c_char = $1 as ::std::os::raw::c_char;");
std::fs::write(out_dir.join("gurobi-extern.rs"), result.into_owned())?;
Ok(())
}