package : added EditableMakefile
Modifications : - added EditableMakefile to PackageBase subclasses - astyle modified as an example - preliminary hook to stop at a certain phase of install
This commit is contained in:
		| @@ -179,11 +179,12 @@ | |||||||
| __all__ = ['Package', | __all__ = ['Package', | ||||||
|            'CMakePackage', |            'CMakePackage', | ||||||
|            'AutotoolsPackage', |            'AutotoolsPackage', | ||||||
|  |            'EditableMakefile', | ||||||
|            'Version', |            'Version', | ||||||
|            'when', |            'when', | ||||||
|            'ver'] |            'ver'] | ||||||
| from spack.package import Package, ExtensionConflictError | 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.version import Version, ver | ||||||
| from spack.multimethod import when | from spack.multimethod import when | ||||||
|  |  | ||||||
|   | |||||||
| @@ -56,6 +56,9 @@ def setup_parser(subparser): | |||||||
|     subparser.add_argument( |     subparser.add_argument( | ||||||
|         '--dirty', action='store_true', dest='dirty', |         '--dirty', action='store_true', dest='dirty', | ||||||
|         help="Install a package *without* cleaning the environment.") |         help="Install a package *without* cleaning the environment.") | ||||||
|  |     subparser.add_argument( | ||||||
|  |         '--stop-at', help="Stop at a particular phase of installation" | ||||||
|  |     ) | ||||||
|     subparser.add_argument( |     subparser.add_argument( | ||||||
|         'packages', nargs=argparse.REMAINDER, help="specs of packages to install") |         'packages', nargs=argparse.REMAINDER, help="specs of packages to install") | ||||||
|     subparser.add_argument( |     subparser.add_argument( | ||||||
| @@ -88,4 +91,6 @@ def install(parser, args): | |||||||
|                 verbose=args.verbose, |                 verbose=args.verbose, | ||||||
|                 fake=args.fake, |                 fake=args.fake, | ||||||
|                 dirty=args.dirty, |                 dirty=args.dirty, | ||||||
|                 explicit=True) |                 explicit=True, | ||||||
|  |                 stop_at=args.stop_at | ||||||
|  |             ) | ||||||
|   | |||||||
| @@ -104,6 +104,10 @@ def phase_wrapper(spec, prefix): | |||||||
|             # and give them the chance to fail |             # and give them the chance to fail | ||||||
|             for check in self.sanity_checks: |             for check in self.sanity_checks: | ||||||
|                 check(instance) |                 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 |         return phase_wrapper | ||||||
|  |  | ||||||
| @@ -123,10 +127,10 @@ def __new__(meta, name, bases, attr_dict): | |||||||
|         # Check if phases is in attr dict, then set |         # Check if phases is in attr dict, then set | ||||||
|         # install phases wrappers |         # install phases wrappers | ||||||
|         if 'phases' in attr_dict: |         if 'phases' in attr_dict: | ||||||
|             phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']] |             _InstallPhase_phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']] | ||||||
|             for phase_name, callback_name in zip(phases, attr_dict['phases']): |             for phase_name, callback_name in zip(_InstallPhase_phases, attr_dict['phases']): | ||||||
|                 attr_dict[phase_name] = InstallPhase(callback_name) |                 attr_dict[phase_name] = InstallPhase(callback_name) | ||||||
|             attr_dict['phases'] = phases |             attr_dict['_InstallPhase_phases'] = _InstallPhase_phases | ||||||
|  |  | ||||||
|         def _append_checks(check_name): |         def _append_checks(check_name): | ||||||
|             # Name of the attribute I am going to check it exists |             # Name of the attribute I am going to check it exists | ||||||
| @@ -956,7 +960,8 @@ def namespace(self): | |||||||
|         return namespace |         return namespace | ||||||
|  |  | ||||||
|     def do_fake_install(self): |     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) |         mkdirp(self.prefix.bin) | ||||||
|         touch(join_path(self.prefix.bin, 'fake')) |         touch(join_path(self.prefix.bin, 'fake')) | ||||||
|         mkdirp(self.prefix.lib) |         mkdirp(self.prefix.lib) | ||||||
| @@ -990,7 +995,7 @@ def do_install(self, | |||||||
|                    fake=False, |                    fake=False, | ||||||
|                    explicit=False, |                    explicit=False, | ||||||
|                    dirty=False, |                    dirty=False, | ||||||
|                    allowed_phases=None): |                    **kwargs): | ||||||
|         """Called by commands to install a package and its dependencies. |         """Called by commands to install a package and its dependencies. | ||||||
|  |  | ||||||
|         Package implementations should override install() to describe |         Package implementations should override install() to describe | ||||||
| @@ -1010,9 +1015,13 @@ def do_install(self, | |||||||
|         make_jobs   -- Number of make jobs to use for install. Default is ncpus |         make_jobs   -- Number of make jobs to use for install. Default is ncpus | ||||||
|         run_tests   -- Runn tests within the package's install() |         run_tests   -- Runn tests within the package's install() | ||||||
|         """ |         """ | ||||||
|         # FIXME : we need a better semantic |         #if allowed_phases is None: | ||||||
|         if allowed_phases is None: |         #    allowed_phases = self.phases | ||||||
|             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: |         if not self.spec.concrete: | ||||||
|             raise ValueError("Can only install concrete packages.") |             raise ValueError("Can only install concrete packages.") | ||||||
| @@ -1097,9 +1106,10 @@ def build_process(): | |||||||
|                                         True): |                                         True): | ||||||
|                             dump_environment(env_path) |                             dump_environment(env_path) | ||||||
|                             try: |                             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 |                                     # TODO : Log to screen the various phases | ||||||
|                                     getattr(self, phase)(self.spec, self.prefix) |                                     getattr(self, phase)(self.spec, self.prefix) | ||||||
|  |                                 self.log() | ||||||
|                             except AttributeError as e: |                             except AttributeError as e: | ||||||
|                                 # FIXME : improve error messages |                                 # FIXME : improve error messages | ||||||
|                                 raise ProcessError(e.message, long_message='') |                                 raise ProcessError(e.message, long_message='') | ||||||
| @@ -1126,9 +1136,10 @@ def build_process(): | |||||||
|             # Create the install prefix and fork the build process. |             # Create the install prefix and fork the build process. | ||||||
|             spack.install_layout.create_install_directory(self.spec) |             spack.install_layout.create_install_directory(self.spec) | ||||||
|         except directory_layout.InstallDirectoryAlreadyExistsError: |         except directory_layout.InstallDirectoryAlreadyExistsError: | ||||||
|  |             # FIXME : refactor this as a prerequisites to configure | ||||||
|             if 'install' in self.phases: |             if 'install' in self.phases: | ||||||
|                 # Abort install if install directory exists. |                 # 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.") |                 tty.warn("Keeping existing install prefix in place.") | ||||||
|                 raise |                 raise | ||||||
|             else: |             else: | ||||||
| @@ -1154,7 +1165,7 @@ def build_process(): | |||||||
|         # the database, so that we don't need to re-read from file. |         # the database, so that we don't need to re-read from file. | ||||||
|         spack.installed_db.add(self.spec, self.prefix, explicit=explicit) |         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 |         # Copy provenance into the install directory on success | ||||||
|         log_install_path = spack.install_layout.build_log_path( |         log_install_path = spack.install_layout.build_log_path( | ||||||
|             self.spec) |             self.spec) | ||||||
| @@ -1533,14 +1544,41 @@ def rpath_args(self): | |||||||
|  |  | ||||||
|  |  | ||||||
| class Package(PackageBase): | class Package(PackageBase): | ||||||
|     phases = ['install', 'log'] |     phases = ['install'] | ||||||
|     # This will be used as a registration decorator in user |     # This will be used as a registration decorator in user | ||||||
|     # packages, if need be |     # packages, if need be | ||||||
|     PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix) |     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): | class AutotoolsPackage(PackageBase): | ||||||
|     phases = ['autoreconf', 'configure', 'build', 'install', 'log'] |     phases = ['autoreconf', 'configure', 'build', 'install'] | ||||||
|  |  | ||||||
|     def autoreconf(self, spec, prefix): |     def autoreconf(self, spec, prefix): | ||||||
|         """Not needed usually, configure should be already there""" |         """Not needed usually, configure should be already there""" | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ | |||||||
| from spack import * | from spack import * | ||||||
|  |  | ||||||
|  |  | ||||||
| class Astyle(Package): | class Astyle(EditableMakefile): | ||||||
|     """ |     """ | ||||||
|     A Free, Fast, and Small Automatic Formatter for C, C++, C++/CLI, |     A Free, Fast, and Small Automatic Formatter for C, C++, C++/CLI, | ||||||
|     Objective-C, C#, and Java Source Code. |     Objective-C, C#, and Java Source Code. | ||||||
| @@ -35,18 +35,14 @@ class Astyle(Package): | |||||||
|  |  | ||||||
|     version('2.04', '30b1193a758b0909d06e7ee8dd9627f6') |     version('2.04', '30b1193a758b0909d06e7ee8dd9627f6') | ||||||
|  |  | ||||||
|     def install(self, spec, prefix): |     parallel = False | ||||||
|  |  | ||||||
|         with working_dir('src'): |     def wdir(self): | ||||||
|             # we need to edit the makefile in place to set compiler: |         return join_path(self.stage.source_path, 'build', self.compiler.name) | ||||||
|             make_file = join_path(self.stage.source_path, |  | ||||||
|                                   'build', 'gcc', 'Makefile') |  | ||||||
|             filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, make_file) |  | ||||||
|  |  | ||||||
|             make('-f', |     def edit(self, spec, prefix): | ||||||
|                  make_file, |         makefile = join_path(self.wdir(), 'Makefile') | ||||||
|                  parallel=False) |         filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, makefile) | ||||||
|  |  | ||||||
|             mkdirp(self.prefix.bin) |     def install_args(self): | ||||||
|             install(join_path(self.stage.source_path, 'src', 'bin', 'astyle'), |         return ['prefix={0}'.format(prefix)] | ||||||
|                     self.prefix.bin) |  | ||||||
|   | |||||||
| @@ -24,16 +24,10 @@ | |||||||
| ############################################################################## | ############################################################################## | ||||||
| from spack import * | from spack import * | ||||||
|  |  | ||||||
| class Blitz(Package): |  | ||||||
|  | class Blitz(AutotoolsPackage): | ||||||
|     """N-dimensional arrays for C++""" |     """N-dimensional arrays for C++""" | ||||||
|     homepage = "http://github.com/blitzpp/blitz" |     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') |     version('1.0.0', '9f040b9827fe22228a892603671a77af') | ||||||
|  |  | ||||||
|     # No dependencies |  | ||||||
|  |  | ||||||
|     def install(self, spec, prefix): |  | ||||||
|         configure('--prefix=%s' % prefix) |  | ||||||
|         make() |  | ||||||
|         make("install") |  | ||||||
|   | |||||||
| @@ -24,7 +24,8 @@ | |||||||
| ############################################################################## | ############################################################################## | ||||||
| from spack import * | from spack import * | ||||||
|  |  | ||||||
| class Gmp(Package): |  | ||||||
|  | class Gmp(AutotoolsPackage): | ||||||
|     """GMP is a free library for arbitrary precision arithmetic, |     """GMP is a free library for arbitrary precision arithmetic, | ||||||
|        operating on signed integers, rational numbers, and |        operating on signed integers, rational numbers, and | ||||||
|        floating-point numbers.""" |        floating-point numbers.""" | ||||||
| @@ -36,8 +37,3 @@ class Gmp(Package): | |||||||
|     version('6.0.0' , '6ef5869ae735db9995619135bd856b84') |     version('6.0.0' , '6ef5869ae735db9995619135bd856b84') | ||||||
|  |  | ||||||
|     depends_on("m4") |     depends_on("m4") | ||||||
|  |  | ||||||
|     def install(self, spec, prefix): |  | ||||||
|         configure("--prefix=%s" % prefix) |  | ||||||
|         make() |  | ||||||
|         make("install") |  | ||||||
|   | |||||||
| @@ -66,8 +66,8 @@ def autoreconf(self, spec, prefix): | |||||||
|         autogen = Executable('./autogen.sh') |         autogen = Executable('./autogen.sh') | ||||||
|         autogen() |         autogen() | ||||||
|  |  | ||||||
|     def config_args(self): |     def configure_args(self): | ||||||
|         return ['--prefix=%s' % prefix, |         return ['--prefix=%s' % self.prefix, | ||||||
|                 '--enable-mpi' if '+mpi' in spec else '--disable-mpi', |                 '--enable-mpi' if '+mpi' in self.spec else '--disable-mpi', | ||||||
|                 '--with-metis={0}'.format(self.spec['metis'].prefix), |                 '--with-metis={0}'.format(self.spec['metis'].prefix), | ||||||
|                 '--enable-optimization'] |                 '--enable-optimization'] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 alalazo
					alalazo