[oneapi] fix mkl deps, externally installed, and docs (#22607)

This commit is contained in:
Robert Cohn 2021-04-07 12:31:08 -04:00 committed by GitHub
parent 6c16f5c5d5
commit c8b4414230
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 55 deletions

View File

@ -38,21 +38,25 @@ Intel no longer releases new versions of Parallel Studio, which can be
used in Spack via the :ref:<intelpackage>. All of its components can used in Spack via the :ref:<intelpackage>. All of its components can
now be found in oneAPI. now be found in oneAPI.
Example Examples
======= ========
We start with a simple example that will be sufficient for most Building a Package With icx
users. Install the oneAPI compilers:: ---------------------------
In this example, we build patchelf with ``icc`` and ``icx``. The
compilers are installed with spack.
Install the oneAPI compilers::
spack install intel-oneapi-compilers spack install intel-oneapi-compilers
Add the oneAPI compilers to the set of compilers that Spack can use:: Add the compilers to your ``compilers.yaml`` so spack can use them::
spack compiler add `spack location -i intel-oneapi-compilers`/compiler/latest/linux/bin/intel64 spack compiler add `spack location -i intel-oneapi-compilers`/compiler/latest/linux/bin/intel64
spack compiler add `spack location -i intel-oneapi-compilers`/compiler/latest/linux/bin spack compiler add `spack location -i intel-oneapi-compilers`/compiler/latest/linux/bin
This adds the compilers to your ``compilers.yaml``. Verify that the Verify that the compilers are available::
compilers are available::
spack compiler list spack compiler list
@ -72,9 +76,11 @@ To build with with ``icx``, do ::
spack install patchelf%oneapi spack install patchelf%oneapi
In addition to compilers, oneAPI contains many libraries. The ``hdf5`` Using oneAPI MPI to Satisfy a Virtual Dependence
package works with any compatible MPI implementation. To build ------------------------------------------------------
``hdf5`` with Intel oneAPI MPI do::
The ``hdf5`` package works with any compatible MPI implementation. To
build ``hdf5`` with Intel oneAPI MPI do::
spack install hdf5 +mpi ^intel-oneapi-mpi spack install hdf5 +mpi ^intel-oneapi-mpi
@ -95,11 +101,23 @@ To use the compilers, add some information about the installation to
spack compiler add /opt/intel/oneapi/compiler/latest/linux/bin spack compiler add /opt/intel/oneapi/compiler/latest/linux/bin
Adapt the paths above if you did not install the tools in the default Adapt the paths above if you did not install the tools in the default
location. After adding the compilers, using them in Spack will be location. After adding the compilers, using them is the same
exactly the same as if you had installed the as if you had installed the ``intel-oneapi-compilers`` package.
``intel-oneapi-compilers`` package. Another option is to manually add Another option is to manually add the configuration to
the configuration to ``compilers.yaml`` as described in :ref:`Compiler ``compilers.yaml`` as described in :ref:`Compiler configuration
configuration <compiler-config>`. <compiler-config>`.
Libraries
---------
If you want Spack to use MKL that you have installed without Spack in
the default location, then add the following to
``~/.spack/packages.yaml``, adjusting the version as appropriate::
intel-oneapi-mkl:
externals:
- spec: intel-oneapi-mkl@2021.1.1
prefix: /opt/intel/oneapi/
Using oneAPI Tools Installed by Spack Using oneAPI Tools Installed by Spack

View File

@ -8,13 +8,13 @@
""" """
from sys import platform from sys import platform
from os.path import basename, dirname, isdir, join from os.path import basename, dirname, isdir
from spack.package import Package from spack.package import Package
from spack.util.environment import EnvironmentModifications from spack.util.environment import EnvironmentModifications
from spack.util.executable import Executable from spack.util.executable import Executable
from llnl.util.filesystem import find_headers, find_libraries from llnl.util.filesystem import find_headers, find_libraries, join_path
class IntelOneApiPackage(Package): class IntelOneApiPackage(Package):
@ -33,6 +33,11 @@ def component_dir(self):
"""Subdirectory for this component in the install prefix.""" """Subdirectory for this component in the install prefix."""
raise NotImplementedError raise NotImplementedError
@property
def component_path(self):
"""Path to component <prefix>/<component>/<version>."""
return join_path(self.prefix, self.component_dir, str(self.spec.version))
def install(self, spec, prefix, installer_path=None): def install(self, spec, prefix, installer_path=None):
"""Shared install method for all oneapi packages.""" """Shared install method for all oneapi packages."""
@ -53,21 +58,20 @@ def install(self, spec, prefix, installer_path=None):
'--install-dir', prefix) '--install-dir', prefix)
# Some installers have a bug and do not return an error code when failing # Some installers have a bug and do not return an error code when failing
if not isdir(join(prefix, self.component_dir)): if not isdir(join_path(prefix, self.component_dir)):
raise RuntimeError('install failed') raise RuntimeError('install failed')
def setup_run_environment(self, env): def setup_run_environment(self, env):
"""Adds environment variables to the generated module file. """Adds environment variables to the generated module file.
These environment variables come from running: These environment variables come from running:
.. code-block:: console .. code-block:: console
$ source {prefix}/setvars.sh --force $ source {prefix}/{component}/{version}/env/vars.sh
""" """
env.extend(EnvironmentModifications.from_sourcing_file( env.extend(EnvironmentModifications.from_sourcing_file(
join(self.prefix, self.component_dir, 'latest/env/vars.sh'))) join_path(self.component_path, 'env', 'vars.sh')))
class IntelOneApiLibraryPackage(IntelOneApiPackage): class IntelOneApiLibraryPackage(IntelOneApiPackage):
@ -75,12 +79,11 @@ class IntelOneApiLibraryPackage(IntelOneApiPackage):
@property @property
def headers(self): def headers(self):
include_path = '%s/%s/latest/include' % ( include_path = join_path(self.component_path, 'include')
self.prefix, self.component_dir)
return find_headers('*', include_path, recursive=True) return find_headers('*', include_path, recursive=True)
@property @property
def libs(self): def libs(self):
lib_path = '%s/%s/latest/lib/intel64' % (self.prefix, self.component_dir) lib_path = join_path(self.component_path, 'lib', 'intel64')
lib_path = lib_path if isdir(lib_path) else dirname(lib_path) lib_path = lib_path if isdir(lib_path) else dirname(lib_path)
return find_libraries('*', root=lib_path, shared=True, recursive=True) return find_libraries('*', root=lib_path, shared=True, recursive=True)

View File

@ -4,8 +4,8 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import glob import glob
import subprocess
from os import path from os import path
import subprocess
from sys import platform from sys import platform
from spack import * from spack import *
@ -36,19 +36,16 @@ class IntelOneapiCompilers(IntelOneApiPackage):
def component_dir(self): def component_dir(self):
return 'compiler' return 'compiler'
def _join_prefix(self, p):
return path.join(self.prefix, 'compiler', 'latest', 'linux', p)
def _ld_library_path(self): def _ld_library_path(self):
dirs = ['lib', dirs = ['lib',
path.join('lib', 'x64'), join_path('lib', 'x64'),
path.join('lib', 'emu'), join_path('lib', 'emu'),
path.join('lib', 'oclfpga', 'host', 'linux64', 'lib'), join_path('lib', 'oclfpga', 'host', 'linux64', 'lib'),
path.join('lib', 'oclfpga', 'linux64', 'lib'), join_path('lib', 'oclfpga', 'linux64', 'lib'),
path.join('compiler', 'lib', 'intel64_lin'), join_path('compiler', 'lib', 'intel64_lin'),
path.join('compiler', 'lib')] join_path('compiler', 'lib')]
for dir in dirs: for dir in dirs:
yield self._join_prefix(dir) yield join_path(self.component_path, 'linux', dir)
def install(self, spec, prefix): def install(self, spec, prefix):
# install cpp # install cpp
@ -60,22 +57,23 @@ def install(self, spec, prefix):
super(IntelOneapiCompilers, self).install( super(IntelOneapiCompilers, self).install(
spec, spec,
prefix, prefix,
installer_path=glob.glob(path.join('fortran-installer', '*'))[0]) installer_path=glob.glob(join_path('fortran-installer', '*'))[0])
# Some installers have a bug and do not return an error code when failing # Some installers have a bug and do not return an error code when failing
if not path.isfile(path.join(prefix, 'compiler', 'latest', 'linux', if not path.isfile(join_path(self.component_path, 'linux',
'bin', 'intel64', 'ifort')): 'bin', 'intel64', 'ifort')):
raise RuntimeError('install failed') raise RuntimeError('install failed')
# set rpath so 'spack compiler add' can check version strings # set rpath so 'spack compiler add' can check version strings
# without setting LD_LIBRARY_PATH # without setting LD_LIBRARY_PATH
rpath = ':'.join(self._ld_library_path()) rpath = ':'.join(self._ld_library_path())
patch_dirs = [path.join('compiler', 'lib', 'intel64_lin'), patch_dirs = [join_path('compiler', 'lib', 'intel64_lin'),
path.join('compiler', 'lib', 'intel64'), join_path('compiler', 'lib', 'intel64'),
'bin'] 'bin']
for pd in patch_dirs: for pd in patch_dirs:
patchables = glob.glob(self._join_prefix(path.join(pd, '*'))) patchables = glob.glob(join_path(self.component_path, 'linux', pd, '*'))
patchables.append(self._join_prefix(path.join('lib', 'icx-lto.so'))) patchables.append(join_path(self.component_path,
'linux', 'lib', 'icx-lto.so'))
for file in patchables: for file in patchables:
# Try to patch all files, patchelf will do nothing if # Try to patch all files, patchelf will do nothing if
# file should not be patched # file should not be patched

View File

@ -36,6 +36,8 @@ def component_dir(self):
@property @property
def libs(self): def libs(self):
lib_path = '{0}/{1}/latest/lib/intel64'.format(self.prefix, self.component_dir) lib_path = join_path(self.component_path, 'lib', 'intel64')
mkl_libs = ['libmkl_intel_ilp64', 'libmkl_sequential', 'libmkl_core'] mkl_libs = ['libmkl_intel_lp64', 'libmkl_sequential', 'libmkl_core']
return find_libraries(mkl_libs, root=lib_path, shared=True, recursive=False) libs = find_libraries(mkl_libs, root=lib_path, shared=True, recursive=False)
libs += find_system_libraries(['libpthread', 'libm', 'libdl'], shared=True)
return libs

View File

@ -4,7 +4,6 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
from os import path
import subprocess import subprocess
from sys import platform from sys import platform
@ -34,7 +33,7 @@ def component_dir(self):
return 'mpi' return 'mpi'
def setup_dependent_package(self, module, dep_spec): def setup_dependent_package(self, module, dep_spec):
dir = join_path(self.prefix, 'mpi', 'latest', 'bin') dir = join_path(self.component_path, 'bin')
self.spec.mpicc = join_path(dir, 'mpicc') self.spec.mpicc = join_path(dir, 'mpicc')
self.spec.mpicxx = join_path(dir, 'mpicxx') self.spec.mpicxx = join_path(dir, 'mpicxx')
self.spec.mpif77 = join_path(dir, 'mpif77') self.spec.mpif77 = join_path(dir, 'mpif77')
@ -48,7 +47,7 @@ def setup_dependent_build_environment(self, env, dependent_spec):
env.set('MPICH_FC', spack_fc) env.set('MPICH_FC', spack_fc)
# Set compiler wrappers for dependent build stage # Set compiler wrappers for dependent build stage
dir = self._join_prefix('bin') dir = join_path(self.component_path, 'bin')
env.set('MPICC', join_path(dir, 'mpicc')) env.set('MPICC', join_path(dir, 'mpicc'))
env.set('MPICXX', join_path(dir, 'mpicxx')) env.set('MPICXX', join_path(dir, 'mpicxx'))
env.set('MPIF77', join_path(dir, 'mpif77')) env.set('MPIF77', join_path(dir, 'mpif77'))
@ -58,22 +57,19 @@ def setup_dependent_build_environment(self, env, dependent_spec):
@property @property
def libs(self): def libs(self):
libs = [] libs = []
for dir in [path.join('lib', 'release_mt'), for dir in [join_path('lib', 'release_mt'),
'lib', 'lib',
path.join('libfabric', 'lib')]: join_path('libfabric', 'lib')]:
lib_path = path.join(self.prefix, 'mpi', 'latest', dir) lib_path = join_path(self.component_path, dir)
ldir = find_libraries('*', root=lib_path, shared=True, recursive=False) ldir = find_libraries('*', root=lib_path, shared=True, recursive=False)
libs += ldir libs += ldir
return libs return libs
def _join_prefix(self, path):
return join_path(self.prefix, 'mpi', 'latest', path)
def install(self, spec, prefix): def install(self, spec, prefix):
super(IntelOneapiMpi, self).install(spec, prefix) super(IntelOneapiMpi, self).install(spec, prefix)
# need to patch libmpi.so so it can always find libfabric # need to patch libmpi.so so it can always find libfabric
libfabric_rpath = self._join_prefix(path.join('libfabric', 'lib')) libfabric_rpath = join_path(self.component_path, 'libfabric', 'lib')
for lib_version in ['debug', 'release', 'release_mt', 'debug_mt']: for lib_version in ['debug', 'release', 'release_mt', 'debug_mt']:
file = self._join_prefix(path.join('lib', lib_version, 'libmpi.so')) file = join_path(self.component_path, 'lib', lib_version, 'libmpi.so')
subprocess.call(['patchelf', '--set-rpath', libfabric_rpath, file]) subprocess.call(['patchelf', '--set-rpath', libfabric_rpath, file])