diff --git a/lib/spack/spack/cmd/compiler.py b/lib/spack/spack/cmd/compiler.py index 72cb1c71c35..622f5de93ed 100644 --- a/lib/spack/spack/cmd/compiler.py +++ b/lib/spack/spack/cmd/compiler.py @@ -87,7 +87,7 @@ def compiler_find(args): if new_compilers: n = len(new_compilers) s = "s" if n > 1 else "" - filename = spack.config.CONFIG.get_config_filename(args.scope, "packages") + filename = spack.config.CONFIG.get_config_filename(args.scope, "compilers") tty.msg(f"Added {n:d} new compiler{s} to {filename}") compiler_strs = sorted(f"{c.spec}" for c in new_compilers) colify(reversed(compiler_strs), indent=4) diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py index 8d66edec174..3b3862ec9ff 100644 --- a/lib/spack/spack/compilers/__init__.py +++ b/lib/spack/spack/compilers/__init__.py @@ -114,35 +114,31 @@ def _to_dict(compiler): def get_compiler_config( - configuration: "spack.config.Configuration", *, scope: Optional[str] = None -) -> List[Dict]: - """Return the compiler configuration for the specified architecture.""" - compilers_yaml = configuration.get("compilers", scope=scope) - if not compilers_yaml: - return [] - return compilers_yaml - - -def get_compiler_config_from_packages( configuration: "spack.config.Configuration", *, scope: Optional[str] = None, init_config: bool = False, ) -> List[Dict]: - """Return the compiler configuration from packages.yaml""" - packages_yaml = configuration.get("packages", scope=scope) - configs = CompilerConfigFactory.from_packages_yaml(packages_yaml) - if configs or not init_config: - return configs + """Return the compiler configuration for the specified architecture.""" + config = configuration.get("compilers", scope=scope) or [] + if config or not init_config: + return config - merged_packages_yaml = configuration.get("packages") - configs = CompilerConfigFactory.from_packages_yaml(merged_packages_yaml) - if configs: + merged_config = configuration.get("compilers") + if merged_config: # Config is empty for this scope # Do not init config because there is a non-empty scope - return configs + return config find_compilers(scope=scope) + config = configuration.get("compilers", scope=scope) + return config + + +def get_compiler_config_from_packages( + configuration: "spack.config.Configuration", *, scope: Optional[str] = None +) -> List[Dict]: + """Return the compiler configuration from packages.yaml""" packages_yaml = configuration.get("packages", scope=scope) return CompilerConfigFactory.from_packages_yaml(packages_yaml) @@ -161,19 +157,24 @@ def compiler_config_files(): return config_files -def add_compiler_to_config(compiler, scope=None): - """Add a Compiler object to the configuration, at the required scope.""" - if not compiler.cc: - tty.debug(f"{compiler.spec} does not have a C compiler") - if not compiler.cxx: - tty.debug(f"{compiler.spec} does not have a C++ compiler") - if not compiler.f77: - tty.debug(f"{compiler.spec} does not have a Fortran77 compiler") - if not compiler.fc: - tty.debug(f"{compiler.spec} does not have a Fortran compiler") +def add_compilers_to_config(compilers, scope=None): + """Add compilers to the config for the specified architecture. + Arguments: + compilers: a list of Compiler objects. + scope: configuration scope to modify. + """ compiler_config = get_compiler_config(configuration=spack.config.CONFIG, scope=scope) - compiler_config.append(_to_dict(compiler)) + for compiler in compilers: + if not compiler.cc: + tty.debug(f"{compiler.spec} does not have a C compiler") + if not compiler.cxx: + tty.debug(f"{compiler.spec} does not have a C++ compiler") + if not compiler.f77: + tty.debug(f"{compiler.spec} does not have a Fortran77 compiler") + if not compiler.fc: + tty.debug(f"{compiler.spec} does not have a Fortran compiler") + compiler_config.append(_to_dict(compiler)) spack.config.set("compilers", compiler_config, scope=scope) @@ -240,12 +241,10 @@ def all_compilers_config( """Return a set of specs for all the compiler versions currently available to build with. These are instances of CompilerSpec. """ - from_compilers_yaml = get_compiler_config(configuration, scope=scope) - if from_compilers_yaml: + from_packages_yaml = get_compiler_config_from_packages(configuration, scope=scope) + if from_packages_yaml: init_config = False - from_packages_yaml = get_compiler_config_from_packages( - configuration, scope=scope, init_config=init_config - ) + from_compilers_yaml = get_compiler_config(configuration, scope=scope, init_config=init_config) result = from_compilers_yaml + from_packages_yaml # Dedupe entries by the compiler they represent @@ -280,6 +279,8 @@ def find_compilers( a certain language max_workers: number of processes used to search for compilers """ + known_compilers = set(all_compilers(init_config=False)) + if path_hints is None: path_hints = get_path("PATH") default_paths = fs.search_paths_for_executables(*path_hints) @@ -320,13 +321,16 @@ def _has_fortran_compilers(x): continue candidate.spec.extra_attributes["compilers"]["fortran"] = gfortran - new_compilers = spack.detection.update_configuration( - valid_compilers, buildable=True, scope=scope - ) - return [ - _compiler_from_config_entry(c["compiler"]) - for c in CompilerConfigFactory.from_specs(new_compilers) - ] + new_compilers = [] + for name, detected in valid_compilers.items(): + for config in CompilerConfigFactory.from_specs([x.spec for x in detected]): + c = _compiler_from_config_entry(config["compiler"]) + if c in known_compilers: + continue + new_compilers.append(c) + + add_compilers_to_config(new_compilers, scope=scope) + return new_compilers def select_new_compilers(compilers, scope=None): diff --git a/lib/spack/spack/cray_manifest.py b/lib/spack/spack/cray_manifest.py index c688b6cea84..22371f68f27 100644 --- a/lib/spack/spack/cray_manifest.py +++ b/lib/spack/spack/cray_manifest.py @@ -227,7 +227,7 @@ def read(path, apply_updates): if apply_updates and compilers: for compiler in compilers: try: - spack.compilers.add_compiler_to_config(compiler) + spack.compilers.add_compilers_to_config([compiler]) except Exception: warnings.warn( f"Could not add compiler {str(compiler.spec)}: " diff --git a/lib/spack/spack/test/cmd/compiler.py b/lib/spack/spack/test/cmd/compiler.py index 959791e379d..7acdb629e82 100644 --- a/lib/spack/spack/test/cmd/compiler.py +++ b/lib/spack/spack/test/cmd/compiler.py @@ -175,7 +175,7 @@ def test_compiler_find_mixed_suffixes( assert "clang@=11.0.0" in output assert "gcc@=8.4.0" in output - config = spack.compilers.all_compilers_config( + config = spack.compilers.get_compiler_config( no_compilers_yaml, scope="site", init_config=False ) clang = next(c["compiler"] for c in config if c["compiler"]["spec"] == "clang@=11.0.0") @@ -212,12 +212,10 @@ def test_compiler_find_prefer_no_suffix(no_compilers_yaml, working_env, compiler assert "clang@=11.0.0" in output assert "gcc@=8.4.0" in output - compiler_config = spack.compilers.get_compiler_config_from_packages( - no_compilers_yaml, scope="site" - ) - clang = next( - c["compiler"] for c in compiler_config if c["compiler"]["spec"] == "clang@=11.0.0" + config = spack.compilers.get_compiler_config( + no_compilers_yaml, scope="site", init_config=False ) + clang = next(c["compiler"] for c in config if c["compiler"]["spec"] == "clang@=11.0.0") assert clang["paths"]["cc"] == str(compilers_dir / "clang") assert clang["paths"]["cxx"] == str(compilers_dir / "clang++") @@ -235,10 +233,10 @@ def test_compiler_find_path_order(no_compilers_yaml, working_env, compilers_dir) compiler("find", "--scope=site") - compiler_config = spack.compilers.get_compiler_config_from_packages( - no_compilers_yaml, scope="site" + config = spack.compilers.get_compiler_config( + no_compilers_yaml, scope="site", init_config=False ) - gcc = next(c["compiler"] for c in compiler_config if c["compiler"]["spec"] == "gcc@=8.4.0") + gcc = next(c["compiler"] for c in config if c["compiler"]["spec"] == "gcc@=8.4.0") assert gcc["paths"] == { "cc": str(new_dir / "gcc-8"), "cxx": str(new_dir / "g++-8"), diff --git a/lib/spack/spack/test/cray_manifest.py b/lib/spack/spack/test/cray_manifest.py index c336b6dc654..532261b3ee8 100644 --- a/lib/spack/spack/test/cray_manifest.py +++ b/lib/spack/spack/test/cray_manifest.py @@ -366,20 +366,20 @@ def test_read_cray_manifest_add_compiler_failure( """Check that cray manifest can be read even if some compilers cannot be added. """ - orig_add_compiler_to_config = spack.compilers.add_compiler_to_config + orig_add_compilers_to_config = spack.compilers.add_compilers_to_config class fail_for_clang: def __init__(self): self.called_with_clang = False - def __call__(self, compiler, **kwargs): - if compiler.name == "clang": + def __call__(self, compilers, **kwargs): + if any(x.name == "clang" for x in compilers): self.called_with_clang = True raise Exception() - return orig_add_compiler_to_config(compiler, **kwargs) + return orig_add_compilers_to_config(compilers, **kwargs) checker = fail_for_clang() - monkeypatch.setattr(spack.compilers, "add_compiler_to_config", checker) + monkeypatch.setattr(spack.compilers, "add_compilers_to_config", checker) with tmpdir.as_cwd(): test_db_fname = "external-db.json"