From 8ed028e2d67f191a32751db8bd487c03f7687b50 Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 8 Jul 2016 12:29:49 +0200 Subject: package : introduced InstallPhase, added decorators for prerequisites and sanity_checks of phases --- var/spack/repos/builtin/packages/szip/package.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'var') diff --git a/var/spack/repos/builtin/packages/szip/package.py b/var/spack/repos/builtin/packages/szip/package.py index fd3a2a209d..ec6d8239a9 100644 --- a/var/spack/repos/builtin/packages/szip/package.py +++ b/var/spack/repos/builtin/packages/szip/package.py @@ -34,6 +34,10 @@ class Szip(Package): version('2.1', '902f831bcefb69c6b635374424acbead') + @Package.sanity_check('install') + def always_raise(self): + raise RuntimeError('Precondition not respected') + def install(self, spec, prefix): configure('--prefix=%s' % prefix, '--enable-production', -- cgit v1.2.3-60-g2f50 From 8f75d343315a2bf7f85d613fdacb993a41a0f62b Mon Sep 17 00:00:00 2001 From: alalazo Date: Fri, 8 Jul 2016 15:11:04 +0200 Subject: package : added a stub for AutotoolsPackage, examples in szip and swiftsim --- lib/spack/spack/__init__.py | 10 +- lib/spack/spack/package.py | 121 ++++++++++++++------- .../repos/builtin/packages/swiftsim/package.py | 18 ++- var/spack/repos/builtin/packages/szip/package.py | 32 +++--- 4 files changed, 109 insertions(+), 72 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index 0e811e5ee7..85a0a4e2f7 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -176,10 +176,14 @@ sys_type = None # 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. # -__all__ = ['Package', 'CMakePackage', \ - 'Version', 'when', 'ver'] +__all__ = ['Package', + 'CMakePackage', + 'AutotoolsPackage', + 'Version', + 'when', + 'ver'] 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.multimethod import when diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 4194f30827..dd5637b9bc 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -38,8 +38,8 @@ import re import string import textwrap import time -import inspect import functools +import inspect from StringIO import StringIO from urlparse import urlparse @@ -74,7 +74,7 @@ class InstallPhase(object): """Manages a single phase of the installation 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. It also provides hooks to execute prerequisite and sanity checks. @@ -116,31 +116,63 @@ class PackageMeta(type): """ phase_fmt = '_InstallPhase_{0}' - def __init__(cls, name, bases, attr_dict): - super(PackageMeta, cls).__init__(name, bases, attr_dict) - # Parse if phases is in attr dict, then set + _InstallPhase_sanity_checks = {} + _InstallPhase_preconditions = {} + + def __new__(meta, name, bases, attr_dict): + # Check if phases is in attr dict, then set # install phases wrappers if 'phases' in attr_dict: - cls.phases = [PackageMeta.phase_fmt.format(name) for name in attr_dict['phases']] - for phase_name, callback_name in zip(cls.phases, attr_dict['phases']): - setattr(cls, phase_name, InstallPhase(callback_name)) + phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']] + for phase_name, callback_name in zip(phases, attr_dict['phases']): + 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) - checks = getattr(cls, attr_name, None) + checks = getattr(meta, attr_name) if checks: 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) - # TODO : this should delete the attribute, as it is just a placeholder - # TODO : to know what to do at class definition time. Clearing it is fine - # TODO : too, but it just leaves an empty dictionary in place - setattr(cls, attr_name, {}) + # Clear the attribute for the next class + setattr(meta, 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 - _transform_checks('preconditions') + _append_checks('preconditions') # Sanity checks - _transform_checks('sanity_checks') + _append_checks('sanity_checks') + return super(PackageMeta, meta).__new__(meta, name, bases, attr_dict) class PackageBase(object): @@ -993,7 +1025,7 @@ class PackageBase(object): # Ensure package is not already installed # 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)) rec = spack.installed_db.get_record(self.spec) if (not rec.explicit) and explicit: @@ -1499,29 +1531,39 @@ class PackageBase(object): """ 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) +class Package(PackageBase): + phases = ['install', 'log'] + # This will be used as a registration decorator in user + # packages, if need be + PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) + - @classmethod - def sanity_check(cls, *args): - return cls._register_checks('sanity_checks', *args) +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') -class Package(PackageBase): - phases = ['install', 'log'] # This will be used as a registration decorator in user # packages, if need be PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) @@ -1637,7 +1679,7 @@ def _hms(seconds): class CMakePackage(PackageBase): - phases = ['setup', 'configure', 'build', 'install', 'provenance'] + phases = ['configure', 'build', 'install', 'provenance'] def make_make(self): import multiprocessing @@ -1657,7 +1699,7 @@ class CMakePackage(PackageBase): def configure_env(self): """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() def spack_transitive_include_path(self): @@ -1720,7 +1762,6 @@ env = dict(os.environ) fout.write('\nproc = subprocess.Popen(cmd, env=env)\nproc.wait()\n') set_executable(setup_fname) - def configure(self, spec, prefix): cmake = which('cmake') with working_dir(self.build_directory, create=True): diff --git a/var/spack/repos/builtin/packages/swiftsim/package.py b/var/spack/repos/builtin/packages/swiftsim/package.py index 42e8fb466a..7c3204f96b 100644 --- a/var/spack/repos/builtin/packages/swiftsim/package.py +++ b/var/spack/repos/builtin/packages/swiftsim/package.py @@ -28,7 +28,7 @@ from spack import * import llnl.util.tty as tty -class Swiftsim(Package): +class Swiftsim(AutotoolsPackage): """ SPH With Inter-dependent Fine-grained Tasking (SWIFT) provides astrophysicists with a state of the art framework to perform @@ -59,19 +59,15 @@ class Swiftsim(Package): tty.warn('This is needed to clone SWIFT repository') spack_env.set('GIT_SSL_NO_VERIFY', 1) - def install(self, spec, prefix): - # Generate configure from configure.ac - # and Makefile.am + def autoreconf(self, spec, prefix): libtoolize() aclocal() autoconf() autogen = Executable('./autogen.sh') autogen() - # Configure and install - options = ['--prefix=%s' % prefix, - '--enable-mpi' if '+mpi' in spec else '--disable-mpi', - '--enable-optimization'] - configure(*options) - make() - make("install") + def config_args(self): + return ['--prefix=%s' % prefix, + '--enable-mpi' if '+mpi' in spec else '--disable-mpi', + '--with-metis={0}'.format(self.spec['metis'].prefix), + '--enable-optimization'] diff --git a/var/spack/repos/builtin/packages/szip/package.py b/var/spack/repos/builtin/packages/szip/package.py index ec6d8239a9..91934f7d03 100644 --- a/var/spack/repos/builtin/packages/szip/package.py +++ b/var/spack/repos/builtin/packages/szip/package.py @@ -24,26 +24,22 @@ ############################################################################## from spack import * -class Szip(Package): - """Szip is an implementation of the extended-Rice lossless compression algorithm. - It provides lossless compression of scientific data, and is provided with HDF - software products.""" - 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" +class Szip(AutotoolsPackage): + """Szip is an implementation of the extended-Rice lossless + compression algorithm. - version('2.1', '902f831bcefb69c6b635374424acbead') + It provides lossless compression of scientific data, and is + provided with HDF software products. + """ - @Package.sanity_check('install') - def always_raise(self): - raise RuntimeError('Precondition not respected') + 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" - def install(self, spec, prefix): - configure('--prefix=%s' % prefix, - '--enable-production', - '--enable-shared', - '--enable-static', - '--enable-encoding') + version('2.1', '902f831bcefb69c6b635374424acbead') - make() - make("install") + def configure_args(self): + return ['--enable-production', + '--enable-shared', + '--enable-static', + '--enable-encoding'] -- cgit v1.2.3-60-g2f50 From a43c63f14953ab105bf80e906dc212a62a0d3f67 Mon Sep 17 00:00:00 2001 From: alalazo Date: Mon, 11 Jul 2016 10:08:19 +0200 Subject: package : added EditableMakefile Modifications : - added EditableMakefile to PackageBase subclasses - astyle modified as an example - preliminary hook to stop at a certain phase of install --- lib/spack/spack/__init__.py | 3 +- lib/spack/spack/cmd/install.py | 7 ++- lib/spack/spack/package.py | 64 +++++++++++++++++----- var/spack/repos/builtin/packages/astyle/package.py | 24 ++++---- var/spack/repos/builtin/packages/blitz/package.py | 12 +--- var/spack/repos/builtin/packages/gmp/package.py | 10 +--- .../repos/builtin/packages/swiftsim/package.py | 6 +- 7 files changed, 78 insertions(+), 48 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index 85a0a4e2f7..c924886b53 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -179,11 +179,12 @@ sys_type = None __all__ = ['Package', 'CMakePackage', 'AutotoolsPackage', + 'EditableMakefile', 'Version', 'when', 'ver'] from spack.package import Package, ExtensionConflictError -from spack.package import CMakePackage, AutotoolsPackage +from spack.package import CMakePackage, AutotoolsPackage, EditableMakefile from spack.version import Version, ver from spack.multimethod import when diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py index 4c076322a9..ae34e06c22 100644 --- a/lib/spack/spack/cmd/install.py +++ b/lib/spack/spack/cmd/install.py @@ -56,6 +56,9 @@ def setup_parser(subparser): subparser.add_argument( '--dirty', action='store_true', dest='dirty', help="Install a package *without* cleaning the environment.") + subparser.add_argument( + '--stop-at', help="Stop at a particular phase of installation" + ) subparser.add_argument( 'packages', nargs=argparse.REMAINDER, help="specs of packages to install") subparser.add_argument( @@ -88,4 +91,6 @@ def install(parser, args): verbose=args.verbose, fake=args.fake, dirty=args.dirty, - explicit=True) + explicit=True, + stop_at=args.stop_at + ) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index dd5637b9bc..2df6e6a433 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -104,6 +104,10 @@ class InstallPhase(object): # and give them the chance to fail for check in self.sanity_checks: check(instance) + # Permit instance to drive the execution + if self.name == instance.last_phase: + raise StopIteration('Stopping at \'{0}\' phase'.format(self.name)) + return phase_wrapper @@ -123,10 +127,10 @@ class PackageMeta(type): # Check if phases is in attr dict, then set # install phases wrappers if 'phases' in attr_dict: - phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']] - for phase_name, callback_name in zip(phases, attr_dict['phases']): + _InstallPhase_phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']] + for phase_name, callback_name in zip(_InstallPhase_phases, attr_dict['phases']): attr_dict[phase_name] = InstallPhase(callback_name) - attr_dict['phases'] = phases + attr_dict['_InstallPhase_phases'] = _InstallPhase_phases def _append_checks(check_name): # Name of the attribute I am going to check it exists @@ -956,7 +960,8 @@ class PackageBase(object): return namespace def do_fake_install(self): - """Make a fake install directory contaiing a 'fake' file in bin.""" + """Make a fake install directory containing a 'fake' file in bin.""" + # FIXME : Make this part of the 'install' behavior ? mkdirp(self.prefix.bin) touch(join_path(self.prefix.bin, 'fake')) mkdirp(self.prefix.lib) @@ -990,7 +995,7 @@ class PackageBase(object): fake=False, explicit=False, dirty=False, - allowed_phases=None): + **kwargs): """Called by commands to install a package and its dependencies. Package implementations should override install() to describe @@ -1010,9 +1015,13 @@ class PackageBase(object): make_jobs -- Number of make jobs to use for install. Default is ncpus run_tests -- Runn tests within the package's install() """ - # FIXME : we need a better semantic - if allowed_phases is None: - allowed_phases = self.phases + #if allowed_phases is None: + # allowed_phases = self.phases + # FIXME : Refine the error message + last_phase = kwargs.get('stop_at', None) + if last_phase is not None and last_phase not in self.phases: + raise KeyError('phase {0} is not among the allowed phases for package {1}'.format(last_phase, self)) + self.last_phase = last_phase if not self.spec.concrete: raise ValueError("Can only install concrete packages.") @@ -1097,9 +1106,10 @@ class PackageBase(object): True): dump_environment(env_path) try: - for phase in filter(lambda x: x in allowed_phases, self.phases): + for phase in self._InstallPhase_phases: # TODO : Log to screen the various phases getattr(self, phase)(self.spec, self.prefix) + self.log() except AttributeError as e: # FIXME : improve error messages raise ProcessError(e.message, long_message='') @@ -1126,9 +1136,10 @@ class PackageBase(object): # Create the install prefix and fork the build process. spack.install_layout.create_install_directory(self.spec) except directory_layout.InstallDirectoryAlreadyExistsError: + # FIXME : refactor this as a prerequisites to configure if 'install' in self.phases: # Abort install if install directory exists. - # But do NOT remove it (you'd be overwriting someon else's stuff) + # But do NOT remove it (you'd be overwriting someone else's stuff) tty.warn("Keeping existing install prefix in place.") raise else: @@ -1154,7 +1165,7 @@ class PackageBase(object): # the database, so that we don't need to re-read from file. spack.installed_db.add(self.spec, self.prefix, explicit=explicit) - def log(self, spec, prefix): + def log(self): # Copy provenance into the install directory on success log_install_path = spack.install_layout.build_log_path( self.spec) @@ -1533,14 +1544,41 @@ class PackageBase(object): class Package(PackageBase): - phases = ['install', 'log'] + phases = ['install'] # This will be used as a registration decorator in user # packages, if need be PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) +class EditableMakefile(PackageBase): + phases = ['edit', 'build', 'install'] + + def wdir(self): + return self.stage.source_path + + def build_args(self): + return list() + + def install_args(self): + return list() + + def edit(self, spec, prefix): + raise NotImplementedError('\'edit\' function not implemented') + + def build(self, spec, prefix): + args = self.build_args() + with working_dir(self.wdir()): + inspect.getmodule(self).make(*args) + + def install(self, spec, prefix): + args = self.install_args() + ['install'] + with working_dir(self.wdir()): + inspect.getmodule(self).make(*args) + + PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) + class AutotoolsPackage(PackageBase): - phases = ['autoreconf', 'configure', 'build', 'install', 'log'] + phases = ['autoreconf', 'configure', 'build', 'install'] def autoreconf(self, spec, prefix): """Not needed usually, configure should be already there""" diff --git a/var/spack/repos/builtin/packages/astyle/package.py b/var/spack/repos/builtin/packages/astyle/package.py index 815c184577..8f85d4ebbb 100644 --- a/var/spack/repos/builtin/packages/astyle/package.py +++ b/var/spack/repos/builtin/packages/astyle/package.py @@ -25,28 +25,24 @@ from spack import * -class Astyle(Package): +class Astyle(EditableMakefile): """ A Free, Fast, and Small Automatic Formatter for C, C++, C++/CLI, Objective-C, C#, and Java Source Code. """ homepage = "http://astyle.sourceforge.net/" - url = "http://downloads.sourceforge.net/project/astyle/astyle/astyle%202.04/astyle_2.04_linux.tar.gz" + url = "http://downloads.sourceforge.net/project/astyle/astyle/astyle%202.04/astyle_2.04_linux.tar.gz" version('2.04', '30b1193a758b0909d06e7ee8dd9627f6') - def install(self, spec, prefix): + parallel = False - with working_dir('src'): - # we need to edit the makefile in place to set compiler: - make_file = join_path(self.stage.source_path, - 'build', 'gcc', 'Makefile') - filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, make_file) + def wdir(self): + return join_path(self.stage.source_path, 'build', self.compiler.name) - make('-f', - make_file, - parallel=False) + def edit(self, spec, prefix): + makefile = join_path(self.wdir(), 'Makefile') + filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, makefile) - mkdirp(self.prefix.bin) - install(join_path(self.stage.source_path, 'src', 'bin', 'astyle'), - self.prefix.bin) + def install_args(self): + return ['prefix={0}'.format(prefix)] diff --git a/var/spack/repos/builtin/packages/blitz/package.py b/var/spack/repos/builtin/packages/blitz/package.py index acc6ddcd07..16ad3bc2ab 100644 --- a/var/spack/repos/builtin/packages/blitz/package.py +++ b/var/spack/repos/builtin/packages/blitz/package.py @@ -24,16 +24,10 @@ ############################################################################## from spack import * -class Blitz(Package): + +class Blitz(AutotoolsPackage): """N-dimensional arrays for C++""" homepage = "http://github.com/blitzpp/blitz" - url = "https://github.com/blitzpp/blitz/tarball/1.0.0" + url = "https://github.com/blitzpp/blitz/tarball/1.0.0" version('1.0.0', '9f040b9827fe22228a892603671a77af') - - # No dependencies - - def install(self, spec, prefix): - configure('--prefix=%s' % prefix) - make() - make("install") diff --git a/var/spack/repos/builtin/packages/gmp/package.py b/var/spack/repos/builtin/packages/gmp/package.py index 3933788425..9bfc8f9611 100644 --- a/var/spack/repos/builtin/packages/gmp/package.py +++ b/var/spack/repos/builtin/packages/gmp/package.py @@ -24,20 +24,16 @@ ############################################################################## from spack import * -class Gmp(Package): + +class Gmp(AutotoolsPackage): """GMP is a free library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and floating-point numbers.""" homepage = "https://gmplib.org" - url = "https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2" + url = "https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2" version('6.1.0' , '86ee6e54ebfc4a90b643a65e402c4048') version('6.0.0a', 'b7ff2d88cae7f8085bd5006096eed470') version('6.0.0' , '6ef5869ae735db9995619135bd856b84') depends_on("m4") - - def install(self, spec, prefix): - configure("--prefix=%s" % prefix) - make() - make("install") diff --git a/var/spack/repos/builtin/packages/swiftsim/package.py b/var/spack/repos/builtin/packages/swiftsim/package.py index 7c3204f96b..f220335336 100644 --- a/var/spack/repos/builtin/packages/swiftsim/package.py +++ b/var/spack/repos/builtin/packages/swiftsim/package.py @@ -66,8 +66,8 @@ class Swiftsim(AutotoolsPackage): autogen = Executable('./autogen.sh') autogen() - def config_args(self): - return ['--prefix=%s' % prefix, - '--enable-mpi' if '+mpi' in spec else '--disable-mpi', + def configure_args(self): + return ['--prefix=%s' % self.prefix, + '--enable-mpi' if '+mpi' in self.spec else '--disable-mpi', '--with-metis={0}'.format(self.spec['metis'].prefix), '--enable-optimization'] -- cgit v1.2.3-60-g2f50 From 97c2224cd6445c0e5395b4ae30a9f4d3bf5670e0 Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 12 Jul 2016 21:28:09 +0200 Subject: package.py : extra arguments, fixed inheritance issue - added attribute to hold extra arguments in PackageBase instances - fixed registration from within packages - examples : hdf5, lzo --- lib/spack/spack/package.py | 16 +++++++++++- var/spack/repos/builtin/packages/hdf5/package.py | 31 ++++++++++++++---------- var/spack/repos/builtin/packages/lzo/package.py | 16 ++++++------ 3 files changed, 41 insertions(+), 22 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 5ceb1ce2a2..c61f8262f7 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -40,6 +40,8 @@ import textwrap import time import functools import inspect +import copy + from StringIO import StringIO from urlparse import urlparse @@ -135,7 +137,17 @@ class PackageMeta(type): checks = getattr(meta, attr_name) if checks: for phase_name, funcs in checks.items(): - phase = attr_dict.get(PackageMeta.phase_fmt.format(phase_name)) + try: + # Search for the phase in the attribute dictionary + phase = attr_dict[PackageMeta.phase_fmt.format(phase_name)] + except KeyError: + # If it is not there it's in the bases + # and we added a check. We need to copy + # and extend + for base in bases: + phase = getattr(base, PackageMeta.phase_fmt.format(phase_name), None) + attr_dict[PackageMeta.phase_fmt.format(phase_name)] = copy.deepcopy(phase) + phase = attr_dict[PackageMeta.phase_fmt.format(phase_name)] getattr(phase, check_name).extend(funcs) # Clear the attribute for the next class setattr(meta, attr_name, {}) @@ -511,6 +523,8 @@ class PackageBase(object): if self.is_extension: spack.repo.get(self.extendee_spec)._check_extendable() + self.extra_args = {} + @property def package_dir(self): """Return the directory where the package.py file lives.""" diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py index 51a5823aa5..54c74901f0 100644 --- a/var/spack/repos/builtin/packages/hdf5/package.py +++ b/var/spack/repos/builtin/packages/hdf5/package.py @@ -27,7 +27,7 @@ from spack import * import shutil -class Hdf5(Package): +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. @@ -58,13 +58,15 @@ class Hdf5(Package): depends_on("szip", when='+szip') depends_on("zlib") - def validate(self, spec): + @AutotoolsPackage.precondition('configure') + def validate(self): """ Checks if incompatible variants have been activated at the same time :param spec: spec of the package :raises RuntimeError: in case of inconsistencies """ + spec = self.spec if '+fortran' in spec and not self.compiler.fc: msg = 'cannot build a fortran variant without a fortran compiler' raise RuntimeError(msg) @@ -73,8 +75,8 @@ class Hdf5(Package): msg = 'cannot use variant +threadsafe with either +cxx or +fortran' raise RuntimeError(msg) - def install(self, spec, prefix): - self.validate(spec) + def configure_args(self): + spec = self.spec # Handle compilation after spec validation extra_args = [] @@ -137,16 +139,19 @@ class Hdf5(Package): '--disable-hl', ]) - configure( - "--prefix=%s" % prefix, - "--with-zlib=%s" % spec['zlib'].prefix, - *extra_args) - make() - make("install") - self.check_install(spec) - - def check_install(self, spec): + return ["--with-zlib=%s" % spec['zlib'].prefix] + extra_args + #configure( + # "--prefix=%s" % prefix, + # "--with-zlib=%s" % spec['zlib'].prefix, + # *extra_args) + #make() + #make("install") + #self.check_install(spec) + + @AutotoolsPackage.sanity_check('install') + 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): diff --git a/var/spack/repos/builtin/packages/lzo/package.py b/var/spack/repos/builtin/packages/lzo/package.py index 0961bbb58c..edf6dc1d4c 100644 --- a/var/spack/repos/builtin/packages/lzo/package.py +++ b/var/spack/repos/builtin/packages/lzo/package.py @@ -25,7 +25,7 @@ from spack import * -class Lzo(Package): +class Lzo(AutotoolsPackage): """Real-time data compression library""" homepage = 'https://www.oberhumer.com/opensource/lzo/' @@ -37,13 +37,13 @@ class Lzo(Package): version('2.06', '95380bd4081f85ef08c5209f4107e9f8') version('2.05', 'c67cda5fa191bab761c7cb06fe091e36') - def install(self, spec, prefix): - configure_args = [ - '--prefix={0}'.format(prefix), + def configure_args(self): + return [ '--disable-dependency-tracking', '--enable-shared' ] - configure(*configure_args) - make() - make('check') - make('install') + + @AutotoolsPackage.sanity_check('build') + def check(self): + if self.extra_args.get('build-tests', False): + make('check') -- cgit v1.2.3-60-g2f50 From 5cc59507f724950f8671803bb9ff616b17f255f7 Mon Sep 17 00:00:00 2001 From: alalazo Date: Wed, 13 Jul 2016 09:21:49 +0200 Subject: package.py : hdf5 and lzo have examples of run_tests --- lib/spack/spack/package.py | 40 +++++++++++++++++++----- var/spack/repos/builtin/packages/hdf5/package.py | 18 ++++------- var/spack/repos/builtin/packages/lzo/package.py | 5 +-- 3 files changed, 41 insertions(+), 22 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index c61f8262f7..50f4e715b1 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -96,25 +96,35 @@ class InstallPhase(object): phase = getattr(instance, self.name) @functools.wraps(phase) def phase_wrapper(spec, prefix): + # Check instance attributes at the beginning of a phase + self._on_phase_start(instance) # Execute phase pre-conditions, # and give them the chance to fail for check in self.preconditions: - check(instance) - # Do something sensible at some point + check(instance) # Do something sensible at some point phase(spec, prefix) # Execute phase sanity_checks, # and give them the chance to fail for check in self.sanity_checks: check(instance) - if getattr(instance, 'last_phase', None) == self.name: - raise StopIteration('Stopping at \'{0}\' phase'.format(self.name)) + # Check instance attributes at the end of a phase + self._on_phase_exit(instance) return phase_wrapper + def _on_phase_start(self, instance): + pass + + def _on_phase_exit(self, instance): + # If a phase has a matching last_phase attribute, + # stop the installation process raising a StopIteration + if getattr(instance, 'last_phase', None) == self.name: + raise StopIteration('Stopping at \'{0}\' phase'.format(self.name)) + class PackageMeta(type): """Conveniently transforms attributes to permit extensible phases - Iterates over the attribute 'phase' and creates / updates private + Iterates over the attribute 'phases' and creates / updates private InstallPhase attributes in the class that is being initialized """ phase_fmt = '_InstallPhase_{0}' @@ -156,14 +166,25 @@ class PackageMeta(type): 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) + check_list = getattr(meta, attr_name) for item in args: - checks = sanity_checks.setdefault(item, []) + checks = check_list.setdefault(item, []) checks.append(func) - setattr(meta, attr_name, sanity_checks) + setattr(meta, attr_name, check_list) return func return _register_sanity_checks + @staticmethod + def on_package_attributes(**attrs): + def _execute_under_condition(func): + @functools.wraps(func) + def _wrapper(instance): + # If all the attributes have the value we require, then execute + if all([getattr(instance, key, None) == value for key, value in attrs.items()]): + func(instance) + return _wrapper + return _execute_under_condition + @classmethod def precondition(cls, *args): return cls._register_checks('preconditions', *args) @@ -181,6 +202,9 @@ class PackageMeta(type): if all([not hasattr(x, 'precondition') for x in bases]): attr_dict['precondition'] = precondition + if all([not hasattr(x, 'on_package_attributes') for x in bases]): + attr_dict['on_package_attributes'] = on_package_attributes + # Preconditions _append_checks('preconditions') # Sanity checks diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py index 54c74901f0..3b2600e671 100644 --- a/var/spack/repos/builtin/packages/hdf5/package.py +++ b/var/spack/repos/builtin/packages/hdf5/package.py @@ -29,8 +29,8 @@ import shutil 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. + 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 = "http://www.hdfgroup.org/HDF5/" @@ -54,9 +54,9 @@ class Hdf5(AutotoolsPackage): variant('szip', default=False, description='Enable szip support') variant('threadsafe', default=False, description='Enable thread-safe capabilities') - depends_on("mpi", when='+mpi') - depends_on("szip", when='+szip') - depends_on("zlib") + depends_on('mpi', when='+mpi') + depends_on('szip', when='+szip') + depends_on('zlib') @AutotoolsPackage.precondition('configure') def validate(self): @@ -140,15 +140,9 @@ class Hdf5(AutotoolsPackage): ]) return ["--with-zlib=%s" % spec['zlib'].prefix] + extra_args - #configure( - # "--prefix=%s" % prefix, - # "--with-zlib=%s" % spec['zlib'].prefix, - # *extra_args) - #make() - #make("install") - #self.check_install(spec) @AutotoolsPackage.sanity_check('install') + @AutotoolsPackage.on_package_attributes(run_tests=True) def check_install(self): "Build and run a small program to test the installed HDF5 library" spec = self.spec diff --git a/var/spack/repos/builtin/packages/lzo/package.py b/var/spack/repos/builtin/packages/lzo/package.py index edf6dc1d4c..9232bbe4e6 100644 --- a/var/spack/repos/builtin/packages/lzo/package.py +++ b/var/spack/repos/builtin/packages/lzo/package.py @@ -44,6 +44,7 @@ class Lzo(AutotoolsPackage): ] @AutotoolsPackage.sanity_check('build') + @AutotoolsPackage.on_package_attributes(run_tests=True) def check(self): - if self.extra_args.get('build-tests', False): - make('check') + make('check') + make('test') -- cgit v1.2.3-60-g2f50 From 7cedd620f1e233e559879dbb84d23db52a1a4a3c Mon Sep 17 00:00:00 2001 From: alalazo Date: Wed, 13 Jul 2016 17:36:06 +0200 Subject: package.py : added CMakePackage, changed qhull, ibmisc, openjpeg to work as examples --- lib/spack/spack/package.py | 254 ++++++++++++--------- var/spack/repos/builtin/packages/ibmisc/package.py | 2 +- .../repos/builtin/packages/openjpeg/package.py | 14 +- var/spack/repos/builtin/packages/qhull/package.py | 12 +- 4 files changed, 159 insertions(+), 123 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 29d7e1dca7..525ff91e87 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -33,15 +33,14 @@ Homebrew makes it very easy to create packages. For a complete rundown on spack and how it differs from homebrew, look at the README. """ +import copy +import functools +import inspect import os +import platform import re -import string import textwrap import time -import functools -import inspect -import copy - from StringIO import StringIO from urlparse import urlparse @@ -65,7 +64,7 @@ from spack import directory_layout from spack.stage import Stage, ResourceStage, StageComposite from spack.util.compression import allowed_archive from spack.util.environment import dump_environment -from spack.util.executable import ProcessError, which +from spack.util.executable import ProcessError from spack.version import * """Allowed URL schemes for spack packages.""" @@ -1644,6 +1643,49 @@ class AutotoolsPackage(PackageBase): PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) +class CMakePackage(PackageBase): + phases = ['cmake', 'build', 'install'] + + def build_type(self): + return 'RelWithDebInfo' + + @property + def std_cmake_args(self): + # standard CMake arguments + args = ['-DCMAKE_INSTALL_PREFIX:PATH={0}'.format(self.prefix), + '-DCMAKE_BUILD_TYPE:STRING={0}'.format(self.build_type())] + if platform.mac_ver()[0]: + args.append('-DCMAKE_FIND_FRAMEWORK:STRING=LAST') + + # Set up CMake rpath + args.append('-DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=FALSE') + rpaths = ':'.join(spack.build_environment.get_rpaths(self)) + args.append('-DCMAKE_INSTALL_RPATH:STRING={0}'.format(rpaths)) + return args + + def wdir(self): + return join_path(self.stage.source_path, 'spack-build') + + def cmake_args(self): + return list() + + def cmake(self, spec, prefix): + options = [self.source_directory] + self.std_cmake_args + self.cmake_args() + create = not os.path.exists(self.wdir()) + with working_dir(self.wdir(), create=create): + inspect.getmodule(self).cmake(*options) + + def build(self, spec, prefix): + with working_dir(self.wdir()): + inspect.getmodule(self).make() + + def install(self, spec, prefix): + with working_dir(self.wdir()): + inspect.getmodule(self).make('install') + + PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) + + def install_dependency_symlinks(pkg, spec, prefix): """Execute a dummy install and flatten dependencies""" flatten_dependencies(spec, prefix) @@ -1753,107 +1795,107 @@ def _hms(seconds): # os.chmod(path, mode) -class CMakePackage(PackageBase): - phases = ['configure', 'build', 'install', 'provenance'] - - def make_make(self): - import multiprocessing - # number of jobs spack will to build with. - jobs = multiprocessing.cpu_count() - if not self.parallel: - jobs = 1 - elif self.make_jobs: - jobs = self.make_jobs - - make = spack.build_environment.MakeExecutable('make', jobs) - return make - - def configure_args(self): - """Returns package-specific arguments to be provided to the configure command.""" - return list() - - def configure_env(self): - """Returns package-specific environment under which the configure command should be run.""" - # FIXME : Why not EnvironmentModules and the hooks that PackageBase already provides ? - return dict() - - def spack_transitive_include_path(self): - return ';'.join( - os.path.join(dep, 'include') - for dep in os.environ['SPACK_DEPENDENCIES'].split(os.pathsep) - ) - - def setup(self, spec, prefix): - cmd = [str(which('cmake'))] + \ - spack.build_environment.get_std_cmake_args(self) + \ - ['-DCMAKE_INSTALL_PREFIX=%s' % os.environ['SPACK_PREFIX'], - '-DCMAKE_C_COMPILER=%s' % os.environ['SPACK_CC'], - '-DCMAKE_CXX_COMPILER=%s' % os.environ['SPACK_CXX'], - '-DCMAKE_Fortran_COMPILER=%s' % os.environ['SPACK_FC']] + \ - self.configure_args() - - env = dict() - env['PATH'] = os.environ['PATH'] - env['SPACK_TRANSITIVE_INCLUDE_PATH'] = self.spack_transitive_include_path() - env['CMAKE_PREFIX_PATH'] = os.environ['CMAKE_PREFIX_PATH'] - - setup_fname = 'spconfig.py' - with open(setup_fname, 'w') as fout: - fout.write(\ -r"""#!%s +# class CMakePackage(PackageBase): +# phases = ['configure', 'build', 'install', 'provenance'] # - -import sys -import os -import subprocess - -def cmdlist(str): - return list(x.strip().replace("'",'') for x in str.split('\n') if x) -env = dict(os.environ) -""" % sys.executable) - - env_vars = sorted(list(env.keys())) - for name in env_vars: - val = env[name] - if string.find(name, 'PATH') < 0: - fout.write('env[%s] = %s\n' % (repr(name),repr(val))) - else: - if name == 'SPACK_TRANSITIVE_INCLUDE_PATH': - sep = ';' - else: - sep = ':' - - fout.write('env[%s] = "%s".join(cmdlist("""\n' % (repr(name),sep)) - for part in string.split(val, sep): - fout.write(' %s\n' % part) - fout.write('"""))\n') - - fout.write("env['CMAKE_TRANSITIVE_INCLUDE_PATH'] = env['SPACK_TRANSITIVE_INCLUDE_PATH'] # Deprecated\n") - fout.write('\ncmd = cmdlist("""\n') - fout.write('%s\n' % cmd[0]) - for arg in cmd[1:]: - fout.write(' %s\n' % arg) - fout.write('""") + sys.argv[1:]\n') - fout.write('\nproc = subprocess.Popen(cmd, env=env)\nproc.wait()\n') - set_executable(setup_fname) - - def configure(self, spec, prefix): - cmake = which('cmake') - with working_dir(self.build_directory, create=True): - os.environ.update(self.configure_env()) - os.environ['SPACK_TRANSITIVE_INCLUDE_PATH'] = self.spack_transitive_include_path() - options = self.configure_args() + spack.build_environment.get_std_cmake_args(self) - cmake(self.source_directory, *options) - - def build(self, spec, prefix): - make = self.make_make() - with working_dir(self.build_directory, create=False): - make() - - def install(self, spec, prefix): - make = self.make_make() - with working_dir(self.build_directory, create=False): - make('install') +# def make_make(self): +# import multiprocessing +# # number of jobs spack will to build with. +# jobs = multiprocessing.cpu_count() +# if not self.parallel: +# jobs = 1 +# elif self.make_jobs: +# jobs = self.make_jobs +# +# make = spack.build_environment.MakeExecutable('make', jobs) +# return make +# +# def configure_args(self): +# """Returns package-specific arguments to be provided to the configure command.""" +# return list() +# +# def configure_env(self): +# """Returns package-specific environment under which the configure command should be run.""" +# # FIXME : Why not EnvironmentModules and the hooks that PackageBase already provides ? +# return dict() +# +# def spack_transitive_include_path(self): +# return ';'.join( +# os.path.join(dep, 'include') +# for dep in os.environ['SPACK_DEPENDENCIES'].split(os.pathsep) +# ) +# +# def setup(self, spec, prefix): +# cmd = [str(which('cmake'))] + \ +# spack.build_environment.get_std_cmake_args(self) + \ +# ['-DCMAKE_INSTALL_PREFIX=%s' % os.environ['SPACK_PREFIX'], +# '-DCMAKE_C_COMPILER=%s' % os.environ['SPACK_CC'], +# '-DCMAKE_CXX_COMPILER=%s' % os.environ['SPACK_CXX'], +# '-DCMAKE_Fortran_COMPILER=%s' % os.environ['SPACK_FC']] + \ +# self.configure_args() +# +# env = dict() +# env['PATH'] = os.environ['PATH'] +# env['SPACK_TRANSITIVE_INCLUDE_PATH'] = self.spack_transitive_include_path() +# env['CMAKE_PREFIX_PATH'] = os.environ['CMAKE_PREFIX_PATH'] +# +# setup_fname = 'spconfig.py' +# with open(setup_fname, 'w') as fout: +# fout.write(\ +# r"""#!%s +# # +# +# import sys +# import os +# import subprocess +# +# def cmdlist(str): +# return list(x.strip().replace("'",'') for x in str.split('\n') if x) +# env = dict(os.environ) +# """ % sys.executable) +# +# env_vars = sorted(list(env.keys())) +# for name in env_vars: +# val = env[name] +# if string.find(name, 'PATH') < 0: +# fout.write('env[%s] = %s\n' % (repr(name),repr(val))) +# else: +# if name == 'SPACK_TRANSITIVE_INCLUDE_PATH': +# sep = ';' +# else: +# sep = ':' +# +# fout.write('env[%s] = "%s".join(cmdlist("""\n' % (repr(name),sep)) +# for part in string.split(val, sep): +# fout.write(' %s\n' % part) +# fout.write('"""))\n') +# +# fout.write("env['CMAKE_TRANSITIVE_INCLUDE_PATH'] = env['SPACK_TRANSITIVE_INCLUDE_PATH'] # Deprecated\n") +# fout.write('\ncmd = cmdlist("""\n') +# fout.write('%s\n' % cmd[0]) +# for arg in cmd[1:]: +# fout.write(' %s\n' % arg) +# fout.write('""") + sys.argv[1:]\n') +# fout.write('\nproc = subprocess.Popen(cmd, env=env)\nproc.wait()\n') +# set_executable(setup_fname) +# +# def configure(self, spec, prefix): +# cmake = which('cmake') +# with working_dir(self.build_directory, create=True): +# os.environ.update(self.configure_env()) +# os.environ['SPACK_TRANSITIVE_INCLUDE_PATH'] = self.spack_transitive_include_path() +# options = self.configure_args() + spack.build_environment.get_std_cmake_args(self) +# cmake(self.source_directory, *options) +# +# def build(self, spec, prefix): +# make = self.make_make() +# with working_dir(self.build_directory, create=False): +# make() +# +# def install(self, spec, prefix): +# make = self.make_make() +# with working_dir(self.build_directory, create=False): +# make('install') class FetchError(spack.error.SpackError): diff --git a/var/spack/repos/builtin/packages/ibmisc/package.py b/var/spack/repos/builtin/packages/ibmisc/package.py index 8e6cf429a7..0da3871582 100644 --- a/var/spack/repos/builtin/packages/ibmisc/package.py +++ b/var/spack/repos/builtin/packages/ibmisc/package.py @@ -34,7 +34,7 @@ class Ibmisc(CMakePackage): depends_on('cmake') depends_on('doxygen') - def configure_args(self): + def cmake_args(self): spec = self.spec return [ '-DUSE_EVERYTRACE=%s' % ('YES' if '+everytrace' in spec else 'NO'), diff --git a/var/spack/repos/builtin/packages/openjpeg/package.py b/var/spack/repos/builtin/packages/openjpeg/package.py index 1d00edb06d..cf2c80817f 100644 --- a/var/spack/repos/builtin/packages/openjpeg/package.py +++ b/var/spack/repos/builtin/packages/openjpeg/package.py @@ -25,9 +25,9 @@ from spack import * -class Openjpeg(Package): - """ - OpenJPEG is an open-source JPEG 2000 codec written in C language. +class Openjpeg(CMakePackage): + """OpenJPEG is an open-source JPEG 2000 codec written in C language. + It has been developed in order to promote the use of JPEG 2000, a still-image compression standard from the Joint Photographic Experts Group (JPEG). @@ -35,7 +35,7 @@ class Openjpeg(Package): ITU-T as a JPEG 2000 Reference Software. """ homepage = "https://github.com/uclouvain/openjpeg" - url = "https://github.com/uclouvain/openjpeg/archive/version.2.1.tar.gz" + url = "https://github.com/uclouvain/openjpeg/archive/version.2.1.tar.gz" version('2.1', '3e1c451c087f8462955426da38aa3b3d') version('2.0.1', '105876ed43ff7dbb2f90b41b5a43cfa5') @@ -44,9 +44,3 @@ class Openjpeg(Package): version('1.5.1', 'd774e4b5a0db5f0f171c4fc0aabfa14e') depends_on('cmake') - - def install(self, spec, prefix): - cmake('.', *std_cmake_args) - - make() - make("install") diff --git a/var/spack/repos/builtin/packages/qhull/package.py b/var/spack/repos/builtin/packages/qhull/package.py index 280c9cc12c..9d8184c745 100644 --- a/var/spack/repos/builtin/packages/qhull/package.py +++ b/var/spack/repos/builtin/packages/qhull/package.py @@ -24,7 +24,8 @@ ############################################################################## from spack import * -class Qhull(Package): + +class Qhull(CMakePackage): """Qhull computes the convex hull, Delaunay triangulation, Voronoi diagram, halfspace intersection about a point, furt hest-site Delaunay triangulation, and furthest-site Voronoi diagram. The @@ -47,8 +48,7 @@ class Qhull(Package): depends_on('cmake') - def install(self, spec, prefix): - with working_dir('spack-build', create=True): - cmake('..', *std_cmake_args) - make() - make("install") + @CMakePackage.sanity_check('build') + @CMakePackage.on_package_attributes(run_tests=True) + def check(self): + make('test') -- cgit v1.2.3-60-g2f50 From f5433477b9f7c98ca00947cf1b1fdc106cca1080 Mon Sep 17 00:00:00 2001 From: alalazo Date: Thu, 11 Aug 2016 09:08:00 +0200 Subject: qa : flake8 issues --- lib/spack/llnl/util/tty/log.py | 17 +++--- lib/spack/spack/build_environment.py | 13 ++--- lib/spack/spack/cmd/setup.py | 7 +-- lib/spack/spack/package.py | 68 ++++++++++++++++-------- var/spack/repos/builtin/packages/hdf5/package.py | 20 +++---- 5 files changed, 76 insertions(+), 49 deletions(-) (limited to 'var') diff --git a/lib/spack/llnl/util/tty/log.py b/lib/spack/llnl/util/tty/log.py index 25ed5254a5..a4ba2a9bdf 100644 --- a/lib/spack/llnl/util/tty/log.py +++ b/lib/spack/llnl/util/tty/log.py @@ -24,12 +24,11 @@ ############################################################################## """Utility classes for logging the output of blocks of code. """ -import sys +import multiprocessing import os import re import select -import inspect -import multiprocessing +import sys import llnl.util.tty as tty import llnl.util.tty.color as color @@ -117,9 +116,10 @@ class log_output(object): # do things ... output will be logged # and also printed to stdout. - Opens a stream in 'w' mode at daemon spawning and closes it at daemon joining. - If echo is True, also prints the output to stdout. + Opens a stream in 'w' mode at daemon spawning and closes it at + daemon joining. If echo is True, also prints the output to stdout. """ + def __init__(self, filename, echo=False, force_color=False, debug=False): self.filename = filename # Various output options @@ -133,7 +133,11 @@ class log_output(object): self.read, self.write = os.pipe() # Sets a daemon that writes to file what it reads from a pipe - self.p = multiprocessing.Process(target=self._spawn_writing_daemon, args=(self.read,), name='logger_daemon') + self.p = multiprocessing.Process( + target=self._spawn_writing_daemon, + args=(self.read,), + name='logger_daemon' + ) self.p.daemon = True # Needed to un-summon the daemon self.parent_pipe, self.child_pipe = multiprocessing.Pipe() @@ -186,6 +190,7 @@ class log_output(object): os.close(self.read) class OutputRedirection(object): + def __init__(self, other): self.__dict__.update(other.__dict__) diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py index f9d795845e..03b044567f 100644 --- a/lib/spack/spack/build_environment.py +++ b/lib/spack/spack/build_environment.py @@ -51,16 +51,14 @@ There are two parts to the build environment: Skimming this module is a nice way to get acquainted with the types of calls you can make from within the install() function. """ +import multiprocessing import os -import sys import shutil -import multiprocessing -import platform +import sys import llnl.util.tty as tty -from llnl.util.filesystem import * - import spack +from llnl.util.filesystem import * from spack.environment import EnvironmentModifications, validate from spack.util.environment import * from spack.util.executable import Executable, which @@ -502,7 +500,10 @@ def fork(pkg, function, dirty=False): child_connection.close() parent_connection, child_connection = multiprocessing.Pipe() - p = multiprocessing.Process(target=child_execution, args=(child_connection,)) + p = multiprocessing.Process( + target=child_execution, + args=(child_connection,) + ) p.start() exc_type, exception, traceback = parent_connection.recv() p.join() diff --git a/lib/spack/spack/cmd/setup.py b/lib/spack/spack/cmd/setup.py index 9553942017..652c08354f 100644 --- a/lib/spack/spack/cmd/setup.py +++ b/lib/spack/spack/cmd/setup.py @@ -58,8 +58,6 @@ def spack_transitive_include_path(): def write_spconfig(package): - spec = package.spec - prefix = spec.prefix # Set-up the environment spack.build_environment.setup_package(package) @@ -79,7 +77,7 @@ def write_spconfig(package): setup_fname = 'spconfig.py' with open(setup_fname, 'w') as fout: fout.write( -r"""#!%s + r"""#!%s # import sys @@ -108,8 +106,7 @@ env = dict(os.environ) fout.write(' %s\n' % part) fout.write('"""))\n') - fout.write( - "env['CMAKE_TRANSITIVE_INCLUDE_PATH'] = env['SPACK_TRANSITIVE_INCLUDE_PATH'] # Deprecated\n") + fout.write("env['CMAKE_TRANSITIVE_INCLUDE_PATH'] = env['SPACK_TRANSITIVE_INCLUDE_PATH'] # Deprecated\n") # NOQA: ignore=E501 fout.write('\ncmd = cmdlist("""\n') fout.write('%s\n' % cmd[0]) for arg in cmd[1:]: diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 0d9067a955..3e25dddb0e 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -75,12 +75,13 @@ _ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"] class InstallPhase(object): """Manages a single phase of the installation - 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 - by subclasses of whatever class declared the phases. + 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 by subclasses of whatever class declared the phases. It also provides hooks to execute prerequisite and sanity checks. """ + def __init__(self, name): self.name = name self.preconditions = [] @@ -94,6 +95,7 @@ class InstallPhase(object): # If instance is there the caller wants to execute the # install phase, thus return a properly set wrapper phase = getattr(instance, self.name) + @functools.wraps(phase) def phase_wrapper(spec, prefix): # Check instance attributes at the beginning of a phase @@ -101,7 +103,8 @@ class InstallPhase(object): # Execute phase pre-conditions, # and give them the chance to fail for check in self.preconditions: - check(instance) # Do something sensible at some point + # Do something sensible at some point + check(instance) phase(spec, prefix) # Execute phase sanity_checks, # and give them the chance to fail @@ -147,8 +150,8 @@ class PackageMeta(type): # Check if phases is in attr dict, then set # install phases wrappers if 'phases' in attr_dict: - _InstallPhase_phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']] - for phase_name, callback_name in zip(_InstallPhase_phases, attr_dict['phases']): + _InstallPhase_phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']] # NOQA: ignore=E501 + for phase_name, callback_name in zip(_InstallPhase_phases, attr_dict['phases']): # NOQA: ignore=E501 attr_dict[phase_name] = InstallPhase(callback_name) attr_dict['_InstallPhase_phases'] = _InstallPhase_phases @@ -160,15 +163,22 @@ class PackageMeta(type): for phase_name, funcs in checks.items(): try: # Search for the phase in the attribute dictionary - phase = attr_dict[PackageMeta.phase_fmt.format(phase_name)] + phase = attr_dict[ + PackageMeta.phase_fmt.format(phase_name)] except KeyError: # If it is not there it's in the bases # and we added a check. We need to copy # and extend for base in bases: - phase = getattr(base, PackageMeta.phase_fmt.format(phase_name), None) - attr_dict[PackageMeta.phase_fmt.format(phase_name)] = phase.copy() - phase = attr_dict[PackageMeta.phase_fmt.format(phase_name)] + phase = getattr( + base, + PackageMeta.phase_fmt.format(phase_name), + None + ) + attr_dict[PackageMeta.phase_fmt.format( + phase_name)] = phase.copy() + phase = attr_dict[ + PackageMeta.phase_fmt.format(phase_name)] getattr(phase, check_name).extend(funcs) # Clear the attribute for the next class setattr(meta, attr_name, {}) @@ -190,8 +200,9 @@ class PackageMeta(type): def _execute_under_condition(func): @functools.wraps(func) def _wrapper(instance): - # If all the attributes have the value we require, then execute - if all([getattr(instance, key, None) == value for key, value in attrs.items()]): + # If all the attributes have the value we require, then + # execute + if all([getattr(instance, key, None) == value for key, value in attrs.items()]): # NOQA: ignore=E501 func(instance) return _wrapper return _execute_under_condition @@ -1081,7 +1092,8 @@ class PackageBase(object): else: self.do_stage() - tty.msg("Building {0} [{1}]".format(self.name, type(self).__base__ )) + tty.msg("Building {0} [{1}]".format( + self.name, type(self).__base__)) self.stage.keep = keep_stage self.build_directory = join_path(self.stage.path, 'spack-build') @@ -1106,13 +1118,22 @@ class PackageBase(object): self.log_path = log_path self.env_path = env_path dump_environment(env_path) - # Spawn a daemon that reads from a pipe and redirects everything to log_path - with log_output(log_path, verbose, sys.stdout.isatty(), True) as log_redirection: - for phase_name, phase in zip(self.phases, self._InstallPhase_phases): - tty.msg('Executing phase : \'{0}\''.format(phase_name)) + # Spawn a daemon that reads from a pipe and redirects + # everything to log_path + redirection_context = log_output( + log_path, verbose, + sys.stdout.isatty(), + True + ) + with redirection_context as log_redirection: + for phase_name, phase in zip(self.phases, self._InstallPhase_phases): # NOQA: ignore=E501 + tty.msg( + 'Executing phase : \'{0}\''.format(phase_name) # NOQA: ignore=E501 + ) # Redirect stdout and stderr to daemon pipe with log_redirection: - getattr(self, phase)(self.spec, self.prefix) + getattr(self, phase)( + self.spec, self.prefix) self.log() # Run post install hooks before build stage is removed. spack.hooks.post_install(self) @@ -1174,7 +1195,7 @@ class PackageBase(object): """ self.last_phase = kwargs.pop('stop_at', None) if self.last_phase is not None and self.last_phase not in self.phases: - tty.die('\'{0.last_phase}\' is not among the allowed phases for package {0.name}'.format(self)) + tty.die('\'{0.last_phase}\' is not among the allowed phases for package {0.name}'.format(self)) # NOQA: ignore=E501 def log(self): # Copy provenance into the install directory on success @@ -1188,7 +1209,8 @@ class PackageBase(object): # Remove first if we're overwriting another build # (can happen with spack setup) try: - shutil.rmtree(packages_dir) # log_install_path and env_install_path are inside this + # log_install_path and env_install_path are inside this + shutil.rmtree(packages_dir) except Exception: # FIXME : this potentially catches too many things... pass @@ -1609,7 +1631,8 @@ class AutotoolsPackage(PackageBase): @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())) + raise RuntimeError( + 'configure script not found in {0}'.format(os.getcwd())) def configure_args(self): return list() @@ -1668,7 +1691,8 @@ class CMakePackage(PackageBase): return list() def cmake(self, spec, prefix): - options = [self.root_cmakelists_dir()] + self.std_cmake_args + self.cmake_args() + options = [self.root_cmakelists_dir()] + self.std_cmake_args + \ + self.cmake_args() create = not os.path.exists(self.wdir()) with working_dir(self.wdir(), create=create): inspect.getmodule(self).cmake(*options) diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py index a7c4b2d85e..601e3278e5 100644 --- a/var/spack/repos/builtin/packages/hdf5/package.py +++ b/var/spack/repos/builtin/packages/hdf5/package.py @@ -149,7 +149,7 @@ class Hdf5(AutotoolsPackage): def check_install(self): "Build and run a small program to test the installed HDF5 library" spec = self.spec - print "Checking HDF5 installation..." + print("Checking HDF5 installation...") checkdir = "spack-check" with working_dir(checkdir, create=True): source = r""" @@ -186,15 +186,15 @@ HDF5 version {version} {version} output = "" success = output == expected if not success: - print "Produced output does not match expected output." - print "Expected output:" - print '-' * 80 - print expected - print '-' * 80 - print "Produced output:" - print '-' * 80 - print output - print '-' * 80 + print("Produced output does not match expected output.") + print("Expected output:") + print('-' * 80) + print(expected) + print('-' * 80) + print("Produced output:") + print('-' * 80) + print(output) + print('-' * 80) raise RuntimeError("HDF5 install check failed") shutil.rmtree(checkdir) -- cgit v1.2.3-60-g2f50 From c7a5dd36e2d25d9f9c438b40b94b7d5833e149a8 Mon Sep 17 00:00:00 2001 From: alalazo Date: Tue, 11 Oct 2016 16:30:06 +0200 Subject: qa : flake8 issues --- var/spack/repos/builtin/packages/gmp/package.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'var') diff --git a/var/spack/repos/builtin/packages/gmp/package.py b/var/spack/repos/builtin/packages/gmp/package.py index de872f09e0..dcabbff67e 100644 --- a/var/spack/repos/builtin/packages/gmp/package.py +++ b/var/spack/repos/builtin/packages/gmp/package.py @@ -41,7 +41,7 @@ class Gmp(AutotoolsPackage): def configure_args(self): args = ['--enable-cxx'] - # We need this flag if we want all the following checks to pass. + # We need this flag if we want all the following checks to pass. if spec.compiler.name == 'intel': args.append('CXXFLAGS=-no-ftz') -- cgit v1.2.3-60-g2f50 From 482f60d1d37d8d18ff62318c23a72808ceacd99e Mon Sep 17 00:00:00 2001 From: alalazo Date: Sat, 22 Oct 2016 01:03:07 +0200 Subject: packages : moved decorators into AutotoolsPackage and CMakePackage --- lib/spack/spack/package.py | 20 ++++++++++++++++++++ var/spack/repos/builtin/packages/autoconf/package.py | 11 ++--------- var/spack/repos/builtin/packages/hdf5/package.py | 4 +--- var/spack/repos/builtin/packages/lzo/package.py | 2 -- var/spack/repos/builtin/packages/qhull/package.py | 2 -- 5 files changed, 23 insertions(+), 16 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 91e6b74dbd..75a708de9c 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -1733,6 +1733,16 @@ class AutotoolsPackage(PackageBase): def install(self, spec, prefix): inspect.getmodule(self).make('install') + @PackageBase.sanity_check('build') + @PackageBase.on_package_attributes(run_tests=True) + def _run_default_function(self): + try: + fn = getattr(self, 'check') + tty.msg('Trying default sanity checks [check]') + fn() + except AttributeError: + tty.msg('Skipping default sanity checks [method `check` not implemented]') # NOQA: ignore=E501 + # This will be used as a registration decorator in user # packages, if need be PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) @@ -1792,6 +1802,16 @@ class CMakePackage(PackageBase): with working_dir(self.wdir()): inspect.getmodule(self).make('install') + @PackageBase.sanity_check('build') + @PackageBase.on_package_attributes(run_tests=True) + def _run_default_function(self): + try: + fn = getattr(self, 'check') + tty.msg('Trying default sanity checks [check]') + fn() + except AttributeError: + tty.msg('Skipping default sanity checks [method `check` not implemented]') # NOQA: ignore=E501 + PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) diff --git a/var/spack/repos/builtin/packages/autoconf/package.py b/var/spack/repos/builtin/packages/autoconf/package.py index 5eb7f3347b..b6aba8c03f 100644 --- a/var/spack/repos/builtin/packages/autoconf/package.py +++ b/var/spack/repos/builtin/packages/autoconf/package.py @@ -25,10 +25,8 @@ from spack import * -class Autoconf(Package): - """ - Autoconf -- system configuration part of autotools - """ +class Autoconf(AutotoolsPackage): + """Autoconf -- system configuration part of autotools""" homepage = 'https://www.gnu.org/software/autoconf/' url = 'http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz' @@ -54,8 +52,3 @@ class Autoconf(Package): 'ifnames'] for name in executables: setattr(module, name, self._make_executable(name)) - - def install(self, spec, prefix): - configure("--prefix=%s" % prefix) - make() - make("install") diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py index 6b18aa4ab8..c92ed284bb 100644 --- a/var/spack/repos/builtin/packages/hdf5/package.py +++ b/var/spack/repos/builtin/packages/hdf5/package.py @@ -143,9 +143,7 @@ class Hdf5(AutotoolsPackage): return ["--with-zlib=%s" % spec['zlib'].prefix] + extra_args - @AutotoolsPackage.sanity_check('install') - @AutotoolsPackage.on_package_attributes(run_tests=True) - def check_install(self): + def check(self): "Build and run a small program to test the installed HDF5 library" spec = self.spec print("Checking HDF5 installation...") diff --git a/var/spack/repos/builtin/packages/lzo/package.py b/var/spack/repos/builtin/packages/lzo/package.py index dc8f316a72..05229b6a62 100644 --- a/var/spack/repos/builtin/packages/lzo/package.py +++ b/var/spack/repos/builtin/packages/lzo/package.py @@ -43,8 +43,6 @@ class Lzo(AutotoolsPackage): '--enable-shared' ] - @AutotoolsPackage.sanity_check('build') - @AutotoolsPackage.on_package_attributes(run_tests=True) def check(self): make('check') make('test') diff --git a/var/spack/repos/builtin/packages/qhull/package.py b/var/spack/repos/builtin/packages/qhull/package.py index e221bf1552..3816b377eb 100644 --- a/var/spack/repos/builtin/packages/qhull/package.py +++ b/var/spack/repos/builtin/packages/qhull/package.py @@ -45,7 +45,5 @@ class Qhull(CMakePackage): depends_on('cmake@2.6:', type='build') - @CMakePackage.sanity_check('build') - @CMakePackage.on_package_attributes(run_tests=True) def check(self): make('test') -- cgit v1.2.3-60-g2f50 From fa3f07c0929ef2beedb3746226d3f826f613e9cc Mon Sep 17 00:00:00 2001 From: alalazo Date: Sun, 23 Oct 2016 19:02:46 +0200 Subject: CMakePackage, AutotoolsPackage : added default behavior on check --- lib/spack/spack/package.py | 33 +++++++++++++++++++++-- var/spack/repos/builtin/packages/hdf5/package.py | 3 ++- var/spack/repos/builtin/packages/lzo/package.py | 4 --- var/spack/repos/builtin/packages/qhull/package.py | 3 --- 4 files changed, 33 insertions(+), 10 deletions(-) (limited to 'var') diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 99796104a5..9483f370dd 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -1055,6 +1055,27 @@ class PackageBase(object): mkdirp(self.prefix.lib) mkdirp(self.prefix.man1) + def _if_make_target_execute(self, target): + try: + # Check if we have a makefile + file = [x for x in ('Makefile', 'makefile') if os.path.exists(x)] + file = file.pop() + except IndexError: + tty.msg('No Makefile found in the build directory') + return + + # Check if 'target' is in the makefile + regex = re.compile('^' + target + ':') + with open(file, 'r') as f: + matches = [line for line in f.readlines() if regex.match(line)] + + if not matches: + tty.msg('Target \'' + target + ':\' not found in Makefile') + return + + # Execute target + inspect.getmodule(self).make(target) + def _get_needed_resources(self): resources = [] # Select the resources that are needed for this build @@ -1747,6 +1768,10 @@ class AutotoolsPackage(PackageBase): except AttributeError: tty.msg('Skipping default sanity checks [method `check` not implemented]') # NOQA: ignore=E501 + def check(self): + self._if_make_target_execute('test') + self._if_make_target_execute('check') + # This will be used as a registration decorator in user # packages, if need be PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) @@ -1814,10 +1839,14 @@ class CMakePackage(PackageBase): def _run_default_function(self): try: fn = getattr(self, 'check') - tty.msg('Trying default sanity checks [check]') + tty.msg('Trying default build sanity checks [check]') fn() except AttributeError: - tty.msg('Skipping default sanity checks [method `check` not implemented]') # NOQA: ignore=E501 + tty.msg('Skipping default build sanity checks [method `check` not implemented]') # NOQA: ignore=E501 + + def check(self): + with working_dir(self.build_directory()): + self._if_make_target_execute('test') PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) diff --git a/var/spack/repos/builtin/packages/hdf5/package.py b/var/spack/repos/builtin/packages/hdf5/package.py index c92ed284bb..cbb7501034 100644 --- a/var/spack/repos/builtin/packages/hdf5/package.py +++ b/var/spack/repos/builtin/packages/hdf5/package.py @@ -144,7 +144,8 @@ class Hdf5(AutotoolsPackage): return ["--with-zlib=%s" % spec['zlib'].prefix] + extra_args def check(self): - "Build and run a small program to test the installed HDF5 library" + super(Hdf5, self).check() + # Build and run a small program to test the installed HDF5 library spec = self.spec print("Checking HDF5 installation...") checkdir = "spack-check" diff --git a/var/spack/repos/builtin/packages/lzo/package.py b/var/spack/repos/builtin/packages/lzo/package.py index 05229b6a62..e9c98842f4 100644 --- a/var/spack/repos/builtin/packages/lzo/package.py +++ b/var/spack/repos/builtin/packages/lzo/package.py @@ -42,7 +42,3 @@ class Lzo(AutotoolsPackage): '--disable-dependency-tracking', '--enable-shared' ] - - def check(self): - make('check') - make('test') diff --git a/var/spack/repos/builtin/packages/qhull/package.py b/var/spack/repos/builtin/packages/qhull/package.py index 3816b377eb..4456c16bd2 100644 --- a/var/spack/repos/builtin/packages/qhull/package.py +++ b/var/spack/repos/builtin/packages/qhull/package.py @@ -44,6 +44,3 @@ class Qhull(CMakePackage): url="http://www.qhull.org/download/qhull-2012.1-src.tgz") depends_on('cmake@2.6:', type='build') - - def check(self): - make('test') -- cgit v1.2.3-60-g2f50 From 7bd735416dcf8235efa77bf21f7e92beacf7d433 Mon Sep 17 00:00:00 2001 From: alalazo Date: Sun, 23 Oct 2016 22:38:19 +0200 Subject: package.py : moved each specialized package to its own module file --- lib/spack/spack/__init__.py | 4 +- lib/spack/spack/build_systems/__init__.py | 0 lib/spack/spack/build_systems/autotools.py | 106 ++++++++++++++ lib/spack/spack/build_systems/cmake.py | 143 +++++++++++++++++++ lib/spack/spack/build_systems/editable_makefile.py | 77 ++++++++++ lib/spack/spack/package.py | 155 --------------------- var/spack/repos/builtin/packages/astyle/package.py | 4 +- 7 files changed, 331 insertions(+), 158 deletions(-) create mode 100644 lib/spack/spack/build_systems/__init__.py create mode 100644 lib/spack/spack/build_systems/autotools.py create mode 100644 lib/spack/spack/build_systems/cmake.py create mode 100644 lib/spack/spack/build_systems/editable_makefile.py (limited to 'var') diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index c7d592befb..918e17323b 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -196,7 +196,9 @@ __all__ = ['Package', 'alldeps', 'nolink'] from spack.package import Package, ExtensionConflictError -from spack.package import CMakePackage, AutotoolsPackage, EditableMakefile +from spack.build_systems.editable_makefile import EditableMakefile +from spack.build_systems.autotools import AutotoolsPackage +from spack.build_systems.cmake import CMakePackage from spack.version import Version, ver from spack.spec import DependencySpec, alldeps, nolink from spack.multimethod import when diff --git a/lib/spack/spack/build_systems/__init__.py b/lib/spack/spack/build_systems/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/spack/spack/build_systems/autotools.py b/lib/spack/spack/build_systems/autotools.py new file mode 100644 index 0000000000..0bb5576708 --- /dev/null +++ b/lib/spack/spack/build_systems/autotools.py @@ -0,0 +1,106 @@ +############################################################################## +# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/llnl/spack +# Please also see the LICENSE file for our notice and the LGPL. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, February 1999. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and +# conditions of the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## + +import inspect +import os.path + +import llnl.util.tty as tty +from spack.package import PackageBase + + +class AutotoolsPackage(PackageBase): + """Specialized class for packages that are built using GNU Autotools + + This class provides four phases that can be overridden: + - autoreconf + - configure + - build + - install + + They all have sensible defaults and for many packages the only thing + necessary will be to override `configure_args` + """ + phases = ['autoreconf', 'configure', 'build', 'install'] + # To be used in UI queries that require to know which + # build-system class we are using + build_system_class = 'AutotoolsPackage' + + def autoreconf(self, spec, prefix): + """Not needed usually, configure should be already there""" + pass + + @PackageBase.sanity_check('autoreconf') + def is_configure_or_die(self): + """Checks the presence of a `configure` file after the + autoreconf phase""" + if not os.path.exists('configure'): + raise RuntimeError( + 'configure script not found in {0}'.format(os.getcwd())) + + def configure_args(self): + """Method to be overridden. Should return an iterable containing + all the arguments that must be passed to configure, except --prefix + """ + return [] + + def configure(self, spec, prefix): + """Runs configure with the arguments specified in `configure_args` + and an appropriately set prefix + """ + options = ['--prefix={0}'.format(prefix)] + self.configure_args() + inspect.getmodule(self).configure(*options) + + def build(self, spec, prefix): + """The usual `make` after configure""" + inspect.getmodule(self).make() + + def install(self, spec, prefix): + """...and the final `make install` after configure""" + inspect.getmodule(self).make('install') + + @PackageBase.sanity_check('build') + @PackageBase.on_package_attributes(run_tests=True) + def _run_default_function(self): + """This function is run after build if self.run_tests == True + + It will search for a method named `check` and run it. A sensible + default is provided in the base class. + """ + try: + fn = getattr(self, 'check') + tty.msg('Trying default sanity checks [check]') + fn() + except AttributeError: + tty.msg('Skipping default sanity checks [method `check` not implemented]') # NOQA: ignore=E501 + + def check(self): + """Default test : search the Makefile for targets `test` and `check` + and run them if found. + """ + self._if_make_target_execute('test') + self._if_make_target_execute('check') + + # Check that self.prefix is there after installation + PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/cmake.py b/lib/spack/spack/build_systems/cmake.py new file mode 100644 index 0000000000..cb1076d7b7 --- /dev/null +++ b/lib/spack/spack/build_systems/cmake.py @@ -0,0 +1,143 @@ +############################################################################## +# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/llnl/spack +# Please also see the LICENSE file for our notice and the LGPL. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, February 1999. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and +# conditions of the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## + +import inspect +import os +import platform + +import llnl.util.tty as tty +import spack.build_environment +from llnl.util.filesystem import working_dir, join_path +from spack.package import PackageBase + + +class CMakePackage(PackageBase): + """Specialized class for packages that are built using cmake + + This class provides three phases that can be overridden: + - cmake + - build + - install + + They all have sensible defaults and for many packages the only thing + necessary will be to override `cmake_args` + """ + phases = ['cmake', 'build', 'install'] + # To be used in UI queries that require to know which + # build-system class we are using + build_system_class = 'CMakePackage' + + def build_type(self): + """Override to provide the correct build_type in case a complex + logic is needed + """ + return 'RelWithDebInfo' + + def root_cmakelists_dir(self): + """Directory where to find the root CMakeLists.txt""" + return self.stage.source_path + + @property + def std_cmake_args(self): + """Standard cmake arguments provided as a property for + convenience of package writers + """ + # standard CMake arguments + return CMakePackage._std_args(self) + + @staticmethod + def _std_args(pkg): + """Computes the standard cmake arguments for a generic package""" + try: + build_type = pkg.build_type() + except AttributeError: + build_type = 'RelWithDebInfo' + + args = ['-DCMAKE_INSTALL_PREFIX:PATH={0}'.format(pkg.prefix), + '-DCMAKE_BUILD_TYPE:STRING={0}'.format(build_type), + '-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON'] + if platform.mac_ver()[0]: + args.append('-DCMAKE_FIND_FRAMEWORK:STRING=LAST') + + # Set up CMake rpath + args.append('-DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=FALSE') + rpaths = ':'.join(spack.build_environment.get_rpaths(pkg)) + args.append('-DCMAKE_INSTALL_RPATH:STRING={0}'.format(rpaths)) + return args + + def build_directory(self): + """Override to provide another place to build the package""" + return join_path(self.stage.source_path, 'spack-build') + + def cmake_args(self): + """Method to be overridden. Should return an iterable containing + all the arguments that must be passed to configure, except: + - CMAKE_INSTALL_PREFIX + - CMAKE_BUILD_TYPE + """ + return [] + + def cmake(self, spec, prefix): + """Run cmake in the build directory""" + options = [self.root_cmakelists_dir()] + self.std_cmake_args + \ + self.cmake_args() + create = not os.path.exists(self.build_directory()) + with working_dir(self.build_directory(), create=create): + inspect.getmodule(self).cmake(*options) + + def build(self, spec, prefix): + """The usual `make` after cmake""" + with working_dir(self.build_directory()): + inspect.getmodule(self).make() + + def install(self, spec, prefix): + """...and the final `make install` after cmake""" + with working_dir(self.build_directory()): + inspect.getmodule(self).make('install') + + @PackageBase.sanity_check('build') + @PackageBase.on_package_attributes(run_tests=True) + def _run_default_function(self): + """This function is run after build if self.run_tests == True + + It will search for a method named `check` and run it. A sensible + default is provided in the base class. + """ + try: + fn = getattr(self, 'check') + tty.msg('Trying default build sanity checks [check]') + fn() + except AttributeError: + tty.msg('Skipping default build sanity checks [method `check` not implemented]') # NOQA: ignore=E501 + + def check(self): + """Default test : search the Makefile for the target `test` + and run them if found. + """ + with working_dir(self.build_directory()): + self._if_make_target_execute('test') + + # Check that self.prefix is there after installation + PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/editable_makefile.py b/lib/spack/spack/build_systems/editable_makefile.py new file mode 100644 index 0000000000..e3adea8363 --- /dev/null +++ b/lib/spack/spack/build_systems/editable_makefile.py @@ -0,0 +1,77 @@ +############################################################################## +# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/llnl/spack +# Please also see the LICENSE file for our notice and the LGPL. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, February 1999. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and +# conditions of the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## + +import inspect + +from llnl.util.filesystem import working_dir +from spack.package import PackageBase + + +class EditableMakefile(PackageBase): + """Specialized class for packages that are built using editable Makefiles + + This class provides three phases that can be overridden: + - edit + - build + - install + + It is necessary to override the 'edit' phase, while 'build' and 'install' + have sensible defaults. + """ + phases = ['edit', 'build', 'install'] + # To be used in UI queries that require to know which + # build-system class we are using + build_system_class = 'EditableMakefile' + + def build_directory(self): + """Directory where the main Makefile is located""" + return self.stage.source_path + + def build_args(self): + """List of arguments that should be passed to make at build time""" + return [] + + def install_args(self): + """List of arguments that should be passed to make at install time""" + return [] + + def edit(self, spec, prefix): + """This phase cannot be defaulted for obvious reasons...""" + raise NotImplementedError('\'edit\' function not implemented') + + def build(self, spec, prefix): + """Default build phase : call make passing build_args""" + args = self.build_args() + with working_dir(self.build_directory()): + inspect.getmodule(self).make(*args) + + def install(self, spec, prefix): + """Default install phase : call make passing install_args""" + args = self.install_args() + ['install'] + with working_dir(self.build_directory()): + inspect.getmodule(self).make(*args) + + # Check that self.prefix is there after installation + PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 9483f370dd..52dbd40f6f 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -38,7 +38,6 @@ import copy import functools import inspect import os -import platform import re import sys import textwrap @@ -48,7 +47,6 @@ from StringIO import StringIO import llnl.util.lock import llnl.util.tty as tty import spack -import spack.build_environment import spack.compilers import spack.directives import spack.error @@ -1698,159 +1696,6 @@ class Package(PackageBase): PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) -class EditableMakefile(PackageBase): - phases = ['edit', 'build', 'install'] - # To be used in UI queries that require to know which - # build-system class we are using - build_system_class = 'EditableMakefile' - - def wdir(self): - return self.stage.source_path - - def build_args(self): - return [] - - def install_args(self): - return [] - - def edit(self, spec, prefix): - raise NotImplementedError('\'edit\' function not implemented') - - def build(self, spec, prefix): - args = self.build_args() - with working_dir(self.wdir()): - inspect.getmodule(self).make(*args) - - def install(self, spec, prefix): - args = self.install_args() + ['install'] - with working_dir(self.wdir()): - inspect.getmodule(self).make(*args) - - PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) - - -class AutotoolsPackage(PackageBase): - phases = ['autoreconf', 'configure', 'build', 'install'] - # To be used in UI queries that require to know which - # build-system class we are using - build_system_class = 'AutotoolsPackage' - - 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 [] - - 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') - - @PackageBase.sanity_check('build') - @PackageBase.on_package_attributes(run_tests=True) - def _run_default_function(self): - try: - fn = getattr(self, 'check') - tty.msg('Trying default sanity checks [check]') - fn() - except AttributeError: - tty.msg('Skipping default sanity checks [method `check` not implemented]') # NOQA: ignore=E501 - - def check(self): - self._if_make_target_execute('test') - self._if_make_target_execute('check') - - # This will be used as a registration decorator in user - # packages, if need be - PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) - - -class CMakePackage(PackageBase): - phases = ['cmake', 'build', 'install'] - # To be used in UI queries that require to know which - # build-system class we are using - build_system_class = 'CMakePackage' - - def build_type(self): - return 'RelWithDebInfo' - - def root_cmakelists_dir(self): - return self.stage.source_path - - @property - def std_cmake_args(self): - # standard CMake arguments - return CMakePackage._std_args(self) - - @staticmethod - def _std_args(pkg): - try: - build_type = pkg.build_type() - except AttributeError: - build_type = 'RelWithDebInfo' - - args = ['-DCMAKE_INSTALL_PREFIX:PATH={0}'.format(pkg.prefix), - '-DCMAKE_BUILD_TYPE:STRING={0}'.format(build_type), - '-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON'] - if platform.mac_ver()[0]: - args.append('-DCMAKE_FIND_FRAMEWORK:STRING=LAST') - - # Set up CMake rpath - args.append('-DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=FALSE') - rpaths = ':'.join(spack.build_environment.get_rpaths(pkg)) - args.append('-DCMAKE_INSTALL_RPATH:STRING={0}'.format(rpaths)) - return args - - def build_directory(self): - return join_path(self.stage.source_path, 'spack-build') - - def cmake_args(self): - return [] - - def cmake(self, spec, prefix): - options = [self.root_cmakelists_dir()] + self.std_cmake_args + \ - self.cmake_args() - create = not os.path.exists(self.build_directory()) - with working_dir(self.build_directory(), create=create): - inspect.getmodule(self).cmake(*options) - - def build(self, spec, prefix): - with working_dir(self.build_directory()): - inspect.getmodule(self).make() - - def install(self, spec, prefix): - with working_dir(self.build_directory()): - inspect.getmodule(self).make('install') - - @PackageBase.sanity_check('build') - @PackageBase.on_package_attributes(run_tests=True) - def _run_default_function(self): - try: - fn = getattr(self, 'check') - tty.msg('Trying default build sanity checks [check]') - fn() - except AttributeError: - tty.msg('Skipping default build sanity checks [method `check` not implemented]') # NOQA: ignore=E501 - - def check(self): - with working_dir(self.build_directory()): - self._if_make_target_execute('test') - - PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) - - def install_dependency_symlinks(pkg, spec, prefix): """Execute a dummy install and flatten dependencies""" flatten_dependencies(spec, prefix) diff --git a/var/spack/repos/builtin/packages/astyle/package.py b/var/spack/repos/builtin/packages/astyle/package.py index 7acb77b304..fdd9c2111e 100644 --- a/var/spack/repos/builtin/packages/astyle/package.py +++ b/var/spack/repos/builtin/packages/astyle/package.py @@ -37,11 +37,11 @@ class Astyle(EditableMakefile): parallel = False - def wdir(self): + def build_directory(self): return join_path(self.stage.source_path, 'build', self.compiler.name) def edit(self, spec, prefix): - makefile = join_path(self.wdir(), 'Makefile') + makefile = join_path(self.build_directory(), 'Makefile') filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, makefile) def install_args(self): -- cgit v1.2.3-60-g2f50 From c1ad4bde28a09f39dbae0f6488dc7b7182d11f93 Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Mon, 24 Oct 2016 16:41:20 -0700 Subject: Rename EditableMakefile to MakefilePackage --- lib/spack/spack/__init__.py | 4 +- lib/spack/spack/build_systems/editable_makefile.py | 77 ---------------------- lib/spack/spack/build_systems/makefile.py | 77 ++++++++++++++++++++++ var/spack/repos/builtin/packages/astyle/package.py | 2 +- 4 files changed, 80 insertions(+), 80 deletions(-) delete mode 100644 lib/spack/spack/build_systems/editable_makefile.py create mode 100644 lib/spack/spack/build_systems/makefile.py (limited to 'var') diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index 918e17323b..67c64276ee 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -189,14 +189,14 @@ sys_type = None __all__ = ['Package', 'CMakePackage', 'AutotoolsPackage', - 'EditableMakefile', + 'MakefilePackage', 'Version', 'when', 'ver', 'alldeps', 'nolink'] from spack.package import Package, ExtensionConflictError -from spack.build_systems.editable_makefile import EditableMakefile +from spack.build_systems.makefile import MakefilePackage from spack.build_systems.autotools import AutotoolsPackage from spack.build_systems.cmake import CMakePackage from spack.version import Version, ver diff --git a/lib/spack/spack/build_systems/editable_makefile.py b/lib/spack/spack/build_systems/editable_makefile.py deleted file mode 100644 index e3adea8363..0000000000 --- a/lib/spack/spack/build_systems/editable_makefile.py +++ /dev/null @@ -1,77 +0,0 @@ -############################################################################## -# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. -# Produced at the Lawrence Livermore National Laboratory. -# -# This file is part of Spack. -# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. -# LLNL-CODE-647188 -# -# For details, see https://github.com/llnl/spack -# Please also see the LICENSE file for our notice and the LGPL. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License (as -# published by the Free Software Foundation) version 2.1, February 1999. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and -# conditions of the GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -############################################################################## - -import inspect - -from llnl.util.filesystem import working_dir -from spack.package import PackageBase - - -class EditableMakefile(PackageBase): - """Specialized class for packages that are built using editable Makefiles - - This class provides three phases that can be overridden: - - edit - - build - - install - - It is necessary to override the 'edit' phase, while 'build' and 'install' - have sensible defaults. - """ - phases = ['edit', 'build', 'install'] - # To be used in UI queries that require to know which - # build-system class we are using - build_system_class = 'EditableMakefile' - - def build_directory(self): - """Directory where the main Makefile is located""" - return self.stage.source_path - - def build_args(self): - """List of arguments that should be passed to make at build time""" - return [] - - def install_args(self): - """List of arguments that should be passed to make at install time""" - return [] - - def edit(self, spec, prefix): - """This phase cannot be defaulted for obvious reasons...""" - raise NotImplementedError('\'edit\' function not implemented') - - def build(self, spec, prefix): - """Default build phase : call make passing build_args""" - args = self.build_args() - with working_dir(self.build_directory()): - inspect.getmodule(self).make(*args) - - def install(self, spec, prefix): - """Default install phase : call make passing install_args""" - args = self.install_args() + ['install'] - with working_dir(self.build_directory()): - inspect.getmodule(self).make(*args) - - # Check that self.prefix is there after installation - PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) diff --git a/lib/spack/spack/build_systems/makefile.py b/lib/spack/spack/build_systems/makefile.py new file mode 100644 index 0000000000..dcddadeedc --- /dev/null +++ b/lib/spack/spack/build_systems/makefile.py @@ -0,0 +1,77 @@ +############################################################################## +# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC. +# Produced at the Lawrence Livermore National Laboratory. +# +# This file is part of Spack. +# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved. +# LLNL-CODE-647188 +# +# For details, see https://github.com/llnl/spack +# Please also see the LICENSE file for our notice and the LGPL. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License (as +# published by the Free Software Foundation) version 2.1, February 1999. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and +# conditions of the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +############################################################################## + +import inspect + +from llnl.util.filesystem import working_dir +from spack.package import PackageBase + + +class MakefilePackage(PackageBase): + """Specialized class for packages that are built using editable Makefiles + + This class provides three phases that can be overridden: + - edit + - build + - install + + It is necessary to override the 'edit' phase, while 'build' and 'install' + have sensible defaults. + """ + phases = ['edit', 'build', 'install'] + # To be used in UI queries that require to know which + # build-system class we are using + build_system_class = 'MakefilePackage' + + def build_directory(self): + """Directory where the main Makefile is located""" + return self.stage.source_path + + def build_args(self): + """List of arguments that should be passed to make at build time""" + return [] + + def install_args(self): + """List of arguments that should be passed to make at install time""" + return [] + + def edit(self, spec, prefix): + """This phase cannot be defaulted for obvious reasons...""" + raise NotImplementedError('\'edit\' function not implemented') + + def build(self, spec, prefix): + """Default build phase : call make passing build_args""" + args = self.build_args() + with working_dir(self.build_directory()): + inspect.getmodule(self).make(*args) + + def install(self, spec, prefix): + """Default install phase : call make passing install_args""" + args = self.install_args() + ['install'] + with working_dir(self.build_directory()): + inspect.getmodule(self).make(*args) + + # Check that self.prefix is there after installation + PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) diff --git a/var/spack/repos/builtin/packages/astyle/package.py b/var/spack/repos/builtin/packages/astyle/package.py index fdd9c2111e..31e1efb591 100644 --- a/var/spack/repos/builtin/packages/astyle/package.py +++ b/var/spack/repos/builtin/packages/astyle/package.py @@ -25,7 +25,7 @@ from spack import * -class Astyle(EditableMakefile): +class Astyle(MakefilePackage): """A Free, Fast, and Small Automatic Formatter for C, C++, C++/CLI, Objective-C, C#, and Java Source Code. """ -- cgit v1.2.3-60-g2f50