Skip to content

Commit 04ddde5

Browse files
committed
Verify HDF5 runtime version via libloading
1 parent 09c54c8 commit 04ddde5

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

libhdf5-lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ edition = "2018"
1313
[build-dependencies]
1414
bindgen = "0.47"
1515
lazy_static = "1.2"
16+
libloading = "0.5"
1617

1718
[target.'cfg(all(unix, not(target_os = "macos")))'.build-dependencies]
1819
pkg-config = "0.3"

libhdf5-lib/build.rs

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
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};
37
use std::path::{Path, PathBuf};
48
use std::process::Command;
59
use std::str;
@@ -72,6 +76,78 @@ fn is_root_dir<P: AsRef<Path>>(path: P) -> bool {
7276
is_inc_dir(path.as_ref().join("include"))
7377
}
7478

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+
75151
#[derive(Clone, Copy, Debug, Default)]
76152
pub struct Header {
77153
pub have_stdbool_h: bool,
@@ -453,7 +529,9 @@ impl LibrarySearcher {
453529
);
454530
}
455531
}
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
457535
} else {
458536
panic!("Unable to determine HDF5 location (set HDF5_DIR to specify it manually).");
459537
}

0 commit comments

Comments
 (0)