concretizer: add basic semantics for compilers

- This handles setting the compiler and falling back to a default
  compiler, as well as providing default values for compilers/compiler
  versions.

- Versions still aren't quite right -- you can't properly override
  versions on compiler specs.
This commit is contained in:
Todd Gamblin 2019-08-11 18:01:16 -07:00
parent f7dce19754
commit 60cf3fdb34
3 changed files with 112 additions and 7 deletions

View file

@ -20,6 +20,7 @@
import spack.cmd import spack.cmd
import spack.spec import spack.spec
import spack.package import spack.package
import spack.package_prefs
import spack.repo import spack.repo
from spack.util.executable import which from spack.util.executable import which
from spack.version import ver from spack.version import ver
@ -187,6 +188,45 @@ def spec_versions(self, spec):
self._or(fn.version(spec.name, v) for v in possible), self._or(fn.version(spec.name, v) for v in possible),
fn.node(spec.name)) fn.node(spec.name))
def compiler_defaults(self):
"""Facts about available compilers."""
compilers = spack.compilers.all_compiler_specs()
compiler_versions = collections.defaultdict(lambda: set())
for compiler in compilers:
compiler_versions[compiler.name].add(compiler.version)
for compiler in compiler_versions:
self.fact(fn.compiler(compiler))
self.rule(
self._or(
fn.compiler_version(compiler, v)
for v in sorted(compiler_versions[compiler])),
fn.compiler(compiler))
def package_compiler_defaults(self, pkg):
"""Add facts about the default compiler.
TODO: integrate full set of preferences into the solve (this only
TODO: considers the top preference)
"""
# get list of all compilers
compiler_list = spack.compilers.all_compiler_specs()
if not compiler_list:
raise spack.compilers.NoCompilersError()
# prefer package preferences, then latest version
ppk = spack.package_prefs.PackagePrefs(pkg.name, 'compiler')
compiler_list = sorted(
compiler_list, key=lambda x: (x.name, x.version), reverse=True)
compiler_list = sorted(compiler_list, key=ppk)
# write out default rules for this package's compilers
default_compiler = compiler_list[0]
self.fact(fn.node_compiler_default(pkg.name, default_compiler.name))
self.fact(fn.node_compiler_default_version(
pkg.name, default_compiler.name, default_compiler.version))
def pkg_rules(self, pkg): def pkg_rules(self, pkg):
pkg = packagize(pkg) pkg = packagize(pkg)
@ -215,6 +255,9 @@ def pkg_rules(self, pkg):
fn.node(pkg.name)) fn.node(pkg.name))
self.out.write('\n') self.out.write('\n')
# default compilers for this package
self.package_compiler_defaults(pkg)
# dependencies # dependencies
for name, conditions in pkg.dependencies.items(): for name, conditions in pkg.dependencies.items():
for cond, dep in conditions.items(): for cond, dep in conditions.items():
@ -239,14 +282,28 @@ def spec_rules(self, spec):
for vname, variant in spec.variants.items(): for vname, variant in spec.variants.items():
self.fact(fn.variant_set(spec.name, vname, variant.value)) self.fact(fn.variant_set(spec.name, vname, variant.value))
# compiler and compiler version
if spec.compiler:
self.fact(fn.node_compiler_set(spec.name, spec.compiler.name))
if spec.compiler.concrete:
self.fact(fn.node_compiler_version_set(
spec.name, spec.compiler.name, spec.compiler.version))
# TODO # TODO
# dependencies # dependencies
# compiler
# external_path # external_path
# external_module # external_module
# compiler_flags # compiler_flags
# namespace # namespace
def arch_defaults(self):
"""Add facts about the default architecture for a package."""
self.h2('Default architecture')
default_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
self.fact(fn.arch_platform_default(default_arch.platform))
self.fact(fn.arch_os_default(default_arch.os))
self.fact(fn.arch_target_default(default_arch.target))
def generate_asp_program(self, specs): def generate_asp_program(self, specs):
"""Write an ASP program for specs. """Write an ASP program for specs.
@ -265,12 +322,8 @@ def generate_asp_program(self, specs):
self.out.write(concretize_lp.decode("utf-8")) self.out.write(concretize_lp.decode("utf-8"))
self.h1('General Constraints') self.h1('General Constraints')
self.compiler_defaults()
self.h2('Default architecture') self.arch_defaults()
default_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
self.fact(fn.arch_platform_default(default_arch.platform))
self.fact(fn.arch_os_default(default_arch.os))
self.fact(fn.arch_target_default(default_arch.target))
self.h1('Package Constraints') self.h1('Package Constraints')
for pkg in pkgs: for pkg in pkgs:
@ -321,6 +374,13 @@ def variant_value(self, pkg, name, value):
def version(self, pkg, version): def version(self, pkg, version):
self._specs[pkg].versions = ver([version]) self._specs[pkg].versions = ver([version])
def node_compiler(self, pkg, compiler):
self._specs[pkg].compiler = spack.spec.CompilerSpec(compiler)
def node_compiler_version(self, pkg, compiler, version):
self._specs[pkg].compiler.versions = spack.version.VersionList(
[version])
def depends_on(self, pkg, dep): def depends_on(self, pkg, dep):
self._specs[pkg]._add_dependency( self._specs[pkg]._add_dependency(
self._specs[dep], ('link', 'run')) self._specs[dep], ('link', 'run'))

View file

@ -6,6 +6,9 @@
{ arch_platform(P, A) : arch_platform(P, A) } = 1 :- node(P). { arch_platform(P, A) : arch_platform(P, A) } = 1 :- node(P).
{ arch_os(P, A) : arch_os(P, A) } = 1 :- node(P). { arch_os(P, A) : arch_os(P, A) } = 1 :- node(P).
{ arch_target(P, T) : arch_target(P, T) } = 1 :- node(P). { arch_target(P, T) : arch_target(P, T) } = 1 :- node(P).
{ node_compiler(P, C) : node_compiler(P, C) } = 1 :- node(P).
{ node_compiler_version(P, C, V) :
node_compiler_version(P, C, V) } = 1 :- node(P).
% one variant value for single-valued variants. % one variant value for single-valued variants.
{ variant_value(P, V, X) : variant_value(P, V, X) } = 1 { variant_value(P, V, X) : variant_value(P, V, X) } = 1
@ -65,3 +68,43 @@ arch_target(P, A) :- node(P), not arch_target_set(P), arch_target_default(A).
arch_platform_set(D, A) :- node(D), depends_on(P, D), arch_platform_set(P, A). arch_platform_set(D, A) :- node(D), depends_on(P, D), arch_platform_set(P, A).
arch_os_set(D, A) :- node(D), depends_on(P, D), arch_os_set(P, A). arch_os_set(D, A) :- node(D), depends_on(P, D), arch_os_set(P, A).
arch_target_set(D, A) :- node(D), depends_on(P, D), arch_target_set(P, A). arch_target_set(D, A) :- node(D), depends_on(P, D), arch_target_set(P, A).
%-----------------------------------------------------------------------------
% Compiler semantics
%-----------------------------------------------------------------------------
% compiler fields are set if set to anything
node_compiler_set(P) :- node_compiler_set(P, _).
node_compiler_version_set(P, C) :- node_compiler_version_set(P, C, _).
% avoid warnings: these are set by generated code and it's ok if they're not
#defined node_compiler_set/2.
#defined node_compiler_version_set/3.
% if compiler value of node is set to anything, it's the value.
node_compiler(P, C)
:- node(P), compiler(C), node_compiler_set(P, C).
node_compiler_version(P, C, V)
:- node(P), compiler(C), compiler_version(C, V), node_compiler(P, C),
node_compiler_version_set(P, C, V).
% node compiler versions can only be from the available compiler versions
node_compiler_version(P, C, V)
:- node(P), compiler(C), node_compiler(P, C),
compiler_version(C, V).
% if no compiler is set, fall back to default.
node_compiler(P, C)
:- node(P), compiler(C), not node_compiler_set(P),
node_compiler_default(P, C).
node_compiler_version(P, C, V)
:- node(P), compiler(C), compiler_version(C, V),
not node_compiler_version_set(P, C, V),
node_compiler_default_version(P, C, V).
% propagate compiler, compiler version to dependencies
node_compiler_set(D, C)
:- node(D), compiler(C), depends_on(P, D), node_compiler_set(P, C).
node_compiler_version_set(D, C, V)
:- node(D), compiler(C), depends_on(P, D), node_compiler(D, C),
node_compiler_version_set(P, C, V).

View file

@ -10,3 +10,5 @@
#show arch_platform/2. #show arch_platform/2.
#show arch_os/2. #show arch_os/2.
#show arch_target/2. #show arch_target/2.
#show node_compiler/2.
#show node_compiler_version/3.