Commit 5d5406d0 authored by Rob Latham's avatar Rob Latham
Browse files

extend builtin HDF5 package instead of copying

This might be the most important thing I learned at the 2020 ECP meeting
parent ca63e132
......@@ -7,360 +7,30 @@ import shutil
import sys
import subprocess
from spack import *
from spack.pkg.builtin.hdf5 import Hdf5
class Hdf5(Hdf5):
class Hdf5(AutotoolsPackage):
"""HDF5 is a data model, library, and file format for storing and managing
data. It supports an unlimited variety of datatypes, and is designed for
flexible and efficient I/O and for high volume and complex data.
homepage = ""
url = ""
list_url = ""
list_depth = 3
git = ""
version('develop', branch='develop')
version('extvol-develop', commit='474b0571462956d282331a9ee12c208d50f41032')
version('rados-develop', branch='feature/rados_vol')
version('rados-old', branch='feature/hdf5_rados')
version('1.10.5', '6d4ce8bf902a97b050f6f491f4268634e252a63dadd6656a1a9be5b7b7726fa8')
version('1.10.4', '8f60dc4dd6ab5fcd23c750d1dc5bca3d0453bdce5c8cdaf0a4a61a9d1122adb2')
version('1.10.3', 'b600d7c914cfa80ae127cd1a1539981213fee9994ac22ebec9e3845e951d9b39')
version('1.10.2', '8d4eae84e533efa57496638fd0dca8c3')
version('1.10.1', '43a2f9466702fb1db31df98ae6677f15')
version('1.10.0-patch1', '9180ff0ef8dc2ef3f61bd37a7404f295')
version('1.10.0', 'bdc935337ee8282579cd6bc4270ad199')
version('1.8.21', '87d8c82eba5cf766d97cd06c054f4639c1049c4adeaa3a79f77f8bd374f80f37')
version('1.8.19', '7f568e2464d4ab0a74d16b23956d900b')
version('1.8.18', 'dd2148b740713ca0295442ec683d7b1c')
version('1.8.17', '7d572f8f3b798a628b8245af0391a0ca')
version('1.8.16', 'b8ed9a36ae142317f88b0c7ef4b9c618')
version('1.8.15', '03cccb5b33dbe975fdcd8ae9dc021f24')
version('1.8.14', 'a482686e733514a51cde12d6fe5c5d95')
version('1.8.13', 'c03426e9e77d7766944654280b467289')
version('1.8.12', 'd804802feb99b87fc668a90e6fa34411')
version('1.8.10', '710aa9fb61a51d61a7e2c09bf0052157')
variant('debug', default=False,
description='Builds a debug version of the library')
variant('shared', default=True,
description='Builds a shared version of the library')
variant('hl', default=False, description='Enable the high-level library')
variant('cxx', default=False, description='Enable C++ support')
variant('fortran', default=False, description='Enable Fortran support')
variant('threadsafe', default=False,
description='Enable thread-safe capabilities')
variant('mpi', default=True, description='Enable MPI support')
variant('szip', default=False, description='Enable szip support')
variant('pic', default=True,
description='Produce position-independent code (for shared libs)')
variant('mobject', default=False, description='Enable support for MObject')
depends_on('autoconf', type='build', when='@develop')
depends_on('automake', type='build', when='@develop')
depends_on('libtool', type='build', when='@develop')
depends_on('m4', type='build', when='@develop')
depends_on('autoconf', type='build', when='@extvol-develop')
depends_on('automake', type='build', when='@extvol-develop')
depends_on('libtool', type='build', when='@extvol-develop')
depends_on('m4', type='build', when='@extvol-develop')
depends_on('pkgconfig',type='build', when='@extvol-develop')
depends_on('autoconf', type='build', when='@rados-old')
depends_on('automake', type='build', when='@rados-old')
depends_on('libtool', type='build', when='@rados-old')
depends_on('m4', type='build', when='@rados-old')
depends_on('pkgconfig',type='build', when='@rados-old')
depends_on('autoconf', type='build', when='@rados-develop')
depends_on('automake', type='build', when='@rados-develop')
depends_on('libtool', type='build', when='@rados-develop')
depends_on('m4', type='build', when='@rados-develop')
depends_on('pkgconfig',type='build', when='@rados-develop')
depends_on('mobject@develop', when='+mobject')
depends_on('mpi', when='+mpi')
# numactl does not currently build on darwin
if sys.platform != 'darwin':
depends_on('numactl', when='+mpi+fortran')
depends_on('szip', when='+szip')
# There are several officially unsupported combinations of the features:
# 1. Thread safety is not guaranteed via high-level C-API but in some cases
# it works.
# conflicts('+threadsafe+hl')
# 2. Thread safety is not guaranteed via Fortran (CXX) API, but it's
# possible for a dependency tree to contain a package that uses Fortran
# (CXX) API in a single thread and another one that uses low-level C-API
# in multiple threads. To allow for such scenarios, we don't specify the
# following conflicts.
# conflicts('+threadsafe+cxx')
# conflicts('+threadsafe+fortran')
# 3. Parallel features are not supported via CXX API, but for the reasons
# described in #2 we allow for such combination.
# conflicts('+mpi+cxx')
# There are known build failures with intel@18.0.1. This issue is
# discussed and patch is provided at
# Turn line comments into block comments to conform with pre-C99 language
# standards. Versions of hdf5 after 1.8.10 don't require this patch,
# either because they conform to pre-C99 or neglect to ask for pre-C99
# language standards from their compiler. The hdf5 build system adds
# the -ansi cflag (run 'man gcc' for info on -ansi) for some versions
# of some compilers (see hdf5-1.8.10/config/gnu-flags). The hdf5 build
# system does not provide an option to disable -ansi, but since the
# pre-C99 code is restricted to just five lines of line comments in
# three src files, this patch accomplishes the simple task of patching the
# three src files and leaves the hdf5 build system alone.
patch('pre-c99-comments.patch', when='@1.8.10')
# There are build errors with GCC 8, see
filter_compiler_wrappers('h5cc', 'h5c++', 'h5fc', relative_root='bin')
def url_for_version(self, version):
url = "{0}/hdf5-{1}/src/hdf5-{1}.tar.gz"
return url.format(version.up_to(2), version)
def autoreconf(self, spec, prefix):
autogen = Executable('./')
def autoreconf(self, spec, prefix):
autogen = Executable('./')
def autoreconf(self, spec, prefix):
autogen = Executable('./')
def autoreconf(self, spec, prefix):
autogen = Executable('./')
def libs(self):
"""HDF5 can be queried for the following parameters:
- "hl": high-level interface
- "cxx": C++ APIs
- "fortran": Fortran APIs
:return: list of matching libraries
query_parameters = self.spec.last_query.extra_parameters
shared = '+shared' in self.spec
# This map contains a translation from query_parameters
# to the libraries needed
query2libraries = {
tuple(): ['libhdf5'],
('cxx', 'fortran', 'hl'): [
('cxx', 'hl'): [
('fortran', 'hl'): [
('hl',): [
('cxx', 'fortran'): [
('cxx',): [
('fortran',): [
# Turn the query into the appropriate key
key = tuple(sorted(query_parameters))
libraries = query2libraries[key]
return find_libraries(
libraries, root=self.prefix, shared=shared, recursive=True
def fortran_check(self):
if '+fortran' in self.spec and not self.compiler.fc:
msg = 'cannot build a Fortran variant without a Fortran compiler'
raise RuntimeError(msg)
def configure_args(self):
# Always enable this option. This does not actually enable any
# features: it only *allows* the user to specify certain
# combinations of other arguments. Enabling it just skips a
# sanity check in configure, so this doesn't merit a variant.
extra_args = ['--enable-unsupported']
extra_args += self.enable_or_disable('threadsafe')
extra_args += self.enable_or_disable('cxx')
extra_args += self.enable_or_disable('hl')
extra_args += self.enable_or_disable('fortran')
if '+szip' in self.spec:
extra_args.append('--with-szlib=%s' % self.spec['szip'].prefix)
if self.spec.satisfies('@1.10:') or self.spec.satisfies('@extvol-develop') or self.spec.satisfies('@rados-develop') or self.spec.satisfies('@rados-old'):
if '+debug' in self.spec:
if '+debug' in self.spec:
# '--enable-fortran2003' no longer exists as of version 1.10.0
if '+fortran' in self.spec:
if '+shared' in self.spec:
if '+pic' in self.spec:
extra_args += ['%s=%s' % (f, self.compiler.pic_flag)
for f in ['CFLAGS', 'CXXFLAGS', 'FCFLAGS']]
config_args = super().configure_args()
if '+mobject' in self.spec:
extra_cflags="CFLAGS=-DHDF5_USE_MOBJECT %s" % subprocess.check_output([str(pkg_config), "--cflags", "mobject-store"]).strip('\n')
extra_libs="LIBS=%s" % subprocess.check_output([str(pkg_config), "--libs", "mobject-store"]).strip('\n')
if '+mpi' in self.spec:
# The HDF5 configure script warns if cxx and mpi are enabled
# together. There doesn't seem to be a real reason for this, except
# that parts of the MPI interface are not accessible via the C++
# interface. Since they are still accessible via the C interface,
# this is not actually a problem.
extra_args += ['--enable-parallel',
'CC=%s' % self.spec['mpi'].mpicc]
if '+cxx' in self.spec:
extra_args.append('CXX=%s' % self.spec['mpi'].mpicxx)
if '+fortran' in self.spec:
extra_args.append('FC=%s' % self.spec['mpi'].mpifc)
extra_args.append('--with-zlib=%s' % self.spec['zlib'].prefix)
pkg_config = which('pkg-config')
extra_libs = "LIBS=%s" % pkg_config('--libs-only-l', "mobject-store",
return extra_args
extra_cflags = "CPPFLAGS=-DHDF5_USE_MOBJECT %s" % pkg_config('--cflags',
'mobject-store', output=str).strip('\n')
def patch_postdeps(self):
if '@:1.8.14' in self.spec:
# On Ubuntu14, HDF5 1.8.12 (and maybe other versions)
# mysteriously end up with "-l -l" in the postdeps in the
# libtool script. Patch this by removing the spurious -l's.
lambda m: 'postdeps="%s"' % ' '.join(
arg for arg in' ') if arg != '-l'),
def check_install(self):
# Build and run a small program to test the installed HDF5 library
spec = self.spec
print("Checking HDF5 installation...")
checkdir = "spack-check"
with working_dir(checkdir, create=True):
source = r"""
#include <hdf5.h>
#include <assert.h>
#include <stdio.h>
int main(int argc, char **argv) {
unsigned majnum, minnum, relnum;
herr_t herr = H5get_libversion(&majnum, &minnum, &relnum);
printf("HDF5 version %d.%d.%d %u.%u.%u\n", H5_VERS_MAJOR, H5_VERS_MINOR,
H5_VERS_RELEASE, majnum, minnum, relnum);
return 0;
expected = """\
HDF5 version {version} {version}
with open("check.c", 'w') as f:
if '+mpi' in spec:
cc = Executable(spec['mpi'].mpicc)
cc = Executable(
cc(*(['-c', "check.c"] + spec['hdf5'].headers.cpp_flags.split()))
cc(*(['-o', "check",
"check.o"] + spec['hdf5'].libs.ld_flags.split()))
check = Executable('./check')
output = check(output=str)
except ProcessError:
output = ""
success = output == expected
if not success:
print("Produced output does not match expected output.")
print("Expected output:")
print('-' * 80)
print('-' * 80)
print("Produced output:")
print('-' * 80)
print('-' * 80)
raise RuntimeError("HDF5 install check failed")
return config_args
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment