|
1 | 1 | use std::env; |
2 | | -use std::fmt::{self, Debug}; |
| 2 | +use std::error::Error; |
| 3 | +use std::fmt::{self, Debug, Display}; |
| 4 | +use std::fs; |
| 5 | +use std::io; |
| 6 | +use std::os::raw::{c_int, c_uint}; |
3 | 7 | use std::path::{Path, PathBuf}; |
4 | 8 | use std::process::Command; |
5 | 9 | use std::str; |
@@ -72,6 +76,78 @@ fn is_root_dir<P: AsRef<Path>>(path: P) -> bool { |
72 | 76 | is_inc_dir(path.as_ref().join("include")) |
73 | 77 | } |
74 | 78 |
|
| 79 | +#[derive(Clone, Debug)] |
| 80 | +struct RuntimeError(String); |
| 81 | + |
| 82 | +impl Error for RuntimeError {} |
| 83 | + |
| 84 | +impl Display for RuntimeError { |
| 85 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 86 | + write!(f, "HDF5 runtime error: {}", self.0) |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +#[allow(non_snake_case, non_camel_case_types)] |
| 91 | +fn get_runtime_version_single<P: AsRef<Path>>(path: P) -> io::Result<Version> { |
| 92 | + let lib = libloading::Library::new(path.as_ref())?; |
| 93 | + |
| 94 | + type H5open_t = unsafe extern "C" fn() -> c_int; |
| 95 | + let H5open = unsafe { lib.get::<H5open_t>(b"H5open")? }; |
| 96 | + |
| 97 | + type H5get_libversion_t = unsafe extern "C" fn(*mut c_uint, *mut c_uint, *mut c_uint) -> c_int; |
| 98 | + let H5get_libversion = unsafe { lib.get::<H5get_libversion_t>(b"H5get_libversion")? }; |
| 99 | + |
| 100 | + let mut v: (c_uint, c_uint, c_uint) = (0, 0, 0); |
| 101 | + unsafe { |
| 102 | + if H5open() != 0 { |
| 103 | + Err(io::Error::new(io::ErrorKind::Other, Box::new(RuntimeError("H5open()".into())))) |
| 104 | + } else if H5get_libversion(&mut v.0, &mut v.1, &mut v.2) != 0 { |
| 105 | + Err(io::Error::new( |
| 106 | + io::ErrorKind::Other, |
| 107 | + Box::new(RuntimeError("H5get_libversion()".into())), |
| 108 | + )) |
| 109 | + } else { |
| 110 | + Ok(Version::new(v.0 as _, v.1 as _, v.2 as _)) |
| 111 | + } |
| 112 | + } |
| 113 | +} |
| 114 | + |
| 115 | +fn validate_runtime_version(config: &Config) { |
| 116 | + let libfiles = &["libhdf5.dylib", "libhdf5.so", "hdf5.dll"]; |
| 117 | + for link_path in &config.link_paths { |
| 118 | + if let Ok(paths) = fs::read_dir(link_path) { |
| 119 | + for path in paths { |
| 120 | + if let Ok(path) = path { |
| 121 | + let path = path.path(); |
| 122 | + if let Some(filename) = path.file_name() { |
| 123 | + let filename = filename.to_str().unwrap_or(""); |
| 124 | + if path.is_file() && libfiles.contains(&filename) { |
| 125 | + println!("Attempting to load: {:?}", path); |
| 126 | + match get_runtime_version_single(&path) { |
| 127 | + Ok(version) => { |
| 128 | + println!(" => runtime version = {:?}", version); |
| 129 | + if version == config.header.version { |
| 130 | + println!("HDF5 library runtime version matches headers."); |
| 131 | + return; |
| 132 | + } |
| 133 | + panic!( |
| 134 | + "Invalid HDF5 runtime version (expected: {:?}).", |
| 135 | + config.header.version |
| 136 | + ); |
| 137 | + } |
| 138 | + Err(err) => { |
| 139 | + println!(" => {}", err); |
| 140 | + } |
| 141 | + } |
| 142 | + } |
| 143 | + } |
| 144 | + } |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | + panic!("Unable to infer HDF5 library runtime version."); |
| 149 | +} |
| 150 | + |
75 | 151 | #[derive(Clone, Copy, Debug, Default)] |
76 | 152 | pub struct Header { |
77 | 153 | pub have_stdbool_h: bool, |
@@ -453,7 +529,9 @@ impl LibrarySearcher { |
453 | 529 | ); |
454 | 530 | } |
455 | 531 | } |
456 | | - Config { inc_dir: inc_dir.clone(), link_paths, header } |
| 532 | + let config = Config { inc_dir: inc_dir.clone(), link_paths, header }; |
| 533 | + validate_runtime_version(&config); |
| 534 | + config |
457 | 535 | } else { |
458 | 536 | panic!("Unable to determine HDF5 location (set HDF5_DIR to specify it manually)."); |
459 | 537 | } |
|
0 commit comments