extern crate bindgen;
extern crate pkg_config;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;
use std::process::Command;
const PREBUILT_BINDINGS_URL: &str = "https://gist.github.com/pkgw/40e36f9dc0d771323205fc0617ac7141/\
raw/6405dba98cd0eec7fab483b3d090b919e1383094/bindings.rs";
fn main() {
let mut do_the_bindgen = true;
let mut builder = bindgen::Builder::default()
.header("src/wrapper.h");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let bindings_path = out_dir.join("bindings.rs");
if cfg!(slurmrs_on_docs_rs) {
do_the_bindgen = false;
Command::new("curl")
.arg("-sSL")
.arg("-o")
.arg(&bindings_path)
.arg(PREBUILT_BINDINGS_URL)
.status()
.expect("failed to execute process");
} else if let Ok(libdir) = env::var("SLURM_LIBDIR") {
println!("cargo:rustc-link-search=native={}", libdir);
println!("cargo:rustc-link-lib=dylib=slurm");
println!("cargo:rustc-link-lib=dylib=slurmdb");
if let Ok(incdir) = env::var("SLURM_INCDIR") {
builder = builder.clang_arg(format!("-I{}", incdir));
}
} else {
let slurm = pkg_config::Config::new().atleast_version("15.0").probe("slurm").unwrap();
println!("cargo:rustc-link-lib=dylib=slurmdb");
for ref path in &slurm.include_paths {
builder = builder.clang_arg(format!("-I{}", path.display()));
}
}
if do_the_bindgen {
let bindings = builder
.whitelist_type("job_.*")
.whitelist_type("slurm_.*")
.whitelist_type("slurmdb_.*")
.whitelist_function("slurm_.*")
.whitelist_function("slurmdb_.*")
.whitelist_var("ESCRIPT.*")
.whitelist_var("ESLURM.*")
.whitelist_var("SLURM.*")
.whitelist_var("SLURMDB.*")
.whitelist_var("SLURMRS.*")
.rustfmt_bindings(true)
.generate()
.expect("Unable to generate bindings");
bindings
.write_to_file(&bindings_path)
.expect("Couldn't write bindings!");
}
let bindings_file = File::open(&bindings_path)
.expect(&format!("couldn't open bindgen output file {}", bindings_path.display()));
let bindings_buf = BufReader::new(bindings_file);
let features_path = out_dir.join("features.rs");
let mut features_file = File::create(&features_path)
.expect(&format!("couldn't create features output file {}", features_path.display()));
writeln!(features_file, "pub const C_API_FEATURES: &[&str] = &[")
.expect(&format!("couldn't write to features output file {}", features_path.display()));
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum State {
Scanning,
CheckingSelectedStepT,
CheckingSubmitResponseMsg,
}
let mut state = State::Scanning;
let mut n_lines = 0;
for maybe_line in bindings_buf.lines() {
let line = maybe_line.expect(&format!("couldn't read bindgen output file {}", bindings_path.display()));
n_lines += 1;
match state {
State::Scanning => {
if line.starts_with("pub struct slurmdb_selected_step_t {") {
state = State::CheckingSelectedStepT;
} else if line.starts_with("pub struct submit_response_msg {") {
state = State::CheckingSubmitResponseMsg;
}
},
State::CheckingSelectedStepT => {
if line == "}" {
state = State::Scanning;
} else if line.contains("pack_job_offset") {
writeln!(features_file, "\"selected_step_t_pack_job_offset\",")
.expect(&format!("couldn't write to features output file {}", features_path.display()));
}
}
State::CheckingSubmitResponseMsg => {
if line == "}" {
state = State::Scanning;
} else if line.contains("job_submit_user_msg") {
writeln!(features_file, "\"submit_response_user_message\",")
.expect(&format!("couldn't write to features output file {}", features_path.display()));
}
}
}
}
assert!(n_lines > 100, "to build this crate you must install a functional \"rustfmt\" (see README.md)");
writeln!(features_file, "];")
.expect(&format!("couldn't write to features output file {}", features_path.display()));
}