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:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							4004f27bc0
						
					
				
				
					commit
					f3537bc66b
				
			@@ -526,56 +526,52 @@ Package Preferences
 | 
			
		||||
In some cases package requirements can be too strong, and package
 | 
			
		||||
preferences are the better option. Package preferences do not impose
 | 
			
		||||
constraints on packages for particular versions or variants values,
 | 
			
		||||
they rather only set defaults -- the concretizer is free to change
 | 
			
		||||
them if it must due to other constraints. Also note that package
 | 
			
		||||
preferences are of lower priority than reuse of already installed
 | 
			
		||||
packages.
 | 
			
		||||
they rather only set defaults. The concretizer is free to change
 | 
			
		||||
them if it must, due to other constraints, and also prefers reusing
 | 
			
		||||
installed packages over building new ones that are a better match for
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
   packages:
 | 
			
		||||
     opencv:
 | 
			
		||||
       compiler: [gcc@4.9]
 | 
			
		||||
       variants: +debug
 | 
			
		||||
     gperftools:
 | 
			
		||||
       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
 | 
			
		||||
concretized.  The opencv package should prefer using GCC 4.9 and
 | 
			
		||||
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.
 | 
			
		||||
In this case, the preference for ``opencv`` is to build with debug options, while
 | 
			
		||||
``gperftools`` prefers version 2.2 over 2.4.
 | 
			
		||||
 | 
			
		||||
Package preferences accept the follow keys or components under
 | 
			
		||||
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.
 | 
			
		||||
Any preference can be overwritten on the command line if explicitly requested.
 | 
			
		||||
 | 
			
		||||
Sometimes a package installation may have constraints that forbid
 | 
			
		||||
the first concretization rule, in which case Spack will use the first
 | 
			
		||||
legal concretization rule.  Going back to the example, if a user
 | 
			
		||||
requests gperftools 2.3 or later, then Spack will install version 2.4
 | 
			
		||||
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.
 | 
			
		||||
Preferences cannot overcome explicit constraints, as they only set a preferred
 | 
			
		||||
ordering among homogeneous attribute values. Going back to the example, if
 | 
			
		||||
``gperftools@2.3:`` was requested, then Spack will install version 2.4
 | 
			
		||||
since the most preferred version 2.2 is prohibited by the version constraint.
 | 
			
		||||
 | 
			
		||||
.. _package_permissions:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -407,7 +407,9 @@ def config_prefer_upstream(args):
 | 
			
		||||
    pkgs = {}
 | 
			
		||||
    for spec in pref_specs:
 | 
			
		||||
        # 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
 | 
			
		||||
 | 
			
		||||
        # 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)
 | 
			
		||||
 | 
			
		||||
        compiler = str(spec.compiler)
 | 
			
		||||
        if compiler not in pkg["compiler"]:
 | 
			
		||||
            pkg["compiler"].append(compiler)
 | 
			
		||||
        if compiler not in all["compiler"]:
 | 
			
		||||
            all["compiler"].append(compiler)
 | 
			
		||||
 | 
			
		||||
        # Get and list all the variants that differ from the default.
 | 
			
		||||
        variants = []
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,66 @@
 | 
			
		||||
   :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 = {
 | 
			
		||||
@@ -15,57 +75,14 @@
 | 
			
		||||
        "type": "object",
 | 
			
		||||
        "default": {},
 | 
			
		||||
        "additionalProperties": False,
 | 
			
		||||
        "patternProperties": {
 | 
			
		||||
            r"\w[\w-]*": {  # package name
 | 
			
		||||
        "properties": {
 | 
			
		||||
            "all": {  # package name
 | 
			
		||||
                "type": "object",
 | 
			
		||||
                "default": {},
 | 
			
		||||
                "additionalProperties": False,
 | 
			
		||||
                "properties": {
 | 
			
		||||
                    "require": {
 | 
			
		||||
                        "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"},
 | 
			
		||||
                        ]
 | 
			
		||||
                    },
 | 
			
		||||
                    "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"}]},
 | 
			
		||||
                    },
 | 
			
		||||
                    "require": requirements,
 | 
			
		||||
                    "version": {},  # Here only to warn users on ignored properties
 | 
			
		||||
                    "target": {
 | 
			
		||||
                        "type": "array",
 | 
			
		||||
                        "default": [],
 | 
			
		||||
@@ -78,22 +95,10 @@
 | 
			
		||||
                        "items": {"type": "string"},
 | 
			
		||||
                    },  # compiler specs
 | 
			
		||||
                    "buildable": {"type": "boolean", "default": True},
 | 
			
		||||
                    "permissions": {
 | 
			
		||||
                        "type": "object",
 | 
			
		||||
                        "additionalProperties": False,
 | 
			
		||||
                        "properties": {
 | 
			
		||||
                            "read": {"type": "string", "enum": ["user", "group", "world"]},
 | 
			
		||||
                            "write": {"type": "string", "enum": ["user", "group", "world"]},
 | 
			
		||||
                            "group": {"type": "string"},
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
                    "permissions": permissions,
 | 
			
		||||
                    # If 'get_full_repo' is promoted to a Package-level
 | 
			
		||||
                    # attribute, it could be useful to set it here
 | 
			
		||||
                    "package_attributes": {
 | 
			
		||||
                        "type": "object",
 | 
			
		||||
                        "additionalProperties": False,
 | 
			
		||||
                        "patternProperties": {r"\w+": {}},
 | 
			
		||||
                    },
 | 
			
		||||
                    "package_attributes": package_attributes,
 | 
			
		||||
                    "providers": {
 | 
			
		||||
                        "type": "object",
 | 
			
		||||
                        "default": {},
 | 
			
		||||
@@ -106,12 +111,40 @@
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
                    "variants": {
 | 
			
		||||
                        "oneOf": [
 | 
			
		||||
                            {"type": "string"},
 | 
			
		||||
                            {"type": "array", "items": {"type": "string"}},
 | 
			
		||||
                        ]
 | 
			
		||||
                    "variants": variants,
 | 
			
		||||
                },
 | 
			
		||||
                "deprecatedProperties": {
 | 
			
		||||
                    "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": {
 | 
			
		||||
                        "type": "array",
 | 
			
		||||
                        "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))
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
    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):
 | 
			
		||||
        rules = self.requirement_rules_from_package_py(pkg)
 | 
			
		||||
        rules.extend(self.requirement_rules_from_packages_yaml(pkg))
 | 
			
		||||
@@ -1375,9 +1352,6 @@ def pkg_rules(self, pkg, tests):
 | 
			
		||||
        # conflicts
 | 
			
		||||
        self.conflict_rules(pkg)
 | 
			
		||||
 | 
			
		||||
        # default compilers for this package
 | 
			
		||||
        self.package_compiler_defaults(pkg)
 | 
			
		||||
 | 
			
		||||
        # virtuals
 | 
			
		||||
        self.package_provider_rules(pkg)
 | 
			
		||||
 | 
			
		||||
@@ -1673,6 +1647,7 @@ def virtual_preferences(self, pkg_name, func):
 | 
			
		||||
            for i, provider in enumerate(providers):
 | 
			
		||||
                provider_name = spack.spec.Spec(provider).name
 | 
			
		||||
                func(vspec, provider_name, i)
 | 
			
		||||
            self.gen.newline()
 | 
			
		||||
 | 
			
		||||
    def provider_defaults(self):
 | 
			
		||||
        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)
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
    def target_preferences(self, pkg_name):
 | 
			
		||||
        key_fn = spack.package_prefs.PackagePrefs(pkg_name, "target")
 | 
			
		||||
    def target_preferences(self):
 | 
			
		||||
        key_fn = spack.package_prefs.PackagePrefs("all", "target")
 | 
			
		||||
 | 
			
		||||
        if not 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.sort(key=key_fn)
 | 
			
		||||
 | 
			
		||||
        offset = 0
 | 
			
		||||
        best_default = self.default_targets[0][1]
 | 
			
		||||
        for i, preferred in enumerate(package_targets):
 | 
			
		||||
            if str(preferred.architecture.target) == best_default and i != 0:
 | 
			
		||||
                offset = 100
 | 
			
		||||
            self.gen.fact(
 | 
			
		||||
                fn.pkg_fact(
 | 
			
		||||
                    pkg_name, fn.target_weight(str(preferred.architecture.target), i + offset)
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
            self.gen.fact(fn.target_weight(str(preferred.architecture.target), i))
 | 
			
		||||
 | 
			
		||||
    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()
 | 
			
		||||
        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):
 | 
			
		||||
        """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.target_preferences()
 | 
			
		||||
 | 
			
		||||
    def virtual_providers(self):
 | 
			
		||||
        self.gen.h2("Virtual providers")
 | 
			
		||||
        msg = (
 | 
			
		||||
@@ -2661,7 +2646,6 @@ def setup(
 | 
			
		||||
            self.pkg_rules(pkg, tests=self.tests)
 | 
			
		||||
            self.gen.h2("Package preferences: %s" % pkg)
 | 
			
		||||
            self.preferred_variants(pkg)
 | 
			
		||||
            self.target_preferences(pkg)
 | 
			
		||||
 | 
			
		||||
        self.gen.h1("Develop specs")
 | 
			
		||||
        # Inject dev_path from environment
 | 
			
		||||
 
 | 
			
		||||
@@ -589,21 +589,15 @@ possible_provider_weight(DependencyNode, VirtualNode, 0, "external")
 | 
			
		||||
  :- provider(DependencyNode, VirtualNode),
 | 
			
		||||
     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
 | 
			
		||||
% according to its priority in the list of providers
 | 
			
		||||
possible_provider_weight(node(DependencyID, Dependency), node(VirtualID, Virtual), Weight, "default")
 | 
			
		||||
  :- provider(node(DependencyID, Dependency), node(VirtualID, Virtual)),
 | 
			
		||||
     default_provider_preference(Virtual, Dependency, Weight).
 | 
			
		||||
possible_provider_weight(node(ProviderID, Provider), node(VirtualID, Virtual), Weight, "default")
 | 
			
		||||
  :- provider(node(ProviderID, Provider), node(VirtualID, Virtual)),
 | 
			
		||||
     default_provider_preference(Virtual, Provider, Weight).
 | 
			
		||||
 | 
			
		||||
% 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.
 | 
			
		||||
#defined virtual/1.
 | 
			
		||||
@@ -1059,7 +1053,7 @@ attr("node_target", PackageNode, Target)
 | 
			
		||||
node_target_weight(node(ID, Package), Weight)
 | 
			
		||||
 :- attr("node", node(ID, Package)),
 | 
			
		||||
    attr("node_target", node(ID, Package), Target),
 | 
			
		||||
    pkg_fact(Package, target_weight(Target, Weight)).
 | 
			
		||||
    target_weight(Target, Weight).
 | 
			
		||||
 | 
			
		||||
% compatibility rules for targets among nodes
 | 
			
		||||
node_target_match(ParentNode, DependencyNode)
 | 
			
		||||
@@ -1181,23 +1175,17 @@ compiler_mismatch_required(PackageNode, DependencyNode)
 | 
			
		||||
#defined allow_compiler/2.
 | 
			
		||||
 | 
			
		||||
% 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),
 | 
			
		||||
    compiler_name(CompilerID, Compiler),
 | 
			
		||||
    compiler_version(CompilerID, V),
 | 
			
		||||
    pkg_fact(Package, node_compiler_preference(Compiler, V, Weight)).
 | 
			
		||||
compiler_weight(node(ID, Package), Weight)
 | 
			
		||||
    compiler_weight(CompilerID, Weight).
 | 
			
		||||
 | 
			
		||||
node_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, _)),
 | 
			
		||||
    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, _).
 | 
			
		||||
    not compiler_weight(CompilerID, _).
 | 
			
		||||
 | 
			
		||||
% 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)
 | 
			
		||||
@@ -1205,7 +1193,7 @@ error(100, "Compiler {1}@{2} requested for {0} cannot be found. Set install_miss
 | 
			
		||||
    not node_compiler(node(ID, Package), _).
 | 
			
		||||
 | 
			
		||||
#defined node_compiler_preference/4.
 | 
			
		||||
#defined default_compiler_preference/3.
 | 
			
		||||
#defined compiler_weight/3.
 | 
			
		||||
 | 
			
		||||
%-----------------------------------------------------------------------------
 | 
			
		||||
% Compiler flags
 | 
			
		||||
@@ -1529,7 +1517,7 @@ opt_criterion(15, "non-preferred compilers").
 | 
			
		||||
#minimize{ 0@15: #true }.
 | 
			
		||||
#minimize{
 | 
			
		||||
    Weight@15+Priority,PackageNode
 | 
			
		||||
    : compiler_weight(PackageNode, Weight),
 | 
			
		||||
    : node_compiler_weight(PackageNode, Weight),
 | 
			
		||||
      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 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("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_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
 | 
			
		||||
#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("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_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
 | 
			
		||||
#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("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_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):
 | 
			
		||||
    config("add", "packages:all:version:[1.0.0]")
 | 
			
		||||
    config("add", "packages:hdf5:version:[1.0.0]")
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -352,8 +352,7 @@ def test_config_add_update_dict_from_file(mutable_empty_config, tmpdir):
 | 
			
		||||
    contents = """spack:
 | 
			
		||||
  packages:
 | 
			
		||||
    all:
 | 
			
		||||
      version:
 | 
			
		||||
      - 1.0.0
 | 
			
		||||
      target: [x86_64]
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
    # 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
 | 
			
		||||
    expected = """packages:
 | 
			
		||||
  all:
 | 
			
		||||
    version:
 | 
			
		||||
    - 1.0.0
 | 
			
		||||
    target: [x86_64]
 | 
			
		||||
    compiler: [gcc]
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
@@ -381,7 +379,7 @@ def test_config_add_invalid_file_fails(tmpdir):
 | 
			
		||||
    # invalid because version requires a list
 | 
			
		||||
    contents = """spack:
 | 
			
		||||
  packages:
 | 
			
		||||
    all:
 | 
			
		||||
    hdf5:
 | 
			
		||||
      version: 1.0.0
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
@@ -631,14 +629,11 @@ def test_config_prefer_upstream(
 | 
			
		||||
    packages = syaml.load(open(cfg_file))["packages"]
 | 
			
		||||
 | 
			
		||||
    # Make sure only the non-default variants are set.
 | 
			
		||||
    assert packages["boost"] == {
 | 
			
		||||
        "compiler": ["gcc@=10.2.1"],
 | 
			
		||||
        "variants": "+debug +graph",
 | 
			
		||||
        "version": ["1.63.0"],
 | 
			
		||||
    }
 | 
			
		||||
    assert packages["dependency-install"] == {"compiler": ["gcc@=10.2.1"], "version": ["2.0"]}
 | 
			
		||||
    assert packages["all"] == {"compiler": ["gcc@=10.2.1"]}
 | 
			
		||||
    assert packages["boost"] == {"variants": "+debug +graph", "version": ["1.63.0"]}
 | 
			
		||||
    assert packages["dependency-install"] == {"version": ["2.0"]}
 | 
			
		||||
    # 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.
 | 
			
		||||
    assert "- hdf5" in output
 | 
			
		||||
 
 | 
			
		||||
@@ -2621,7 +2621,7 @@ def test_env_write_only_non_default_nested(tmpdir):
 | 
			
		||||
  - matrix:
 | 
			
		||||
    - [mpileaks]
 | 
			
		||||
  packages:
 | 
			
		||||
    mpileaks:
 | 
			
		||||
    all:
 | 
			
		||||
      compiler: [gcc]
 | 
			
		||||
  view: true
 | 
			
		||||
"""
 | 
			
		||||
 
 | 
			
		||||
@@ -105,17 +105,13 @@ def test_preferred_variants_from_wildcard(self):
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.parametrize(
 | 
			
		||||
        "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):
 | 
			
		||||
        """Test preferred compilers are applied correctly"""
 | 
			
		||||
        spec = Spec(spec_str)
 | 
			
		||||
        update_packages(spec.name, "compiler", [compiler_str])
 | 
			
		||||
        spec.concretize()
 | 
			
		||||
        # 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))
 | 
			
		||||
        update_packages("all", "compiler", [compiler_str])
 | 
			
		||||
        spec = spack.spec.Spec(spec_str).concretized()
 | 
			
		||||
        assert spec.compiler == CompilerSpec(compiler_str)
 | 
			
		||||
 | 
			
		||||
    @pytest.mark.only_clingo("Use case not supported by the original concretizer")
 | 
			
		||||
    def test_preferred_target(self, mutable_mock_repo):
 | 
			
		||||
@@ -124,7 +120,7 @@ def test_preferred_target(self, mutable_mock_repo):
 | 
			
		||||
        default = str(spec.target)
 | 
			
		||||
        preferred = str(spec.target.family)
 | 
			
		||||
 | 
			
		||||
        update_packages("mpich", "target", [preferred])
 | 
			
		||||
        update_packages("all", "target", [preferred])
 | 
			
		||||
        spec = concretize("mpich")
 | 
			
		||||
        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["mpich"].target) == preferred
 | 
			
		||||
 | 
			
		||||
        update_packages("mpileaks", "target", [default])
 | 
			
		||||
        update_packages("all", "target", [default])
 | 
			
		||||
        spec = concretize("mpileaks")
 | 
			
		||||
        assert str(spec["mpileaks"].target) == default
 | 
			
		||||
        assert str(spec["mpich"].target) == default
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ def env_yaml(tmpdir):
 | 
			
		||||
        verify_ssl: False
 | 
			
		||||
        dirty: False
 | 
			
		||||
    packages:
 | 
			
		||||
        libelf:
 | 
			
		||||
        all:
 | 
			
		||||
            compiler: [ 'gcc@4.5.3' ]
 | 
			
		||||
    repos:
 | 
			
		||||
        - /x/y/z
 | 
			
		||||
@@ -942,7 +942,7 @@ def test_single_file_scope(config, env_yaml):
 | 
			
		||||
        # from the single-file config
 | 
			
		||||
        assert spack.config.get("config:verify_ssl") 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
 | 
			
		||||
        assert spack.config.get("config:checksum") is True
 | 
			
		||||
@@ -965,7 +965,7 @@ def test_single_file_scope_section_override(tmpdir, config):
 | 
			
		||||
    config:
 | 
			
		||||
        verify_ssl: False
 | 
			
		||||
    packages::
 | 
			
		||||
        libelf:
 | 
			
		||||
        all:
 | 
			
		||||
            compiler: [ 'gcc@4.5.3' ]
 | 
			
		||||
    repos:
 | 
			
		||||
        - /x/y/z
 | 
			
		||||
@@ -977,7 +977,7 @@ def test_single_file_scope_section_override(tmpdir, config):
 | 
			
		||||
    with spack.config.override(scope):
 | 
			
		||||
        # from the single-file config
 | 
			
		||||
        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
 | 
			
		||||
        assert spack.config.get("config:checksum") is True
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user