1
0
mirror of https://github.com/TREX-CoE/trexio.git synced 2024-06-02 19:35:40 +02:00
trexio/rust/trexio/build.rs

728 lines
27 KiB
Rust

extern crate reqwest;
extern crate tar;
extern crate flate2;
const VERSION: &str = "2.4.2";
const WRAPPER_H: &str = "wrapper.h";
const GENERATED_RS: &str = "generated.rs";
use std::env;
use std::path::PathBuf;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
use serde_json::Value;
use flate2::read::GzDecoder;
use tar::Archive;
fn download_trexio() -> PathBuf {
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let trexio_url = format!("https://github.com/TREX-CoE/trexio/releases/download/v{VERSION}/trexio-{VERSION}.tar.gz");
// Download the .tar.gz archive
let tar_gz = out_path.join("trexio.tar.gz");
let trexio_dir= out_path.join("trexio_dir");
let mut resp = reqwest::blocking::get(trexio_url).expect("Failed to download the archive");
let mut out = File::create(tar_gz.clone()).expect("Failed to create archive file");
std::io::copy(&mut resp, &mut out).expect("Failed to copy content");
// Unpack the .tar.gz archive
let tar_gz = File::open(tar_gz).unwrap();
let tar = GzDecoder::new(tar_gz);
let mut archive = Archive::new(tar);
archive.unpack(trexio_dir.clone()).expect("Failed to unpack");
// Assume that the archive extracts to a directory named 'trexio-0.1.0'
trexio_dir.join(format!("trexio-{}", VERSION))
}
fn install_trexio(trexio_dir: &PathBuf) -> PathBuf {
println!("{}", trexio_dir.display());
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let install_path = out_path.join("trexio_install");
// Run configure script
let configure_status = std::process::Command::new("./configure")
.arg(format!("--prefix={}",install_path.display()))
.arg("--without-fortran")
.current_dir(&trexio_dir)
.status()
.unwrap();
assert!(configure_status.success());
// Run make
let make_status = std::process::Command::new("make")
.arg("install")
.current_dir(&trexio_dir)
.status()
.unwrap();
assert!(make_status.success());
install_path
}
/// This function reads from `trexio.h`, extracts the exit codes and backends, and writes them to `wrapper.h`.
fn make_interface(trexio_h: &PathBuf) -> io::Result<()> {
let mut err = HashMap::new();
let mut be = HashMap::new();
let trexio_file = File::open(trexio_h)?;
let trexio_reader = BufReader::new(trexio_file);
for line in trexio_reader.lines() {
let line = line?;
let buf = line.trim_start();
if buf.starts_with("#define TREXIO_") && buf.contains("(trexio_exit_code)") {
let buf2 = buf.replace(")", "");
let buf2 = buf2.replace("(", "");
let buf2: Vec<&str> = buf2.split_whitespace().collect();
err.insert(buf2[1].to_string(), buf2[3].trim().parse::<i32>().unwrap());
}
if buf.starts_with("#define TREXIO_") && buf.contains("(back_end_t)") {
let buf2 = buf.replace(")", "");
let buf2 = buf2.replace("(", "");
let buf2: Vec<&str> = buf2.split_whitespace().collect();
be.insert(buf2[1].to_string(), buf2[3].trim().parse::<i32>().unwrap());
}
}
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let wrapper_h = out_path.join(WRAPPER_H);
let mut wrapper_file = File::create(wrapper_h)?;
write!(&mut wrapper_file, "#include <trexio.h>\n")?;
for (k, v) in &err {
write!(&mut wrapper_file, "#undef {}\n", k)?;
write!(&mut wrapper_file, "const trexio_exit_code {} = {};\n", k, v)?;
}
for (k, v) in &be {
write!(&mut wrapper_file, "#undef {}\n", k)?;
write!(&mut wrapper_file, "const back_end_t {} = {};\n", k, v)?;
}
write!(&mut wrapper_file, "#undef TREXIO_AUTO\n")?;
write!(&mut wrapper_file, "const back_end_t TREXIO_AUTO = TREXIO_INVALID_BACK_END;\n")?;
Ok(())
}
/// Type conversions for Rust API
fn convert_r(typ: &str) -> String {
match typ {
"int" => "i64",
"int special" => "usize",
"float" | "float sparse" | "float buffered" => "f64",
"dim" | "dim readonly" | "index" => "usize",
"str" => "str",
_ => panic!("Unknown type to convert: {}", typ)
}.to_string()
}
/// Type conversion to call C functions
fn convert_c(typ: &str) -> String {
match typ {
"int" | "int special" | "dim" | "dim readonly" | "index" => "i64",
"float" | "float sparse" | "float buffered" => "f64",
"str" => "str",
_ => panic!("Unknown type to convert: {}", typ)
}.to_string()
}
/// Generate has-functions for checking the existence of groups and elements in a TREXIO file.
///
/// # Parameters
/// * `data` - The JSON-like data containing the groups and elements.
///
/// # Returns
/// A `Vec<String>` containing the generated Rust code as strings.
fn make_has_functions(data: &Value) -> Vec<String> {
let mut r = Vec::new();
if let Value::Object(groups) = data {
for (group, elements) in groups.iter() {
let group_l = group.to_lowercase();
let has_group_func = format!(
"/// Checks if the group `{group}` exists in the file.
/// # Parameters
///
/// None
///
/// # Returns
///
/// * `Result<bool, ExitCode>` - Returns `Ok(true)` if the element exists in the file,
/// otherwise returns `Ok(false)`. An error during the execution results in `Err(ExitCode)`.
pub fn has_{group_l}(&self) -> Result<bool, ExitCode> {{
let rc = unsafe {{ c::trexio_has_{group}(self.ptr) }};
match rc {{
c::TREXIO_SUCCESS => Ok(true),
c::TREXIO_HAS_NOT => Ok(false),
x => Err(ExitCode::from(x)),
}}
}}");
r.push(has_group_func);
if let Value::Object(elements_map) = elements {
for (element, _types_value) in elements_map.iter() {
let element_l = element.to_lowercase();
let has_element_func = format!(
"/// Checks if the element `{element}` of the group `{group}` exists in the file.
///
/// # Parameters
///
/// None
///
/// # Returns
///
/// * `Result<bool, ExitCode>` - Returns `Ok(true)` if the element exists in the file,
/// otherwise returns `Ok(false)`. An error during the execution results in `Err(ExitCode)`.
pub fn has_{group_l}_{element_l}(&self) -> Result<bool, ExitCode> {{
let rc = unsafe {{ c::trexio_has_{group}_{element}(self.ptr) }};
match rc {{
c::TREXIO_SUCCESS => Ok(true),
c::TREXIO_HAS_NOT => Ok(false),
x => Err(ExitCode::from(x)),
}}
}}");
r.push(has_element_func);
}
}
}
}
r
}
fn make_scalar_functions(data: &serde_json::Value) -> Vec<String> {
let mut r: Vec<String> = Vec::new();
for group in data.as_object().unwrap().keys() {
let group_l = group.to_lowercase();
for (element, attributes) in data[group].as_object().unwrap() {
let typ = attributes[0].as_str().unwrap();
let type_c = convert_c(typ);
let type_r = convert_r(typ);
let element_l = element.to_lowercase();
if attributes[1].as_array().unwrap().is_empty() {
match typ {
"int" | "float" | "dim" | "index" => {
let s = format!(r#"
/// Reads the scalar element `{element}` from the group `{group}` in the file.
///
/// # Parameters
///
/// None
///
/// # Returns
///
/// * `Result<{type_r}, ExitCode>` - Returns the scalar element as a `{type_r}` upon successful
/// operation. If the operation fails, it returns `Err(ExitCode)`.
pub fn read_{group_l}_{element_l}(&self) -> Result<{type_r}, ExitCode> {{
let mut data_c: {type_c} = 0{type_c};
let (rc, data) = unsafe {{
let rc = c::trexio_read_{group}_{element}_64(self.ptr, &mut data_c);
(rc, data_c.try_into().expect("try_into failed in read_{group_l}_{element_l}"))
}};
rc_return(data, rc)
}}
/// Writes the scalar element `{element}` into the group `{group}` in the file.
///
/// # Parameters
///
/// * `data: {type_r}` - A `{type_r}` scalar element that will be written into `{element}` in the group `{group}`.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` upon successful operation, otherwise returns `Err(ExitCode)`.
pub fn write_{group_l}_{element_l}(&self, data: {type_r}) -> Result<(), ExitCode> {{
let data: {type_c} = data.try_into().expect("try_into failed in write_{group_l}_{element_l}");
let rc = unsafe {{ c::trexio_write_{group}_{element}_64(self.ptr, data) }};
rc_return((), rc)
}}
"#);
r.push(s);
},
"str" => {
let s = format!(r#"
/// Reads the string attribute `{element}` contained in the group `{group}`.
/// # Parameters
///
/// * `capacity: usize` - The maximum buffer size allocated for the string to be read.
///
/// # Returns
///
/// * `Result<String, ExitCode>` - Returns the attribute as a `String` upon successful operation.
/// If the operation fails, it returns `Err(ExitCode)`.
pub fn read_{group_l}_{element_l}(&self, capacity: usize) -> Result<String, ExitCode> {{
let data_c = CString::new(vec![ b' ' ; capacity]).expect("CString::new failed");
let (rc, data) = unsafe {{
let data_c = data_c.into_raw() as *mut c_char;
let rc = c::trexio_read_{group}_{element}(self.ptr, data_c, capacity.try_into().expect("try_into failed in read_{group_l}_{element_l}"));
(rc, CString::from_raw(data_c))
}};
let result : String = CString::into_string(data).expect("into_string failed in read_{group_l}_{element_l}");
rc_return(result, rc)
}}
/// Writes the string attribute `{element}` into the group `{group}`.
///
/// # Parameters
///
/// * `data: &str` - The string attribute that will be written into the `{element}` field in the `{group}` group.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` upon successful operation.
/// If the operation fails, it returns `Err(ExitCode)`.
pub fn write_{group_l}_{element_l}(&self, data: &str) -> Result<(), ExitCode> {{
let size : i32 = data.len().try_into().expect("try_into failed in write_{group_l}_{element_l}");
let data = string_to_c(data);
let data = data.as_ptr() as *const c_char;
let rc = unsafe {{ c::trexio_write_{group}_{element}(self.ptr, data, size) }};
rc_return((), rc)
}}
"#);
r.push(s);
},
"dim readonly" => {
let s = format!(r#"
/// Reads the dimensioning variable `{element}` from the group `{group}`.
///
/// # Parameters
///
/// None.
///
/// # Returns
///
/// * `Result<{type_r}, ExitCode>` - Returns the dimensioning variable `{element}` of type `{type_r}`
/// upon successful operation. If the operation fails, it returns `Err(ExitCode)`.
pub fn read_{group_l}_{element_l}(&self) -> Result<{type_r}, ExitCode> {{
let mut data_c: {type_c} = 0{type_c};
let (rc, data) = unsafe {{
let rc = c::trexio_read_{group}_{element}_64(self.ptr, &mut data_c);
(rc, data_c.try_into().expect("try_into failed in read_{group_l}_{element_l}"))
}};
rc_return(data, rc)
}}
"#);
r.push(s);
},
_ => {}
}
}
}
}
r
}
fn make_array_functions(data: &serde_json::Value) -> Vec<String> {
let mut r: Vec<String> = Vec::new();
for group in data.as_object().unwrap().keys() {
let group_l = group.to_lowercase();
for (element, attributes) in data[group].as_object().unwrap() {
let typ = attributes[0].as_str().unwrap();
let type_c = convert_c(typ);
let type_r = convert_r(typ);
let element_l = element.to_lowercase();
let dimensions = attributes[1].as_array().unwrap();
let dimensions: Vec<&str> = dimensions.iter().map(|x| x.as_str().unwrap()).collect();
let dimensions_str = format!("{:?}", dimensions).replace("\"","");
if ! dimensions.is_empty() {
match typ {
"int" | "float" | "dim" | "index" => {
r.push(format!(r#"
/// Reads the `{element}` array from the group `{group}` in the file.
///
/// # Dimensions
///
/// The array is of dimension `{dimensions_str}`.
///
/// # Returns
///
/// * `Result<Vec<{type_r}>, ExitCode>` - Returns a flattened one-dimensional vector that contains
/// the elements of the `{element}` array. If the operation is unsuccessful, it returns `Err(ExitCode)`.
///
///"#));
if dimensions.len() > 1 {
r.push(format!(r#"
/// # Example
///
/// To reshape the one-dimensional vector back into a two-dimensional array, you can use the [`chunks`] method:
///
/// ```text
/// let one_d_array = trexio_file.read_{}_{}()?;"#, group_l, element_l));
if let Some(dim) = dimensions.first() {
if dim.contains('.') {
let parts: Vec<&str> = dim.split('.').collect();
r.push(format!("/// let {}_{} = trexio_file.read_{}_{}()?;", parts[0], parts[1], parts[0], parts[1]));
r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}_{}).collect();", parts[0], parts[1]));
} else {
r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}).collect();", dim));
}
}
r.push(String::from("/// ```"));
r.push(String::from("///\n/// [`chunks`]: slice::chunks"));
}
r.push(format!(r#"pub fn read_{}_{}(&self) -> Result<Vec<{}>, ExitCode> {{
let mut size = 1;"#, group_l, element_l, type_r));
for dim in &dimensions {
if dim.contains('.') {
let parts: Vec<&str> = dim.split('.').collect();
r.push(format!(" size *= self.read_{}_{}()?;", parts[0], parts[1]));
} else {
r.push(format!(" size *= {};", dim));
}
}
r.push(format!(r#" let mut data: Vec<{type_r}> = Vec::with_capacity(size);
let rc = unsafe {{
let data_c = data.as_mut_ptr() as *mut {type_c};
let rc = c::trexio_read_safe_{group}_{element}_64(self.ptr, data_c, size.try_into().expect("try_into failed in read_{group}_{element} (size)"));
data.set_len(size);
rc
}};
rc_return(data, rc)
}}"#));
r.push(format!(r#"
/// Writes the `{element}` array into the group `{group}` in the file.
///
/// # Parameters
///
/// * `data: &[{type_r}]` - A one-dimensional vector that contains the elements of the `{element}` array
/// to be written into the file. The vector should be flattened from a two-dimensional array with
/// dimensions `{dimensions_str}`.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful,
/// otherwise returns `Err(ExitCode)`.""", """\
pub fn write_{group_l}_{element_l}(&self, data: &[{type_r}]) -> Result<(), ExitCode> {{
let size: i64 = data.len().try_into().expect("try_into failed in write_{group_l}_{element_l}");
let data = data.as_ptr() as *const {type_c};
let rc = unsafe {{ c::trexio_write_safe_{group}_{element}_64(self.ptr, data, size) }};
rc_return((), rc)
}}
"#));
}
,
"str" => {
r.push(format!(r#"
/// Reads the `{element}` array from the group `{group}` in the file.
///
/// # Dimensions
///
/// The array is of dimension `{dimensions_str}`.
///
/// # Returns
///
/// * `Result<Vec<{type_r}>, ExitCode>` - Returns a flattened one-dimensional vector that contains
/// the elements of the `{element}` array. If the operation is unsuccessful, it returns `Err(ExitCode)`.
///
/// "#));
if dimensions.len() > 1 {
r.push(format!(r#"/// # Example
///
/// To reshape the one-dimensional vector back into a two-dimensional array, you can use the [`chunks`] method:
///
/// ```text
/// let one_d_array = trexio_file.read_{}_{}()?;"#, group_l, element_l));
if let Some(dim) = dimensions.first() {
if dim.contains('.') {
let parts: Vec<&str> = dim.split('.').collect();
r.push(format!("/// let {}_{} = trexio_file.read_{}_{}()?;", parts[0], parts[1], parts[0], parts[1]));
r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}_{}).collect();", parts[0], parts[1]));
} else {
r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}).collect();", dim));
}
}
r.push(String::from("/// ```"));
r.push(String::from("///\n/// [`chunks`]: slice::chunks"));
}
r.push(format!(r#"pub fn read_{}_{}(&self, capacity: usize) -> Result<Vec<String>, ExitCode> {{
let mut size = 1;"#, group_l, element_l));
for dim in &dimensions {
if dim.contains('.') {
let parts: Vec<&str> = dim.split('.').collect();
r.push(format!(" size *= self.read_{}_{}()?;", parts[0], parts[1]));
} else {
r.push(format!(" size *= {};", dim));
}
}
r.push(format!(r#" // Allocate an array of *mut i8 pointers (initialized to null)
let mut dset_out: Vec<*mut i8> = vec![std::ptr::null_mut(); size];
// Allocate C-style strings and populate dset_out
for item in dset_out.iter_mut().take(size) {{
let c_str: *mut i8 = unsafe {{ std::alloc::alloc_zeroed(std::alloc::Layout::array::<i8>(capacity).unwrap()) as *mut i8 }};
if c_str.is_null() {{
return Err(ExitCode::AllocationFailed);
}}
*item = c_str;
}}
let rc = unsafe {{
c::trexio_read_{group}_{element}(self.ptr, dset_out.as_mut_ptr(), capacity.try_into().expect("try_into failed in read_{group}_{element} (capacity)") )
}};
// Convert the populated C strings to Rust Strings
let mut rust_strings = Vec::new();
for &c_str in &dset_out {{
let rust_str = unsafe {{
std::ffi::CStr::from_ptr(c_str)
.to_string_lossy()
.into_owned()
}};
rust_strings.push(rust_str);
}}
// Clean up allocated C strings
for &c_str in &dset_out {{
unsafe {{ std::alloc::dealloc(c_str as *mut u8, std::alloc::Layout::array::<i8>(capacity).unwrap()) }};
}}
rc_return(rust_strings, rc)
}}
/// Writes the `{element}` array into the group `{group}` in the file.
///
/// # Parameters
///
/// * `data: &[{type_r}]` - A one-dimensional vector that contains the elements of the `{element}` array
/// to be written into the file. The vector should be flattened from a two-dimensional array with
/// dimensions `{dimensions_str}`.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful,
/// otherwise returns `Err(ExitCode)`.
pub fn write_{group_l}_{element_l}(&self, data: &[&str]) -> Result<(), ExitCode> {{
let mut size = 0;
// Find longest string
for s in data {{
let l = s.len();
size = if l>size {{l}} else {{size}};
}}
size += 1;
let data_c : Vec<CString> = data.iter().map(|&x| string_to_c(x)).collect::<Vec<_>>();
let data_c : Vec<*const c_char> = data_c.iter().map(|x| x.as_ptr() as *const c_char).collect::<Vec<_>>();
let size : i32 = size.try_into().expect("try_into failed in write_{group}_{element} (size)");
let data_c = data_c.as_ptr() as *mut *const c_char;
let rc = unsafe {{ c::trexio_write_{group}_{element}(self.ptr, data_c, size) }};
rc_return((), rc)
}}
"#));
},
"float sparse" => {
let size = dimensions.len();
let typ = [ "(", (vec![ "usize" ; size ]).join(", ").as_str(),", f64)"].join("");
r.push(format!(r#"
/// Reads a buffer of {element} from group {group}.
///
/// # Parameters
///
/// * `offset: usize` - The starting point in the array from which data will be read.
/// * `buffer_size: usize` - The size of the buffer in which read data will be stored.
///
/// # Returns
///
/// * `Result<Vec<{typ}>, ExitCode>` - Returns a vector of tuples containing
/// the indices and the value of the element. The vector has a length of at most `buffer_size`.
///
/// # Notes
///
/// The reading process is a buffered operation, meaning that only a segment of the full array
/// is read into the memory.
pub fn read_{group_l}_{element_l}(&self, offset: usize, buffer_size:usize) -> Result<Vec<{typ}>, ExitCode> {{
let mut idx = Vec::<i32>::with_capacity({size}*buffer_size);
let mut val = Vec::<f64>::with_capacity(buffer_size);
let idx_ptr = idx.as_ptr() as *mut i32;
let val_ptr = val.as_ptr() as *mut f64;
let offset: i64 = offset.try_into().expect("try_into failed in read_{group}_{element} (offset)");
let mut buffer_size_read: i64 = buffer_size.try_into().expect("try_into failed in read_{group}_{element} (buffer_size)");
let rc = unsafe {{ c::trexio_read_safe_{group}_{element}(self.ptr,
offset, &mut buffer_size_read, idx_ptr, buffer_size_read, val_ptr, buffer_size_read)
}};
let rc = match ExitCode::from(rc) {{
ExitCode::End => ExitCode::to_c(&ExitCode::Success),
_ => rc
}};
let buffer_size_read: usize = buffer_size_read.try_into().expect("try_into failed in read_{group}_{element} (buffer_size)");
unsafe {{ idx.set_len({size}*buffer_size_read) }};
unsafe {{ val.set_len(buffer_size_read) }};
let idx: Vec::<&[i32]> = idx.chunks({size}).collect();
let mut result = Vec::<{typ}>::with_capacity(buffer_size);
for (i, v) in zip(idx, val) {{
result.push( ("#));
let mut x = Vec::new();
for k in 0..size {
x.push(format!("i[{k}].try_into().unwrap()"))
};
x.push("v));\n }\n rc_return(result, rc)\n}".to_string());
r.push(x.join(", "));
r.push(format!(r#"/// Writes a buffer of {element} from group {group}.
///
/// # Parameters
///
/// * `offset: usize` - The starting point in the array at which data will be written.
/// * `data: &[{typ}]` - A slice of tuples containing the indices and the value of the element.
///
/// # Returns
///
/// * `Result<(), ExitCode>` - Returns `Ok(())` if the writing operation is successful,
/// otherwise returns `Err(ExitCode)`.
///
/// # Notes
///
/// The writing process is a buffered operation, meaning that only a segment of the full array
/// is written into the file.
pub fn write_{group_l}_{element_l}(&self, offset: usize, data: &[{typ}]) -> Result<(), ExitCode> {{
let mut idx = Vec::<i32>::with_capacity({size}*data.len());
let mut val = Vec::<f64>::with_capacity(data.len());
for d in data {{ "#));
let mut x = Vec::new();
for k in 0..size {
x.push(format!(" idx.push(d.{k}.try_into().unwrap());"))
};
r.push(x.join("\n"));
r.push(format!(r#"
val.push(d.{size});
}}
let size_max: i64 = data.len().try_into().expect("try_into failed in write_{group}_{element} (size_max)");
let buffer_size = size_max;
let idx_ptr = idx.as_ptr() as *const i32;
let val_ptr = val.as_ptr() as *const f64;
let offset: i64 = offset.try_into().expect("try_into failed in write_{group}_{element} (offset)");
let rc = unsafe {{ c::trexio_write_safe_{group}_{element}(self.ptr,
offset, buffer_size, idx_ptr, size_max, val_ptr, size_max) }};
rc_return((), rc)
}}"#));
},
_ => {}
}
}
}
}
r
}
/// Reads the JSON file, processes its contents, and generates Rust functions according to the specifications in the JSON data.
fn make_functions(json_path: &PathBuf) -> std::io::Result<()> {
let file = File::open(json_path).unwrap();
let data: Value = serde_json::from_reader(file).unwrap();
let mut r: Vec<String> = vec![
String::from("
use std::ffi::CString;
use std::iter::zip;
/// This implementation block includes additional functions automatically generated from tables.
/// For more details, refer to [TREXIO tables documentation](https://trex-coe.github.io/trexio/trex.html).
impl File {
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::type_complexity)]
"),
];
r.append(&mut make_has_functions(&data));
r.append(&mut make_scalar_functions(&data));
r.append(&mut make_array_functions(&data));
r.push(String::from("}"));
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let generated_rs = out_path.join(GENERATED_RS);
let mut f = File::create(&generated_rs)?;
f.write_all(r.join("\n").as_bytes())?;
Ok(())
}
fn main() {
let source_path = download_trexio();
println!("source path: {}", source_path.display());
let install_path = install_trexio(&source_path);
println!("install path: {}", install_path.display());
// Tell cargo to look for shared libraries in the specified directory
println!("cargo:rustc-link-search={}/lib", install_path.display());
// Tell cargo to tell rustc to link the system trexio shared library.
println!("cargo:rustc-link-lib=trexio");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let trexio_h = install_path.join("include").join("trexio.h");
println!("trexio.h: {}", trexio_h.display());
make_interface(&trexio_h).unwrap();
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let wrapper_h = out_path.join(WRAPPER_H);
println!("wrapper.h: {}", wrapper_h.display());
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header(wrapper_h.to_str().unwrap())
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let bindings_path = out_path.join("bindings.rs");
println!("bindings.rs: {}", bindings_path.display());
bindings
.write_to_file(&bindings_path)
.expect("Couldn't write bindings!");
let json_path = source_path.join("trex.json");
println!("json path: {}", json_path.display());
make_functions(&json_path).unwrap();
}