This commit is contained in:
Gregory Becker
2022-05-13 09:40:20 -07:00
parent cf71baff30
commit 6e9b16279a
5 changed files with 439 additions and 107 deletions

View File

@@ -136,13 +136,13 @@ def solve(parser, args):
)
fmt = " @K{%%-8d} %%-%ds%%9s %%7s" % maxlen
for i, (idx, build_idx, name) in enumerate(result.criteria, 1):
for i, (installed_cost, build_cost, name) in enumerate(result.criteria, 1):
color.cprint(
fmt % (
i,
name,
"-" if build_idx is None else opt[idx],
opt[idx] if build_idx is None else opt[build_idx],
"-" if build_cost is None else installed_cost,
installed_cost if build_cost is None else build_cost,
)
)
print()

View File

@@ -59,6 +59,8 @@
#: may be very large or take the time (sometimes hours) to minimize them
minimize_cores = False
# TODO: Remove this after fixing tests that touch it
full_cores = None
# backward compatibility functions for clingo ASTs
def ast_getter(*names):
@@ -111,9 +113,10 @@ def getter(node):
def build_criteria_names(costs, tuples):
"""Construct an ordered mapping from criteria names to indices in the cost list."""
"""Construct an ordered mapping from criteria names to costs."""
# pull optimization criteria names out of the solution
priorities_names = []
costs = costs[28:] # first 28 are high-priority error avoiding criteria
num_fixed = 0
for pred, args in tuples:
@@ -123,6 +126,10 @@ def build_criteria_names(costs, tuples):
priority, name = args[:2]
priority = int(priority)
if priority >= 1000:
# We don't print the error-avoiding criteria
continue
# add the priority of this opt criterion and its name
priorities_names.append((priority, name))
@@ -151,12 +158,12 @@ def build_criteria_names(costs, tuples):
# mapping from priority to index in cost list
indices = dict((p, i) for i, (p, n) in enumerate(priorities_names))
# make a list that has each name with its build and non-build priority
# make a list that has each name with its build and non-build costs
criteria = [
(p - fixed_priority_offset + num_build, None, name) for p, name in fixed
(costs[p - fixed_priority_offset + num_build], None, name) for p, name in fixed
]
for (i, name), (b, _) in zip(installed, build):
criteria.append((indices[i], indices[b], name))
criteria.append((costs[indices[i]], costs[indices[b]], name))
return criteria
@@ -495,6 +502,7 @@ def __init__(self, cores=True):
'depends_on', 'hash', 'node_flag_compiler_default', 'node_flag_source',
'build', 'node', 'root',
]
self.assumption_names = ['error', 'internal_error']
# At high debug levels, include internal errors in output
if spack.error.debug > 2:
@@ -532,7 +540,7 @@ def fact(self, head):
# Only functions relevant for constructing good error messages are
# assumptions, and only when using cores.
choice = self.cores and symbol.name in self.assumption_names
choice = False
self.backend.add_rule([atom], [], choice=choice)
if choice:
self.assumptions.append(atom)
@@ -650,6 +658,9 @@ def stringify(x):
(sym.name, [stringify(a) for a in sym.arguments])
for sym in best_model
]
# print(tuples)
# for t in tuples:
# print(t)
answers = builder.build_specs(tuples)
# add best spec to the results
@@ -1953,6 +1964,103 @@ def node_os(self, pkg, os):
def node_target(self, pkg, target):
self._arch(pkg).target = target
def conflict_triggered(self, msg):
raise spack.error.SpackError(msg)
def no_version(self, pkg):
raise RuntimeError("No versions available for package %s" % pkg)
def versions_conflict(self, pkg, version1, version2):
msg = "No version for %s satisfies @%s and @%s" % (pkg, version1, version2)
raise spack.error.SpackError(msg)
def version_unsatisfiable(self, pkg, constraint):
raise spack.error.SpackError("%s spec cannot satisfy @%s" % (pkg, constraint))
def no_variant_value(self, pkg, variant):
raise RuntimeError("No satisfying value for variant %s of package %s" % (variant, pkg))
def multiple_values_sv_variant(self, pkg, variant, value1, value2):
raise spack.error.SpackError("multiple values for variant")
def invalid_variant_value(self, pkg, variant, value):
raise RuntimeError("Invalid variant value")
def unnecessary(self, pkg):
raise RuntimeError("something doesn't depend on package %s" % pkg)
def cyclic_dependency(self, pkg1, pkg2):
raise RuntimeError("Cyclic dependency between %s and %s" % (pkg1, pkg2))
def no_provider(self, virtual):
raise RuntimeError("No provider for virtual %s" % virtual)
def multiple_providers(self, virtual, provider1, provider2):
raise spack.error.SpackError("Multiple providers")
def invalid_external_spec(self, pkg):
raise spack.error.SpecError("Invalid external spec")
def inactive_variant_set(self, pkg, variant):
raise spack.error.SpackError("Cannot set conditional variant %s for package %s that cannot be satisfied" % (variant, pkg))
def disjoint_variant_values(self, pkg, variant, value1, value2):
msg = "%s variant %s cannot have both values %s and %s, as they come from disjoing value sets" % (pkg, variant, value1, value2)
raise spack.error.SpackError(msg)
def variant_none_and_other(self, pkg, variant, value):
msg = "%s variant %s cannot have values %s and 'none'" % (pkg, variant, value)
raise spack.error.SpackError(msg)
def no_os(self, pkg):
raise spack.error.SpackError("No os for %s" % pkg)
def multiple_os(self, pkg, os1, os2):
msg = "Multiple OS for %s: %s and %s" % (pkg, os1, os2)
raise spack.error.SpackError(msg)
def os_not_buildable(self, pkg, os1):
msg = "%s os %s is not buildable" % (pkg, os1)
raise spack.error.SpackError(msg)
def os_incompatible(self, pkg, dep, p_os, d_os):
msg = "%s and dependency %s have incompatible OSs %s and %s" % (pkg, dep, p_os, d_os)
raise spack.error.SpackError(msg)
def no_target(self, pkg):
raise spack.error.SpackError("%s has no target" % pkg)
def multiple_targets(self, pkg, target1, target2):
msg = "%s has multiple targets, %s and %s" % (pkg, target1, target2)
raise spack.error.SpackError(msg)
def target_unsatisfiable(self, pkg, target, constraint):
msg = "%s target cannot satisfy constraint %s" % (pkg, constraint)
raise spack.error.SpackError(msg)
def target_incompatible(self, pkg, dep):
msg = "No compatible targets possible for %s and %s" % (pkg, dep)
raise spack.error.SpackError(msg)
def compiler_target_mismatch(self, pkg, target, compiler, version):
msg = "%s compiler %s@%s incompatible with target %s"
raise spack.error.SpackError(msg)
def invalid_target(self, pkg, target):
msg = "%s target %s is not compatible with this machine" % (pkg, target)
raise spack.error.SpackError(msg)
def no_compiler_version(self, pkg):
raise spack.error.SpackError("%s has no compiler version" % pkg)
def multiple_compiler_versions(self, pkg, compiler1, ver1, compiler2, ver2):
msg = "%s compilers %s@%s and %s@%s incompatible" % (pkg, compiler1, ver1, compiler2, ver2)
raise spack.error.SpackError(msg)
def compiler_os_mismatch(self, pkg, compiler, version, os):
msg = "%s compiler %s@%s incompatible with os %s" % (pkg, compiler, version, os)
raise spack.error.SpackError(msg)
def variant_value(self, pkg, name, value):
# FIXME: is there a way not to special case 'dev_path' everywhere?
if name == 'dev_path':
@@ -2080,6 +2188,9 @@ def build_specs(self, function_tuples):
# them here so that directives that build objects (like node and
# node_compiler) are called in the right order.
function_tuples.sort(key=lambda f: {
"conflict_triggered": -4,
"multiple_values_sv_variant": -4,
"no_variant_value": -4,
"hash": -3,
"node": -2,
"node_compiler": -1,
@@ -2091,7 +2202,6 @@ def build_specs(self, function_tuples):
continue
action = getattr(self, name, None)
# print out unknown actions so we can display them for debugging
if not action:
msg = "%s(%s)" % (name, ", ".join(str(a) for a in args))
@@ -2103,7 +2213,7 @@ def build_specs(self, function_tuples):
# ignore predicates on virtual packages, as they're used for
# solving but don't construct anything
pkg = args[0]
if spack.repo.path.is_virtual(pkg):
if spack.repo.path.is_virtual(pkg) and name not in ("no_provider", "multiple_providers"):
continue
# if we've already gotten a concrete spec for this pkg,

View File

@@ -12,7 +12,7 @@
%-----------------------------------------------------------------------------
% each node must have a single version
:- not 1 { version(Package, _) } 1, node(Package).
%:- not 1 { version(Package, _) } 1, node(Package).
% each node must have a single platform, os and target
:- not 1 { node_platform(Package, _) } 1, node(Package), internal_error("A node must have exactly one platform").
@@ -48,8 +48,14 @@ version_declared(Package, Version) :- version_declared(Package, Version, _).
% If something is a package, it has only one version and that must be a
% declared version.
1 { version(Package, Version) : version_declared(Package, Version) } 1
:- node(Package), error("Each node must have exactly one version").
{ version(Package, Version) : version_declared(Package, Version) }
:- node(Package).%, error("Each node must have exactly one version").
versions_conflict(Package, Version1, Version2)
:- node(Package),
version(Package, Version1),
version(Package, Version2),
Version1 < Version2. % WLOG
no_version(Package) :- node(Package), not version(Package, _).
% A virtual package may have or not a version, but never has more than one
:- virtual_node(Package), 2 { version(Package, _) }.
@@ -65,14 +71,22 @@ possible_version_weight(Package, Weight)
% node_version_satisfies implies that exactly one of the satisfying versions
% is the package's version, and vice versa.
1 { version(Package, Version) : version_satisfies(Package, Constraint, Version) } 1
{ version(Package, Version) : version_satisfies(Package, Constraint, Version) }
:- node_version_satisfies(Package, Constraint).
%error("no version satisfies the given constraints").
version_unsatisfiable(Package, Constraint)
:- node_version_satisfies(Package, Constraint),
error("no version satisfies the given constraints").
C = #count{ Version : version(Package, Version), version_satisfies(Package, Constraint, Version)},
C < 1.
node_version_satisfies(Package, Constraint)
:- version(Package, Version), version_satisfies(Package, Constraint, Version).
#defined version_satisfies/3.
#defined deprecated_version/2.
#defined version_unsatisfiable/2.
#defined versions_conflict/3.
#defined no_version/1.
%-----------------------------------------------------------------------------
% Spec conditions and imposed constraints
@@ -165,32 +179,33 @@ node(Dependency) :- node(Package), depends_on(Package, Dependency).
% dependencies) and get a two-node unconnected graph
needed(Package) :- root(Package).
needed(Dependency) :- needed(Package), depends_on(Package, Dependency).
:- node(Package), not needed(Package),
error("All dependencies must be reachable from root").
unnecessary(Package) :- node(Package), not needed(Package).
% error("All dependencies must be reachable from root").
% Avoid cycles in the DAG
% some combinations of conditional dependencies can result in cycles;
% this ensures that we solve around them
path(Parent, Child) :- depends_on(Parent, Child).
path(Parent, Descendant) :- path(Parent, A), depends_on(A, Descendant).
:- path(A, B), path(B, A), error("Cyclic dependencies are not allowed").
cyclic_dependency(A, B) :- path(A, B), path(B, A).%, error("Cyclic dependencies are not allowed").
#defined error/1.
#defined unnecessary/1.
#defined cyclic_dependency/2.
#defined dependency_type/2.
#defined dependency_condition/3.
%-----------------------------------------------------------------------------
% Conflicts
%-----------------------------------------------------------------------------
:- node(Package),
conflict_triggered(Msg) :- node(Package),
conflict(Package, TriggerID, ConstraintID, Msg),
condition_holds(TriggerID),
condition_holds(ConstraintID),
not external(Package), % ignore conflicts for externals
error("A conflict was triggered").
not external(Package). % ignore conflicts for externals
#defined conflict/4.
#defined conflict_triggered/1.
%-----------------------------------------------------------------------------
% Virtual dependencies
@@ -210,8 +225,17 @@ virtual_node(Virtual)
% If there's a virtual node, we must select one and only one provider.
% The provider must be selected among the possible providers.
1 { provider(Package, Virtual) : possible_provider(Package, Virtual) } 1
:- virtual_node(Virtual), error("Virtual packages must be satisfied by a unique provider").
{ provider(Package, Virtual) : possible_provider(Package, Virtual) }
:- virtual_node(Virtual).%, error("Virtual packages must be satisfied by a unique provider").
no_provider(Virtual)
:- virtual_node(Virtual),
P = #count{ Package : provider(Package, Virtual)},
P < 1.
multiple_providers(Virtual, P1, P2)
:- virtual_node(Virtual),
provider(P1, Virtual),
provider(P2, Virtual),
P1 < P2.
% virtual roots imply virtual nodes, and that one provider is a root
virtual_node(Virtual) :- virtual_root(Virtual).
@@ -351,9 +375,17 @@ attr("node_compiler_version_satisfies", Package, Compiler, Version)
%-----------------------------------------------------------------------------
% if a package is external its version must be one of the external versions
1 { external_version(Package, Version, Weight):
version_declared(Package, Version, Weight, "external") } 1
:- external(Package), error("External package version does not satisfy external spec").
{ external_version(Package, Version, Weight):
version_declared(Package, Version, Weight, "external") }
:- external(Package).%, error("External package version does not satisfy external spec").
invalid_external_spec(Package)
:- external(Package),
not external_version(Package, _, _).
invalid_external_spec(Package)
:- external(Package),
external_version(Package, Version1, Weight1),
external_version(Package, Version2, Weight2),
(Version1, Weight1) < (Version2, Weight2). % WLOG
version_weight(Package, Weight) :- external_version(Package, Version, Weight).
version(Package, Version) :- external_version(Package, Version, Weight).
@@ -385,8 +417,8 @@ external_conditions_hold(Package, LocalIndex) :-
% it cannot happen that a spec is external, but none of the external specs
% conditions hold.
:- external(Package), not external_conditions_hold(Package, _),
error("External package does not satisfy external spec").
invalid_external_spec(Package) :- external(Package), not external_conditions_hold(Package, _).%,
% error("External package does not satisfy external spec").
#defined possible_external/3.
#defined external_spec_index/3.
@@ -403,16 +435,18 @@ variant(Package, Variant) :- variant_condition(ID, Package, Variant),
condition_holds(ID).
% a variant cannot be set if it is not a variant on the package
:- variant_set(Package, Variant),
not variant(Package, Variant),
build(Package),
error("Unsatisfied conditional variants cannot be set").
inactive_variant_set(Package, Variant)
:- variant_set(Package, Variant),
not variant(Package, Variant),
build(Package).
% error("Unsatisfied conditional variants cannot be set").
% a variant cannot take on a value if it is not a variant of the package
:- variant_value(Package, Variant, _),
not variant(Package, Variant),
build(Package),
error("Unsatisfied conditional variants cannot take on a variant value").
inactive_variant_set(Package, Variant)
:- variant_value(Package, Variant, _),
not variant(Package, Variant),
build(Package).
% error("Unsatisfied conditional variants cannot take on a variant value").
% if a variant is sticky and not set its value is the default value
variant_value(Package, Variant, Value) :-
@@ -426,22 +460,25 @@ variant_value(Package, Variant, Value) :-
{
variant_value(Package, Variant, Value)
: variant_possible_value(Package, Variant, Value)
} 1
:- node(Package),
variant(Package, Variant),
variant_single_value(Package, Variant),
build(Package),
error("Single valued variants must have a single value").
% at least one variant value.
1 {
variant_value(Package, Variant, Value)
: variant_possible_value(Package, Variant, Value)
}
:- node(Package),
variant(Package, Variant),
build(Package),
internal_error("All variants must have a value").
build(Package).
% error("Single valued variants must have a single value").
multiple_values_sv_variant(Package, Variant, Value1, Value2)
:- node(Package),
variant(Package, Variant),
variant_single_value(Package, Variant),
build(Package),
variant_value(Package, Variant, Value1),
variant_value(Package, Variant, Value2),
Value1 < Value2. % WLOG
no_variant_value(Package, Variant)
:- node(Package),
variant(Package, Variant),
build(Package),
C = #count{ Value : variant_value(Package, Variant, Value) },
C < 1.
% if a variant is set to anything, it is considered 'set'.
variant_set(Package, Variant) :- variant_set(Package, Variant, _).
@@ -449,21 +486,23 @@ variant_set(Package, Variant) :- variant_set(Package, Variant, _).
% A variant cannot have a value that is not also a possible value
% This only applies to packages we need to build -- concrete packages may
% have been built w/different variants from older/different package versions.
:- variant_value(Package, Variant, Value),
not variant_possible_value(Package, Variant, Value),
build(Package),
error("Variant set to invalid value").
invalid_variant_value(Package, Variant, Value)
:- variant_value(Package, Variant, Value),
not variant_possible_value(Package, Variant, Value),
build(Package).
%error("Variant set to invalid value").
% Some multi valued variants accept multiple values from disjoint sets.
% Ensure that we respect that constraint and we don't pick values from more
% than one set at once
:- variant_value(Package, Variant, Value1),
variant_value(Package, Variant, Value2),
variant_value_from_disjoint_sets(Package, Variant, Value1, Set1),
variant_value_from_disjoint_sets(Package, Variant, Value2, Set2),
Set1 < Set2,
build(Package),
error("Variant values selected from multiple disjoint sets").
disjoint_variant_values(Package, Variant, Value1, Value2)
:- variant_value(Package, Variant, Value1),
variant_value(Package, Variant, Value2),
variant_value_from_disjoint_sets(Package, Variant, Value1, Set1),
variant_value_from_disjoint_sets(Package, Variant, Value2, Set2),
Set1 < Set2,
build(Package).
%error("Variant values selected from multiple disjoint sets").
% variant_set is an explicitly set variant value. If it's not 'set',
% we revert to the default value. If it is set, we force the set value
@@ -521,12 +560,11 @@ variant_default_value(Package, Variant, Value) :- variant_default_value_from_cli
% Treat 'none' in a special way - it cannot be combined with other
% values even if the variant is multi-valued
:- 2 {
variant_value(Package, Variant, Value) : variant_possible_value(Package, Variant, Value)
},
variant_value(Package, Variant, "none"),
build(Package),
error("Variant value 'none' cannot be combined with any other value").
variant_none_and_other(Package, Variant, Value)
:- variant_value(Package, Variant, Value),
variant_value(Package, Variant, "none"),
Value != "none",
build(Package).
% patches and dev_path are special variants -- they don't have to be
% declared in the package, so we just allow them to spring into existence
@@ -552,6 +590,9 @@ variant_single_value(Package, "dev_path")
#defined variant_default_value_from_packages_yaml/3.
#defined variant_default_value_from_package_py/3.
#defined variant_value_from_disjoint_sets/4.
#defined invalid_variant_value/3.
#defined multiple_values_sv_variant/4.
#defined no_variant_value/2.
%-----------------------------------------------------------------------------
% Platform semantics
@@ -579,20 +620,26 @@ node_platform_set(Package) :- node_platform_set(Package, _).
os(OS) :- os(OS, _).
% one os per node
1 { node_os(Package, OS) : os(OS) } 1 :-
node(Package), error("Each node must have exactly one OS").
{ node_os(Package, OS) : os(OS) } :- node(Package).%, error("Each node must have exactly one OS").
no_os(Package) :- node(Package), C = #count{ OS : node_os(Package, OS)}, C < 1.
multiple_os(Package, OS1, OS2)
:- node(Package),
node_os(Package, OS1),
node_os(Package, OS2),
OS1 < OS2.
% can't have a non-buildable OS on a node we need to build
:- build(Package), node_os(Package, OS), not buildable_os(OS),
error("No available OS can be built for").
os_not_buildable(Package, OS) :- build(Package), node_os(Package, OS), not buildable_os(OS).
% error("No available OS can be built for").
% can't have dependencies on incompatible OS's
:- depends_on(Package, Dependency),
node_os(Package, PackageOS),
node_os(Dependency, DependencyOS),
not os_compatible(PackageOS, DependencyOS),
build(Package),
error("Dependencies must have compatible OS's with their dependents").
os_incompatible(Package, Dependency, PackageOS, DependencyOS)
:- depends_on(Package, Dependency),
node_os(Package, PackageOS),
node_os(Dependency, DependencyOS),
not os_compatible(PackageOS, DependencyOS),
build(Package).
%error("Dependencies must have compatible OS's with their dependents").
% give OS choice weights according to os declarations
node_os_weight(Package, Weight)
@@ -624,14 +671,20 @@ node_os(Package, OS) :- node_os_set(Package, OS), node(Package).
%-----------------------------------------------------------------------------
% Each node has only one target chosen among the known targets
1 { node_target(Package, Target) : target(Target) } 1 :- node(Package), error("Each node must have exactly one target").
{ node_target(Package, Target) : target(Target) } :- node(Package).%, error("Each node must have exactly one target").
no_target(Package) :- node(Package), C = #count{Target : node_target(Package, Target)}, C < 1.
multiple_targets(Package, Target1, Target2)
:- node(Package),
node_target(Package, Target1),
node_target(Package, Target2),
Target1 < Target2.
% If a node must satisfy a target constraint, enforce it
:- node_target(Package, Target),
node_target_satisfies(Package, Constraint),
not target_satisfies(Constraint, Target),
error("Node targets must satisfy node target constraints").
target_unsatisfiable(Package, Target, Constraint)
:- node_target(Package, Target),
node_target_satisfies(Package, Constraint),
not target_satisfies(Constraint, Target).
% error("Node targets must satisfy node target constraints").
% If a node has a target and the target satisfies a constraint, then the target
% associated with the node satisfies the same constraint
@@ -639,10 +692,11 @@ node_target_satisfies(Package, Constraint)
:- node_target(Package, Target), target_satisfies(Constraint, Target).
% If a node has a target, all of its dependencies must be compatible with that target
:- depends_on(Package, Dependency),
node_target(Package, Target),
not node_target_compatible(Dependency, Target),
error("Dependency node targets must be compatible with dependent targets").
target_incompatible(Package, Dependency)
:- depends_on(Package, Dependency),
node_target(Package, Target),
not node_target_compatible(Dependency, Target).
% error("Dependency node targets must be compatible with dependent targets").
% Intermediate step for performance reasons
% When the integrity constraint above was formulated including this logic
@@ -683,12 +737,13 @@ target_weight(Target, Package, Weight)
:- package_target_weight(Target, Package, Weight).
% can't use targets on node if the compiler for the node doesn't support them
:- node_target(Package, Target),
not compiler_supports_target(Compiler, Version, Target),
node_compiler(Package, Compiler),
node_compiler_version(Package, Compiler, Version),
build(Package),
error("No satisfying compiler available is compatible with a satisfying target").
compiler_target_mismatch(Package, Target, Compiler, Version)
:- node_target(Package, Target),
not compiler_supports_target(Compiler, Version, Target),
node_compiler(Package, Compiler),
node_compiler_version(Package, Compiler, Version),
build(Package).
%error("No satisfying compiler available is compatible with a satisfying target").
% if a target is set explicitly, respect it
node_target(Package, Target)
@@ -715,8 +770,11 @@ node_target_mismatch(Parent, Dependency)
not node_target_match(Parent, Dependency).
% disallow reusing concrete specs that don't have a compatible target
:- node(Package), node_target(Package, Target), not target(Target),
error("No satisfying package's target is compatible with this machine").
invalid_target(Package, Target)
:- node(Package),
node_target(Package, Target),
not target(Target).
% error("No satisfying package's target is compatible with this machine").
#defined node_target_set/2.
#defined package_target_weight/3.
@@ -728,10 +786,21 @@ compiler(Compiler) :- compiler_version(Compiler, _).
% There must be only one compiler set per built node. The compiler
% is chosen among available versions.
1 { node_compiler_version(Package, Compiler, Version) : compiler_version(Compiler, Version) } 1 :-
{ node_compiler_version(Package, Compiler, Version) : compiler_version(Compiler, Version) } :-
node(Package),
build(Package),
error("Each node must have exactly one compiler").
build(Package).
% error("Each node must have exactly one compiler").
no_compiler_version(Package)
:- node(Package),
build(Package),
C = #count{ Version : node_compiler_version(Package, _, Version)},
C < 1.
multiple_compiler_versions(Package, Compiler1, Version1, Compiler2, Version2)
:- node(Package),
build(Package),
node_compiler_version(Package, Compiler1, Version1),
node_compiler_version(Package, Compiler2, Version2),
(Compiler1, Version1) < (Compiler2, Version2).
% Sometimes we just need to know the compiler and not the version
node_compiler(Package, Compiler) :- node_compiler_version(Package, Compiler, _).
@@ -765,11 +834,13 @@ node_compiler_version(Package, Compiler, Version) :- node_compiler_version_set(P
% Cannot select a compiler if it is not supported on the OS
% Compilers that are explicitly marked as allowed
% are excluded from this check
:- node_compiler_version(Package, Compiler, Version), node_os(Package, OS),
not compiler_supports_os(Compiler, Version, OS),
not allow_compiler(Compiler, Version),
build(Package),
error("No satisfying compiler available is compatible with a satisfying os").
compiler_os_mismatch(Package, Compiler, Version, OS)
:- node_compiler_version(Package, Compiler, Version),
node_os(Package, OS),
not compiler_supports_os(Compiler, Version, OS),
not allow_compiler(Compiler, Version),
build(Package).
% error("No satisfying compiler available is compatible with a satisfying os").
% If a package and one of its dependencies don't have the
% same compiler there's a mismatch.
@@ -912,6 +983,124 @@ build_priority(Package, 0) :- node(Package), not optimize_for_reuse().
#defined installed_hash/2.
%-----------------------------------------------------------------
% Optimization to avoid errors
%-----------------------------------------------------------------
% Some errors are handled as rules instead of constraints because
% it allows us to explain why something failed. Here we optimize
% HEAVILY against the facts generated by those rules.
opt_criterion(1000, "errors").
#minimize{ 0@1000: #true }.
#minimize{ 1000@1000,Msg: conflict_triggered(Msg) }.
opt_criterion(1001, "errors").
#minimize{ 0@1001: #true }.
#minimize{ 1000@1001,Package,Variant,Value1,Value2: multiple_values_sv_variant(Package, Variant, Value1, Value2) }.
opt_criterion(1002, "errors").
#minimize{ 0@1002: #true }.
#minimize{ 1000@1002,Package,Variant: no_variant_value(Package, Variant) }.
opt_criterion(1003, "errors").
#minimize{ 0@1003: #true }.
#minimize{ 1000@1003,Package,Variant,Value: invalid_variant_value(Package, Variant, Value) }.
opt_criterion(1004, "errors").
#minimize{ 0@1004: #true }.
#minimize{ 1000@1004,Package : no_version(Package) }.
opt_criterion(1005, "errors").
#minimize{ 0@1005: #true }.
#minimize{ 1000@1005,Package,Version1,Version2 : versions_conflict(Package, Version1, Version2) }.
opt_criterion(1006, "errors").
#minimize{ 0@1006: #true }.
#minimize{ 1000@1006,Package,Constraint : version_unsatisfiable(Package, Constraint) }.
opt_criterion(1007, "errors").
#minimize{ 0@1007: #true }.
#minimize{ 1000@1007,Package : unnecessary(Package) }.
opt_criterion(1008, "errors").
#minimize{ 0@1008: #true }.
#minimize{ 1000@1008,Package1,Package2 : cyclic_dependency(Package1, Package2) }.
opt_criterion(1009, "errors").
#minimize{ 0@1009: #true }.
#minimize{ 1000@1009,Virtual : no_provider(Virtual) }.
opt_criterion(1010, "errors").
#minimize{ 0@1010: #true }.
#minimize{ 1000@1010,Virtual,Package1,Package2 : multiple_providers(Virtual, Package1, Package2) }.
opt_criterion(1011, "errors").
#minimize{ 0@1011: #true }.
#minimize{ 1000@1011,Package : invalid_external_spec(Package) }.
opt_criterion(1012, "errors").
#minimize{ 0@1012: #true }.
#minimize{ 1000@1012,Package,Variant : inactive_variant_set(Package, Variant) }.
opt_criterion(1013, "errors").
#minimize{ 0@1013: #true }.
#minimize{ 1000@1013,Package,Variant,Value1,Value2 : disjoint_variant_values(Package, Variant, Value1, Value2) }.
opt_criterion(1014, "errors").
#minimize{ 0@1014: #true }.
#minimize{ 1000@1014,Package,Variant,Value : variant_none_and_other(Package, Variant, Value) }.
opt_criterion(1015, "errors").
#minimize{ 0@1015: #true }.
#minimize{ 1000@1015,Package : no_os(Package) }.
opt_criterion(1016, "errors").
#minimize{ 0@1016: #true }.
#minimize{ 1000@1016,Package,OS1,OS2 : multiple_os(Package, OS1, OS2) }.
opt_criterion(1017, "errors").
#minimize{ 0@1017: #true }.
#minimize{ 1000@1017,Package,OS : os_not_buildable(Package, OS) }.
opt_criterion(1018, "errors").
#minimize{ 0@1018: #true }.
#minimize{ 1000@1018,Package,Dependency,POS,DOS : os_incompatible(Package, Dependency, POS, DOS) }.
opt_criterion(1019, "errors").
#minimize{ 0@1019: #true }.
#minimize{ 1000@1019,Package : no_target(Package) }.
opt_criterion(1020, "errors").
#minimize{ 0@1020: #true }.
#minimize{ 1000@1020,Package,Target1, Target2 : multiple_targets(Package, Target1, Target2) }.
opt_criterion(1021, "errors").
#minimize{ 0@1021: #true }.
#minimize{ 1000@1021,Package,Target,Constraint : target_unsatisfiable(Package, Target, Constraint) }.
opt_criterion(1022, "errors").
#minimize{ 0@1022: #true }.
#minimize{ 1000@1022,Package,Dependency : target_incompatible(Package, Dependency) }.
opt_criterion(1023, "errors").
#minimize{ 0@1023: #true }.
#minimize{ 1000@1023,Package,Target,Compiler,Version : compiler_target_mismatch(Package, Target, Compiler, Version) }.
opt_criterion(1024, "errors").
#minimize{ 0@1024: #true }.
#minimize{ 1000@1024,Package,Target : invalid_target(Package, Target) }.
opt_criterion(1025, "errors").
#minimize{ 0@1025: #true }.
#minimize{ 1000@1025,Package : no_compiler_version(Package) }.
opt_criterion(1026, "errors").
#minimize{ 0@1026: #true }.
#minimize{ 1000@1026,Package,Compiler1,Version1,Compiler2,Version2 : multiple_compiler_versions(Package, Compiler1, Version1, Compiler2, Version2) }.
opt_criterion(1027, "errors").
#minimize{ 0@1027: #true }.
#minimize{ 1000@1027,Package,Compiler,Version,OS : compiler_os_mismatch(Package, Compiler, Version, OS) }.
%-----------------------------------------------------------------------------
% How to optimize the spec (high to low priority)
%-----------------------------------------------------------------------------

View File

@@ -34,3 +34,35 @@
% deprecated packages
#show deprecated/2.
% error types
#show conflict_triggered/1.
#show no_version/1.
#show versions_conflict/3.
#show no_variant_value/2.
#show multiple_values_sv_variant/4.
#show invalid_variant_value/3.
#show version_unsatisfiable/2.
#show unnecessary/1.
#show cyclic_dependency/2.
#show no_provider/1.
#show multiple_providers/3.
#show invalid_external_spec/1.
#show inactive_variant_set/2.
#show disjoint_variant_values/4.
#show variant_none_and_other/3.
#show no_os/1.
#show multiple_os/3.
#show os_not_buildable/2.
#show os_incompatible/4.
#show no_target/1.
#show multiple_targets/3.
#show target_unsatisfiable/3.
#show target_incompatible/2.
#show compiler_target_mismatch/4.
#show invalid_target/2.
#show no_compiler_version/1.
#show multiple_compiler_versions/5.
#show compiler_os_mismatch/4.
% debug

View File

@@ -645,7 +645,7 @@ def test_conflicts_show_cores(self, conflict_spec, monkeypatch):
with pytest.raises(spack.error.SpackError) as e:
s.concretize()
assert "conflict_trigger(" in e.value.message
assert "conflict" in e.value.message
def test_conflict_in_all_directives_true(self):
s = Spec('when-directives-true')
@@ -862,7 +862,8 @@ def test_conditional_variants(self, spec_str, expected, unexpected):
def test_conditional_variants_fail(self, bad_spec):
with pytest.raises(
(spack.error.UnsatisfiableSpecError,
vt.InvalidVariantForSpecError)
vt.InvalidVariantForSpecError,
spack.error.SpackError)
):
_ = Spec('conditional-variant-pkg' + bad_spec).concretized()
@@ -1435,7 +1436,7 @@ def test_provider_must_meet_requirements(self):
# A package can be a provider of a virtual only if the underlying
# requirements are met.
s = spack.spec.Spec('unsat-virtual-dependency')
with pytest.raises((RuntimeError, spack.error.UnsatisfiableSpecError)):
with pytest.raises((RuntimeError, spack.error.UnsatisfiableSpecError, spack.error.SpackError)):
s.concretize()
@pytest.mark.regression('23951')
@@ -1539,7 +1540,7 @@ def test_conditional_values_in_variants(self, spec_str):
)
s = Spec(spec_str)
with pytest.raises((RuntimeError, spack.error.UnsatisfiableSpecError)):
with pytest.raises((RuntimeError, spack.error.UnsatisfiableSpecError, spack.error.SpackError)):
s.concretize()
def test_conditional_values_in_conditional_variant(self):