concretizer: generate facts for externals

Generate only facts for external specs. Substitute the
use of already grounded rules with non-grounded rules
in concretize.lp
This commit is contained in:
Massimiliano Culpo 2020-12-29 12:45:11 +01:00 committed by Todd Gamblin
parent a4accff266
commit eca1dd8738
3 changed files with 42 additions and 41 deletions

View file

@ -793,9 +793,6 @@ def external_packages(self):
if pkg_name not in spack.repo.path: if pkg_name not in spack.repo.path:
continue continue
if 'externals' not in data:
self.gen.fact(fn.external(pkg_name).symbol(positive=False))
self.gen.h2('External package: {0}'.format(pkg_name)) self.gen.h2('External package: {0}'.format(pkg_name))
# Check if the external package is buildable. If it is # Check if the external package is buildable. If it is
# not then "external(<pkg>)" is a fact. # not then "external(<pkg>)" is a fact.
@ -807,52 +804,40 @@ def external_packages(self):
externals = data.get('externals', []) externals = data.get('externals', [])
external_specs = [spack.spec.Spec(x['spec']) for x in externals] external_specs = [spack.spec.Spec(x['spec']) for x in externals]
# Compute versions with appropriate weights # Compute versions with appropriate weights. This accounts for the
# fact that we should prefer more recent versions, but specs in
# packages.yaml may not be ordered in that sense.
external_versions = [ external_versions = [
(x.version, idx) for idx, x in enumerate(external_specs) (x.version, local_idx)
for local_idx, x in enumerate(external_specs)
] ]
external_versions = [ external_versions = [
(v, -(w + 1), idx) (v, -(w + 1), local_idx)
for w, (v, idx) in enumerate(sorted(external_versions)) for w, (v, local_idx) in enumerate(sorted(external_versions))
] ]
for version, weight, id in external_versions: for version, weight, id in external_versions:
self.gen.fact(fn.external_version_declared( self.gen.fact(fn.external_version_declared(
pkg_name, str(version), weight, id pkg_name, str(version), weight, id
)) ))
# Establish an equivalence between "external_spec(pkg, id)" for local_idx, spec in enumerate(external_specs):
# and the clauses of that spec, so that we have a uniform global_id = self._condition_id_counter
# way to identify it self._condition_id_counter += 1
spec_id_list = []
for id, spec in enumerate(external_specs): # Declare the global ID associated with this external spec
self.gen.newline() self.gen.fact(fn.external_spec(global_id, pkg_name))
spec_id = fn.external_spec(pkg_name, id)
# Local index into packages.yaml
self.gen.fact(fn.external_spec_index(global_id, pkg_name, local_idx))
# Add conditions to be satisfied for this external
self.possible_versions[spec.name].add(spec.version) self.possible_versions[spec.name].add(spec.version)
clauses = self.spec_clauses(spec, body=True) clauses = self.spec_clauses(spec, body=True)
# This is an iff below, wish it could be written in a
# more compact form
self.gen.rule(head=spec_id.symbol(), body=AspAnd(*clauses))
for clause in clauses: for clause in clauses:
self.gen.rule(clause, spec_id.symbol()) self.gen.fact(
spec_id_list.append(spec_id) fn.external_spec_condition(global_id, clause.name, *clause.args)
)
# TODO: find another way to do everything below, without self.gen.newline()
# TODO: generating ground rules.
# If one of the external specs is selected then the package
# is external and viceversa
# TODO: make it possible to declare the rule like below
# self.gen.iff(expr1=fn.external(pkg_name),
# expr2=one_of_the_externals)
self.gen.newline()
# FIXME: self.gen.one_of_iff(fn.external(pkg_name), spec_id_list)
one_of_the_externals = self.gen.one_of(*spec_id_list)
external_str = fn.external(pkg_name)
external_rule = "{0} :- {1}.\n{1} :- {0}.\n".format(
external_str, str(one_of_the_externals)
)
self.gen.out.write(external_rule)
self.gen.control.add("base", [], external_rule)
def preferred_variants(self, pkg_name): def preferred_variants(self, pkg_name):
"""Facts on concretization preferences, as read from packages.yaml""" """Facts on concretization preferences, as read from packages.yaml"""
@ -1513,7 +1498,7 @@ def node_flag_source(self, pkg, source):
def no_flags(self, pkg, flag_type): def no_flags(self, pkg, flag_type):
self._specs[pkg].compiler_flags[flag_type] = [] self._specs[pkg].compiler_flags[flag_type] = []
def external_spec(self, pkg, idx): def external_spec_selected(self, global_id, pkg, idx):
"""This means that the external spec and index idx """This means that the external spec and index idx
has been selected for this package. has been selected for this package.
""" """

View file

@ -258,9 +258,25 @@ external(Package) :-
version(Package, Version), version_weight(Package, Weight), version(Package, Version), version_weight(Package, Weight),
external_version_declared(Package, Version, Weight, ID). external_version_declared(Package, Version, Weight, ID).
external_spec(Package, ID) :- % determine if an external spec has been selected
external_spec_selected(ID, Package, LocalIndex) :-
version(Package, Version), version_weight(Package, Weight), version(Package, Version), version_weight(Package, Weight),
external_version_declared(Package, Version, Weight, ID). external_spec_index(ID, Package, LocalIndex),
external_version_declared(Package, Version, Weight, LocalIndex),
external_spec_conditions_hold(ID, Package).
% determine if all the conditions on an external spec hold. If they do
% the spec can be selected.
external_spec_conditions_hold(ID, Package) :-
attr(Name, Arg1) : external_spec_condition(ID, Name, Arg1);
attr(Name, Arg1, Arg2) : external_spec_condition(ID, Name, Arg1, Arg2);
attr(Name, Arg1, Arg2, Arg3) : external_spec_condition(ID, Name, Arg1, Arg2, Arg3);
external_spec(ID, Package);
node(Package).
% it cannot happen that a spec is external, but none of the external specs
% conditions hold.
:- external(Package), not external_spec_conditions_hold(_, Package).
%----------------------------------------------------------------------------- %-----------------------------------------------------------------------------
% Variant semantics % Variant semantics

View file

@ -24,4 +24,4 @@
#show compiler_weight/2. #show compiler_weight/2.
#show node_target_match/2. #show node_target_match/2.
#show node_target_weight/2. #show node_target_weight/2.
#show external_spec/2. #show external_spec_selected/3.