concretizer: added logic for preferred variants

If preferred variants are present, they'll
set the default value of a variant. Otherwise
the default value is what is encoded
in package.py
This commit is contained in:
Massimiliano Culpo 2020-10-12 19:13:20 +02:00 committed by Todd Gamblin
parent 81c7cf45e1
commit d4b83daa48
4 changed files with 63 additions and 25 deletions

View File

@ -819,12 +819,16 @@ def pkg_rules(self, pkg):
if single_value:
self.gen.fact(fn.variant_single_value(pkg.name, name))
self.gen.fact(
fn.variant_default_value(pkg.name, name, variant.default))
fn.variant_default_value_from_package_py(
pkg.name, name, variant.default)
)
else:
defaults = variant.default.split(',')
for val in sorted(defaults):
self.gen.fact(
fn.variant_default_value(pkg.name, name, val))
fn.variant_default_value_from_package_py(
pkg.name, name, val)
)
values = variant.values
if values is None:
@ -947,16 +951,16 @@ def external_packages(self):
self.gen.fact(fn.external_only(pkg_name))
# Read a list of all the specs for this package
externals = data['externals']
externals = data.get('externals', [])
external_specs = [spack.spec.Spec(x['spec']) for x in externals]
# Compute versions with appropriate weights
external_versions = [
(x.version, id) for id, x in enumerate(external_specs)
(x.version, idx) for idx, x in enumerate(external_specs)
]
external_versions = [
(v, -(w + 1), id)
for w, (v, id) in enumerate(sorted(external_versions))
(v, -(w + 1), idx)
for w, (v, idx) in enumerate(sorted(external_versions))
]
for version, weight, id in external_versions:
self.gen.fact(fn.external_version_declared(
@ -993,6 +997,26 @@ def external_packages(self):
self.gen.out.write(external_rule)
self.gen.control.add("base", [], external_rule)
def concretization_preferences(self, pkg_name):
"""Facts on concretization preferences, as read from packages.yaml"""
preferences = spack.package_prefs.PackagePrefs
preferred_variants = preferences.preferred_variants(pkg_name)
if not preferred_variants:
return
self.gen.h2('Concretization preferences {0}'.format(pkg_name))
for variant_name in sorted(preferred_variants):
variant = preferred_variants[variant_name]
values = variant.value
if not isinstance(values, tuple):
values = (values,)
for value in values:
self.gen.fact(fn.variant_default_value_from_packages_yaml(
pkg_name, variant.name, value
))
def flag_defaults(self):
self.gen.h2("Compiler flag defaults")
@ -1370,6 +1394,7 @@ def setup(self, driver, specs):
for pkg in sorted(pkgs):
self.gen.h2('Package: %s' % pkg)
self.pkg_rules(pkg)
self.concretization_preferences(pkg)
self.gen.h1('Spec Constraints')
for spec in sorted(specs):

View File

@ -163,7 +163,16 @@ variant_not_default(Package, Variant, Value, 0)
variant_default_value(Package, Variant, Value),
node(Package).
% suppress wranings about this atom being unset. It's only set if some
% The default value for a variant in a package is what is written
% in the package.py file, unless some preference is set in packages.yaml
variant_default_value(Package, Variant, Value)
:- variant_default_value_from_package_py(Package, Variant, Value),
not variant_default_value_from_packages_yaml(Package, Variant, _).
variant_default_value(Package, Variant, Value)
:- variant_default_value_from_packages_yaml(Package, Variant, Value).
% suppress warnings about this atom being unset. It's only set if some
% spec or some package sets it, and without this, clingo will give
% warnings like 'info: atom does not occur in any rule head'.
#defined variant/2.
@ -171,6 +180,7 @@ variant_not_default(Package, Variant, Value, 0)
#defined variant_single_value/2.
#defined variant_default_value/3.
#defined variant_possible_value/3.
#defined variant_default_value_from_packages_yaml/3.
%-----------------------------------------------------------------------------
% Platform semantics

View File

@ -70,19 +70,22 @@ def assert_variant_values(spec, **variants):
@pytest.mark.usefixtures('concretize_scope', 'mock_packages')
class TestConcretizePreferences(object):
def test_preferred_variants(self):
"""Test preferred variants are applied correctly
"""
update_packages('mpileaks', 'variants', '~debug~opt+shared+static')
assert_variant_values(
'mpileaks', debug=False, opt=False, shared=True, static=True
)
update_packages(
'mpileaks', 'variants', ['+debug', '+opt', '~shared', '-static']
)
assert_variant_values(
'mpileaks', debug=True, opt=True, shared=False, static=False
)
@pytest.mark.parametrize('package_name,variant_value,expected_results', [
('mpileaks', '~debug~opt+shared+static',
{'debug': False, 'opt': False, 'shared': True, 'static': True}),
# Check that using a list of variants instead of a single string works
('mpileaks', ['~debug', '~opt', '+shared', '+static'],
{'debug': False, 'opt': False, 'shared': True, 'static': True}),
# Use different values for the variants and check them again
('mpileaks', ['+debug', '+opt', '~shared', '-static'],
{'debug': True, 'opt': True, 'shared': False, 'static': False}),
])
def test_preferred_variants(
self, package_name, variant_value, expected_results
):
"""Test preferred variants are applied correctly"""
update_packages(package_name, 'variants', variant_value)
assert_variant_values(package_name, **expected_results)
def test_preferred_variants_from_wildcard(self):
"""

View File

@ -42,16 +42,16 @@ class Plasma(CMakePackage):
depends_on("blas")
depends_on("lapack")
conflicts("atlas") # does not have LAPACKE interface
conflicts("^atlas") # does not have LAPACKE interface
# missing LAPACKE features and/or CBLAS headers
conflicts("netlib-lapack@:3.5.999")
conflicts("^netlib-lapack@:3.5.999")
# clashes with OpenBLAS declarations and has a problem compiling on its own
conflicts("cblas")
conflicts("^cblas")
conflicts("openblas-with-lapack") # incomplete LAPACK implementation
conflicts("veclibfort")
conflicts("^openblas-with-lapack") # incomplete LAPACK implementation
conflicts("^veclibfort")
# only GCC 4.9+ and higher have sufficient support for OpenMP 4+ tasks+deps
conflicts("%gcc@:4.8.99", when='@:17.1')