package : added a stub for AutotoolsPackage, examples in szip and swiftsim
This commit is contained in:
		| @@ -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 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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): | ||||||
|   | |||||||
| @@ -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', | ||||||
|  |                 '--with-metis={0}'.format(self.spec['metis'].prefix), | ||||||
|                 '--enable-optimization'] |                 '--enable-optimization'] | ||||||
|         configure(*options) |  | ||||||
|         make() |  | ||||||
|         make("install") |  | ||||||
|   | |||||||
| @@ -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') |  | ||||||
|  |  | ||||||
|     def install(self, spec, prefix): |  | ||||||
|         configure('--prefix=%s' % prefix, |  | ||||||
|                   '--enable-production', |  | ||||||
|                 '--enable-shared', |                 '--enable-shared', | ||||||
|                 '--enable-static', |                 '--enable-static', | ||||||
|                   '--enable-encoding') |                 '--enable-encoding'] | ||||||
|  |  | ||||||
|         make() |  | ||||||
|         make("install") |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 alalazo
					alalazo