ASP-based solver: tweak heuristic, modify compiler encoding (#35989)
This PR does 2 unrelated things: 1. It changes the encoding of the compilers 2. It tweaks the heuristic for the solves in a0d88179074f81d13a3fad629a43d86334e7f982 Both were initially motivated by trying to get a performance gain but, while 2 showed significant speed-ups[^1], 1 instead didn't. I kept it anyhow, since I think the code related to compilers is more consolidated with the new encoding and we might get some performance improvement out of it if we can base our errors on the `node_compiler(Package, CompilerID)` atoms instead of `attrs`. [^1]: In general the changes in the heuristic brought a ~10% speed-up on the tests I did. I'll post detailed results below. Add a warning about compilers.yaml that is triggered if there are multiple compilers with the same spec, os and target (since they can't be selected by users with the spec syntax only).
This commit is contained in:
parent
34ef01a5c8
commit
8517a74f37
2 changed files with 187 additions and 158 deletions
|
@ -818,6 +818,9 @@ def __init__(self, tests=False):
|
|||
self.compiler_version_constraints = set()
|
||||
self.post_facts = []
|
||||
|
||||
# (ID, CompilerSpec) -> dictionary of attributes
|
||||
self.compiler_info = collections.defaultdict(dict)
|
||||
|
||||
# hashes we've already added facts for
|
||||
self.seen_hashes = set()
|
||||
self.reusable_and_possible = {}
|
||||
|
@ -942,54 +945,38 @@ def conflict_rules(self, pkg):
|
|||
self.gen.fact(fn.conflict(pkg.name, trigger_id, constraint_id, conflict_msg))
|
||||
self.gen.newline()
|
||||
|
||||
def available_compilers(self):
|
||||
def compiler_facts(self):
|
||||
"""Facts about available compilers."""
|
||||
|
||||
self.gen.h2("Available compilers")
|
||||
compilers = self.possible_compilers
|
||||
indexed_possible_compilers = list(enumerate(self.possible_compilers))
|
||||
for compiler_id, compiler in indexed_possible_compilers:
|
||||
self.gen.fact(fn.compiler_id(compiler_id))
|
||||
self.gen.fact(fn.compiler_name(compiler_id, compiler.spec.name))
|
||||
self.gen.fact(fn.compiler_version(compiler_id, compiler.spec.version))
|
||||
|
||||
compiler_versions = collections.defaultdict(lambda: set())
|
||||
for compiler in compilers:
|
||||
compiler_versions[compiler.name].add(compiler.version)
|
||||
if compiler.operating_system:
|
||||
self.gen.fact(fn.compiler_os(compiler_id, compiler.operating_system))
|
||||
|
||||
for compiler in sorted(compiler_versions):
|
||||
for v in sorted(compiler_versions[compiler]):
|
||||
self.gen.fact(fn.compiler_version(compiler, v))
|
||||
if compiler.target is not None:
|
||||
self.gen.fact(fn.compiler_target(compiler_id, compiler.target))
|
||||
|
||||
for flag_type, flags in compiler.flags.items():
|
||||
for flag in flags:
|
||||
self.gen.fact(fn.compiler_flag(compiler_id, flag_type, flag))
|
||||
|
||||
self.gen.newline()
|
||||
|
||||
def compiler_defaults(self):
|
||||
"""Set compiler defaults, given a list of possible compilers."""
|
||||
self.gen.h2("Default compiler preferences")
|
||||
# Set compiler defaults, given a list of possible compilers
|
||||
self.gen.h2("Default compiler preferences (CompilerID, Weight)")
|
||||
|
||||
compiler_list = self.possible_compilers.copy()
|
||||
compiler_list = sorted(compiler_list, key=lambda x: (x.name, x.version), reverse=True)
|
||||
ppk = spack.package_prefs.PackagePrefs("all", "compiler", all=False)
|
||||
matches = sorted(compiler_list, key=ppk)
|
||||
matches = sorted(indexed_possible_compilers, key=lambda x: ppk(x[1].spec))
|
||||
|
||||
for i, cspec in enumerate(matches):
|
||||
f = fn.default_compiler_preference(cspec.name, cspec.version, i)
|
||||
for weight, (compiler_id, cspec) in enumerate(matches):
|
||||
f = fn.default_compiler_preference(compiler_id, weight)
|
||||
self.gen.fact(f)
|
||||
|
||||
# Enumerate target families. This may be redundant, but compilers with
|
||||
# custom versions will be able to concretize properly.
|
||||
for entry in spack.compilers.all_compilers_config():
|
||||
compiler_entry = entry["compiler"]
|
||||
cspec = spack.spec.CompilerSpec(compiler_entry["spec"])
|
||||
if not compiler_entry.get("target", None):
|
||||
continue
|
||||
|
||||
self.gen.fact(
|
||||
fn.compiler_supports_target(cspec.name, cspec.version, compiler_entry["target"])
|
||||
)
|
||||
|
||||
def compiler_supports_os(self):
|
||||
compilers_yaml = spack.compilers.all_compilers_config()
|
||||
for entry in compilers_yaml:
|
||||
c = spack.spec.CompilerSpec(entry["compiler"]["spec"])
|
||||
operating_system = entry["compiler"]["operating_system"]
|
||||
self.gen.fact(fn.compiler_supports_os(c.name, c.version, operating_system))
|
||||
|
||||
def package_compiler_defaults(self, pkg):
|
||||
"""Facts about packages' compiler prefs."""
|
||||
|
||||
|
@ -998,14 +985,16 @@ def package_compiler_defaults(self, pkg):
|
|||
if not pkg_prefs or "compiler" not in pkg_prefs:
|
||||
return
|
||||
|
||||
compiler_list = self.possible_compilers.copy()
|
||||
compiler_list = self.possible_compilers
|
||||
compiler_list = sorted(compiler_list, key=lambda x: (x.name, x.version), reverse=True)
|
||||
ppk = spack.package_prefs.PackagePrefs(pkg.name, "compiler", all=False)
|
||||
matches = sorted(compiler_list, key=ppk)
|
||||
matches = sorted(compiler_list, key=lambda x: ppk(x.spec))
|
||||
|
||||
for i, cspec in enumerate(reversed(matches)):
|
||||
for i, compiler in enumerate(reversed(matches)):
|
||||
self.gen.fact(
|
||||
fn.node_compiler_preference(pkg.name, cspec.name, cspec.version, -i * 100)
|
||||
fn.node_compiler_preference(
|
||||
pkg.name, compiler.spec.name, compiler.spec.version, -i * 100
|
||||
)
|
||||
)
|
||||
|
||||
def package_requirement_rules(self, pkg):
|
||||
|
@ -1392,28 +1381,6 @@ def target_preferences(self, pkg_name):
|
|||
fn.target_weight(pkg_name, str(preferred.architecture.target), i + offset)
|
||||
)
|
||||
|
||||
def flag_defaults(self):
|
||||
self.gen.h2("Compiler flag defaults")
|
||||
|
||||
# types of flags that can be on specs
|
||||
for flag in spack.spec.FlagMap.valid_compiler_flags():
|
||||
self.gen.fact(fn.flag_type(flag))
|
||||
self.gen.newline()
|
||||
|
||||
# flags from compilers.yaml
|
||||
compilers = all_compilers_in_config()
|
||||
seen = set()
|
||||
for compiler in compilers:
|
||||
# if there are multiple with the same spec, only use the first
|
||||
if compiler.spec in seen:
|
||||
continue
|
||||
seen.add(compiler.spec)
|
||||
for name, flags in compiler.flags.items():
|
||||
for flag in flags:
|
||||
self.gen.fact(
|
||||
fn.compiler_version_flag(compiler.name, compiler.version, name, flag)
|
||||
)
|
||||
|
||||
def spec_clauses(self, *args, **kwargs):
|
||||
"""Wrap a call to `_spec_clauses()` into a try/except block that
|
||||
raises a comprehensible error message in case of failure.
|
||||
|
@ -1770,8 +1737,6 @@ def target_defaults(self, specs):
|
|||
if granularity == "generic":
|
||||
candidate_targets = [t for t in candidate_targets if t.vendor == "generic"]
|
||||
|
||||
compilers = self.possible_compilers
|
||||
|
||||
# Add targets explicitly requested from specs
|
||||
for spec in specs:
|
||||
if not spec.architecture or not spec.architecture.target:
|
||||
|
@ -1788,8 +1753,14 @@ def target_defaults(self, specs):
|
|||
if ancestor not in candidate_targets:
|
||||
candidate_targets.append(ancestor)
|
||||
|
||||
best_targets = set([uarch.family.name])
|
||||
for compiler in sorted(compilers):
|
||||
best_targets = {uarch.family.name}
|
||||
for compiler_id, compiler in enumerate(self.possible_compilers):
|
||||
# Stub support for cross-compilation, to be expanded later
|
||||
if compiler.target is not None and compiler.target != str(uarch.family):
|
||||
self.gen.fact(fn.compiler_supports_target(compiler_id, compiler.target))
|
||||
self.gen.newline()
|
||||
continue
|
||||
|
||||
supported = self._supported_targets(compiler.name, compiler.version, candidate_targets)
|
||||
|
||||
# If we can't find supported targets it may be due to custom
|
||||
|
@ -1808,20 +1779,19 @@ def target_defaults(self, specs):
|
|||
|
||||
for target in supported:
|
||||
best_targets.add(target.name)
|
||||
self.gen.fact(
|
||||
fn.compiler_supports_target(compiler.name, compiler.version, target.name)
|
||||
)
|
||||
self.gen.fact(fn.compiler_supports_target(compiler_id, target.name))
|
||||
|
||||
self.gen.fact(
|
||||
fn.compiler_supports_target(compiler.name, compiler.version, uarch.family.name)
|
||||
)
|
||||
self.gen.fact(fn.compiler_supports_target(compiler_id, uarch.family.name))
|
||||
self.gen.newline()
|
||||
|
||||
i = 0 # TODO compute per-target offset?
|
||||
for target in candidate_targets:
|
||||
self.gen.fact(fn.target(target.name))
|
||||
self.gen.fact(fn.target_family(target.name, target.family.name))
|
||||
for parent in sorted(target.parents):
|
||||
self.gen.fact(fn.target_parent(target.name, parent.name))
|
||||
self.gen.fact(fn.target_compatible(target.name, target.name))
|
||||
# Code for ancestor can run on target
|
||||
for ancestor in target.ancestors:
|
||||
self.gen.fact(fn.target_compatible(target.name, ancestor.name))
|
||||
|
||||
# prefer best possible targets; weight others poorly so
|
||||
# they're not used unless set explicitly
|
||||
|
@ -1832,10 +1802,10 @@ def target_defaults(self, specs):
|
|||
i += 1
|
||||
else:
|
||||
self.default_targets.append((100, target.name))
|
||||
|
||||
self.default_targets = list(sorted(set(self.default_targets)))
|
||||
self.gen.newline()
|
||||
|
||||
self.default_targets = list(sorted(set(self.default_targets)))
|
||||
|
||||
def virtual_providers(self):
|
||||
self.gen.h2("Virtual providers")
|
||||
msg = (
|
||||
|
@ -1851,6 +1821,22 @@ def virtual_providers(self):
|
|||
|
||||
def generate_possible_compilers(self, specs):
|
||||
compilers = all_compilers_in_config()
|
||||
|
||||
# Search for compilers which differs only by aspects that are
|
||||
# not selectable by users using the spec syntax
|
||||
seen, sanitized_list = set(), []
|
||||
for compiler in compilers:
|
||||
key = compiler.spec, compiler.operating_system, compiler.target
|
||||
if key in seen:
|
||||
warnings.warn(
|
||||
f"duplicate found for {compiler.spec} on "
|
||||
f"{compiler.operating_system}/{compiler.target}. "
|
||||
f"Edit your compilers.yaml configuration to remove it."
|
||||
)
|
||||
continue
|
||||
sanitized_list.append(compiler)
|
||||
seen.add(key)
|
||||
|
||||
cspecs = set([c.spec for c in compilers])
|
||||
|
||||
# add compiler specs from the input line to possibilities if we
|
||||
|
@ -1871,10 +1857,21 @@ def generate_possible_compilers(self, specs):
|
|||
# Allow unknown compilers to exist if the associated spec
|
||||
# is already built
|
||||
else:
|
||||
cspecs.add(s.compiler)
|
||||
compiler_cls = spack.compilers.class_for_compiler_name(s.compiler.name)
|
||||
compilers.append(
|
||||
compiler_cls(
|
||||
s.compiler, operating_system=None, target=None, paths=[None] * 4
|
||||
)
|
||||
)
|
||||
self.gen.fact(fn.allow_compiler(s.compiler.name, s.compiler.version))
|
||||
|
||||
return cspecs
|
||||
return list(
|
||||
sorted(
|
||||
compilers,
|
||||
key=lambda compiler: (compiler.spec.name, compiler.spec.version),
|
||||
reverse=True,
|
||||
)
|
||||
)
|
||||
|
||||
def define_version_constraints(self):
|
||||
"""Define what version_satisfies(...) means in ASP logic."""
|
||||
|
@ -1931,14 +1928,12 @@ def versions_for(v):
|
|||
self.possible_versions[pkg_name].add(version)
|
||||
|
||||
def define_compiler_version_constraints(self):
|
||||
compiler_list = spack.compilers.all_compiler_specs()
|
||||
compiler_list = list(sorted(set(compiler_list)))
|
||||
for constraint in sorted(self.compiler_version_constraints):
|
||||
for compiler in compiler_list:
|
||||
if compiler.satisfies(constraint):
|
||||
for compiler_id, compiler in enumerate(self.possible_compilers):
|
||||
if compiler.spec.satisfies(constraint):
|
||||
self.gen.fact(
|
||||
fn.compiler_version_satisfies(
|
||||
constraint.name, constraint.versions, compiler.version
|
||||
constraint.name, constraint.versions, compiler_id
|
||||
)
|
||||
)
|
||||
self.gen.newline()
|
||||
|
@ -2099,10 +2094,13 @@ def setup(self, driver, specs, reuse=None):
|
|||
for reusable_spec in reuse:
|
||||
self._facts_from_concrete_spec(reusable_spec, possible)
|
||||
|
||||
self.gen.h1("Possible flags on nodes")
|
||||
for flag in spack.spec.FlagMap.valid_compiler_flags():
|
||||
self.gen.fact(fn.flag_type(flag))
|
||||
self.gen.newline()
|
||||
|
||||
self.gen.h1("General Constraints")
|
||||
self.available_compilers()
|
||||
self.compiler_defaults()
|
||||
self.compiler_supports_os()
|
||||
self.compiler_facts()
|
||||
|
||||
# architecture defaults
|
||||
self.platform_defaults()
|
||||
|
@ -2113,7 +2111,6 @@ def setup(self, driver, specs, reuse=None):
|
|||
self.provider_defaults()
|
||||
self.provider_requirements()
|
||||
self.external_packages()
|
||||
self.flag_defaults()
|
||||
|
||||
self.gen.h1("Package Constraints")
|
||||
for pkg in sorted(self.pkgs):
|
||||
|
@ -2294,7 +2291,7 @@ def reorder_flags(self):
|
|||
flags will appear last on the compile line, in the order they
|
||||
were specified.
|
||||
|
||||
The solver determines wihch flags are on nodes; this routine
|
||||
The solver determines which flags are on nodes; this routine
|
||||
imposes order afterwards.
|
||||
"""
|
||||
# reverse compilers so we get highest priority compilers that share a spec
|
||||
|
|
|
@ -522,7 +522,7 @@ error(2, "{0} and {1} cannot both propagate variant '{2}' to package {3} with va
|
|||
attr("variant_propagate", Package, Variant, Value1, Source1),
|
||||
attr("variant_propagate", Package, Variant, Value2, Source2),
|
||||
variant(Package, Variant),
|
||||
Value1 != Value2.
|
||||
Value1 < Value2.
|
||||
|
||||
% a variant cannot be set if it is not a variant on the package
|
||||
error(2, "Cannot set variant '{0}' for package '{1}' because the variant condition cannot be satisfied for the given spec", Variant, Package)
|
||||
|
@ -816,25 +816,15 @@ node_target_compatible(Package, Target)
|
|||
:- attr("node_target", Package, MyTarget),
|
||||
target_compatible(Target, MyTarget).
|
||||
|
||||
% target_compatible(T1, T2) means code for T2 can run on T1
|
||||
% This order is dependent -> dependency in the node DAG, which
|
||||
% is contravariant with the target DAG.
|
||||
target_compatible(Target, Target) :- target(Target).
|
||||
target_compatible(Child, Parent) :- target_parent(Child, Parent).
|
||||
target_compatible(Descendent, Ancestor)
|
||||
:- target_parent(Target, Ancestor),
|
||||
target_compatible(Descendent, Target),
|
||||
target(Target).
|
||||
|
||||
#defined target_satisfies/2.
|
||||
#defined target_parent/2.
|
||||
|
||||
% can't use targets on node if the compiler for the node doesn't support them
|
||||
error(2, "{0} compiler '{2}@{3}' incompatible with 'target={1}'", Package, Target, Compiler, Version)
|
||||
:- attr("node_target", Package, Target),
|
||||
not compiler_supports_target(Compiler, Version, Target),
|
||||
attr("node_compiler", Package, Compiler),
|
||||
attr("node_compiler_version", Package, Compiler, Version),
|
||||
node_compiler(Package, CompilerID),
|
||||
not compiler_supports_target(CompilerID, Target),
|
||||
compiler_name(CompilerID, Compiler),
|
||||
compiler_version(CompilerID, Version),
|
||||
build(Package).
|
||||
|
||||
% if a target is set explicitly, respect it
|
||||
|
@ -868,32 +858,44 @@ error(2, "'{0} target={1}' is not compatible with this machine", Package, Target
|
|||
%-----------------------------------------------------------------------------
|
||||
% Compiler semantics
|
||||
%-----------------------------------------------------------------------------
|
||||
compiler(Compiler) :- compiler_version(Compiler, _).
|
||||
|
||||
% There must be only one compiler set per built node. The compiler
|
||||
% is chosen among available versions.
|
||||
{ attr("node_compiler_version", Package, Compiler, Version) : compiler_version(Compiler, Version) } :-
|
||||
% There must be only one compiler set per built node.
|
||||
{ node_compiler(Package, CompilerID) : compiler_id(CompilerID) } :-
|
||||
attr("node", Package),
|
||||
build(Package).
|
||||
|
||||
% Infer the compiler that matches a reused node
|
||||
node_compiler(Package, CompilerID)
|
||||
:- attr("node_compiler_version", Package, CompilerName, CompilerVersion),
|
||||
attr("node", Package),
|
||||
compiler_name(CompilerID, CompilerName),
|
||||
compiler_version(CompilerID, CompilerVersion),
|
||||
concrete(Package).
|
||||
|
||||
% Expand the internal attribute into "attr("node_compiler_version")
|
||||
attr("node_compiler_version", Package, CompilerName, CompilerVersion)
|
||||
:- node_compiler(Package, CompilerID),
|
||||
compiler_name(CompilerID, CompilerName),
|
||||
compiler_version(CompilerID, CompilerVersion),
|
||||
build(Package).
|
||||
|
||||
attr("node_compiler", Package, CompilerName)
|
||||
:- attr("node_compiler_version", Package, CompilerName, CompilerVersion).
|
||||
|
||||
error(2, "No valid compiler version found for '{0}'", Package)
|
||||
:- attr("node", Package),
|
||||
C = #count{ Version : attr("node_compiler_version", Package, _, Version)},
|
||||
C < 1.
|
||||
error(2, "'{0}' compiler constraints '%{1}@{2}' and '%{3}@{4}' are incompatible", Package, Compiler1, Version1, Compiler2, Version2)
|
||||
:- attr("node", Package),
|
||||
attr("node_compiler_version", Package, Compiler1, Version1),
|
||||
attr("node_compiler_version", Package, Compiler2, Version2),
|
||||
(Compiler1, Version1) < (Compiler2, Version2). % see[1]
|
||||
not node_compiler(Package, _).
|
||||
|
||||
% Sometimes we just need to know the compiler and not the version
|
||||
attr("node_compiler", Package, Compiler) :- attr("node_compiler_version", Package, Compiler, _).
|
||||
error(2, "Cannot concretize {0} with two compilers {1}@{2} and {3}@{4}", Package, C1, V1, C2, V2)
|
||||
:- attr("node", Package),
|
||||
attr("node_compiler_version", Package, C1, V1),
|
||||
attr("node_compiler_version", Package, C2, V2),
|
||||
(C1, V1) < (C2, V2). % see[1]
|
||||
|
||||
% We can't have a compiler be enforced and select the version from another compiler
|
||||
error(2, "Cannot concretize {0} with two compilers {1}@{2} and {3}@{4}", Package, C1, V1, C2, V2)
|
||||
:- attr("node_compiler_version", Package, C1, V1),
|
||||
attr("node_compiler_version", Package, C2, V2),
|
||||
(C1, V1) != (C2, V2).
|
||||
(C1, V1) < (C2, V2).
|
||||
|
||||
error(2, "Cannot concretize {0} with two compilers {1} and {2}@{3}", Package, Compiler1, Compiler2, Version)
|
||||
:- attr("node_compiler", Package, Compiler1),
|
||||
|
@ -904,37 +906,41 @@ error(2, "Cannot concretize {0} with two compilers {1} and {2}@{3}", Package, Co
|
|||
error(1, "No valid compiler for {0} satisfies '%{1}'", Package, Compiler)
|
||||
:- attr("node", Package),
|
||||
attr("node_compiler_version_satisfies", Package, Compiler, ":"),
|
||||
C = #count{ Version : attr("node_compiler_version", Package, Compiler, Version), compiler_version_satisfies(Compiler, ":", Version) },
|
||||
C < 1.
|
||||
not compiler_version_satisfies(Compiler, ":", _).
|
||||
|
||||
% If the compiler of a node must satisfy a constraint, then its version
|
||||
% must be chosen among the ones that satisfy said constraint
|
||||
error(2, "No valid version for '{0}' compiler '{1}' satisfies '@{2}'", Package, Compiler, Constraint)
|
||||
:- attr("node", Package),
|
||||
attr("node_compiler_version_satisfies", Package, Compiler, Constraint),
|
||||
C = #count{ Version : attr("node_compiler_version", Package, Compiler, Version), compiler_version_satisfies(Compiler, Constraint, Version) },
|
||||
C < 1.
|
||||
not compiler_version_satisfies(Compiler, Constraint, _).
|
||||
|
||||
% If the node is associated with a compiler and the compiler satisfy a constraint, then
|
||||
% the compiler associated with the node satisfy the same constraint
|
||||
attr("node_compiler_version_satisfies", Package, Compiler, Constraint)
|
||||
:- attr("node_compiler_version", Package, Compiler, Version),
|
||||
compiler_version_satisfies(Compiler, Constraint, Version).
|
||||
:- node_compiler(Package, CompilerID),
|
||||
compiler_name(CompilerID, Compiler),
|
||||
compiler_version_satisfies(Compiler, Constraint, CompilerID).
|
||||
|
||||
#defined compiler_version_satisfies/3.
|
||||
|
||||
% If the compiler version was set from the command line,
|
||||
% respect it verbatim
|
||||
attr("node_compiler_version", Package, Compiler, Version) :-
|
||||
attr("node_compiler_version_set", Package, Compiler, Version).
|
||||
:- attr("node_compiler_version_set", Package, Compiler, Version),
|
||||
not attr("node_compiler_version", Package, Compiler, Version).
|
||||
|
||||
:- attr("node_compiler_set", Package, Compiler),
|
||||
not attr("node_compiler_version", Package, Compiler, _).
|
||||
|
||||
% Cannot select a compiler if it is not supported on the OS
|
||||
% Compilers that are explicitly marked as allowed
|
||||
% are excluded from this check
|
||||
error(2, "{0} compiler '%{1}@{2}' incompatible with 'os={3}'", Package, Compiler, Version, OS)
|
||||
:- attr("node_compiler_version", Package, Compiler, Version),
|
||||
attr("node_os", Package, OS),
|
||||
not compiler_supports_os(Compiler, Version, OS),
|
||||
:- attr("node_os", Package, OS),
|
||||
node_compiler(Package, CompilerID),
|
||||
compiler_name(CompilerID, Compiler),
|
||||
compiler_version(CompilerID, Version),
|
||||
not compiler_os(CompilerID, OS),
|
||||
not allow_compiler(Compiler, Version),
|
||||
build(Package).
|
||||
|
||||
|
@ -942,8 +948,8 @@ error(2, "{0} compiler '%{1}@{2}' incompatible with 'os={3}'", Package, Compiler
|
|||
% same compiler there's a mismatch.
|
||||
compiler_match(Package, Dependency)
|
||||
:- depends_on(Package, Dependency),
|
||||
attr("node_compiler_version", Package, Compiler, Version),
|
||||
attr("node_compiler_version", Dependency, Compiler, Version).
|
||||
node_compiler(Package, CompilerID),
|
||||
node_compiler(Dependency, CompilerID).
|
||||
|
||||
compiler_mismatch(Package, Dependency)
|
||||
:- depends_on(Package, Dependency),
|
||||
|
@ -955,25 +961,32 @@ compiler_mismatch_required(Package, Dependency)
|
|||
attr("node_compiler_set", Dependency, _),
|
||||
not compiler_match(Package, Dependency).
|
||||
|
||||
#defined compiler_supports_os/3.
|
||||
#defined compiler_os/3.
|
||||
#defined allow_compiler/2.
|
||||
|
||||
% compilers weighted by preference according to packages.yaml
|
||||
compiler_weight(Package, Weight)
|
||||
:- attr("node_compiler_version", Package, Compiler, V),
|
||||
:- node_compiler(Package, CompilerID),
|
||||
compiler_name(CompilerID, Compiler),
|
||||
compiler_version(CompilerID, V),
|
||||
node_compiler_preference(Package, Compiler, V, Weight).
|
||||
compiler_weight(Package, Weight)
|
||||
:- attr("node_compiler_version", Package, Compiler, V),
|
||||
:- node_compiler(Package, CompilerID),
|
||||
compiler_name(CompilerID, Compiler),
|
||||
compiler_version(CompilerID, V),
|
||||
not node_compiler_preference(Package, Compiler, V, _),
|
||||
default_compiler_preference(Compiler, V, Weight).
|
||||
default_compiler_preference(CompilerID, Weight).
|
||||
compiler_weight(Package, 100)
|
||||
:- attr("node_compiler_version", Package, Compiler, Version),
|
||||
not node_compiler_preference(Package, Compiler, Version, _),
|
||||
not default_compiler_preference(Compiler, Version, _).
|
||||
:- node_compiler(Package, CompilerID),
|
||||
compiler_name(CompilerID, Compiler),
|
||||
compiler_version(CompilerID, V),
|
||||
not node_compiler_preference(Package, Compiler, V, _),
|
||||
not default_compiler_preference(CompilerID, _).
|
||||
|
||||
% For the time being, be strict and reuse only if the compiler match one we have on the system
|
||||
error(2, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missing_compilers:true if intended.", Package, Compiler, Version)
|
||||
:- attr("node_compiler_version", Package, Compiler, Version), not compiler_version(Compiler, Version).
|
||||
:- attr("node_compiler_version", Package, Compiler, Version),
|
||||
not node_compiler(Package, _).
|
||||
|
||||
#defined node_compiler_preference/4.
|
||||
#defined default_compiler_preference/3.
|
||||
|
@ -985,10 +998,11 @@ error(2, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missin
|
|||
% propagate flags when compiler match
|
||||
can_inherit_flags(Package, Dependency, FlagType)
|
||||
:- depends_on(Package, Dependency),
|
||||
attr("node_compiler", Package, Compiler),
|
||||
attr("node_compiler", Dependency, Compiler),
|
||||
node_compiler(Package, CompilerID),
|
||||
node_compiler(Dependency, CompilerID),
|
||||
not attr("node_flag_set", Dependency, FlagType, _),
|
||||
compiler(Compiler), flag_type(FlagType).
|
||||
compiler_id(CompilerID),
|
||||
flag_type(FlagType).
|
||||
|
||||
node_flag_inherited(Dependency, FlagType, Flag)
|
||||
:- attr("node_flag_set", Package, FlagType, Flag), can_inherit_flags(Package, Dependency, FlagType),
|
||||
|
@ -1005,7 +1019,7 @@ error(2, "{0} and {1} cannot both propagate compiler flags '{2}' to {3}", Source
|
|||
attr("node_flag_propagate", Source2, FlagType),
|
||||
can_inherit_flags(Source1, Package, FlagType),
|
||||
can_inherit_flags(Source2, Package, FlagType),
|
||||
Source1 != Source2.
|
||||
Source1 < Source2.
|
||||
|
||||
% remember where flags came from
|
||||
attr("node_flag_source", Package, FlagType, Package) :- attr("node_flag_set", Package, FlagType, _).
|
||||
|
@ -1015,19 +1029,21 @@ attr("node_flag_source", Dependency, FlagType, Q)
|
|||
|
||||
% compiler flags from compilers.yaml are put on nodes if compiler matches
|
||||
attr("node_flag", Package, FlagType, Flag)
|
||||
:- compiler_version_flag(Compiler, Version, FlagType, Flag),
|
||||
attr("node_compiler_version", Package, Compiler, Version),
|
||||
:- compiler_flag(CompilerID, FlagType, Flag),
|
||||
node_compiler(Package, CompilerID),
|
||||
flag_type(FlagType),
|
||||
compiler(Compiler),
|
||||
compiler_version(Compiler, Version).
|
||||
compiler_id(CompilerID),
|
||||
compiler_name(CompilerID, CompilerName),
|
||||
compiler_version(CompilerID, Version).
|
||||
|
||||
attr("node_flag_compiler_default", Package)
|
||||
:- not attr("node_flag_set", Package, FlagType, _),
|
||||
compiler_version_flag(Compiler, Version, FlagType, Flag),
|
||||
attr("node_compiler_version", Package, Compiler, Version),
|
||||
compiler_flag(CompilerID, FlagType, Flag),
|
||||
node_compiler(Package, CompilerID),
|
||||
flag_type(FlagType),
|
||||
compiler(Compiler),
|
||||
compiler_version(Compiler, Version).
|
||||
compiler_id(CompilerID),
|
||||
compiler_name(CompilerID, CompilerName),
|
||||
compiler_version(CompilerID, Version).
|
||||
|
||||
% if a flag is set to something or inherited, it's included
|
||||
attr("node_flag", Package, FlagType, Flag) :- attr("node_flag_set", Package, FlagType, Flag).
|
||||
|
@ -1038,7 +1054,7 @@ attr("node_flag", Package, FlagType, Flag)
|
|||
attr("no_flags", Package, FlagType)
|
||||
:- not attr("node_flag", Package, FlagType, _), attr("node", Package), flag_type(FlagType).
|
||||
|
||||
#defined compiler_version_flag/4.
|
||||
#defined compiler_flag/3.
|
||||
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
|
@ -1054,7 +1070,7 @@ attr("no_flags", Package, FlagType)
|
|||
% You can't install a hash, if it is not installed
|
||||
:- attr("hash", Package, Hash), not installed_hash(Package, Hash).
|
||||
% This should be redundant given the constraint above
|
||||
:- attr("hash", Package, Hash1), attr("hash", Package, Hash2), Hash1 != Hash2.
|
||||
:- attr("hash", Package, Hash1), attr("hash", Package, Hash2), Hash1 < Hash2.
|
||||
|
||||
% if a hash is selected, we impose all the constraints that implies
|
||||
impose(Hash) :- attr("hash", Package, Hash).
|
||||
|
@ -1311,13 +1327,29 @@ opt_criterion(5, "non-preferred targets").
|
|||
%-----------------
|
||||
% Domain heuristic
|
||||
%-----------------
|
||||
#heuristic attr("version", Package, Version) : version_declared(Package, Version, 0), attr("node", Package). [10, true]
|
||||
#heuristic version_weight(Package, 0) : version_declared(Package, Version, 0), attr("node", Package). [10, true]
|
||||
#heuristic attr("node_target", Package, Target) : package_target_weight(Target, Package, 0), attr("node", Package). [10, true]
|
||||
#heuristic node_target_weight(Package, 0) : attr("node", Package). [10, true]
|
||||
#heuristic literal_solved(ID) : literal(ID). [1, sign]
|
||||
#heuristic literal_solved(ID) : literal(ID). [50, init]
|
||||
#heuristic attr("hash", Package, Hash) : attr("root", Package). [45, init]
|
||||
|
||||
#heuristic attr("version", Package, Version) : version_declared(Package, Version, 0), attr("root", Package). [40, true]
|
||||
#heuristic version_weight(Package, 0) : version_declared(Package, Version, 0), attr("root", Package). [40, true]
|
||||
#heuristic attr("variant_value", Package, Variant, Value) : variant_default_value(Package, Variant, Value), attr("root", Package). [40, true]
|
||||
#heuristic attr("node_target", Package, Target) : package_target_weight(Target, Package, 0), attr("root", Package). [40, true]
|
||||
#heuristic node_target_weight(Package, 0) : attr("root", Package). [40, true]
|
||||
#heuristic node_compiler(Package, CompilerID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("root", Package). [40, true]
|
||||
|
||||
#heuristic provider(Package, Virtual) : possible_provider_weight(Package, Virtual, 0, _), attr("virtual_node", Virtual). [30, true]
|
||||
#heuristic provider_weight(Package, Virtual, 0, R) : possible_provider_weight(Package, Virtual, 0, R), attr("virtual_node", Virtual). [30, true]
|
||||
#heuristic attr("node", Package) : possible_provider_weight(Package, Virtual, 0, _), attr("virtual_node", Virtual). [30, true]
|
||||
|
||||
#heuristic attr("version", Package, Version) : version_declared(Package, Version, 0), attr("node", Package). [20, true]
|
||||
#heuristic version_weight(Package, 0) : version_declared(Package, Version, 0), attr("node", Package). [20, true]
|
||||
|
||||
#heuristic attr("node_target", Package, Target) : package_target_weight(Target, Package, 0), attr("node", Package). [20, true]
|
||||
#heuristic node_target_weight(Package, 0) : attr("node", Package). [20, true]
|
||||
#heuristic node_compiler(Package, CompilerID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("node", Package). [15, true]
|
||||
|
||||
#heuristic attr("variant_value", Package, Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", Package). [10, true]
|
||||
#heuristic provider(Package, Virtual) : possible_provider_weight(Package, Virtual, 0, _), attr("virtual_node", Virtual). [10, true]
|
||||
#heuristic attr("node", Package) : possible_provider_weight(Package, Virtual, 0, _), attr("virtual_node", Virtual). [10, true]
|
||||
#heuristic attr("node_os", Package, OS) : buildable_os(OS). [10, true]
|
||||
|
||||
%-----------
|
||||
|
|
Loading…
Reference in a new issue