diff --git a/etc/spack/defaults/concretizer.yaml b/etc/spack/defaults/concretizer.yaml index f239a4d0838..2432fa4867b 100644 --- a/etc/spack/defaults/concretizer.yaml +++ b/etc/spack/defaults/concretizer.yaml @@ -43,6 +43,22 @@ concretizer: # (e.g. py-setuptools, cmake etc.) # "full" (experimental): allows separation of the entire build-tool stack (e.g. the entire "cmake" subDAG) strategy: minimal + # Maximum number of duplicates in a DAG, when using a strategy that allows duplicates. "default" is the + # number used if there isn't a more specific alternative + max_dupes: + default: 1 + # Virtuals + c: 2 + cxx: 2 + fortran: 1 + # Regular packages + cmake: 2 + gmake: 2 + py-cython: 2 + py-flit-core: 2 + py-setuptools: 2 + gcc: 2 + llvm: 2 # Option to specify compatibility between operating systems for reuse of compilers and packages # Specified as a key: [list] where the key is the os that is being targeted, and the list contains the OS's # it can reuse. Note this is a directional compatibility so mutual compatibility between two OS's diff --git a/lib/spack/spack/schema/concretizer.py b/lib/spack/spack/schema/concretizer.py index 99a70a716cd..32c8367f548 100644 --- a/lib/spack/spack/schema/concretizer.py +++ b/lib/spack/spack/schema/concretizer.py @@ -84,7 +84,11 @@ "duplicates": { "type": "object", "properties": { - "strategy": {"type": "string", "enum": ["none", "minimal", "full"]} + "strategy": {"type": "string", "enum": ["none", "minimal", "full"]}, + "max_dupes": { + "type": "object", + "additional_properties": {"type": "integer", "minimum": 1}, + }, }, }, "static_analysis": {"type": "boolean"}, diff --git a/lib/spack/spack/solver/input_analysis.py b/lib/spack/spack/solver/input_analysis.py index 61c45b2c8f1..260f2a1e292 100644 --- a/lib/spack/spack/solver/input_analysis.py +++ b/lib/spack/spack/solver/input_analysis.py @@ -468,16 +468,29 @@ def possible_packages_facts(self, gen, fn): gen.newline() gen.h2("Packages with at multiple possible nodes (build-tools)") + default = spack.config.CONFIG.get("concretizer:duplicates:max_dupes:default", 2) for package_name in sorted(self.possible_dependencies() & build_tools): - gen.fact(fn.max_dupes(package_name, 2)) - gen.fact(fn.multiple_unification_sets(package_name)) + max_dupes = spack.config.CONFIG.get( + f"concretizer:duplicates:max_dupes:{package_name}", default + ) + gen.fact(fn.max_dupes(package_name, max_dupes)) + if max_dupes > 1: + gen.fact(fn.multiple_unification_sets(package_name)) gen.newline() - gen.h2("Maximum number of nodes (virtual packages)") - for package_name in sorted(self.possible_virtuals()): + gen.h2("Maximum number of nodes (link-run virtuals)") + for package_name in sorted(self._link_run_virtuals): gen.fact(fn.max_dupes(package_name, 1)) gen.newline() + gen.h2("Maximum number of nodes (other virtuals)") + for package_name in sorted(self.possible_virtuals() - self._link_run_virtuals): + max_dupes = spack.config.CONFIG.get( + f"concretizer:duplicates:max_dupes:{package_name}", default + ) + gen.fact(fn.max_dupes(package_name, max_dupes)) + gen.newline() + gen.h2("Possible package in link-run subDAG") for name in sorted(self._link_run): gen.fact(fn.possible_in_link_run(name))