Skip to content
Merged
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,32 @@ jobs:
- name: Build and test all crates
run: cargo test -vv

mingw:
name: mingw
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
rust: [stable]
steps:
- name: Checkout repository
uses: actions/checkout@v2
with: {submodules: true}
- name: Install Rust (${{matrix.rust}})
uses: actions-rs/toolchain@v1
with: {toolchain: '${{matrix.rust}}', target: x86_64-pc-windows-gnu, profile: minimal, override: true}
- name: Install HDF5
shell: pwsh
run: |
$env:PATH="$env:PATH;C:\msys64\mingw64\bin;C:\msys64\usr\bin;"
C:\msys64\usr\bin\pacman.exe -Syu --noconfirm
C:\msys64\usr\bin\pacman.exe -S --noconfirm mingw-w64-x86_64-hdf5 mingw-w64-x86_64-pkgconf
- name: Build and test all crates
shell: pwsh
run: |
$env:PATH="$env:PATH;C:\msys64\mingw64\bin;"
cargo test -vv --target=x86_64-pc-windows-gnu

msrv:
name: Minimal Supported Rust Version
runs-on: ubuntu-20.04
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- Avoid creating unaligned references in `H5Type` derive macro.
- Applying filters without chunking will now produce an explicit error.
- Fixed a bug where chunking could not be enabled for zero-sized extents.
- Fixed library finding on Windows with MSYS2-distributed MinGW HDF5.

## 0.8.1

Expand Down
2 changes: 1 addition & 1 deletion hdf5-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ deprecated = ["hdf5-src/deprecated"]
libloading = "0.8"
regex = { workspace = true }

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

[target.'cfg(windows)'.build-dependencies]
Expand Down
60 changes: 45 additions & 15 deletions hdf5-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl Version {
}

pub fn parse(s: &str) -> Option<Self> {
let re = Regex::new(r"^(1)\.(8|10|12|13|14)\.(\d\d?)(_\d+)?(-(patch)?\d+)?$").ok()?;
let re = Regex::new(r"^(1)\.(8|10|12|13|14)\.(\d\d?)(_\d+)?((-|.)(patch)?\d+)?$").ok()?;
let captures = re.captures(s)?;
Some(Self {
major: captures.get(1).and_then(|c| c.as_str().parse::<u8>().ok())?,
Expand Down Expand Up @@ -73,6 +73,13 @@ fn is_root_dir<P: AsRef<Path>>(path: P) -> bool {
is_inc_dir(path.as_ref().join("include"))
}

#[allow(dead_code)]
fn is_msvc() -> bool {
// `cfg!(target_env = "msvc")` will report wrong value when using
// MSVC toolchain targeting GNU.
std::env::var("CARGO_CFG_TARGET_ENV").unwrap() == "msvc"
}

#[derive(Clone, Debug)]
struct RuntimeError(String);

Expand Down Expand Up @@ -115,7 +122,7 @@ fn get_runtime_version_single<P: AsRef<Path>>(path: P) -> Result<Version, Box<dy

fn validate_runtime_version(config: &Config) {
println!("Looking for HDF5 library binary...");
let libfiles = &["libhdf5.dylib", "libhdf5.so", "hdf5.dll"];
let libfiles = &["libhdf5.dylib", "libhdf5.so", "hdf5.dll", "libhdf5-0.dll", "libhdf5-310.dll"];
let mut link_paths = config.link_paths.clone();
if cfg!(all(unix, not(target_os = "macos"))) {
if let Some(ldv) = run_command("ld", &["--verbose"]) {
Expand Down Expand Up @@ -233,16 +240,24 @@ pub struct LibrarySearcher {
pub inc_dir: Option<PathBuf>,
pub link_paths: Vec<PathBuf>,
pub user_provided_dir: bool,
pub pkg_conf_found: bool,
}

#[cfg(all(unix, not(target_os = "macos")))]
mod unix {
#[cfg(any(all(unix, not(target_os = "macos")), windows))]
mod pkgconf {
use super::{is_inc_dir, LibrarySearcher};

pub fn find_hdf5_via_pkg_config(config: &mut LibrarySearcher) {
if config.inc_dir.is_some() {
return;
}

// If we're going to windows-gnu we can use pkg-config, but only so long as
// we're coming from a windows host.
if cfg!(windows) {
std::env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");
}

// Try pkg-config. Note that HDF5 only ships pkg-config metadata
// in CMake builds (which is not what homebrew uses, for example).
// Still, this would work sometimes on Linux.
Expand Down Expand Up @@ -272,8 +287,16 @@ mod unix {
} else {
println!("Unable to locate HDF5 headers from pkg-config info.");
}

config.pkg_conf_found = true;
}
}
}

#[cfg(all(unix, not(target_os = "macos")))]
mod unix {
pub use super::pkgconf::find_hdf5_via_pkg_config;
use super::{is_inc_dir, LibrarySearcher};

pub fn find_hdf5_in_default_location(config: &mut LibrarySearcher) {
if config.inc_dir.is_some() {
Expand Down Expand Up @@ -373,6 +396,7 @@ mod macos {

#[cfg(windows)]
mod windows {
pub use super::pkgconf::find_hdf5_via_pkg_config;
use super::*;

use std::io;
Expand Down Expand Up @@ -461,7 +485,7 @@ mod windows {

pub fn find_hdf5_via_winreg(config: &mut LibrarySearcher) {
// Official HDF5 binaries on Windows are built for MSVC toolchain only.
if config.inc_dir.is_some() || !cfg!(target_env = "msvc") {
if config.inc_dir.is_some() || !is_msvc() {
return;
}
// Check the list of installed programs, see if there's HDF5 anywhere;
Expand All @@ -476,11 +500,13 @@ mod windows {
pub fn validate_env_path(config: &LibrarySearcher) {
if let Some(ref inc_dir) = config.inc_dir {
let var_path = env::var("PATH").unwrap_or_else(|_| Default::default());
let bin_dir = inc_dir.parent().unwrap().join("bin");
let bin_dir = inc_dir.parent().unwrap().join("bin").canonicalize().unwrap();
for path in env::split_paths(&var_path) {
if path == bin_dir {
println!("Found in PATH: {:?}", path);
return;
if let Ok(path) = path.canonicalize() {
if path == bin_dir {
println!("Found in PATH: {:?}", path);
return;
}
}
}
panic!("{:?} not found in PATH.", bin_dir);
Expand All @@ -502,7 +528,7 @@ impl LibrarySearcher {
config.user_provided_dir = true;
config.inc_dir = Some(root.join("include"));
}
if cfg!(target_env = "msvc") {
if is_msvc() {
// in order to allow HDF5_DIR to be pointed to a conda environment, we have
// to support MSVC as a special case (where the root is in $PREFIX/Library)
if let Some(ref inc_dir) = config.inc_dir {
Expand Down Expand Up @@ -541,6 +567,7 @@ impl LibrarySearcher {
#[cfg(windows)]
{
self::windows::find_hdf5_via_winreg(self);
self::windows::find_hdf5_via_pkg_config(self);
// the check below is for dynamic linking only
self::windows::validate_env_path(self);
}
Expand Down Expand Up @@ -570,17 +597,20 @@ impl LibrarySearcher {
if link_paths.is_empty() {
if let Some(root_dir) = inc_dir.parent() {
link_paths.push(root_dir.join("lib"));
if cfg!(target_env = "msvc") {
link_paths.push(root_dir.join("bin"));
}
link_paths.push(root_dir.join("bin"));
}
}
let header = Header::parse(inc_dir);
if let Some(version) = self.version {
assert_eq!(header.version, version, "HDF5 header version mismatch",);
}
let config = Config { inc_dir: inc_dir.clone(), link_paths, header };
validate_runtime_version(&config);
// Don't check version if pkg-config finds the library and this is a windows target.
// We trust the pkg-config provided path, to avoid updating dll names every time
// the package updates.
if !(self.pkg_conf_found && cfg!(windows)) {
validate_runtime_version(&config);
}
config
} else {
panic!("Unable to determine HDF5 location (set HDF5_DIR to specify it manually).");
Expand All @@ -604,7 +634,7 @@ impl Config {
println!("cargo:rerun-if-env-changed=HDF5_DIR");
println!("cargo:rerun-if-env-changed=HDF5_VERSION");

if cfg!(target_env = "msvc") {
if is_msvc() {
println!("cargo:msvc_dll_indirection=1");
}
println!("cargo:include={}", self.inc_dir.to_str().unwrap());
Expand Down