Skip to content

Commit

Permalink
Separable module configuration -- without the bugs this time (spack#2…
Browse files Browse the repository at this point in the history
…3703)

Currently, module configurations are inconsistent because modulefiles are generated with the configs for the active environment, but are shared among all environments (and spack outside any environment).

This PR fixes that by allowing Spack environments (or other spack config scopes) to define additional sets of modules to generate. Each set of modules can enable either lmod or tcl modules, and contains all of the previously available module configuration. The user defines the name of each module set -- the set configured in Spack by default is named "default", and is the one returned by module manipulation commands in the absence of user intervention.

As part of this change, the module roots configuration moved from the config section to inside each module configuration.

Additionally, it adds a feature that the modulefiles for an environment can be configured to be relative to an environment view rather than the underlying prefix. This will not be enabled by default, as it should only be enabled within an environment and for non-default views constructed with separate projections per-spec.
  • Loading branch information
becker33 authored May 28, 2021
1 parent 9b99f85 commit 7490d63
Show file tree
Hide file tree
Showing 36 changed files with 691 additions and 222 deletions.
7 changes: 0 additions & 7 deletions etc/spack/defaults/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,6 @@ config:
template_dirs:
- $spack/share/spack/templates


# Locations where different types of modules should be installed.
module_roots:
tcl: $spack/share/spack/modules
lmod: $spack/share/spack/lmod


# Temporary locations Spack can try to use for builds.
#
# Recommended options are given below.
Expand Down
11 changes: 6 additions & 5 deletions etc/spack/defaults/linux/modules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
# ~/.spack/modules.yaml
# -------------------------------------------------------------------------
modules:
prefix_inspections:
lib:
- LD_LIBRARY_PATH
lib64:
- LD_LIBRARY_PATH
default:
prefix_inspections:
lib:
- LD_LIBRARY_PATH
lib64:
- LD_LIBRARY_PATH
23 changes: 18 additions & 5 deletions etc/spack/defaults/modules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
# ~/.spack/modules.yaml
# -------------------------------------------------------------------------
modules:
enable:
- tcl
# Paths to check when creating modules for all module sets
prefix_inspections:
bin:
- PATH
Expand All @@ -34,6 +33,20 @@ modules:
'':
- CMAKE_PREFIX_PATH

lmod:
hierarchy:
- mpi
# These are configurations for the module set named "default"
default:
# These values are defaulted in the code. They are not defaulted here so
# that we can enable backwards compatibility with the old syntax more
# easily (old value is in the config yaml, config:module_roots)
# Where to install modules
# roots:
# tcl: $spack/share/spack/modules
# lmod: $spack/share/spack/lmod
# What type of modules to use
enable:
- tcl

# Default configurations if lmod is enabled
lmod:
hierarchy:
- mpi
2 changes: 2 additions & 0 deletions lib/spack/docs/environments.rst
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,8 @@ Spack Environment managed views are updated every time the environment
is written out to the lock file ``spack.lock``, so the concrete
environment and the view are always compatible.

.. _configuring_environment_views:

"""""""""""""""""""""""""""""
Configuring environment views
"""""""""""""""""""""""""""""
Expand Down
150 changes: 134 additions & 16 deletions lib/spack/docs/module_file_support.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,24 @@ Module file customization
-------------------------

Module files are generated by post-install hooks after the successful
installation of a package. The table below summarizes the essential
information associated with the different file formats
that can be generated by Spack:
installation of a package.

.. note::

Spack only generates modulefiles when a package is installed. If
you attempt to install a package and it is already installed, Spack
will not regenerate modulefiles for the package. This may to
inconsistent modulefiles if the Spack module configuration has
changed since the package was installed, either by editing a file
or changing scopes or environments.

Later in this section there is a subsection on :ref:`regenerating
modules <cmd-spack-module-refresh>` that will allow you to bring
your modules to a consistent state.

The table below summarizes the essential information associated with
the different file formats that can be generated by Spack:


+-----------------------------+--------------------+-------------------------------+----------------------------------------------+----------------------+
| | **Hook name** | **Default root directory** | **Default template file** | **Compatible tools** |
Expand Down Expand Up @@ -163,6 +178,46 @@ the installation folder of each package for the presence of a set of subdirector
(``bin``, ``man``, ``share/man``, etc.). If any is found its full path is prepended
to the environment variables listed below the folder name.

Spack modules can be configured for multiple module sets. The default
module set is named ``default``. All Spack commands which operate on
modules default to apply the ``default`` module set, but can be
applied to any module set in the configuration. Settings applied at
the root of the configuration (e.g. ``modules:enable`` rather than
``modules:default:enable``) are applied to the default module set for
backwards compatibility.

"""""""""""""""""""""""""
Changing the modules root
"""""""""""""""""""""""""

As shown in the table above, the default module root for ``lmod`` is
``$spack/share/spack/lmod`` and the default root for ``tcl`` is
``$spack/share/spack/modules``. This can be overridden for any module
set by changing the ``roots`` key of the configuration.

.. code-block:: yaml
modules:
default:
roots:
tcl: /path/to/install/tcl/modules
my_custom_lmod_modules:
roots:
lmod: /path/to/install/custom/lmod/modules
...
This configuration will create two module sets. The default module set
will install its ``tcl`` modules to ``/path/to/install/tcl/modules``
(and still install its lmod modules, if any, to the default
location). The set ``my_custom_lmod_modules`` will install its lmod
modules to ``/path/to/install/custom/lmod/modules`` (and still install
its tcl modules, if any, to the default location).

Obviously, having multiple module sets install modules to the default
location could be confusing to users of your modules. In the next
section, we will discuss enabling and disabling module types (module
file generators) for each module set.

""""""""""""""""""""
Activate other hooks
""""""""""""""""""""
Expand All @@ -178,13 +233,14 @@ to the generator being customized:
.. code-block:: yaml
modules:
enable:
- tcl
- lmod
tcl:
# contains environment modules specific customizations
lmod:
# contains lmod specific customizations
default:
enable:
- tcl
- lmod
tcl:
# contains environment modules specific customizations
lmod:
# contains lmod specific customizations
In general, the configuration options that you can use in ``modules.yaml`` will
either change the layout of the module files on the filesystem, or they will affect
Expand Down Expand Up @@ -399,10 +455,16 @@ that are already in the LMod hierarchy.
Customize environment modifications
"""""""""""""""""""""""""""""""""""

You can control which prefixes in a Spack package are added to environment
variables with the ``prefix_inspections`` section; this section maps relative
prefixes to the list of environment variables which should be updated with
those prefixes.
You can control which prefixes in a Spack package are added to
environment variables with the ``prefix_inspections`` section; this
section maps relative prefixes to the list of environment variables
which should be updated with those prefixes.

The ``prefix_inspections`` configuration is different from other
settings in that a ``prefix_inspections`` configuration at the
``modules`` level of the configuration file applies to all module
sets. This allows users to make general overrides to the default
inspections and customize them per-module-set.

.. code-block:: yaml
Expand All @@ -415,10 +477,66 @@ those prefixes.
'':
- CMAKE_PREFIX_PATH
In this case, for a Spack package ``foo`` installed to ``/spack/prefix/foo``,
the generated module file for ``foo`` would update ``PATH`` to contain
Prefix inspections are only applied if the relative path inside the
installation prefix exists. In this case, for a Spack package ``foo``
installed to ``/spack/prefix/foo``, if ``foo`` installs executables to
``bin`` but no libraries in ``lib``, the generated module file for
``foo`` would update ``PATH`` to contain ``/spack/prefix/foo/bin`` and
``CMAKE_PREFIX_PATH`` to contain ``/spack/prefix/foo``, but would not
update ``LIBRARY_PATH``.

There is a special case for prefix inspections relative to environment
views. If all of the following conditions hold for a module set
configuration:

#. The configuration is for an :ref:`environment <environments>` and
will never be applied outside the environment,
#. The environment in question is configured to use a :ref:`view
<filesystem-views>`,
#. The :ref:`environment view is configured
<configuring_environment_views>` with a projection that ensures
every package is linked to a unique directory,

then the module set may be configured to create modules relative to
the environment view. This is specified by the ``use_view``
configuration option in the module set. If ``True``, the module set is
constructed relative to the default view of the
environment. Otherwise, the value must be the name of the environment
view relative to which to construct modules, or ``False-ish`` to
disable the feature explicitly (the default is ``False``).

If the ``use_view`` value is set in the config, then the prefix
inspections for the package are done relative to the package's path in
the view.

.. code-block:: yaml
spack:
modules:
view_relative_modules:
use_view: my_view
prefix_inspections:
bin:
- PATH
view:
my_view:
projections:
root: /path/to/my/view
all: '{name}-{hash}'
The ``spack`` key is relevant to :ref:`environment <environments>`
configuration, and the view key is discussed in detail in the section
on :ref:`Configuring environment views
<configuring_environment_views>`. With this configuration the
generated module for package ``foo`` would set ``PATH`` to include
``/path/to/my/view/foo-<hash>/bin`` instead of
``/spack/prefix/foo/bin``.

The ``use_view`` option is useful when deploying a large software
stack to users who are likely to inspect the modules to find full
paths to software, when it is desirable to present the users with a
simpler set of paths than those generated by the Spack install tree.

""""""""""""""""""""""""""""""""""""
Filter out environment modifications
""""""""""""""""""""""""""""""""""""
Expand Down
3 changes: 3 additions & 0 deletions lib/spack/spack/cmd/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,9 @@ def env_loads_setup_parser(subparser):
"""list modules for an installed environment '(see spack module loads)'"""
subparser.add_argument(
'env', nargs='?', help='name of env to generate loads file for')
subparser.add_argument(
'-n', '--module-set-name', default='default',
help='module set for which to generate load operations')
subparser.add_argument(
'-m', '--module-type', choices=('tcl', 'lmod'),
help='type of module system to generate loads for')
Expand Down
10 changes: 5 additions & 5 deletions lib/spack/spack/cmd/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def install_specs(cli_args, kwargs, specs):
with env.write_transaction():
specs_to_install.append(
env.concretize_and_add(abstract, concrete))
env.write(regenerate_views=False)
env.write(regenerate=False)

# Install the validated list of cli specs
if specs_to_install:
Expand Down Expand Up @@ -340,7 +340,7 @@ def get_tests(specs):

# save view regeneration for later, so that we only do it
# once, as it can be slow.
env.write(regenerate_views=False)
env.write(regenerate=False)

specs = env.all_specs()
if not args.log_file and not reporter.filename:
Expand All @@ -354,9 +354,9 @@ def get_tests(specs):
tty.debug("Regenerating environment views for {0}"
.format(env.name))
with env.write_transaction():
# It is not strictly required to synchronize view regeneration
# but doing so can prevent redundant work in the filesystem.
env.regenerate_views()
# write env to trigger view generation and modulefile
# generation
env.write()
return
else:
msg = "install requires a package argument or active environment"
Expand Down
Loading

0 comments on commit 7490d63

Please sign in to comment.