Advanced packaging tutorial: reorganize for binary caches (#9804)
Update all examples that need an MPI provider to build with MPICH; reorganize so that fixing MPICH (as part of environment section) comes first in the tutorial (most examples in the tutorial use an MPI provider).
This commit is contained in:
parent
a8e8d80750
commit
2a5d5fda26
@ -38,6 +38,14 @@ in a separate package repository, which can be enabled with:
|
||||
|
||||
$ spack repo add --scope=site var/spack/repos/tutorial
|
||||
|
||||
This section of the tutorial may also require a newer version of gcc, which
|
||||
you can add with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ spack install gcc@7.2.0
|
||||
$ spack compiler add --scope=site path/to/spack-installed-gcc/bin
|
||||
|
||||
If you are using the tutorial docker image, all dependency packages
|
||||
will have been installed. Otherwise, to install these packages you can use
|
||||
the following commands:
|
||||
@ -47,24 +55,155 @@ the following commands:
|
||||
$ spack install openblas
|
||||
$ spack install netlib-lapack
|
||||
$ spack install mpich
|
||||
$ spack install openmpi
|
||||
$ spack install --only=dependencies armadillo ^openblas
|
||||
$ spack install --only=dependencies netcdf
|
||||
$ spack install --only=dependencies elpa
|
||||
|
||||
Now, you are ready to set your preferred ``EDITOR`` and continue with
|
||||
the rest of the tutorial.
|
||||
|
||||
.. note::
|
||||
|
||||
Several of these packages depend on an MPI implementation. You can use
|
||||
OpenMPI if you install it from scratch, but this is slow (>10 min.).
|
||||
A binary cache of MPICH may be provided, in which case you can force
|
||||
the package to use it and install quickly. All tutorial examples with
|
||||
packages that depend on MPICH include the spec syntax for building with it
|
||||
|
||||
.. _adv_pkg_tutorial_start:
|
||||
|
||||
---------------------------------------
|
||||
Modifying a package's build environment
|
||||
---------------------------------------
|
||||
|
||||
Spack sets up several environment variables like ``PATH`` by default to aid in
|
||||
building a package, but many packages make use of environment variables which
|
||||
convey specific information about their dependencies (e.g., ``MPICC``).
|
||||
This section covers how to update your Spack packages so that package-specific
|
||||
environment variables are defined at build-time.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Set environment variables in dependent packages at build-time
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Dependencies can set environment variables that are required when their
|
||||
dependents build. For example, when a package depends on a python extension
|
||||
like py-numpy, Spack's ``python`` package will add it to ``PYTHONPATH``
|
||||
so it is available at build time; this is required because the default setup
|
||||
that spack does is not sufficient for python to import modules.
|
||||
|
||||
To provide environment setup for a dependent, a package can implement the
|
||||
:py:func:`setup_dependent_environment <spack.package.PackageBase.setup_dependent_environment>`
|
||||
function. This function takes as a parameter a :py:class:`EnvironmentModifications <spack.util.environment.EnvironmentModifications>`
|
||||
object which includes convenience methods to update the environment. For
|
||||
example, an MPI implementation can set ``MPICC`` for packages that depend on it:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
spack_env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
|
||||
|
||||
In this case packages that depend on ``mpi`` will have ``MPICC`` defined in
|
||||
their environment when they build. This section is focused on modifying the
|
||||
build-time environment represented by ``spack_env``, but it's worth noting that
|
||||
modifications to ``run_env`` are included in Spack's automatically-generated
|
||||
module files.
|
||||
|
||||
We can practice by editing the ``mpich`` package to set the ``MPICC``
|
||||
environment variable in the build-time environment of dependent packages.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack edit mpich
|
||||
|
||||
Once you're finished, the method should look like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
spack_env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
|
||||
spack_env.set('MPICXX', join_path(self.prefix.bin, 'mpic++'))
|
||||
spack_env.set('MPIF77', join_path(self.prefix.bin, 'mpif77'))
|
||||
spack_env.set('MPIF90', join_path(self.prefix.bin, 'mpif90'))
|
||||
|
||||
spack_env.set('MPICH_CC', spack_cc)
|
||||
spack_env.set('MPICH_CXX', spack_cxx)
|
||||
spack_env.set('MPICH_F77', spack_f77)
|
||||
spack_env.set('MPICH_F90', spack_fc)
|
||||
spack_env.set('MPICH_FC', spack_fc)
|
||||
|
||||
At this point we can, for instance, install ``netlib-scalapack`` with
|
||||
``mpich``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack install netlib-scalapack ^mpich
|
||||
...
|
||||
==> Created stage in /usr/local/var/spack/stage/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
|
||||
==> No patches needed for netlib-scalapack
|
||||
==> Building netlib-scalapack [CMakePackage]
|
||||
==> Executing phase: 'cmake'
|
||||
==> Executing phase: 'build'
|
||||
==> Executing phase: 'install'
|
||||
==> Successfully installed netlib-scalapack
|
||||
Fetch: 0.01s. Build: 3m 59.86s. Total: 3m 59.87s.
|
||||
[+] /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
|
||||
|
||||
|
||||
and double check the environment logs to verify that every variable was
|
||||
set to the correct value.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Set environment variables in your own package
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Packages can modify their own build-time environment by implementing the
|
||||
:py:func:`setup_environment <spack.package.PackageBase.setup_environment>` function.
|
||||
For ``qt`` this looks like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_environment(self, spack_env, run_env):
|
||||
spack_env.set('MAKEFLAGS', '-j{0}'.format(make_jobs))
|
||||
run_env.set('QTDIR', self.prefix)
|
||||
|
||||
When ``qt`` builds, ``MAKEFLAGS`` will be defined in the environment.
|
||||
|
||||
To contrast with ``qt``'s :py:func:`setup_dependent_environment <spack.package.PackageBase.setup_dependent_environment>`
|
||||
function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
spack_env.set('QTDIR', self.prefix)
|
||||
|
||||
Let's see how it works by completing the ``elpa`` package:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack edit elpa
|
||||
|
||||
In the end your method should look like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_environment(self, spack_env, run_env):
|
||||
spec = self.spec
|
||||
|
||||
spack_env.set('CC', spec['mpi'].mpicc)
|
||||
spack_env.set('FC', spec['mpi'].mpifc)
|
||||
spack_env.set('CXX', spec['mpi'].mpicxx)
|
||||
spack_env.set('SCALAPACK_LDFLAGS', spec['scalapack'].libs.joined())
|
||||
|
||||
spack_env.append_flags('LDFLAGS', spec['lapack'].libs.search_flags)
|
||||
spack_env.append_flags('LIBS', spec['lapack'].libs.link_flags)
|
||||
|
||||
At this point it's possible to proceed with the installation of ``elpa ^mpich``
|
||||
|
||||
------------------------------
|
||||
Retrieving library information
|
||||
------------------------------
|
||||
|
||||
Although Spack attempts to help packages locate their dependency libraries
|
||||
automatically (e.g. by setting PKG_CONFIG_PATH and CMAKE_PREFIX_PATH), a
|
||||
package may have unique configuration options that are required to locate
|
||||
automatically (e.g. by setting ``PKG_CONFIG_PATH`` and ``CMAKE_PREFIX_PATH``),
|
||||
a package may have unique configuration options that are required to locate
|
||||
libraries. When a package needs information about dependency libraries, the
|
||||
general approach in Spack is to query the dependencies for the locations of
|
||||
their libraries and set configuration options accordingly. By default most
|
||||
@ -130,11 +269,11 @@ is as easy as accessing the their ``libs`` attribute. Furthermore, the interface
|
||||
remains the same whether you are querying regular or virtual dependencies.
|
||||
|
||||
At this point you can complete the installation of ``armadillo`` using ``openblas``
|
||||
as a LAPACK provider:
|
||||
as a LAPACK provider (``armadillo ^openblas ^mpich``):
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack install armadillo ^openblas
|
||||
root@advanced-packaging-tutorial:/# spack install armadillo ^openblas ^mpich
|
||||
==> pkg-config is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
|
||||
...
|
||||
==> superlu is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/superlu-5.2.1-q2mbtw2wo4kpzis2e2n227ip2fquxrno
|
||||
@ -179,12 +318,12 @@ follow this naming scheme must implement this function themselves, e.g.
|
||||
|
||||
This issue is common for packages which implement an interface (i.e.
|
||||
virtual package providers in Spack). If we try to build another version of
|
||||
``armadillo`` tied to ``netlib-lapack`` we'll notice that this time the
|
||||
installation won't complete:
|
||||
``armadillo`` tied to ``netlib-lapack`` (``armadillo ^netlib-lapack ^mpich``)
|
||||
we'll notice that this time the installation won't complete:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack install armadillo ^netlib-lapack
|
||||
root@advanced-packaging-tutorial:/# spack install armadillo ^netlib-lapack ^mpich
|
||||
==> pkg-config is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/pkg-config-0.29.2-ae2hwm7q57byfbxtymts55xppqwk7ecj
|
||||
...
|
||||
==> openmpi is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/openmpi-3.0.0-yo5qkfvumpmgmvlbalqcadu46j5bd52f
|
||||
@ -226,7 +365,7 @@ What we need to implement is:
|
||||
def lapack_libs(self):
|
||||
shared = True if '+shared' in self.spec else False
|
||||
return find_libraries(
|
||||
'liblapack', root=self.prefix, shared=shared, recurse=True
|
||||
'liblapack', root=self.prefix, shared=shared, recursive=True
|
||||
)
|
||||
|
||||
i.e., a property that returns the correct list of libraries for the LAPACK interface.
|
||||
@ -236,11 +375,11 @@ We use the name ``lapack_libs`` rather than ``libs`` because
|
||||
as a separate library file. Using this name ensures that when
|
||||
dependents ask for ``lapack`` libraries, ``netlib-lapack`` will retrieve only
|
||||
the libraries associated with the ``lapack`` interface. Now we can finally
|
||||
install ``armadillo ^netlib-lapack``:
|
||||
install ``armadillo ^netlib-lapack ^mpich``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack install armadillo ^netlib-lapack
|
||||
root@advanced-packaging-tutorial:/# spack install armadillo ^netlib-lapack ^mpich
|
||||
...
|
||||
|
||||
==> Building armadillo [CMakePackage]
|
||||
@ -256,133 +395,6 @@ libraries associated with the interfaces it provides, dependents do not need
|
||||
to include special-case logic for different implementations and for example
|
||||
need only ask for :code:`spec['blas'].libs`.
|
||||
|
||||
---------------------------------------
|
||||
Modifying a package's build environment
|
||||
---------------------------------------
|
||||
|
||||
Spack sets up several environment variables like PATH by default to aid in
|
||||
building a package, but many packages make use of environment variables which
|
||||
convey specific information about their dependencies (e.g., MPICC). This
|
||||
section covers how update your Spack packages so that package-specific
|
||||
environment variables are defined at build-time.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Set environment variables in dependent packages at build-time
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Dependencies can set environment variables that are required when their
|
||||
dependents build. For example, when a package depends on a python extension
|
||||
like py-numpy, Spack's ``python`` package will add it to ``PYTHONPATH``
|
||||
so it is available at build time; this is required because the default setup
|
||||
that spack does is not sufficient for python to import modules.
|
||||
|
||||
To provide environment setup for a dependent, a package can implement the
|
||||
:py:func:`setup_dependent_environment <spack.package.PackageBase.setup_dependent_environment>`
|
||||
function. This function takes as a parameter a :py:class:`EnvironmentModifications <spack.util.environment.EnvironmentModifications>`
|
||||
object which includes convenience methods to update the environment. For
|
||||
example, an MPI implementation can set ``MPICC`` for packages that depend on it:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
spack_env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
|
||||
|
||||
In this case packages that depend on ``mpi`` will have ``MPICC`` defined in
|
||||
their environment when they build. This section is focused on modifying the
|
||||
build-time environment represented by ``spack_env``, but it's worth noting that
|
||||
modifications to ``run_env`` are included in Spack's automatically-generated
|
||||
module files.
|
||||
|
||||
We can practice by editing the ``mpich`` package to set the ``MPICC``
|
||||
environment variable in the build-time environment of dependent packages.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack edit mpich
|
||||
|
||||
Once you're finished, the method should look like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
spack_env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
|
||||
spack_env.set('MPICXX', join_path(self.prefix.bin, 'mpic++'))
|
||||
spack_env.set('MPIF77', join_path(self.prefix.bin, 'mpif77'))
|
||||
spack_env.set('MPIF90', join_path(self.prefix.bin, 'mpif90'))
|
||||
|
||||
spack_env.set('MPICH_CC', spack_cc)
|
||||
spack_env.set('MPICH_CXX', spack_cxx)
|
||||
spack_env.set('MPICH_F77', spack_f77)
|
||||
spack_env.set('MPICH_F90', spack_fc)
|
||||
spack_env.set('MPICH_FC', spack_fc)
|
||||
|
||||
At this point we can, for instance, install ``netlib-scalapack``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack install netlib-scalapack ^mpich
|
||||
...
|
||||
==> Created stage in /usr/local/var/spack/stage/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
|
||||
==> No patches needed for netlib-scalapack
|
||||
==> Building netlib-scalapack [CMakePackage]
|
||||
==> Executing phase: 'cmake'
|
||||
==> Executing phase: 'build'
|
||||
==> Executing phase: 'install'
|
||||
==> Successfully installed netlib-scalapack
|
||||
Fetch: 0.01s. Build: 3m 59.86s. Total: 3m 59.87s.
|
||||
[+] /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/netlib-scalapack-2.0.2-km7tsbgoyyywonyejkjoojskhc5knz3z
|
||||
|
||||
|
||||
and double check the environment logs to verify that every variable was
|
||||
set to the correct value.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Set environment variables in your own package
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Packages can modify their own build-time environment by implementing the
|
||||
:py:func:`setup_environment <spack.package.PackageBase.setup_environment>` function.
|
||||
For ``qt`` this looks like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_environment(self, spack_env, run_env):
|
||||
spack_env.set('MAKEFLAGS', '-j{0}'.format(make_jobs))
|
||||
run_env.set('QTDIR', self.prefix)
|
||||
|
||||
When ``qt`` builds, ``MAKEFLAGS`` will be defined in the environment.
|
||||
|
||||
To contrast with ``qt``'s :py:func:`setup_dependent_environment <spack.package.PackageBase.setup_dependent_environment>`
|
||||
function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
|
||||
spack_env.set('QTDIR', self.prefix)
|
||||
|
||||
Let's see how it works by completing the ``elpa`` package:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack edit elpa
|
||||
|
||||
In the end your method should look like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def setup_environment(self, spack_env, run_env):
|
||||
spec = self.spec
|
||||
|
||||
spack_env.set('CC', spec['mpi'].mpicc)
|
||||
spack_env.set('FC', spec['mpi'].mpifc)
|
||||
spack_env.set('CXX', spec['mpi'].mpicxx)
|
||||
spack_env.set('SCALAPACK_LDFLAGS', spec['scalapack'].libs.joined())
|
||||
|
||||
spack_env.append_flags('LDFLAGS', spec['lapack'].libs.search_flags)
|
||||
spack_env.append_flags('LIBS', spec['lapack'].libs.link_flags)
|
||||
|
||||
At this point it's possible to proceed with the installation of ``elpa``.
|
||||
|
||||
----------------------
|
||||
Other Packaging Topics
|
||||
----------------------
|
||||
@ -425,11 +437,11 @@ for extra parameters after the subscript key. In fact, any of the keys used in t
|
||||
can be followed by a comma-separated list of extra parameters which can be
|
||||
inspected by the package receiving the request to fine-tune a response.
|
||||
|
||||
Let's look at an example and try to install ``netcdf``:
|
||||
Let's look at an example and try to install ``netcdf ^mpich``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack install netcdf
|
||||
root@advanced-packaging-tutorial:/# spack install netcdf ^mpich
|
||||
==> libsigsegv is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
|
||||
==> m4 is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a
|
||||
...
|
||||
@ -471,11 +483,11 @@ If you followed the instructions correctly, the code added to the
|
||||
)
|
||||
|
||||
where we highlighted the line retrieving the extra parameters. Now we can successfully
|
||||
complete the installation of ``netcdf``:
|
||||
complete the installation of ``netcdf ^mpich``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
root@advanced-packaging-tutorial:/# spack install netcdf
|
||||
root@advanced-packaging-tutorial:/# spack install netcdf ^mpich
|
||||
==> libsigsegv is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/libsigsegv-2.11-fypapcprssrj3nstp6njprskeyynsgaz
|
||||
==> m4 is already installed in /usr/local/opt/spack/linux-ubuntu16.04-x86_64/gcc-5.4.0/m4-1.4.18-r5envx3kqctwwflhd4qax4ahqtt6x43a
|
||||
...
|
||||
|
Loading…
Reference in New Issue
Block a user