intel oneapi classic bootstrapping (#31285)

The `intel` compiler at versions > 20 is provided by the `intel-oneapi-compilers-classic`
package (a thin wrapper around the `intel-oneapi-compilers` package), and the `oneapi`
compiler is provided by the `intel-oneapi-compilers` package. 

Prior to this work, neither of these compilers could be bootstrapped by Spack as part of
an install with `install_missing_compilers: True`.

Changes made to make these two packages bootstrappable:

1. The `intel-oneapi-compilers-classic` package includes a bin directory and symlinks
   to the compiler executables, not just logical pointers in Spack.
2. Spack can look for bootstrapped compilers in directories other than `$prefix/bin`,
   defined on a per-package basis
3. `intel-oneapi-compilers` specifies a non-default search directory for the
   compiler executables.
4. The `spack.compilers` module now can make more advanced associations between
   packages and compilers, not just simple name translations
5. Spack support for lmod hierarchies accounts for differences between package
   names and the associated compiler names for `intel-oneapi-compilers/oneapi`,
   `intel-oneapi-compilers-classic/intel@20:`, `llvm+clang/clang`, and
   `llvm-amdgpu/rocmcc`.

- [x] full end-to-end testing
- [x] add unit tests
This commit is contained in:
Greg Becker
2022-11-07 21:50:16 -08:00
committed by GitHub
parent f099a68e65
commit c9561c5a0e
8 changed files with 119 additions and 30 deletions

View File

@@ -49,12 +49,26 @@
"clang": "llvm+clang",
"oneapi": "intel-oneapi-compilers",
"rocmcc": "llvm-amdgpu",
"intel@2020:": "intel-oneapi-compilers-classic",
}
# TODO: generating this from the previous dict causes docs errors
package_name_to_compiler_name = {
"llvm": "clang",
"intel-oneapi-compilers": "oneapi",
"llvm-amdgpu": "rocmcc",
"intel-oneapi-compilers-classic": "intel",
}
def pkg_spec_for_compiler(cspec):
"""Return the spec of the package that provides the compiler."""
spec_str = "%s@%s" % (_compiler_to_pkg.get(cspec.name, cspec.name), cspec.versions)
for spec, package in _compiler_to_pkg.items():
if cspec.satisfies(spec):
spec_str = "%s@%s" % (package, cspec.versions)
break
else:
spec_str = str(cspec)
return spack.spec.Spec(spec_str)

View File

@@ -1241,6 +1241,12 @@ def _add_tasks(self, request, all_deps):
fail_fast = request.install_args.get("fail_fast")
self.fail_fast = self.fail_fast or fail_fast
def _add_compiler_package_to_config(self, pkg):
compiler_search_prefix = getattr(pkg, "compiler_search_prefix", pkg.spec.prefix)
spack.compilers.add_compilers_to_config(
spack.compilers.find_compilers([compiler_search_prefix])
)
def _install_task(self, task):
"""
Perform the installation of the requested spec and/or dependency
@@ -1266,9 +1272,7 @@ def _install_task(self, task):
if use_cache and _install_from_cache(pkg, cache_only, explicit, unsigned):
self._update_installed(task)
if task.compiler:
spack.compilers.add_compilers_to_config(
spack.compilers.find_compilers([pkg.spec.prefix])
)
self._add_compiler_package_to_config(pkg)
return
pkg.run_tests = tests is True or tests and pkg.name in tests
@@ -1296,9 +1300,7 @@ def _install_task(self, task):
# If a compiler, ensure it is added to the configuration
if task.compiler:
spack.compilers.add_compilers_to_config(
spack.compilers.find_compilers([pkg.spec.prefix])
)
self._add_compiler_package_to_config(pkg)
except spack.build_environment.StopPhase as e:
# A StopPhase exception means that do_install was asked to
# stop early from clients, and is not an error at this point
@@ -1717,9 +1719,7 @@ def install(self):
# It's an already installed compiler, add it to the config
if task.compiler:
spack.compilers.add_compilers_to_config(
spack.compilers.find_compilers([pkg.spec.prefix])
)
self._add_compiler_package_to_config(pkg)
else:
# At this point we've failed to get a write or a read

View File

@@ -184,22 +184,10 @@ def provides(self):
# If it is in the list of supported compilers family -> compiler
if self.spec.name in spack.compilers.supported_compilers():
provides["compiler"] = spack.spec.CompilerSpec(str(self.spec))
# Special case for llvm
if self.spec.name == "llvm":
provides["compiler"] = spack.spec.CompilerSpec(str(self.spec))
provides["compiler"].name = "clang"
# Special case for llvm-amdgpu
if self.spec.name == "llvm-amdgpu":
provides["compiler"] = spack.spec.CompilerSpec(str(self.spec))
provides["compiler"].name = "rocmcc"
# Special case for oneapi
if self.spec.name == "intel-oneapi-compilers":
provides["compiler"] = spack.spec.CompilerSpec(str(self.spec))
provides["compiler"].name = "oneapi"
# Special case for oneapi classic
if self.spec.name == "intel-oneapi-compilers-classic":
provides["compiler"] = spack.spec.CompilerSpec(str(self.spec))
provides["compiler"].name = "intel"
elif self.spec.name in spack.compilers.package_name_to_compiler_name:
# If it is the package for a supported compiler, but of a different name
cname = spack.compilers.package_name_to_compiler_name[self.spec.name]
provides["compiler"] = spack.spec.CompilerSpec("%s@%s" % (cname, self.spec.version))
# All the other tokens in the hierarchy must be virtual dependencies
for x in self.hierarchy_tokens:

View File

@@ -487,6 +487,17 @@ def fake_package_list(compiler, architecture, pkgs):
assert installer.build_pq[0][1].compiler
def test_bootstrapping_compilers_with_different_names_from_spec(
install_mockery, mutable_config, mock_fetch
):
with spack.config.override("config:install_missing_compilers", True):
with spack.concretize.disable_compiler_existence_check():
spec = spack.spec.Spec("trivial-install-test-package%oneapi@22.2.0").concretized()
spec.package.do_install()
assert spack.spec.CompilerSpec("oneapi@22.2.0") in spack.compilers.all_compiler_specs()
def test_dump_packages_deps_ok(install_mockery, tmpdir, mock_packages):
"""Test happy path for dump_packages with dependencies."""

View File

@@ -81,6 +81,15 @@ def test_file_layout(self, compiler, provider, factory, module_configuration):
else:
assert repetitions == 1
def test_compilers_provided_different_name(self, factory, module_configuration):
module_configuration("complex_hierarchy")
module, spec = factory("intel-oneapi-compilers%clang@3.3")
provides = module.conf.provides
assert "compiler" in provides
assert provides["compiler"] == spack.spec.CompilerSpec("oneapi@3.0")
def test_simple_case(self, modulefile_content, module_configuration):
"""Tests the generation of a simple TCL module file."""