package : added a stub for AutotoolsPackage, examples in szip and swiftsim

This commit is contained in:
alalazo 2016-07-08 15:11:04 +02:00
parent 8ed028e2d6
commit 8f75d34331
4 changed files with 110 additions and 73 deletions

View file

@ -176,10 +176,14 @@
# TODO: it's not clear where all the stuff that needs to be included in packages # TODO: it's not clear where all the stuff that needs to be included in packages
# should live. This file is overloaded for spack core vs. for packages. # should live. This file is overloaded for spack core vs. for packages.
# #
__all__ = ['Package', 'CMakePackage', \ __all__ = ['Package',
'Version', 'when', 'ver'] 'CMakePackage',
'AutotoolsPackage',
'Version',
'when',
'ver']
from spack.package import Package, ExtensionConflictError from spack.package import Package, ExtensionConflictError
from spack.package import CMakePackage from spack.package import CMakePackage, AutotoolsPackage
from spack.version import Version, ver from spack.version import Version, ver
from spack.multimethod import when from spack.multimethod import when

View file

@ -38,8 +38,8 @@
import string import string
import textwrap import textwrap
import time import time
import inspect
import functools import functools
import inspect
from StringIO import StringIO from StringIO import StringIO
from urlparse import urlparse from urlparse import urlparse
@ -74,7 +74,7 @@ class InstallPhase(object):
"""Manages a single phase of the installation """Manages a single phase of the installation
This descriptor stores at creation time the name of the method it should search This descriptor stores at creation time the name of the method it should search
for execution. The method is retrieved at get time, so that it can be overridden for execution. The method is retrieved at __get__ time, so that it can be overridden
by subclasses of whatever class declared the phases. by subclasses of whatever class declared the phases.
It also provides hooks to execute prerequisite and sanity checks. It also provides hooks to execute prerequisite and sanity checks.
@ -116,31 +116,63 @@ class PackageMeta(type):
""" """
phase_fmt = '_InstallPhase_{0}' phase_fmt = '_InstallPhase_{0}'
def __init__(cls, name, bases, attr_dict): _InstallPhase_sanity_checks = {}
super(PackageMeta, cls).__init__(name, bases, attr_dict) _InstallPhase_preconditions = {}
# Parse if phases is in attr dict, then set
def __new__(meta, name, bases, attr_dict):
# Check if phases is in attr dict, then set
# install phases wrappers # install phases wrappers
if 'phases' in attr_dict: if 'phases' in attr_dict:
cls.phases = [PackageMeta.phase_fmt.format(name) for name in attr_dict['phases']] phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']]
for phase_name, callback_name in zip(cls.phases, attr_dict['phases']): for phase_name, callback_name in zip(phases, attr_dict['phases']):
setattr(cls, phase_name, InstallPhase(callback_name)) attr_dict[phase_name] = InstallPhase(callback_name)
attr_dict['phases'] = phases
def _transform_checks(check_name): def _append_checks(check_name):
# Name of the attribute I am going to check it exists
attr_name = PackageMeta.phase_fmt.format(check_name) attr_name = PackageMeta.phase_fmt.format(check_name)
checks = getattr(cls, attr_name, None) checks = getattr(meta, attr_name)
if checks: if checks:
for phase_name, funcs in checks.items(): for phase_name, funcs in checks.items():
phase = getattr(cls, PackageMeta.phase_fmt.format(phase_name)) phase = attr_dict.get(PackageMeta.phase_fmt.format(phase_name))
getattr(phase, check_name).extend(funcs) getattr(phase, check_name).extend(funcs)
# TODO : this should delete the attribute, as it is just a placeholder # Clear the attribute for the next class
# TODO : to know what to do at class definition time. Clearing it is fine setattr(meta, attr_name, {})
# TODO : too, but it just leaves an empty dictionary in place
setattr(cls, attr_name, {}) @classmethod
def _register_checks(cls, check_type, *args):
def _register_sanity_checks(func):
attr_name = PackageMeta.phase_fmt.format(check_type)
sanity_checks = getattr(meta, attr_name)
for item in args:
checks = sanity_checks.setdefault(item, [])
checks.append(func)
setattr(meta, attr_name, sanity_checks)
return func
return _register_sanity_checks
@classmethod
def precondition(cls, *args):
return cls._register_checks('preconditions', *args)
@classmethod
def sanity_check(cls, *args):
return cls._register_checks('sanity_checks', *args)
if all([not hasattr(x, '_register_checks') for x in bases]):
attr_dict['_register_checks'] = _register_checks
if all([not hasattr(x, 'sanity_check') for x in bases]):
attr_dict['sanity_check'] = sanity_check
if all([not hasattr(x, 'precondition') for x in bases]):
attr_dict['precondition'] = precondition
# Preconditions # Preconditions
_transform_checks('preconditions') _append_checks('preconditions')
# Sanity checks # Sanity checks
_transform_checks('sanity_checks') _append_checks('sanity_checks')
return super(PackageMeta, meta).__new__(meta, name, bases, attr_dict)
class PackageBase(object): class PackageBase(object):
@ -993,7 +1025,7 @@ def do_install(self,
# Ensure package is not already installed # Ensure package is not already installed
# FIXME : skip condition : if any is True skip the installation # FIXME : skip condition : if any is True skip the installation
if 'install' in self.phases and spack.install_layout.check_installed(self.spec): if spack.install_layout.check_installed(self.spec):
tty.msg("%s is already installed in %s" % (self.name, self.prefix)) tty.msg("%s is already installed in %s" % (self.name, self.prefix))
rec = spack.installed_db.get_record(self.spec) rec = spack.installed_db.get_record(self.spec)
if (not rec.explicit) and explicit: if (not rec.explicit) and explicit:
@ -1499,26 +1531,6 @@ def rpath_args(self):
""" """
return " ".join("-Wl,-rpath,%s" % p for p in self.rpath) return " ".join("-Wl,-rpath,%s" % p for p in self.rpath)
@classmethod
def _register_checks(cls, check_type, *args):
def _register_sanity_checks(func):
attr_name = PackageMeta.phase_fmt.format(check_type)
sanity_checks = getattr(cls, attr_name, {})
for item in args:
checks = sanity_checks.setdefault(item, [])
checks.append(func)
setattr(cls, attr_name, sanity_checks)
return func
return _register_sanity_checks
@classmethod
def precondition(cls, *args):
return cls._register_checks('preconditions', *args)
@classmethod
def sanity_check(cls, *args):
return cls._register_checks('sanity_checks', *args)
class Package(PackageBase): class Package(PackageBase):
phases = ['install', 'log'] phases = ['install', 'log']
@ -1527,6 +1539,36 @@ class Package(PackageBase):
PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
class AutotoolsPackage(PackageBase):
phases = ['autoreconf', 'configure', 'build', 'install', 'log']
def autoreconf(self, spec, prefix):
"""Not needed usually, configure should be already there"""
pass
@PackageBase.sanity_check('autoreconf')
def is_configure_or_die(self):
if not os.path.exists('configure'):
raise RuntimeError('configure script not found in {0}'.format(os.getcwd()))
def configure_args(self):
return list()
def configure(self, spec, prefix):
options = ['--prefix={0}'.format(prefix)] + self.configure_args()
inspect.getmodule(self).configure(*options)
def build(self, spec, prefix):
inspect.getmodule(self).make()
def install(self, spec, prefix):
inspect.getmodule(self).make('install')
# This will be used as a registration decorator in user
# packages, if need be
PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
def install_dependency_symlinks(pkg, spec, prefix): def install_dependency_symlinks(pkg, spec, prefix):
"""Execute a dummy install and flatten dependencies""" """Execute a dummy install and flatten dependencies"""
flatten_dependencies(spec, prefix) flatten_dependencies(spec, prefix)
@ -1637,7 +1679,7 @@ def _hms(seconds):
class CMakePackage(PackageBase): class CMakePackage(PackageBase):
phases = ['setup', 'configure', 'build', 'install', 'provenance'] phases = ['configure', 'build', 'install', 'provenance']
def make_make(self): def make_make(self):
import multiprocessing import multiprocessing
@ -1657,7 +1699,7 @@ def configure_args(self):
def configure_env(self): def configure_env(self):
"""Returns package-specific environment under which the configure command should be run.""" """Returns package-specific environment under which the configure command should be run."""
# FIXME : Why not EnvironmentModules # FIXME : Why not EnvironmentModules and the hooks that PackageBase already provides ?
return dict() return dict()
def spack_transitive_include_path(self): def spack_transitive_include_path(self):
@ -1720,7 +1762,6 @@ def cmdlist(str):
fout.write('\nproc = subprocess.Popen(cmd, env=env)\nproc.wait()\n') fout.write('\nproc = subprocess.Popen(cmd, env=env)\nproc.wait()\n')
set_executable(setup_fname) set_executable(setup_fname)
def configure(self, spec, prefix): def configure(self, spec, prefix):
cmake = which('cmake') cmake = which('cmake')
with working_dir(self.build_directory, create=True): with working_dir(self.build_directory, create=True):

View file

@ -28,7 +28,7 @@
import llnl.util.tty as tty import llnl.util.tty as tty
class Swiftsim(Package): class Swiftsim(AutotoolsPackage):
""" """
SPH With Inter-dependent Fine-grained Tasking (SWIFT) provides SPH With Inter-dependent Fine-grained Tasking (SWIFT) provides
astrophysicists with a state of the art framework to perform astrophysicists with a state of the art framework to perform
@ -59,19 +59,15 @@ def setup_environment(self, spack_env, run_env):
tty.warn('This is needed to clone SWIFT repository') tty.warn('This is needed to clone SWIFT repository')
spack_env.set('GIT_SSL_NO_VERIFY', 1) spack_env.set('GIT_SSL_NO_VERIFY', 1)
def install(self, spec, prefix): def autoreconf(self, spec, prefix):
# Generate configure from configure.ac
# and Makefile.am
libtoolize() libtoolize()
aclocal() aclocal()
autoconf() autoconf()
autogen = Executable('./autogen.sh') autogen = Executable('./autogen.sh')
autogen() autogen()
# Configure and install def config_args(self):
options = ['--prefix=%s' % prefix, return ['--prefix=%s' % prefix,
'--enable-mpi' if '+mpi' in spec else '--disable-mpi', '--enable-mpi' if '+mpi' in spec else '--disable-mpi',
'--enable-optimization'] '--with-metis={0}'.format(self.spec['metis'].prefix),
configure(*options) '--enable-optimization']
make()
make("install")

View file

@ -24,26 +24,22 @@
############################################################################## ##############################################################################
from spack import * from spack import *
class Szip(Package):
"""Szip is an implementation of the extended-Rice lossless compression algorithm. class Szip(AutotoolsPackage):
It provides lossless compression of scientific data, and is provided with HDF """Szip is an implementation of the extended-Rice lossless
software products.""" compression algorithm.
It provides lossless compression of scientific data, and is
provided with HDF software products.
"""
homepage = "https://www.hdfgroup.org/doc_resource/SZIP/" homepage = "https://www.hdfgroup.org/doc_resource/SZIP/"
url = "http://www.hdfgroup.org/ftp/lib-external/szip/2.1/src/szip-2.1.tar.gz" url = "http://www.hdfgroup.org/ftp/lib-external/szip/2.1/src/szip-2.1.tar.gz"
version('2.1', '902f831bcefb69c6b635374424acbead') version('2.1', '902f831bcefb69c6b635374424acbead')
@Package.sanity_check('install') def configure_args(self):
def always_raise(self): return ['--enable-production',
raise RuntimeError('Precondition not respected') '--enable-shared',
'--enable-static',
def install(self, spec, prefix): '--enable-encoding']
configure('--prefix=%s' % prefix,
'--enable-production',
'--enable-shared',
'--enable-static',
'--enable-encoding')
make()
make("install")