Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate and provide fitsio "long names" from longnam.h #382

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 139 additions & 1 deletion fitsio-sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use std::path::PathBuf;
use std::{
env,
fs::File,
io::{BufReader, BufWriter, Read, Write},
path::PathBuf,
};

fn generate_bindings<'p>(include_paths: impl Iterator<Item = &'p PathBuf>) {
#[cfg(feature = "with-bindgen")]
Expand Down Expand Up @@ -45,6 +50,8 @@ fn main() {
_ => panic!("Could not read from cfitsio source directory ext/cfitsio !"),
}

generate_aliases_mod_file(std::iter::once(&cfitsio_project_dir));

// Translate rustc optimisation levels to things a C compiler can
// understand. I don't know if all C compilers agree here, but it should
// at least work for gcc.
Expand Down Expand Up @@ -92,6 +99,7 @@ fn main() {
match config.probe(package_name) {
Ok(lib) => {
generate_bindings(lib.include_paths.iter());
generate_aliases_mod_file(lib.include_paths.iter());
}
Err(e) => {
if let pkg_config::Error::Failure { output, .. } = &e {
Expand All @@ -117,3 +125,133 @@ fn main() {
}
};
}

fn generate_aliases_mod_file<'p>(include_paths: impl Iterator<Item = &'p PathBuf>) {
let out_dir = env::var("OUT_DIR").expect("set by cargo");

let mut long_name_header = PathBuf::new();
let mut long_name_header_found = false;
for include_path in include_paths {
long_name_header = include_path.join("longnam.h");
if long_name_header.exists() {
long_name_header_found = true;
break;
} else {
long_name_header.clear();
};
}

let out = PathBuf::from(out_dir).join("aliases.rs");
if long_name_header_found {
// We've found the fits long names that this library was compiled with,
// now let's alias them.
let mut file = BufReader::new(match File::open(&long_name_header) {
Ok(f) => f,
Err(e) => {
eprintln!("There was a problem attempting to read {long_name_header:?}");
panic!("{}", e);
}
});
let mut buffer = String::new();
file.read_to_string(&mut buffer).expect("file can be read");

#[cfg(not(feature = "bindgen"))]
let mut buffer2 = String::new();

let mut aliases = Vec::new();
// fits_open_file is special and has a dirty macro associated with it:
// #define fits_open_file(A, B, C, D) ffopentest( CFITSIO_SONAME, A, B, C, D)
// Include this alias manually.
aliases.push(("fits_open_file", "ffopen"));

// These are the other functions to handle carefully.
let bad_long_names = [
"fits_open_file", // Handled above
"fits_parse_output_url", // Not included in this crate?
];

// There may be functions missing in the crate's provided bindings. Find
// them and don't allow long names to be provided for them.
#[cfg(not(feature = "bindgen"))]
let mut available_short_names = Vec::new();
#[cfg(not(feature = "bindgen"))]
{
#[cfg(target_pointer_width = "64")]
let filename = "src/bindings_64.rs";
#[cfg(target_pointer_width = "32")]
let filename = "src/bindings_32.rs";

let mut file = BufReader::new(match File::open(filename) {
Ok(f) => f,
Err(e) => {
eprintln!("There was a problem attempting to read {filename:?}");
panic!("{}", e);
}
});
file.read_to_string(&mut buffer2).expect("file can be read");
for line in buffer2.lines() {
if line.trim_ascii_start().starts_with("pub fn ff") {
if let Some(fn_name) = line
.split_ascii_whitespace()
.nth(2)
.and_then(|fn_name| fn_name.strip_suffix('('))
{
available_short_names.push(fn_name);
}
}
}
}

'line: for line in buffer.lines() {
if line.starts_with("#define") && line.contains("fits_") {
let mut macro_define_elems = line.split_ascii_whitespace().skip(1);
if let (Some(long_name), Some(fitsio_name)) =
(macro_define_elems.next(), macro_define_elems.next())
{
// Handle any last trickery.
if macro_define_elems.count() != 0 {
continue;
}
for bad_long_name in bad_long_names {
if long_name.contains(bad_long_name) {
continue 'line;
}
}
#[cfg(not(feature = "bindgen"))]
if !available_short_names.contains(&fitsio_name) {
continue;
}

aliases.push((long_name, fitsio_name));
}
}
}

// Now write out these aliases.
let mut out_file = BufWriter::new(match File::create(&out) {
Ok(f) => f,
Err(e) => {
eprintln!("There was a problem attempting to create a file at {out:?}");
panic!("{}", e);
}
});
for (long, short) in aliases {
writeln!(&mut out_file, "pub use crate::{short} as {long};")
.expect("file can be written");
}
} else {
// The long names include file couldn't be found. Use the pre-filled
// default aliases file instead.
// N.B. fitsio.h includes longnam.h, so the following code probably
// never runs.
match std::fs::copy("default-aliases.rs", &out) {
Ok(_) => (),
Err(e) => {
eprintln!(
"There was a problem attempting to copy from 'default-aliases.rs' to {out:?}"
);
panic!("{}", e);
}
}
}
}
Loading
Loading