ASP: targets, compilers and providers soft-preferences are only global (#31261)
Modify the packages.yaml schema so that soft-preferences on targets, compilers and providers can only be specified under the "all" attribute. This makes them effectively global preferences. Version preferences instead can only be specified under a package specific section. If a preference attribute is found in a section where it should not be, it will be ignored and a warning is printed to screen.
This commit is contained in:
parent
4004f27bc0
commit
f3537bc66b
@ -526,56 +526,52 @@ Package Preferences
|
|||||||
In some cases package requirements can be too strong, and package
|
In some cases package requirements can be too strong, and package
|
||||||
preferences are the better option. Package preferences do not impose
|
preferences are the better option. Package preferences do not impose
|
||||||
constraints on packages for particular versions or variants values,
|
constraints on packages for particular versions or variants values,
|
||||||
they rather only set defaults -- the concretizer is free to change
|
they rather only set defaults. The concretizer is free to change
|
||||||
them if it must due to other constraints. Also note that package
|
them if it must, due to other constraints, and also prefers reusing
|
||||||
preferences are of lower priority than reuse of already installed
|
installed packages over building new ones that are a better match for
|
||||||
packages.
|
preferences.
|
||||||
|
|
||||||
Here's an example ``packages.yaml`` file that sets preferred packages:
|
Most package preferences (``compilers``, ``target`` and ``providers``)
|
||||||
|
can only be set globally under the ``all`` section of ``packages.yaml``:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
packages:
|
||||||
|
all:
|
||||||
|
compiler: [gcc@12.2.0, clang@12:, oneapi@2023:]
|
||||||
|
target: [x86_64_v3]
|
||||||
|
providers:
|
||||||
|
mpi: [mvapich2, mpich, openmpi]
|
||||||
|
|
||||||
|
These preferences override Spack's default and effectively reorder priorities
|
||||||
|
when looking for the best compiler, target or virtual package provider. Each
|
||||||
|
preference takes an ordered list of spec constraints, with earlier entries in
|
||||||
|
the list being preferred over later entries.
|
||||||
|
|
||||||
|
In the example above all packages prefer to be compiled with ``gcc@12.2.0``,
|
||||||
|
to target the ``x86_64_v3`` microarchitecture and to use ``mvapich2`` if they
|
||||||
|
depend on ``mpi``.
|
||||||
|
|
||||||
|
The ``variants`` and ``version`` preferences can be set under
|
||||||
|
package specific sections of the ``packages.yaml`` file:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
opencv:
|
opencv:
|
||||||
compiler: [gcc@4.9]
|
|
||||||
variants: +debug
|
variants: +debug
|
||||||
gperftools:
|
gperftools:
|
||||||
version: [2.2, 2.4, 2.3]
|
version: [2.2, 2.4, 2.3]
|
||||||
all:
|
|
||||||
compiler: [gcc@4.4.7, 'gcc@4.6:', intel, clang, pgi]
|
|
||||||
target: [sandybridge]
|
|
||||||
providers:
|
|
||||||
mpi: [mvapich2, mpich, openmpi]
|
|
||||||
|
|
||||||
At a high level, this example is specifying how packages are preferably
|
In this case, the preference for ``opencv`` is to build with debug options, while
|
||||||
concretized. The opencv package should prefer using GCC 4.9 and
|
``gperftools`` prefers version 2.2 over 2.4.
|
||||||
be built with debug options. The gperftools package should prefer version
|
|
||||||
2.2 over 2.4. Every package on the system should prefer mvapich2 for
|
|
||||||
its MPI and GCC 4.4.7 (except for opencv, which overrides this by preferring GCC 4.9).
|
|
||||||
These options are used to fill in implicit defaults. Any of them can be overwritten
|
|
||||||
on the command line if explicitly requested.
|
|
||||||
|
|
||||||
Package preferences accept the follow keys or components under
|
Any preference can be overwritten on the command line if explicitly requested.
|
||||||
the specific package (or ``all``) section: ``compiler``, ``variants``,
|
|
||||||
``version``, ``providers``, and ``target``. Each component has an
|
|
||||||
ordered list of spec ``constraints``, with earlier entries in the
|
|
||||||
list being preferred over later entries.
|
|
||||||
|
|
||||||
Sometimes a package installation may have constraints that forbid
|
Preferences cannot overcome explicit constraints, as they only set a preferred
|
||||||
the first concretization rule, in which case Spack will use the first
|
ordering among homogeneous attribute values. Going back to the example, if
|
||||||
legal concretization rule. Going back to the example, if a user
|
``gperftools@2.3:`` was requested, then Spack will install version 2.4
|
||||||
requests gperftools 2.3 or later, then Spack will install version 2.4
|
since the most preferred version 2.2 is prohibited by the version constraint.
|
||||||
as the 2.4 version of gperftools is preferred over 2.3.
|
|
||||||
|
|
||||||
An explicit concretization rule in the preferred section will always
|
|
||||||
take preference over unlisted concretizations. In the above example,
|
|
||||||
xlc isn't listed in the compiler list. Every listed compiler from
|
|
||||||
gcc to pgi will thus be preferred over the xlc compiler.
|
|
||||||
|
|
||||||
The syntax for the ``provider`` section differs slightly from other
|
|
||||||
concretization rules. A provider lists a value that packages may
|
|
||||||
``depends_on`` (e.g, MPI) and a list of rules for fulfilling that
|
|
||||||
dependency.
|
|
||||||
|
|
||||||
.. _package_permissions:
|
.. _package_permissions:
|
||||||
|
|
||||||
|
@ -407,7 +407,9 @@ def config_prefer_upstream(args):
|
|||||||
pkgs = {}
|
pkgs = {}
|
||||||
for spec in pref_specs:
|
for spec in pref_specs:
|
||||||
# Collect all the upstream compilers and versions for this package.
|
# Collect all the upstream compilers and versions for this package.
|
||||||
pkg = pkgs.get(spec.name, {"version": [], "compiler": []})
|
pkg = pkgs.get(spec.name, {"version": []})
|
||||||
|
all = pkgs.get("all", {"compiler": []})
|
||||||
|
pkgs["all"] = all
|
||||||
pkgs[spec.name] = pkg
|
pkgs[spec.name] = pkg
|
||||||
|
|
||||||
# We have no existing variant if this is our first added version.
|
# We have no existing variant if this is our first added version.
|
||||||
@ -418,8 +420,8 @@ def config_prefer_upstream(args):
|
|||||||
pkg["version"].append(version)
|
pkg["version"].append(version)
|
||||||
|
|
||||||
compiler = str(spec.compiler)
|
compiler = str(spec.compiler)
|
||||||
if compiler not in pkg["compiler"]:
|
if compiler not in all["compiler"]:
|
||||||
pkg["compiler"].append(compiler)
|
all["compiler"].append(compiler)
|
||||||
|
|
||||||
# Get and list all the variants that differ from the default.
|
# Get and list all the variants that differ from the default.
|
||||||
variants = []
|
variants = []
|
||||||
|
@ -8,6 +8,66 @@
|
|||||||
:lines: 13-
|
:lines: 13-
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
permissions = {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
"properties": {
|
||||||
|
"read": {"type": "string", "enum": ["user", "group", "world"]},
|
||||||
|
"write": {"type": "string", "enum": ["user", "group", "world"]},
|
||||||
|
"group": {"type": "string"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
variants = {"oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}]}
|
||||||
|
|
||||||
|
requirements = {
|
||||||
|
"oneOf": [
|
||||||
|
# 'require' can be a list of requirement_groups.
|
||||||
|
# each requirement group is a list of one or more
|
||||||
|
# specs. Either at least one or exactly one spec
|
||||||
|
# in the group must be satisfied (depending on
|
||||||
|
# whether you use "any_of" or "one_of",
|
||||||
|
# repectively)
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
"properties": {
|
||||||
|
"one_of": {"type": "array", "items": {"type": "string"}},
|
||||||
|
"any_of": {"type": "array", "items": {"type": "string"}},
|
||||||
|
"spec": {"type": "string"},
|
||||||
|
"message": {"type": "string"},
|
||||||
|
"when": {"type": "string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{"type": "string"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# Shorthand for a single requirement group with
|
||||||
|
# one member
|
||||||
|
{"type": "string"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
permissions = {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
"properties": {
|
||||||
|
"read": {"type": "string", "enum": ["user", "group", "world"]},
|
||||||
|
"write": {"type": "string", "enum": ["user", "group", "world"]},
|
||||||
|
"group": {"type": "string"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
package_attributes = {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": False,
|
||||||
|
"patternProperties": {r"\w+": {}},
|
||||||
|
}
|
||||||
|
|
||||||
#: Properties for inclusion in other schemas
|
#: Properties for inclusion in other schemas
|
||||||
properties = {
|
properties = {
|
||||||
@ -15,57 +75,14 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"default": {},
|
"default": {},
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
"patternProperties": {
|
"properties": {
|
||||||
r"\w[\w-]*": { # package name
|
"all": { # package name
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"default": {},
|
"default": {},
|
||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
"properties": {
|
"properties": {
|
||||||
"require": {
|
"require": requirements,
|
||||||
"oneOf": [
|
"version": {}, # Here only to warn users on ignored properties
|
||||||
# 'require' can be a list of requirement_groups.
|
|
||||||
# each requirement group is a list of one or more
|
|
||||||
# specs. Either at least one or exactly one spec
|
|
||||||
# in the group must be satisfied (depending on
|
|
||||||
# whether you use "any_of" or "one_of",
|
|
||||||
# repectively)
|
|
||||||
{
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": False,
|
|
||||||
"properties": {
|
|
||||||
"one_of": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {"type": "string"},
|
|
||||||
},
|
|
||||||
"any_of": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {"type": "string"},
|
|
||||||
},
|
|
||||||
"spec": {"type": "string"},
|
|
||||||
"message": {"type": "string"},
|
|
||||||
"when": {"type": "string"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{"type": "string"},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
# Shorthand for a single requirement group with
|
|
||||||
# one member
|
|
||||||
{"type": "string"},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "array",
|
|
||||||
"default": [],
|
|
||||||
# version strings (type should be string, number is still possible
|
|
||||||
# but deprecated. this is to avoid issues with e.g. 3.10 -> 3.1)
|
|
||||||
"items": {"anyOf": [{"type": "string"}, {"type": "number"}]},
|
|
||||||
},
|
|
||||||
"target": {
|
"target": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"default": [],
|
"default": [],
|
||||||
@ -78,22 +95,10 @@
|
|||||||
"items": {"type": "string"},
|
"items": {"type": "string"},
|
||||||
}, # compiler specs
|
}, # compiler specs
|
||||||
"buildable": {"type": "boolean", "default": True},
|
"buildable": {"type": "boolean", "default": True},
|
||||||
"permissions": {
|
"permissions": permissions,
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": False,
|
|
||||||
"properties": {
|
|
||||||
"read": {"type": "string", "enum": ["user", "group", "world"]},
|
|
||||||
"write": {"type": "string", "enum": ["user", "group", "world"]},
|
|
||||||
"group": {"type": "string"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
# If 'get_full_repo' is promoted to a Package-level
|
# If 'get_full_repo' is promoted to a Package-level
|
||||||
# attribute, it could be useful to set it here
|
# attribute, it could be useful to set it here
|
||||||
"package_attributes": {
|
"package_attributes": package_attributes,
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": False,
|
|
||||||
"patternProperties": {r"\w+": {}},
|
|
||||||
},
|
|
||||||
"providers": {
|
"providers": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"default": {},
|
"default": {},
|
||||||
@ -106,12 +111,40 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"variants": {
|
"variants": variants,
|
||||||
"oneOf": [
|
},
|
||||||
{"type": "string"},
|
"deprecatedProperties": {
|
||||||
{"type": "array", "items": {"type": "string"}},
|
"properties": ["version"],
|
||||||
]
|
"message": "setting version preferences in the 'all' section of packages.yaml "
|
||||||
|
"is deprecated and will be removed in v0.22\n\n\tThese preferences "
|
||||||
|
"will be ignored by Spack. You can set them only in package specific sections "
|
||||||
|
"of the same file.\n",
|
||||||
|
"error": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patternProperties": {
|
||||||
|
r"(?!^all$)(^\w[\w-]*)": { # package name
|
||||||
|
"type": "object",
|
||||||
|
"default": {},
|
||||||
|
"additionalProperties": False,
|
||||||
|
"properties": {
|
||||||
|
"require": requirements,
|
||||||
|
"version": {
|
||||||
|
"type": "array",
|
||||||
|
"default": [],
|
||||||
|
# version strings
|
||||||
|
"items": {"anyOf": [{"type": "string"}, {"type": "number"}]},
|
||||||
},
|
},
|
||||||
|
"target": {}, # Here only to warn users on ignored properties
|
||||||
|
"compiler": {}, # Here only to warn users on ignored properties
|
||||||
|
"buildable": {"type": "boolean", "default": True},
|
||||||
|
"permissions": permissions,
|
||||||
|
# If 'get_full_repo' is promoted to a Package-level
|
||||||
|
# attribute, it could be useful to set it here
|
||||||
|
"package_attributes": package_attributes,
|
||||||
|
"providers": {}, # Here only to warn users on ignored properties
|
||||||
|
"variants": variants,
|
||||||
"externals": {
|
"externals": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@ -127,6 +160,14 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"deprecatedProperties": {
|
||||||
|
"properties": ["target", "compiler", "providers"],
|
||||||
|
"message": "setting compiler, target or provider preferences in a package "
|
||||||
|
"specific section of packages.yaml is deprecated, and will be removed in "
|
||||||
|
"v0.22.\n\n\tThese preferences will be ignored by Spack. You "
|
||||||
|
"can set them only in the 'all' section of the same file.\n",
|
||||||
|
"error": False,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1258,32 +1258,9 @@ def compiler_facts(self):
|
|||||||
matches = sorted(indexed_possible_compilers, key=lambda x: ppk(x[1].spec))
|
matches = sorted(indexed_possible_compilers, key=lambda x: ppk(x[1].spec))
|
||||||
|
|
||||||
for weight, (compiler_id, cspec) in enumerate(matches):
|
for weight, (compiler_id, cspec) in enumerate(matches):
|
||||||
f = fn.default_compiler_preference(compiler_id, weight)
|
f = fn.compiler_weight(compiler_id, weight)
|
||||||
self.gen.fact(f)
|
self.gen.fact(f)
|
||||||
|
|
||||||
def package_compiler_defaults(self, pkg):
|
|
||||||
"""Facts about packages' compiler prefs."""
|
|
||||||
|
|
||||||
packages = spack.config.get("packages")
|
|
||||||
pkg_prefs = packages.get(pkg.name)
|
|
||||||
if not pkg_prefs or "compiler" not in pkg_prefs:
|
|
||||||
return
|
|
||||||
|
|
||||||
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=lambda x: ppk(x.spec))
|
|
||||||
|
|
||||||
for i, compiler in enumerate(reversed(matches)):
|
|
||||||
self.gen.fact(
|
|
||||||
fn.pkg_fact(
|
|
||||||
pkg.name,
|
|
||||||
fn.node_compiler_preference(
|
|
||||||
compiler.spec.name, compiler.spec.version, -i * 100
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def package_requirement_rules(self, pkg):
|
def package_requirement_rules(self, pkg):
|
||||||
rules = self.requirement_rules_from_package_py(pkg)
|
rules = self.requirement_rules_from_package_py(pkg)
|
||||||
rules.extend(self.requirement_rules_from_packages_yaml(pkg))
|
rules.extend(self.requirement_rules_from_packages_yaml(pkg))
|
||||||
@ -1375,9 +1352,6 @@ def pkg_rules(self, pkg, tests):
|
|||||||
# conflicts
|
# conflicts
|
||||||
self.conflict_rules(pkg)
|
self.conflict_rules(pkg)
|
||||||
|
|
||||||
# default compilers for this package
|
|
||||||
self.package_compiler_defaults(pkg)
|
|
||||||
|
|
||||||
# virtuals
|
# virtuals
|
||||||
self.package_provider_rules(pkg)
|
self.package_provider_rules(pkg)
|
||||||
|
|
||||||
@ -1673,6 +1647,7 @@ def virtual_preferences(self, pkg_name, func):
|
|||||||
for i, provider in enumerate(providers):
|
for i, provider in enumerate(providers):
|
||||||
provider_name = spack.spec.Spec(provider).name
|
provider_name = spack.spec.Spec(provider).name
|
||||||
func(vspec, provider_name, i)
|
func(vspec, provider_name, i)
|
||||||
|
self.gen.newline()
|
||||||
|
|
||||||
def provider_defaults(self):
|
def provider_defaults(self):
|
||||||
self.gen.h2("Default virtual providers")
|
self.gen.h2("Default virtual providers")
|
||||||
@ -1865,8 +1840,8 @@ def preferred_variants(self, pkg_name):
|
|||||||
fn.variant_default_value_from_packages_yaml(pkg_name, variant.name, value)
|
fn.variant_default_value_from_packages_yaml(pkg_name, variant.name, value)
|
||||||
)
|
)
|
||||||
|
|
||||||
def target_preferences(self, pkg_name):
|
def target_preferences(self):
|
||||||
key_fn = spack.package_prefs.PackagePrefs(pkg_name, "target")
|
key_fn = spack.package_prefs.PackagePrefs("all", "target")
|
||||||
|
|
||||||
if not self.target_specs_cache:
|
if not self.target_specs_cache:
|
||||||
self.target_specs_cache = [
|
self.target_specs_cache = [
|
||||||
@ -1876,17 +1851,25 @@ def target_preferences(self, pkg_name):
|
|||||||
|
|
||||||
package_targets = self.target_specs_cache[:]
|
package_targets = self.target_specs_cache[:]
|
||||||
package_targets.sort(key=key_fn)
|
package_targets.sort(key=key_fn)
|
||||||
|
|
||||||
offset = 0
|
|
||||||
best_default = self.default_targets[0][1]
|
|
||||||
for i, preferred in enumerate(package_targets):
|
for i, preferred in enumerate(package_targets):
|
||||||
if str(preferred.architecture.target) == best_default and i != 0:
|
self.gen.fact(fn.target_weight(str(preferred.architecture.target), i))
|
||||||
offset = 100
|
|
||||||
self.gen.fact(
|
def flag_defaults(self):
|
||||||
fn.pkg_fact(
|
self.gen.h2("Compiler flag defaults")
|
||||||
pkg_name, fn.target_weight(str(preferred.architecture.target), i + offset)
|
|
||||||
)
|
# 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()
|
||||||
|
for compiler in compilers:
|
||||||
|
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):
|
def spec_clauses(self, *args, **kwargs):
|
||||||
"""Wrap a call to `_spec_clauses()` into a try/except block that
|
"""Wrap a call to `_spec_clauses()` into a try/except block that
|
||||||
@ -2340,6 +2323,8 @@ def target_defaults(self, specs):
|
|||||||
|
|
||||||
self.default_targets = list(sorted(set(self.default_targets)))
|
self.default_targets = list(sorted(set(self.default_targets)))
|
||||||
|
|
||||||
|
self.target_preferences()
|
||||||
|
|
||||||
def virtual_providers(self):
|
def virtual_providers(self):
|
||||||
self.gen.h2("Virtual providers")
|
self.gen.h2("Virtual providers")
|
||||||
msg = (
|
msg = (
|
||||||
@ -2661,7 +2646,6 @@ def setup(
|
|||||||
self.pkg_rules(pkg, tests=self.tests)
|
self.pkg_rules(pkg, tests=self.tests)
|
||||||
self.gen.h2("Package preferences: %s" % pkg)
|
self.gen.h2("Package preferences: %s" % pkg)
|
||||||
self.preferred_variants(pkg)
|
self.preferred_variants(pkg)
|
||||||
self.target_preferences(pkg)
|
|
||||||
|
|
||||||
self.gen.h1("Develop specs")
|
self.gen.h1("Develop specs")
|
||||||
# Inject dev_path from environment
|
# Inject dev_path from environment
|
||||||
|
@ -589,21 +589,15 @@ possible_provider_weight(DependencyNode, VirtualNode, 0, "external")
|
|||||||
:- provider(DependencyNode, VirtualNode),
|
:- provider(DependencyNode, VirtualNode),
|
||||||
external(DependencyNode).
|
external(DependencyNode).
|
||||||
|
|
||||||
% A provider mentioned in packages.yaml can use a weight
|
|
||||||
% according to its priority in the list of providers
|
|
||||||
possible_provider_weight(node(DependencyID, Dependency), node(VirtualID, Virtual), Weight, "packages_yaml")
|
|
||||||
:- provider(node(DependencyID, Dependency), node(VirtualID, Virtual)),
|
|
||||||
depends_on(node(ID, Package), node(DependencyID, Dependency)),
|
|
||||||
pkg_fact(Package, provider_preference(Virtual, Dependency, Weight)).
|
|
||||||
|
|
||||||
% A provider mentioned in the default configuration can use a weight
|
% A provider mentioned in the default configuration can use a weight
|
||||||
% according to its priority in the list of providers
|
% according to its priority in the list of providers
|
||||||
possible_provider_weight(node(DependencyID, Dependency), node(VirtualID, Virtual), Weight, "default")
|
possible_provider_weight(node(ProviderID, Provider), node(VirtualID, Virtual), Weight, "default")
|
||||||
:- provider(node(DependencyID, Dependency), node(VirtualID, Virtual)),
|
:- provider(node(ProviderID, Provider), node(VirtualID, Virtual)),
|
||||||
default_provider_preference(Virtual, Dependency, Weight).
|
default_provider_preference(Virtual, Provider, Weight).
|
||||||
|
|
||||||
% Any provider can use 100 as a weight, which is very high and discourage its use
|
% Any provider can use 100 as a weight, which is very high and discourage its use
|
||||||
possible_provider_weight(node(DependencyID, Dependency), VirtualNode, 100, "fallback") :- provider(node(DependencyID, Dependency), VirtualNode).
|
possible_provider_weight(node(ProviderID, Provider), VirtualNode, 100, "fallback")
|
||||||
|
:- provider(node(ProviderID, Provider), VirtualNode).
|
||||||
|
|
||||||
% do not warn if generated program contains none of these.
|
% do not warn if generated program contains none of these.
|
||||||
#defined virtual/1.
|
#defined virtual/1.
|
||||||
@ -1059,7 +1053,7 @@ attr("node_target", PackageNode, Target)
|
|||||||
node_target_weight(node(ID, Package), Weight)
|
node_target_weight(node(ID, Package), Weight)
|
||||||
:- attr("node", node(ID, Package)),
|
:- attr("node", node(ID, Package)),
|
||||||
attr("node_target", node(ID, Package), Target),
|
attr("node_target", node(ID, Package), Target),
|
||||||
pkg_fact(Package, target_weight(Target, Weight)).
|
target_weight(Target, Weight).
|
||||||
|
|
||||||
% compatibility rules for targets among nodes
|
% compatibility rules for targets among nodes
|
||||||
node_target_match(ParentNode, DependencyNode)
|
node_target_match(ParentNode, DependencyNode)
|
||||||
@ -1181,23 +1175,17 @@ compiler_mismatch_required(PackageNode, DependencyNode)
|
|||||||
#defined allow_compiler/2.
|
#defined allow_compiler/2.
|
||||||
|
|
||||||
% compilers weighted by preference according to packages.yaml
|
% compilers weighted by preference according to packages.yaml
|
||||||
compiler_weight(node(ID, Package), Weight)
|
node_compiler_weight(node(ID, Package), Weight)
|
||||||
:- node_compiler(node(ID, Package), CompilerID),
|
:- node_compiler(node(ID, Package), CompilerID),
|
||||||
compiler_name(CompilerID, Compiler),
|
compiler_name(CompilerID, Compiler),
|
||||||
compiler_version(CompilerID, V),
|
compiler_version(CompilerID, V),
|
||||||
pkg_fact(Package, node_compiler_preference(Compiler, V, Weight)).
|
compiler_weight(CompilerID, Weight).
|
||||||
compiler_weight(node(ID, Package), Weight)
|
|
||||||
|
node_compiler_weight(node(ID, Package), 100)
|
||||||
:- node_compiler(node(ID, Package), CompilerID),
|
:- node_compiler(node(ID, Package), CompilerID),
|
||||||
compiler_name(CompilerID, Compiler),
|
compiler_name(CompilerID, Compiler),
|
||||||
compiler_version(CompilerID, V),
|
compiler_version(CompilerID, V),
|
||||||
not pkg_fact(Package, node_compiler_preference(Compiler, V, _)),
|
not compiler_weight(CompilerID, _).
|
||||||
default_compiler_preference(CompilerID, Weight).
|
|
||||||
compiler_weight(node(ID, Package), 100)
|
|
||||||
:- node_compiler(node(ID, Package), CompilerID),
|
|
||||||
compiler_name(CompilerID, Compiler),
|
|
||||||
compiler_version(CompilerID, V),
|
|
||||||
not pkg_fact(Package, node_compiler_preference(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
|
% For the time being, be strict and reuse only if the compiler match one we have on the system
|
||||||
error(100, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missing_compilers:true if intended.", Package, Compiler, Version)
|
error(100, "Compiler {1}@{2} requested for {0} cannot be found. Set install_missing_compilers:true if intended.", Package, Compiler, Version)
|
||||||
@ -1205,7 +1193,7 @@ error(100, "Compiler {1}@{2} requested for {0} cannot be found. Set install_miss
|
|||||||
not node_compiler(node(ID, Package), _).
|
not node_compiler(node(ID, Package), _).
|
||||||
|
|
||||||
#defined node_compiler_preference/4.
|
#defined node_compiler_preference/4.
|
||||||
#defined default_compiler_preference/3.
|
#defined compiler_weight/3.
|
||||||
|
|
||||||
%-----------------------------------------------------------------------------
|
%-----------------------------------------------------------------------------
|
||||||
% Compiler flags
|
% Compiler flags
|
||||||
@ -1529,7 +1517,7 @@ opt_criterion(15, "non-preferred compilers").
|
|||||||
#minimize{ 0@15: #true }.
|
#minimize{ 0@15: #true }.
|
||||||
#minimize{
|
#minimize{
|
||||||
Weight@15+Priority,PackageNode
|
Weight@15+Priority,PackageNode
|
||||||
: compiler_weight(PackageNode, Weight),
|
: node_compiler_weight(PackageNode, Weight),
|
||||||
build_priority(PackageNode, Priority)
|
build_priority(PackageNode, Priority)
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
#heuristic attr("version", node(0, Package), Version) : pkg_fact(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [35, true]
|
#heuristic attr("version", node(0, Package), Version) : pkg_fact(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [35, true]
|
||||||
#heuristic version_weight(node(0, Package), 0) : pkg_fact(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [35, true]
|
#heuristic version_weight(node(0, Package), 0) : pkg_fact(Package, version_declared(Version, 0)), attr("root", node(0, Package)). [35, true]
|
||||||
#heuristic attr("variant_value", node(0, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("root", node(0, Package)). [35, true]
|
#heuristic attr("variant_value", node(0, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("root", node(0, Package)). [35, true]
|
||||||
#heuristic attr("node_target", node(0, Package), Target) : pkg_fact(Package, target_weight(Target, 0)), attr("root", node(0, Package)). [35, true]
|
#heuristic attr("node_target", node(0, Package), Target) : target_weight(Target, 0), attr("root", node(0, Package)). [35, true]
|
||||||
#heuristic node_target_weight(node(0, Package), 0) : attr("root", node(0, Package)). [35, true]
|
#heuristic node_target_weight(node(0, Package), 0) : attr("root", node(0, Package)). [35, true]
|
||||||
#heuristic node_compiler(node(0, Package), CompilerID) : default_compiler_preference(ID, 0), compiler_id(ID), attr("root", node(0, Package)). [35, true]
|
#heuristic node_compiler(node(0, Package), CompilerID) : compiler_weight(ID, 0), compiler_id(ID), attr("root", node(0, Package)). [35, true]
|
||||||
|
|
||||||
% Providers
|
% Providers
|
||||||
#heuristic attr("node", node(0, Package)) : default_provider_preference(Virtual, Package, 0), possible_in_link_run(Package). [30, true]
|
#heuristic attr("node", node(0, Package)) : default_provider_preference(Virtual, Package, 0), possible_in_link_run(Package). [30, true]
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#heuristic attr("variant_value", node(ID, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
#heuristic attr("variant_value", node(ID, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||||
#heuristic attr("node_target", node(ID, Package), Target) : pkg_fact(Package, target_weight(Target, 0)), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
#heuristic attr("node_target", node(ID, Package), Target) : pkg_fact(Package, target_weight(Target, 0)), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||||
#heuristic node_target_weight(node(ID, Package), 0) : attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
#heuristic node_target_weight(node(ID, Package), 0) : attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||||
#heuristic node_compiler(node(ID, Package), CompilerID) : default_compiler_preference(CompilerID, 0), compiler_id(CompilerID), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
#heuristic node_compiler(node(ID, Package), CompilerID) : compiler_weight(CompilerID, 0), compiler_id(CompilerID), attr("node", node(ID, Package)), ID > 0. [25-5*ID, true]
|
||||||
|
|
||||||
% node(ID, _), split build dependencies
|
% node(ID, _), split build dependencies
|
||||||
#heuristic attr("version", node(ID, Package), Version) : pkg_fact(Package, version_declared(Version, 0)), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
#heuristic attr("version", node(ID, Package), Version) : pkg_fact(Package, version_declared(Version, 0)), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||||
@ -21,4 +21,4 @@
|
|||||||
#heuristic attr("variant_value", node(ID, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
#heuristic attr("variant_value", node(ID, Package), Variant, Value) : variant_default_value(Package, Variant, Value), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||||
#heuristic attr("node_target", node(ID, Package), Target) : pkg_fact(Package, target_weight(Target, 0)), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
#heuristic attr("node_target", node(ID, Package), Target) : pkg_fact(Package, target_weight(Target, 0)), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||||
#heuristic node_target_weight(node(ID, Package), 0) : attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
#heuristic node_target_weight(node(ID, Package), 0) : attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||||
#heuristic node_compiler(node(ID, Package), CompilerID) : default_compiler_preference(CompilerID, 0), compiler_id(CompilerID), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
#heuristic node_compiler(node(ID, Package), CompilerID) : compiler_weight(CompilerID, 0), compiler_id(CompilerID), attr("node", node(ID, Package)), multiple_unification_sets(Package), ID > 0. [25, true]
|
||||||
|
@ -215,10 +215,10 @@ def test_config_add_override_leaf(mutable_empty_config):
|
|||||||
|
|
||||||
|
|
||||||
def test_config_add_update_dict(mutable_empty_config):
|
def test_config_add_update_dict(mutable_empty_config):
|
||||||
config("add", "packages:all:version:[1.0.0]")
|
config("add", "packages:hdf5:version:[1.0.0]")
|
||||||
output = config("get", "packages")
|
output = config("get", "packages")
|
||||||
|
|
||||||
expected = "packages:\n all:\n version: [1.0.0]\n"
|
expected = "packages:\n hdf5:\n version: [1.0.0]\n"
|
||||||
assert output == expected
|
assert output == expected
|
||||||
|
|
||||||
|
|
||||||
@ -352,8 +352,7 @@ def test_config_add_update_dict_from_file(mutable_empty_config, tmpdir):
|
|||||||
contents = """spack:
|
contents = """spack:
|
||||||
packages:
|
packages:
|
||||||
all:
|
all:
|
||||||
version:
|
target: [x86_64]
|
||||||
- 1.0.0
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# create temp file and add it to config
|
# create temp file and add it to config
|
||||||
@ -368,8 +367,7 @@ def test_config_add_update_dict_from_file(mutable_empty_config, tmpdir):
|
|||||||
# added config comes before prior config
|
# added config comes before prior config
|
||||||
expected = """packages:
|
expected = """packages:
|
||||||
all:
|
all:
|
||||||
version:
|
target: [x86_64]
|
||||||
- 1.0.0
|
|
||||||
compiler: [gcc]
|
compiler: [gcc]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -381,7 +379,7 @@ def test_config_add_invalid_file_fails(tmpdir):
|
|||||||
# invalid because version requires a list
|
# invalid because version requires a list
|
||||||
contents = """spack:
|
contents = """spack:
|
||||||
packages:
|
packages:
|
||||||
all:
|
hdf5:
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -631,14 +629,11 @@ def test_config_prefer_upstream(
|
|||||||
packages = syaml.load(open(cfg_file))["packages"]
|
packages = syaml.load(open(cfg_file))["packages"]
|
||||||
|
|
||||||
# Make sure only the non-default variants are set.
|
# Make sure only the non-default variants are set.
|
||||||
assert packages["boost"] == {
|
assert packages["all"] == {"compiler": ["gcc@=10.2.1"]}
|
||||||
"compiler": ["gcc@=10.2.1"],
|
assert packages["boost"] == {"variants": "+debug +graph", "version": ["1.63.0"]}
|
||||||
"variants": "+debug +graph",
|
assert packages["dependency-install"] == {"version": ["2.0"]}
|
||||||
"version": ["1.63.0"],
|
|
||||||
}
|
|
||||||
assert packages["dependency-install"] == {"compiler": ["gcc@=10.2.1"], "version": ["2.0"]}
|
|
||||||
# Ensure that neither variant gets listed for hdf5, since they conflict
|
# Ensure that neither variant gets listed for hdf5, since they conflict
|
||||||
assert packages["hdf5"] == {"compiler": ["gcc@=10.2.1"], "version": ["2.3"]}
|
assert packages["hdf5"] == {"version": ["2.3"]}
|
||||||
|
|
||||||
# Make sure a message about the conflicting hdf5's was given.
|
# Make sure a message about the conflicting hdf5's was given.
|
||||||
assert "- hdf5" in output
|
assert "- hdf5" in output
|
||||||
|
@ -2621,7 +2621,7 @@ def test_env_write_only_non_default_nested(tmpdir):
|
|||||||
- matrix:
|
- matrix:
|
||||||
- [mpileaks]
|
- [mpileaks]
|
||||||
packages:
|
packages:
|
||||||
mpileaks:
|
all:
|
||||||
compiler: [gcc]
|
compiler: [gcc]
|
||||||
view: true
|
view: true
|
||||||
"""
|
"""
|
||||||
|
@ -105,17 +105,13 @@ def test_preferred_variants_from_wildcard(self):
|
|||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"compiler_str,spec_str",
|
"compiler_str,spec_str",
|
||||||
[("gcc@4.5.0", "mpileaks"), ("clang@12.0.0", "mpileaks"), ("gcc@4.5.0", "openmpi")],
|
[("gcc@=4.5.0", "mpileaks"), ("clang@=12.0.0", "mpileaks"), ("gcc@=4.5.0", "openmpi")],
|
||||||
)
|
)
|
||||||
def test_preferred_compilers(self, compiler_str, spec_str):
|
def test_preferred_compilers(self, compiler_str, spec_str):
|
||||||
"""Test preferred compilers are applied correctly"""
|
"""Test preferred compilers are applied correctly"""
|
||||||
spec = Spec(spec_str)
|
update_packages("all", "compiler", [compiler_str])
|
||||||
update_packages(spec.name, "compiler", [compiler_str])
|
spec = spack.spec.Spec(spec_str).concretized()
|
||||||
spec.concretize()
|
assert spec.compiler == CompilerSpec(compiler_str)
|
||||||
# note: lhs has concrete compiler version, rhs still abstract.
|
|
||||||
# Could be made more strict by checking for equality with `gcc@=4.5.0`
|
|
||||||
# etc.
|
|
||||||
assert spec.compiler.satisfies(CompilerSpec(compiler_str))
|
|
||||||
|
|
||||||
@pytest.mark.only_clingo("Use case not supported by the original concretizer")
|
@pytest.mark.only_clingo("Use case not supported by the original concretizer")
|
||||||
def test_preferred_target(self, mutable_mock_repo):
|
def test_preferred_target(self, mutable_mock_repo):
|
||||||
@ -124,7 +120,7 @@ def test_preferred_target(self, mutable_mock_repo):
|
|||||||
default = str(spec.target)
|
default = str(spec.target)
|
||||||
preferred = str(spec.target.family)
|
preferred = str(spec.target.family)
|
||||||
|
|
||||||
update_packages("mpich", "target", [preferred])
|
update_packages("all", "target", [preferred])
|
||||||
spec = concretize("mpich")
|
spec = concretize("mpich")
|
||||||
assert str(spec.target) == preferred
|
assert str(spec.target) == preferred
|
||||||
|
|
||||||
@ -132,7 +128,7 @@ def test_preferred_target(self, mutable_mock_repo):
|
|||||||
assert str(spec["mpileaks"].target) == preferred
|
assert str(spec["mpileaks"].target) == preferred
|
||||||
assert str(spec["mpich"].target) == preferred
|
assert str(spec["mpich"].target) == preferred
|
||||||
|
|
||||||
update_packages("mpileaks", "target", [default])
|
update_packages("all", "target", [default])
|
||||||
spec = concretize("mpileaks")
|
spec = concretize("mpileaks")
|
||||||
assert str(spec["mpileaks"].target) == default
|
assert str(spec["mpileaks"].target) == default
|
||||||
assert str(spec["mpich"].target) == default
|
assert str(spec["mpich"].target) == default
|
||||||
|
@ -78,7 +78,7 @@ def env_yaml(tmpdir):
|
|||||||
verify_ssl: False
|
verify_ssl: False
|
||||||
dirty: False
|
dirty: False
|
||||||
packages:
|
packages:
|
||||||
libelf:
|
all:
|
||||||
compiler: [ 'gcc@4.5.3' ]
|
compiler: [ 'gcc@4.5.3' ]
|
||||||
repos:
|
repos:
|
||||||
- /x/y/z
|
- /x/y/z
|
||||||
@ -942,7 +942,7 @@ def test_single_file_scope(config, env_yaml):
|
|||||||
# from the single-file config
|
# from the single-file config
|
||||||
assert spack.config.get("config:verify_ssl") is False
|
assert spack.config.get("config:verify_ssl") is False
|
||||||
assert spack.config.get("config:dirty") is False
|
assert spack.config.get("config:dirty") is False
|
||||||
assert spack.config.get("packages:libelf:compiler") == ["gcc@4.5.3"]
|
assert spack.config.get("packages:all:compiler") == ["gcc@4.5.3"]
|
||||||
|
|
||||||
# from the lower config scopes
|
# from the lower config scopes
|
||||||
assert spack.config.get("config:checksum") is True
|
assert spack.config.get("config:checksum") is True
|
||||||
@ -965,7 +965,7 @@ def test_single_file_scope_section_override(tmpdir, config):
|
|||||||
config:
|
config:
|
||||||
verify_ssl: False
|
verify_ssl: False
|
||||||
packages::
|
packages::
|
||||||
libelf:
|
all:
|
||||||
compiler: [ 'gcc@4.5.3' ]
|
compiler: [ 'gcc@4.5.3' ]
|
||||||
repos:
|
repos:
|
||||||
- /x/y/z
|
- /x/y/z
|
||||||
@ -977,7 +977,7 @@ def test_single_file_scope_section_override(tmpdir, config):
|
|||||||
with spack.config.override(scope):
|
with spack.config.override(scope):
|
||||||
# from the single-file config
|
# from the single-file config
|
||||||
assert spack.config.get("config:verify_ssl") is False
|
assert spack.config.get("config:verify_ssl") is False
|
||||||
assert spack.config.get("packages:libelf:compiler") == ["gcc@4.5.3"]
|
assert spack.config.get("packages:all:compiler") == ["gcc@4.5.3"]
|
||||||
|
|
||||||
# from the lower config scopes
|
# from the lower config scopes
|
||||||
assert spack.config.get("config:checksum") is True
|
assert spack.config.get("config:checksum") is True
|
||||||
|
Loading…
Reference in New Issue
Block a user