From 6cf6eac3de05f54916c184a1e662b619a49d728e Mon Sep 17 00:00:00 2001 From: Todd Gamblin Date: Sat, 23 Nov 2013 15:18:43 -0800 Subject: [PATCH] Move concretization into its own class. Allows easy overriding of a single policy. --- lib/spack/spack/concretize.py | 108 +++++++++++--------- lib/spack/spack/globals.py | 8 ++ lib/spack/spack/relations.py | 2 +- lib/spack/spack/spec.py | 9 +- lib/spack/spack/test/mock_packages/mpich.py | 2 + 5 files changed, 73 insertions(+), 56 deletions(-) diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py index 6acae39039..2d33a544e0 100644 --- a/lib/spack/spack/concretize.py +++ b/lib/spack/spack/concretize.py @@ -15,66 +15,72 @@ from spack.spec import * -def concretize_version(spec): - """If the spec is already concrete, return. Otherwise take - the most recent available version, and default to the package's - version if there are no avaialble versions. +class DefaultConcretizer(object): + """This class doesn't have any state, it just provides some methods for + concretization. You can subclass it to override just some of the + default concretization strategies, or you can override all of them. """ - # return if already concrete. - if spec.versions.concrete: - return - pkg = spec.package + def concretize_version(self, spec): + """If the spec is already concrete, return. Otherwise take + the most recent available version, and default to the package's + version if there are no avaialble versions. + """ + # return if already concrete. + if spec.versions.concrete: + return - # If there are known avaialble versions, return the most recent - available_versions = pkg.available_versions - if available_versions: - spec.versions = ver([available_versions[-1]]) - else: - spec.versions = ver([pkg.version]) + pkg = spec.package + + # If there are known avaialble versions, return the most recent + available_versions = pkg.available_versions + if available_versions: + spec.versions = ver([available_versions[-1]]) + else: + spec.versions = ver([pkg.version]) -def concretize_architecture(spec): - """If the spec already had an architecture, return. Otherwise if - the root of the DAG has an architecture, then use that. - Otherwise take the system's default architecture. + def concretize_architecture(self, spec): + """If the spec already had an architecture, return. Otherwise if + the root of the DAG has an architecture, then use that. + Otherwise take the system's default architecture. - Intuition: Architectures won't be set a lot, and generally you - want the host system's architecture. When architectures are - mised in a spec, it is likely because the tool requries a - cross-compiled component, e.g. for tools that run on BlueGene - or Cray machines. These constraints will likely come directly - from packages, so require the user to be explicit if they want - to mess with the architecture, and revert to the default when - they're not explicit. - """ - if spec.architecture is not None: - return + Intuition: Architectures won't be set a lot, and generally you + want the host system's architecture. When architectures are + mised in a spec, it is likely because the tool requries a + cross-compiled component, e.g. for tools that run on BlueGene + or Cray machines. These constraints will likely come directly + from packages, so require the user to be explicit if they want + to mess with the architecture, and revert to the default when + they're not explicit. + """ + if spec.architecture is not None: + return - if spec.root.architecture: - spec.architecture = spec.root.architecture - else: - spec.architecture = spack.arch.sys_type() + if spec.root.architecture: + spec.architecture = spec.root.architecture + else: + spec.architecture = spack.arch.sys_type() -def concretize_compiler(spec): - """Currently just sets the compiler to gcc or throws an exception - if the compiler is set to something else. + def concretize_compiler(self, spec): + """Currently just sets the compiler to gcc or throws an exception + if the compiler is set to something else. - TODO: implement below description. + TODO: implement below description. - If the spec already has a compiler, we're done. If not, then - take the compiler used for the nearest ancestor with a concrete - compiler, or use the system default if there is no ancestor - with a compiler. + If the spec already has a compiler, we're done. If not, then + take the compiler used for the nearest ancestor with a concrete + compiler, or use the system default if there is no ancestor + with a compiler. - Intuition: Use the system default if no package that depends on - this one has a strict compiler requirement. Otherwise, try to - build with the compiler that will be used by libraries that - link to this one, to maximize compatibility. - """ - if spec.compiler and spec.compiler.concrete: - if spec.compiler != spack.compilers.default_compiler(): - raise spack.spec.UnknownCompilerError(str(spec.compiler)) - else: - spec.compiler = spack.compilers.default_compiler() + Intuition: Use the system default if no package that depends on + this one has a strict compiler requirement. Otherwise, try to + build with the compiler that will be used by libraries that + link to this one, to maximize compatibility. + """ + if spec.compiler and spec.compiler.concrete: + if spec.compiler != spack.compilers.default_compiler(): + raise spack.spec.UnknownCompilerError(str(spec.compiler)) + else: + spec.compiler = spack.compilers.default_compiler() diff --git a/lib/spack/spack/globals.py b/lib/spack/spack/globals.py index 3b2359e21d..7b746a0734 100644 --- a/lib/spack/spack/globals.py +++ b/lib/spack/spack/globals.py @@ -5,6 +5,7 @@ from spack.util.filesystem import * from spack.util.executable import * from spack.directory_layout import DefaultDirectoryLayout +from spack.concretize import DefaultConcretizer # This lives in $prefix/lib/spac/spack/__file__ prefix = ancestor(__file__, 4) @@ -31,6 +32,13 @@ # install_layout = DefaultDirectoryLayout(install_path) +# +# This controls how things are concretized in spack. +# Replace it with a subclass if you want different +# policies. +# +concretizer = DefaultConcretizer() + # Version information spack_version = Version("0.5") diff --git a/lib/spack/spack/relations.py b/lib/spack/spack/relations.py index f936f6e364..0d1983257b 100644 --- a/lib/spack/spack/relations.py +++ b/lib/spack/spack/relations.py @@ -81,4 +81,4 @@ def provides(*args): # Get the enclosing package's scope and add deps to it. provided = _caller_locals().setdefault("provided", []) for name in args: - provides.append(name) + provided.append(name) diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 73542b9179..d14957c23b 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -67,7 +67,6 @@ import tty import spack.parse import spack.error -import spack.concretize import spack.compilers import spack.compilers.gcc import spack.packages as packages @@ -330,6 +329,8 @@ def virtual(self): """Right now, a spec is virtual if no package exists with its name. TODO: revisit this -- might need to use a separate namespace and be more explicit about this. + Possible idea: just use conventin and make virtual deps all + caps, e.g., MPI vs mpi. """ return not packages.exists(self.name) @@ -400,9 +401,9 @@ def _concretize_helper(self, presets): if self.name in presets: self.constrain(presets[self.name]) else: - spack.concretize.concretize_architecture(self) - spack.concretize.concretize_compiler(self) - spack.concretize.concretize_version(self) + spack.concretizer.concretize_architecture(self) + spack.concretizer.concretize_compiler(self) + spack.concretizer.concretize_version(self) presets[self.name] = self diff --git a/lib/spack/spack/test/mock_packages/mpich.py b/lib/spack/spack/test/mock_packages/mpich.py index 85c4c2d939..2972c34df0 100644 --- a/lib/spack/spack/test/mock_packages/mpich.py +++ b/lib/spack/spack/test/mock_packages/mpich.py @@ -10,6 +10,8 @@ class Mpich(Package): versions = '1.0.3, 1.3.2p1, 1.4.1p1, 3.0.4, 3.1b1' + provides('mpi') + def install(self, prefix): configure("--prefix=%s" % prefix) make()