# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os import sys from spack.package import * class Hdf(AutotoolsPackage): """HDF4 (also known as HDF) is a library and multi-object file format for storing and managing data between machines.""" homepage = "https://portal.hdfgroup.org" url = "https://support.hdfgroup.org/ftp/HDF/releases/HDF4.2.14/src/hdf-4.2.14.tar.gz" list_url = "https://support.hdfgroup.org/ftp/HDF/releases/" list_depth = 2 maintainers("lrknox") version("4.2.15", sha256="dbeeef525af7c2d01539906c28953f0fdab7dba603d1bc1ec4a5af60d002c459") version("4.2.14", sha256="2d383e87c8a0ca6a5352adbd1d5546e6cc43dc21ff7d90f93efa644d85c0b14a") version("4.2.13", sha256="be9813c1dc3712c2df977d4960e1f13f20f447dfa8c3ce53331d610c1f470483") version("4.2.12", sha256="dd419c55e85d1a0e13f3ea5ed35d00710033ccb16c85df088eb7925d486e040c") version("4.2.11", sha256="c3f7753b2fb9b27d09eced4d2164605f111f270c9a60b37a578f7de02de86d24") variant("szip", default=False, description="Enable szip support") variant( "external-xdr", default=sys.platform != "darwin", description="Use an external XDR backend" ) variant("netcdf", default=False, description="Build NetCDF API (version 2.3.2)") variant("fortran", default=False, description="Enable Fortran interface") variant("java", default=False, description="Enable Java JNI interface") variant("shared", default=False, description="Enable shared library") variant("pic", default=True, description="Produce position-independent code") depends_on("zlib-api") depends_on("jpeg") depends_on("szip", when="+szip") depends_on("rpc", when="+external-xdr") depends_on("bison", type="build") depends_on("flex", type="build") depends_on("java@7:", when="+java", type=("build", "run")) # https://forum.hdfgroup.org/t/cant-build-hdf-4-2-14-with-jdk-11-and-enable-java/5702 patch("disable_doclint.patch", when="@:4.2.14^java@9:") conflicts("^libjpeg@:6a") # configure: error: Cannot build shared fortran libraries. # Please configure with --disable-fortran flag. conflicts("+fortran", when="+shared") # configure: error: Java requires shared libraries to be built conflicts("+java", when="~shared") # configure: WARNING: unrecognized options: --enable-java conflicts("+java", when="@:4.2.11") # The Java interface library uses netcdf-related macro definitions even # when netcdf is disabled and the macros are not defined, e.g.: # hdfsdsImp.c:158:30: error: 'MAX_NC_NAME' undeclared conflicts("+java", when="@4.2.12:4.2.13~netcdf") # TODO: '@:4.2.14 ~external-xdr' and the fact that we compile for 64 bit # architecture should be in conflict # https://github.com/knedlsepp/nixpkgs/commit/c1a2918c849a5bc766c6d55d96bc6cf85c9d27f4 patch( "https://src.fedoraproject.org/rpms/hdf/raw/edbe5f49646b609f5bc9aeeee5a2be47e9556e8c/f/hdf-ppc.patch?full_index=1", sha256="5434f29a87856aa05124c7a9409b3ec3106c30b1ad722720773623190f6bfda8", when="@4.2.15:", ) patch( "https://src.fedoraproject.org/rpms/hdf/raw/edbe5f49646b609f5bc9aeeee5a2be47e9556e8c/f/hdf-4.2.4-sparc.patch?full_index=1", sha256="ce75518cccbeb80ab976b299225ea6104c3eec1ec13c09e2289913279fcf1b39", when="@4.2.15:", ) patch( "https://src.fedoraproject.org/rpms/hdf/raw/edbe5f49646b609f5bc9aeeee5a2be47e9556e8c/f/hdf-s390.patch?full_index=1", sha256="f7d67e8c3d0dad8bfca308936c6ac917cc0b63222c6339a29efdce14e8be6475", when="@4.2.15:", ) patch( "https://src.fedoraproject.org/rpms/hdf/raw/edbe5f49646b609f5bc9aeeee5a2be47e9556e8c/f/hdf-arm.patch?full_index=1", sha256="d54592df281c92e7e655b8312d18bef9ed096848de9430510e0699e98246ccd3", when="@4.2.15:", ) patch( "https://src.fedoraproject.org/rpms/hdf/raw/edbe5f49646b609f5bc9aeeee5a2be47e9556e8c/f/hdf-aarch64.patch?full_index=1", sha256="49733dd6143be7b30a28d386701df64a72507974274f7e4c0a9e74205510ea72", when="@4.2.15:", ) # https://github.com/NOAA-EMC/spack-stack/issues/317 patch("hdfi_h_apple_m1.patch", when="@4.2.15: target=aarch64: platform=darwin") @property def libs(self): """HDF can be queried for the following parameters: - "shared": shared libraries (default if '+shared') - "static": static libraries (default if '~shared') - "transitive": append transitive dependencies to the list of static libraries (the argument is ignored if shared libraries are requested) :return: list of matching libraries """ libraries = ["libmfhdf", "libdf"] query_parameters = self.spec.last_query.extra_parameters if "shared" in query_parameters: shared = True elif "static" in query_parameters: shared = False else: shared = "+shared" in self.spec libs = find_libraries(libraries, root=self.prefix, shared=shared, recursive=True) if not libs: msg = "Unable to recursively locate {0} {1} libraries in {2}" raise spack.error.NoLibrariesError( msg.format("shared" if shared else "static", self.spec.name, self.spec.prefix) ) if not shared and "transitive" in query_parameters: libs += self.spec["jpeg:transitive"].libs libs += self.spec["zlib:transitive"].libs if "+szip" in self.spec: libs += self.spec["szip:transitive"].libs if "+external-xdr" in self.spec and self.spec["rpc"].name != "libc": libs += self.spec["rpc:transitive"].libs return libs def flag_handler(self, name, flags): if "+pic" in self.spec: if name == "cflags": flags.append(self.compiler.cc_pic_flag) elif name == "fflags": flags.append(self.compiler.f77_pic_flag) if name == "cflags": # https://forum.hdfgroup.org/t/help-building-hdf4-with-clang-error-implicit-declaration-of-function-test-mgr-szip-is-invalid-in-c99/7680 if self.spec.satisfies("@:4.2.15 %apple-clang") or self.spec.satisfies("%clang@16:"): flags.append("-Wno-error=implicit-function-declaration") if self.spec.satisfies("%clang@16:"): flags.append("-Wno-error=implicit-int") return flags, None, None def configure_args(self): config_args = [ "--enable-production", "--enable-static", "--with-zlib=%s" % self.spec["zlib-api"].prefix, "--with-jpeg=%s" % self.spec["jpeg"].prefix, ] config_args += self.enable_or_disable("shared") config_args += self.enable_or_disable("netcdf") config_args += self.enable_or_disable("fortran") config_args += self.enable_or_disable("java") if "+szip" in self.spec: config_args.append("--with-szlib=%s" % self.spec["szip"].prefix) else: config_args.append("--without-szlib") if "~external-xdr" in self.spec: config_args.append("--enable-hdf4-xdr") elif self.spec["rpc"].name != "libc": # We should not specify '--disable-hdf4-xdr' due to a bug in the # configure script. config_args.append("LIBS=%s" % self.spec["rpc"].libs.link_flags) config_args.append("LDFLAGS=%s" % self.spec["rpc"].libs.search_flags) # https://github.com/Parallel-NetCDF/PnetCDF/issues/61 if self.spec.satisfies("%gcc@10:"): config_args.extend( ["FFLAGS=-fallow-argument-mismatch", "FCFLAGS=-fallow-argument-mismatch"] ) return config_args # Otherwise, we randomly get: # SDgetfilename: # incorrect file being opened - expected , retrieved def check(self): with working_dir(self.build_directory): make("check", parallel=False) extra_install_tests = join_path("hdf", "util", "testfiles") # Filter h4cc compiler wrapper to substitute the Spack compiler # wrappers with the path of the underlying compilers. filter_compiler_wrappers("h4cc", relative_root="bin") @property def cached_tests_work_dir(self): """The working directory for cached test sources.""" return join_path(self.test_suite.current_test_cache_dir, self.extra_install_tests) @run_after("install") def setup_build_tests(self): """Copy the build test files after the package is installed to an install test subdirectory for use during `spack test run`.""" self.cache_extra_test_sources(self.extra_install_tests) def _check_version_match(self, exe): """Ensure exe version check yields spec version.""" path = join_path(self.prefix.bin, exe) if not os.path.isfile(path): raise SkipTest(f"{exe} is not installed") exe = which(path) out = exe("-V", output=str.split, error=str.split) vers = f"Version {self.spec.version.up_to(2)}" assert vers in out def test_hdfimport_version(self): """ensure hdfimport version matches spec""" self._check_version_match("hdfimport") def test_hrepack_version(self): """ensure hrepack version matches spec""" self._check_version_match("hrepack") def test_ncdump_version(self): """ensure ncdump version matches spec""" self._check_version_match("hrepack") def test_ncgen_version(self): """ensure ncgen version matches spec""" self._check_version_match("ncgen") def test_gif_converters(self): """test image conversion sequence and diff""" base_name = "storm110" storm_fn = join_path(self.cached_tests_work_dir, f"{base_name}.hdf") if not os.path.exists(storm_fn): raise SkipTest(f"Missing test image {storm_fn}") if not os.path.exists(self.prefix.bin.hdf2gif) or not os.path.exists( self.prefix.bin.gif2hdf ): raise SkipTest("Missing one or more installed: 'hdf2gif', 'gif2hdf'") gif_fn = f"{base_name}.gif" new_hdf_fn = f"{base_name}gif.hdf" with test_part( self, "test_gif_converters_hdf2gif", purpose=f"convert {base_name} hdf-to-gif" ): hdf2gif = which(self.prefix.bin.hdf2gif) hdf2gif(storm_fn, gif_fn) with test_part( self, "test_gif_converters_gif2hdf", purpose=f"convert {base_name} gif-to-hdf" ): gif2hdf = which(self.prefix.bin.gif2hdf) gif2hdf(gif_fn, new_hdf_fn) with test_part( self, "test_gif_converters_hdiff", purpose=f"compare new and orig {base_name} hdf" ): hdiff = which(self.prefix.bin.hdiff) hdiff(new_hdf_fn, storm_fn) def test_list(self): """compare low-level HDF file information to expected""" base_name = "storm110" if not os.path.isfile(self.prefix.bin.hdfls): raise SkipTest("hdfls is not installed") test_data_dir = self.test_suite.current_test_data_dir details_file = os.path.join(test_data_dir, f"{base_name}.out") expected = get_escaped_text_output(details_file) storm_fn = os.path.join(self.cached_tests_work_dir, f"{base_name}.hdf") hdfls = which(self.prefix.bin.hdfls) out = hdfls(storm_fn, output=str.split, error=str.split) check_outputs(expected, out)