Skip to content

Commit 0276592

Browse files
authored
Fix building with MSYS2 distributed MinGW hdf5 (#229)
1 parent eb75034 commit 0276592

File tree

4 files changed

+73
-16
lines changed

4 files changed

+73
-16
lines changed

.github/workflows/ci.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,32 @@ jobs:
237237
- name: Build and test all crates
238238
run: cargo test -vv
239239

240+
mingw:
241+
name: mingw
242+
runs-on: windows-latest
243+
strategy:
244+
fail-fast: false
245+
matrix:
246+
rust: [stable]
247+
steps:
248+
- name: Checkout repository
249+
uses: actions/checkout@v2
250+
with: {submodules: true}
251+
- name: Install Rust (${{matrix.rust}})
252+
uses: actions-rs/toolchain@v1
253+
with: {toolchain: '${{matrix.rust}}', target: x86_64-pc-windows-gnu, profile: minimal, override: true}
254+
- name: Install HDF5
255+
shell: pwsh
256+
run: |
257+
$env:PATH="$env:PATH;C:\msys64\mingw64\bin;C:\msys64\usr\bin;"
258+
C:\msys64\usr\bin\pacman.exe -Syu --noconfirm
259+
C:\msys64\usr\bin\pacman.exe -S --noconfirm mingw-w64-x86_64-hdf5 mingw-w64-x86_64-pkgconf
260+
- name: Build and test all crates
261+
shell: pwsh
262+
run: |
263+
$env:PATH="$env:PATH;C:\msys64\mingw64\bin;"
264+
cargo test -vv --target=x86_64-pc-windows-gnu
265+
240266
msrv:
241267
name: Minimal Supported Rust Version
242268
runs-on: ubuntu-20.04

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
- Avoid creating unaligned references in `H5Type` derive macro.
2929
- Applying filters without chunking will now produce an explicit error.
3030
- Fixed a bug where chunking could not be enabled for zero-sized extents.
31+
- Fixed library finding on Windows with MSYS2-distributed MinGW HDF5.
3132

3233
## 0.8.1
3334

hdf5-sys/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ deprecated = ["hdf5-src/deprecated"]
3434
libloading = "0.8"
3535
regex = { workspace = true }
3636

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

4040
[target.'cfg(windows)'.build-dependencies]

hdf5-sys/build.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl Version {
2929
}
3030

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

76+
#[allow(dead_code)]
77+
fn is_msvc() -> bool {
78+
// `cfg!(target_env = "msvc")` will report wrong value when using
79+
// MSVC toolchain targeting GNU.
80+
std::env::var("CARGO_CFG_TARGET_ENV").unwrap() == "msvc"
81+
}
82+
7683
#[derive(Clone, Debug)]
7784
struct RuntimeError(String);
7885

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

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

238-
#[cfg(all(unix, not(target_os = "macos")))]
239-
mod unix {
246+
#[cfg(any(all(unix, not(target_os = "macos")), windows))]
247+
mod pkgconf {
240248
use super::{is_inc_dir, LibrarySearcher};
241249

242250
pub fn find_hdf5_via_pkg_config(config: &mut LibrarySearcher) {
243251
if config.inc_dir.is_some() {
244252
return;
245253
}
254+
255+
// If we're going to windows-gnu we can use pkg-config, but only so long as
256+
// we're coming from a windows host.
257+
if cfg!(windows) {
258+
std::env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");
259+
}
260+
246261
// Try pkg-config. Note that HDF5 only ships pkg-config metadata
247262
// in CMake builds (which is not what homebrew uses, for example).
248263
// Still, this would work sometimes on Linux.
@@ -272,8 +287,16 @@ mod unix {
272287
} else {
273288
println!("Unable to locate HDF5 headers from pkg-config info.");
274289
}
290+
291+
config.pkg_conf_found = true;
275292
}
276293
}
294+
}
295+
296+
#[cfg(all(unix, not(target_os = "macos")))]
297+
mod unix {
298+
pub use super::pkgconf::find_hdf5_via_pkg_config;
299+
use super::{is_inc_dir, LibrarySearcher};
277300

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

374397
#[cfg(windows)]
375398
mod windows {
399+
pub use super::pkgconf::find_hdf5_via_pkg_config;
376400
use super::*;
377401

378402
use std::io;
@@ -461,7 +485,7 @@ mod windows {
461485

462486
pub fn find_hdf5_via_winreg(config: &mut LibrarySearcher) {
463487
// Official HDF5 binaries on Windows are built for MSVC toolchain only.
464-
if config.inc_dir.is_some() || !cfg!(target_env = "msvc") {
488+
if config.inc_dir.is_some() || !is_msvc() {
465489
return;
466490
}
467491
// Check the list of installed programs, see if there's HDF5 anywhere;
@@ -476,11 +500,13 @@ mod windows {
476500
pub fn validate_env_path(config: &LibrarySearcher) {
477501
if let Some(ref inc_dir) = config.inc_dir {
478502
let var_path = env::var("PATH").unwrap_or_else(|_| Default::default());
479-
let bin_dir = inc_dir.parent().unwrap().join("bin");
503+
let bin_dir = inc_dir.parent().unwrap().join("bin").canonicalize().unwrap();
480504
for path in env::split_paths(&var_path) {
481-
if path == bin_dir {
482-
println!("Found in PATH: {:?}", path);
483-
return;
505+
if let Ok(path) = path.canonicalize() {
506+
if path == bin_dir {
507+
println!("Found in PATH: {:?}", path);
508+
return;
509+
}
484510
}
485511
}
486512
panic!("{:?} not found in PATH.", bin_dir);
@@ -502,7 +528,7 @@ impl LibrarySearcher {
502528
config.user_provided_dir = true;
503529
config.inc_dir = Some(root.join("include"));
504530
}
505-
if cfg!(target_env = "msvc") {
531+
if is_msvc() {
506532
// in order to allow HDF5_DIR to be pointed to a conda environment, we have
507533
// to support MSVC as a special case (where the root is in $PREFIX/Library)
508534
if let Some(ref inc_dir) = config.inc_dir {
@@ -541,6 +567,7 @@ impl LibrarySearcher {
541567
#[cfg(windows)]
542568
{
543569
self::windows::find_hdf5_via_winreg(self);
570+
self::windows::find_hdf5_via_pkg_config(self);
544571
// the check below is for dynamic linking only
545572
self::windows::validate_env_path(self);
546573
}
@@ -570,17 +597,20 @@ impl LibrarySearcher {
570597
if link_paths.is_empty() {
571598
if let Some(root_dir) = inc_dir.parent() {
572599
link_paths.push(root_dir.join("lib"));
573-
if cfg!(target_env = "msvc") {
574-
link_paths.push(root_dir.join("bin"));
575-
}
600+
link_paths.push(root_dir.join("bin"));
576601
}
577602
}
578603
let header = Header::parse(inc_dir);
579604
if let Some(version) = self.version {
580605
assert_eq!(header.version, version, "HDF5 header version mismatch",);
581606
}
582607
let config = Config { inc_dir: inc_dir.clone(), link_paths, header };
583-
validate_runtime_version(&config);
608+
// Don't check version if pkg-config finds the library and this is a windows target.
609+
// We trust the pkg-config provided path, to avoid updating dll names every time
610+
// the package updates.
611+
if !(self.pkg_conf_found && cfg!(windows)) {
612+
validate_runtime_version(&config);
613+
}
584614
config
585615
} else {
586616
panic!("Unable to determine HDF5 location (set HDF5_DIR to specify it manually).");
@@ -604,7 +634,7 @@ impl Config {
604634
println!("cargo:rerun-if-env-changed=HDF5_DIR");
605635
println!("cargo:rerun-if-env-changed=HDF5_VERSION");
606636

607-
if cfg!(target_env = "msvc") {
637+
if is_msvc() {
608638
println!("cargo:msvc_dll_indirection=1");
609639
}
610640
println!("cargo:include={}", self.inc_dir.to_str().unwrap());

0 commit comments

Comments
 (0)