summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@gmail.com>2019-10-17 19:17:21 +0200
committerGreg Becker <becker33@llnl.gov>2019-10-17 10:17:21 -0700
commit9ddc98e46a73d53e9937cad1a430a34522d241de (patch)
tree3d7991d457dba508e4a58c12f31dcc969d126f28 /lib
parentcf9de058aaa6bfde635868422b504e4fb1413359 (diff)
downloadspack-9ddc98e46a73d53e9937cad1a430a34522d241de.tar.gz
spack-9ddc98e46a73d53e9937cad1a430a34522d241de.tar.bz2
spack-9ddc98e46a73d53e9937cad1a430a34522d241de.tar.xz
spack-9ddc98e46a73d53e9937cad1a430a34522d241de.zip
Separate setting build environment and run environment in packages (#11115)
* Methods setting the environment now do it separately for build and run Before this commit the `*_environment` methods were setting modifications to both the build-time and run-time environment simultaneously. This might cause issues as the two environments inherently rely on different preconditions: 1. The build-time environment is set before building a package, thus the package prefix doesn't exist and can't be inspected 2. The run-time environment instead is set assuming the target package has been already installed Here we split each of these functions into two: one setting the build-time environment, one the run-time. We also adopt a fallback strategy that inspects for old methods and executes them as before, but prints a deprecation warning to tty. This permits to port packages to use the new methods in a distributed way, rather than having to modify all the packages at once. * Added a test that fails if any package uses the old API Marked the test xfail for now as we have a lot of packages in that state. * Added a test to check that a package modified by a PR is up to date This test can be used any time we deprecate a method call to ensure that during the first modification of the package we update also the deprecated calls. * Updated documentation
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/docs/module_file_support.rst14
-rw-r--r--lib/spack/docs/packaging_guide.rst71
-rw-r--r--lib/spack/docs/tutorial_advanced_packaging.rst79
-rw-r--r--lib/spack/spack/build_environment.py64
-rw-r--r--lib/spack/spack/cmd/flake8.py9
-rw-r--r--lib/spack/spack/modules/common.py17
-rw-r--r--lib/spack/spack/package.py131
-rw-r--r--lib/spack/spack/test/package_sanity.py50
8 files changed, 275 insertions, 160 deletions
diff --git a/lib/spack/docs/module_file_support.rst b/lib/spack/docs/module_file_support.rst
index 7ce2398af2..1b5de3a0e8 100644
--- a/lib/spack/docs/module_file_support.rst
+++ b/lib/spack/docs/module_file_support.rst
@@ -303,8 +303,7 @@ content of the module files generated by Spack. The first one:
.. code-block:: python
- def setup_environment(self, spack_env, run_env):
- """Set up the compile and runtime environments for a package."""
+ def setup_run_environment(self, env):
pass
can alter the content of the module file associated with the same package where it is overridden.
@@ -312,16 +311,15 @@ The second method:
.. code-block:: python
- def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
- """Set up the environment of packages that depend on this one"""
+ def setup_dependent_run_environment(self, env, dependent_spec):
pass
can instead inject run-time environment modifications in the module files of packages
that depend on it. In both cases you need to fill ``run_env`` with the desired
list of environment modifications.
-.. note::
- The ``r`` package and callback APIs
+.. admonition:: The ``r`` package and callback APIs
+
An example in which it is crucial to override both methods
is given by the ``r`` package. This package installs libraries and headers
in non-standard locations and it is possible to prepend the appropriate directory
@@ -336,14 +334,14 @@ list of environment modifications.
with the following snippet:
.. literalinclude:: _spack_root/var/spack/repos/builtin/packages/r/package.py
- :pyobject: R.setup_environment
+ :pyobject: R.setup_run_environment
The ``r`` package also knows which environment variable should be modified
to make language extensions provided by other packages available, and modifies
it appropriately in the override of the second method:
.. literalinclude:: _spack_root/var/spack/repos/builtin/packages/r/package.py
- :pyobject: R.setup_dependent_environment
+ :pyobject: R.setup_dependent_run_environment
.. _modules-yaml:
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst
index 5adb996232..767a744baa 100644
--- a/lib/spack/docs/packaging_guide.rst
+++ b/lib/spack/docs/packaging_guide.rst
@@ -2032,55 +2032,58 @@ appear in the package file (or in this case, in the list).
.. _setup-dependent-environment:
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-``setup_dependent_environment()``
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Spack provides a mechanism for dependencies to provide variables that
-can be used in their dependents' build. Any package can declare a
-``setup_dependent_environment()`` function, and this function will be
-called before the ``install()`` method of any dependent packages.
-This allows dependencies to set up environment variables and other
-properties to be used by dependents.
-
-The function declaration should look like this:
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Influence how dependents are built or run
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Spack provides a mechanism for dependencies to influence the
+environment of their dependents by overriding the
+:meth:`setup_dependent_run_environment <spack.package.PackageBase.setup_dependent_run_environment>`
+or the
+:meth:`setup_dependent_build_environment <spack.package.PackageBase.setup_dependent_build_environment>`
+methods.
+The Qt package, for instance, uses this call:
.. literalinclude:: _spack_root/var/spack/repos/builtin/packages/qt/package.py
- :pyobject: Qt.setup_dependent_environment
+ :pyobject: Qt.setup_dependent_build_environment
:linenos:
-Here, the Qt package sets the ``QTDIR`` environment variable so that
-packages that depend on a particular Qt installation will find it.
-
-The arguments to this function are:
+to set the ``QTDIR`` environment variable so that packages
+that depend on a particular Qt installation will find it.
+Another good example of how a dependency can influence
+the build environment of dependents is the Python package:
-* **spack_env**: List of environment modifications to be applied when
- the dependent package is built within Spack.
-* **run_env**: List of environment modifications to be applied when
- the dependent package is run outside of Spack. These are added to the
- resulting module file.
-* **dependent_spec**: The spec of the dependent package about to be
- built. This allows the extendee (self) to query the dependent's state.
- Note that *this* package's spec is available as ``self.spec``.
+.. literalinclude:: _spack_root/var/spack/repos/builtin/packages/python/package.py
+ :pyobject: Python.setup_dependent_build_environment
+ :linenos:
-A good example of using these is in the Python package:
+In the method above it is ensured that any package that depends on Python
+will have the ``PYTHONPATH``, ``PYTHONHOME`` and ``PATH`` environment
+variables set appropriately before starting the installation. To make things
+even simpler the ``python setup.py`` command is also inserted into the module
+scope of dependents by overriding a third method called
+:meth:`setup_dependent_package <spack.package.PackageBase.setup_dependent_package>`
+:
.. literalinclude:: _spack_root/var/spack/repos/builtin/packages/python/package.py
- :pyobject: Python.setup_dependent_environment
+ :pyobject: Python.setup_dependent_package
:linenos:
-The first thing that happens here is that the ``python`` command is
-inserted into module scope of the dependent. This allows most python
-packages to have a very simple install method, like this:
+This allows most python packages to have a very simple install procedure,
+like the following:
.. code-block:: python
def install(self, spec, prefix):
- python('setup.py', 'install', '--prefix={0}'.format(prefix))
+ setup_py('install', '--prefix={0}'.format(prefix))
+
+Finally the Python package takes also care of the modifications to ``PYTHONPATH``
+to allow dependencies to run correctly:
+
+.. literalinclude:: _spack_root/var/spack/repos/builtin/packages/python/package.py
+ :pyobject: Python.setup_dependent_run_environment
+ :linenos:
-Python's ``setup_dependent_environment`` method also sets up some
-other variables, creates a directory, and sets up the ``PYTHONPATH``
-so that dependent packages can find their dependencies at build time.
.. _packaging_conflicts:
diff --git a/lib/spack/docs/tutorial_advanced_packaging.rst b/lib/spack/docs/tutorial_advanced_packaging.rst
index bd90f724a7..876a6e8f70 100644
--- a/lib/spack/docs/tutorial_advanced_packaging.rst
+++ b/lib/spack/docs/tutorial_advanced_packaging.rst
@@ -90,21 +90,23 @@ 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>`
+Any package can override the
+:py:func:`setup_dependent_build_environment <spack.package.PackageBase.setup_dependent_build_environment>`
+method to setup the build environment for a dependent.
+This method takes as an argument 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'))
+ def setup_dependent_build_environment(self, env, dependent_spec):
+ 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
+their environment when they build. This section is focused on setting up the
+build-time environment but it's worth noting that a similar method called
+:py:func:`setup_dependent_run_environment <spack.package.PackageBase.setup_dependent_run_environment>`
+can be used to code modifications that will be included in Spack's automatically-generated
module files.
We can practice by editing the ``mpich`` package to set the ``MPICC``
@@ -118,17 +120,17 @@ 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'))
+ def setup_dependent_build_environment(self, env, dependent_spec):
+ env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
+ env.set('MPICXX', join_path(self.prefix.bin, 'mpic++'))
+ env.set('MPIF77', join_path(self.prefix.bin, 'mpif77'))
+ 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)
+ env.set('MPICH_CC', spack_cc)
+ env.set('MPICH_CXX', spack_cxx)
+ env.set('MPICH_F77', spack_f77)
+ env.set('MPICH_F90', spack_fc)
+ env.set('MPICH_FC', spack_fc)
At this point we can, for instance, install ``netlib-scalapack`` with
``mpich``:
@@ -155,25 +157,32 @@ 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:
+Packages can override the
+:py:func:`setup_build_environment <spack.package.PackageBase.setup_build_environment>`
+or the
+:py:func:`setup_run_environment <spack.package.PackageBase.setup_run_environment>`
+methods to modify their own build-time or run-time environment respectively.
+An example of a package that overrides both methods is ``qt``:
.. 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)
+ def setup_build_environment(self, env):
+ env.set('MAKEFLAGS', '-j{0}'.format(make_jobs))
-When ``qt`` builds, ``MAKEFLAGS`` will be defined in the environment.
+ def setup_run_environment(self, env):
+ env.set('QTDIR', self.prefix)
-To contrast with ``qt``'s :py:func:`setup_dependent_environment <spack.package.PackageBase.setup_dependent_environment>`
+When ``qt`` builds, ``MAKEFLAGS`` will be defined in the environment. Likewise, when a
+module file is created for ``qt`` it will contain commands to define ``QTDIR`` appropriately.
+
+To contrast with ``qt``'s
+:py:func:`setup_dependent_build_environment <spack.package.PackageBase.setup_dependent_build_environment>`
function:
.. code-block:: python
- def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
- spack_env.set('QTDIR', self.prefix)
+ def setup_dependent_build_environment(self, env, dependent_spec):
+ env.set('QTDIR', self.prefix)
Let's see how it works by completing the ``elpa`` package:
@@ -185,16 +194,16 @@ In the end your method should look like:
.. code-block:: python
- def setup_environment(self, spack_env, run_env):
+ def setup_build_environment(self, 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())
+ env.set('CC', spec['mpi'].mpicc)
+ env.set('FC', spec['mpi'].mpifc)
+ env.set('CXX', spec['mpi'].mpicxx)
+ 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)
+ env.append_flags('LDFLAGS', spec['lapack'].libs.search_flags)
+ env.append_flags('LIBS', spec['lapack'].libs.link_flags)
At this point it's possible to proceed with the installation of ``elpa ^mpich``
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 3702a989c3..db99a7a4c1 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -673,35 +673,26 @@ def load_external_modules(pkg):
def setup_package(pkg, dirty):
"""Execute all environment setup routines."""
- spack_env = EnvironmentModifications()
- run_env = EnvironmentModifications()
+ build_env = EnvironmentModifications()
if not dirty:
clean_environment()
- set_compiler_environment_variables(pkg, spack_env)
- set_build_environment_variables(pkg, spack_env, dirty)
- pkg.architecture.platform.setup_platform_environment(pkg, spack_env)
+ set_compiler_environment_variables(pkg, build_env)
+ set_build_environment_variables(pkg, build_env, dirty)
+ pkg.architecture.platform.setup_platform_environment(pkg, build_env)
- # traverse in postorder so package can use vars from its dependencies
- spec = pkg.spec
- for dspec in pkg.spec.traverse(order='post', root=False,
- deptype=('build', 'test')):
- spkg = dspec.package
- set_module_variables_for_package(spkg)
-
- # Allow dependencies to modify the module
- dpkg = dspec.package
- dpkg.setup_dependent_package(pkg.module, spec)
- dpkg.setup_dependent_environment(spack_env, run_env, spec)
+ build_env.extend(
+ modifications_from_dependencies(pkg.spec, context='build')
+ )
- if (not dirty) and (not spack_env.is_unset('CPATH')):
+ if (not dirty) and (not build_env.is_unset('CPATH')):
tty.debug("A dependency has updated CPATH, this may lead pkg-config"
" to assume that the package is part of the system"
" includes and omit it when invoked with '--cflags'.")
set_module_variables_for_package(pkg)
- pkg.setup_environment(spack_env, run_env)
+ pkg.setup_build_environment(build_env)
# Loading modules, in particular if they are meant to be used outside
# of Spack, can change environment variables that are relevant to the
@@ -711,7 +702,7 @@ def setup_package(pkg, dirty):
# unnecessary. Modules affecting these variables will be overwritten anyway
with preserve_environment('CC', 'CXX', 'FC', 'F77'):
# All module loads that otherwise would belong in previous
- # functions have to occur after the spack_env object has its
+ # functions have to occur after the build_env object has its
# modifications applied. Otherwise the environment modifications
# could undo module changes, such as unsetting LD_LIBRARY_PATH
# after a module changes it.
@@ -727,8 +718,39 @@ def setup_package(pkg, dirty):
load_external_modules(pkg)
# Make sure nothing's strange about the Spack environment.
- validate(spack_env, tty.warn)
- spack_env.apply_modifications()
+ validate(build_env, tty.warn)
+ build_env.apply_modifications()
+
+
+def modifications_from_dependencies(spec, context):
+ """Returns the environment modifications that are required by
+ the dependencies of a spec and also applies modifications
+ to this spec's package at module scope, if need be.
+
+ Args:
+ spec (Spec): spec for which we want the modifications
+ context (str): either 'build' for build-time modifications or 'run'
+ for run-time modifications
+ """
+ env = EnvironmentModifications()
+ pkg = spec.package
+
+ # Maps the context to deptype and method to be called
+ deptype_and_method = {
+ 'build': (('build', 'link', 'test'),
+ 'setup_dependent_build_environment'),
+ 'run': (('link', 'run'), 'setup_dependent_run_environment')
+ }
+ deptype, method = deptype_and_method[context]
+
+ for dspec in spec.traverse(order='post', root=False, deptype=deptype):
+ dpkg = dspec.package
+ set_module_variables_for_package(dpkg)
+ # Allow dependencies to modify the module
+ dpkg.setup_dependent_package(pkg.module, spec)
+ getattr(dpkg, method)(env, spec)
+
+ return env
def fork(pkg, function, dirty, fake):
diff --git a/lib/spack/spack/cmd/flake8.py b/lib/spack/spack/cmd/flake8.py
index ebcad88a06..61f7dd567f 100644
--- a/lib/spack/spack/cmd/flake8.py
+++ b/lib/spack/spack/cmd/flake8.py
@@ -93,12 +93,11 @@ pattern_exemptions = dict(
for file_pattern, error_dict in pattern_exemptions.items())
-def changed_files(args):
+def changed_files(base=None, untracked=True, all_files=False):
"""Get list of changed files in the Spack repository."""
git = which('git', required=True)
- base = args.base
if base is None:
base = os.environ.get('TRAVIS_BRANCH', 'develop')
@@ -114,11 +113,11 @@ def changed_files(args):
]
# Add new files that are untracked
- if args.untracked:
+ if untracked:
git_args.append(['ls-files', '--exclude-standard', '--other'])
# add everything if the user asked for it
- if args.all:
+ if all_files:
git_args.append(['ls-files', '--exclude-standard'])
excludes = [os.path.realpath(f) for f in exclude_directories]
@@ -246,7 +245,7 @@ def flake8(parser, args):
with working_dir(spack.paths.prefix):
if not file_list:
- file_list = changed_files(args)
+ file_list = changed_files(args.base, args.untracked, args.all)
print('=======================================================')
print('flake8: running flake8 code checks on spack.')
diff --git a/lib/spack/spack/modules/common.py b/lib/spack/spack/modules/common.py
index 116d4f5471..d38ede1385 100644
--- a/lib/spack/spack/modules/common.py
+++ b/lib/spack/spack/modules/common.py
@@ -634,23 +634,16 @@ class BaseContext(tengine.Context):
exclude=spack.util.environment.is_system_path
)
- # Modifications that are coded at package level
- _ = spack.util.environment.EnvironmentModifications()
- # TODO : the code down below is quite similar to
- # TODO : build_environment.setup_package and needs to be factored out
- # TODO : to a single place
# Let the extendee/dependency modify their extensions/dependencies
# before asking for package-specific modifications
- for item in dependencies(self.spec, 'all'):
- package = self.spec[item.name].package
- build_environment.set_module_variables_for_package(package)
- package.setup_dependent_package(
- self.spec.package.module, self.spec
+ env.extend(
+ build_environment.modifications_from_dependencies(
+ self.spec, context='run'
)
- package.setup_dependent_environment(_, env, self.spec)
+ )
# Package specific modifications
build_environment.set_module_variables_for_package(self.spec.package)
- self.spec.package.setup_environment(_, env)
+ self.spec.package.setup_run_environment(env)
# Modifications required from modules.yaml
env.extend(self.conf.env)
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index ecff265508..e3d4f1b6e9 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -45,6 +45,7 @@ import spack.mixins
import spack.multimethod
import spack.repo
import spack.url
+import spack.util.environment
import spack.util.web
import spack.multimethod
import spack.binary_distribution as binary_distribution
@@ -1951,68 +1952,108 @@ class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)):
"""
return (None, None, flags)
- def setup_environment(self, spack_env, run_env):
- """Set up the compile and runtime environments for a package.
+ def _get_legacy_environment_method(self, method_name):
+ legacy_fn = getattr(self, method_name, None)
+ name_prefix = method_name.split('_environment')[0]
+ if legacy_fn:
+ msg = '[DEPRECATED METHOD]\n"{0}" ' \
+ 'still defines the deprecated method "{1}" ' \
+ '[should be split into "{2}_build_environment" and ' \
+ '"{2}_run_environment"]'
+ tty.debug(msg.format(self.name, method_name, name_prefix))
+ return legacy_fn
- ``spack_env`` and ``run_env`` are ``EnvironmentModifications``
- objects. Package authors can call methods on them to alter
- the environment within Spack and at runtime.
+ def setup_build_environment(self, env):
+ """Sets up the build environment for a package.
- Both ``spack_env`` and ``run_env`` are applied within the build
- process, before this package's ``install()`` method is called.
+ This method will be called before the current package prefix exists in
+ Spack's store.
- Modifications in ``run_env`` will *also* be added to the
- generated environment modules for this package.
-
- Default implementation does nothing, but this can be
- overridden if the package needs a particular environment.
-
- Example:
+ Args:
+ env (EnvironmentModifications): environment modifications to be
+ applied when the package is built. Package authors can call
+ methods on it to alter the build environment.
+ """
+ legacy_fn = self._get_legacy_environment_method('setup_environment')
+ if legacy_fn:
+ _ = spack.util.environment.EnvironmentModifications()
+ legacy_fn(env, _)
- 1. Qt extensions need ``QTDIR`` set.
+ def setup_run_environment(self, env):
+ """Sets up the run environment for a package.
Args:
- spack_env (EnvironmentModifications): List of environment
- modifications to be applied when this package is built
- within Spack.
- run_env (EnvironmentModifications): List of environment
- modifications to be applied when this package is run outside
- of Spack. These are added to the resulting module file.
+ env (EnvironmentModifications): environment modifications to be
+ applied when the package is run. Package authors can call
+ methods on it to alter the run environment.
"""
- pass
+ legacy_fn = self._get_legacy_environment_method('setup_environment')
+ if legacy_fn:
+ _ = spack.util.environment.EnvironmentModifications()
+ legacy_fn(_, env)
- def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
- """Set up the environment of packages that depend on this one.
+ def setup_dependent_build_environment(self, env, dependent_spec):
+ """Sets up the build environment of packages that depend on this one.
- This is similar to ``setup_environment``, but it is used to
- modify the compile and runtime environments of packages that
- *depend* on this one. This gives packages like Python and
- others that follow the extension model a way to implement
- common environment or compile-time settings for dependencies.
+ This is similar to ``setup_build_environment``, but it is used to
+ modify the build environments of packages that *depend* on this one.
- This is useful if there are some common steps to installing
- all extensions for a certain package.
+ This gives packages like Python and others that follow the extension
+ model a way to implement common environment or compile-time settings
+ for dependencies.
- Example:
+ This method will be called before the dependent package prefix exists
+ in Spack's store.
- 1. Installing python modules generally requires ``PYTHONPATH`` to point
- to the ``lib/pythonX.Y/site-packages`` directory in the module's
- install prefix. This method could be used to set that variable.
+ Examples:
+ 1. Installing python modules generally requires ``PYTHONPATH``
+ to point to the ``lib/pythonX.Y/site-packages`` directory in the
+ module's install prefix. This method could be used to set that
+ variable.
Args:
- spack_env (EnvironmentModifications): List of environment
- modifications to be applied when the dependent package is
- built within Spack.
- run_env (EnvironmentModifications): List of environment
- modifications to be applied when the dependent package is
- run outside of Spack. These are added to the resulting
- module file.
- dependent_spec (Spec): The spec of the dependent package
+ env (EnvironmentModifications): environment modifications to be
+ applied when the dependent package is built. Package authors
+ can call methods on it to alter the build environment.
+
+ dependent_spec (Spec): the spec of the dependent package
about to be built. This allows the extendee (self) to query
the dependent's state. Note that *this* package's spec is
- available as ``self.spec``.
+ available as ``self.spec``
"""
- pass
+ legacy_fn = self._get_legacy_environment_method(
+ 'setup_dependent_environment'
+ )
+ if legacy_fn:
+ _ = spack.util.environment.EnvironmentModifications()
+ legacy_fn(env, _, dependent_spec)
+
+ def setup_dependent_run_environment(self, env, dependent_spec):
+ """Sets up the run environment of packages that depend on this one.
+
+ This is similar to ``setup_run_environment``, but it is used to
+ modify the run environments of packages that *depend* on this one.
+
+ This gives packages like Python and others that follow the extension
+ model a way to implement common environment or run-time settings
+ for dependencies.
+
+ Args:
+ env (EnvironmentModifications): environment modifications to be
+ applied when the dependent package is run. Package authors
+ can call methods on it to alter the build environment.
+
+ dependent_spec (Spec): The spec of the dependent package
+ about to be run. This allows the extendee (self) to query
+ the dependent's state. Note that *this* package's spec is
+ available as ``self.spec``
+ """
+ legacy_fn = self._get_legacy_environment_method(
+ 'setup_dependent_environment'
+ )
+ if legacy_fn:
+ _ = spack.util.environment.EnvironmentModifications()
+ legacy_fn(_, env, dependent_spec)
def setup_dependent_package(self, module, dependent_spec):
"""Set up Python module-scope variables for dependent packages.
diff --git a/lib/spack/spack/test/package_sanity.py b/lib/spack/spack/test/package_sanity.py
index 1dd96dccec..f83a2dbb8e 100644
--- a/lib/spack/spack/test/package_sanity.py
+++ b/lib/spack/spack/test/package_sanity.py
@@ -4,6 +4,7 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
"""This test does sanity checks on Spack's builtin package database."""
+import os.path
import re
import pytest
@@ -11,6 +12,10 @@ import pytest
import spack.fetch_strategy
import spack.paths
import spack.repo
+import spack.util.executable as executable
+# A few functions from this module are used to
+# do sanity checks only on packagess modified by a PR
+import spack.cmd.flake8 as flake8
import spack.util.crypto as crypto
@@ -134,3 +139,48 @@ def test_all_packages_use_sha256_checksums():
)
assert [] == errors
+
+
+@pytest.mark.xfail
+def test_api_for_build_and_run_environment():
+ """Ensure that every package uses the correct API to set build and
+ run environment, and not the old one.
+ """
+ failing = []
+ for pkg in spack.repo.path.all_packages():
+ add_to_list = (hasattr(pkg, 'setup_environment') or
+ hasattr(pkg, 'setup_dependent_environment'))
+ if add_to_list:
+ failing.append(pkg)
+
+ msg = ('there are {0} packages using the old API to set build '
+ 'and run environment [{1}]')
+ assert not failing, msg.format(
+ len(failing), ','.join(x.name for x in failing)
+ )
+
+
+@pytest.mark.skipif(
+ not executable.which('git'), reason='requires git to be installed'
+)
+def test_prs_update_old_api():
+ """Ensures that every package modified in a PR doesn't contain
+ deprecated calls to any method.
+ """
+ changed_package_files = [
+ x for x in flake8.changed_files() if flake8.is_package(x)
+ ]
+ failing = []
+ for file in changed_package_files:
+ name = os.path.basename(os.path.dirname(file))
+ pkg = spack.repo.get(name)
+
+ # Check for old APIs
+ failed = (hasattr(pkg, 'setup_environment') or
+ hasattr(pkg, 'setup_dependent_environment'))
+ if failed:
+ failing.append(pkg)
+ msg = 'there are {0} packages still using old APIs in this PR [{1}]'
+ assert not failing, msg.format(
+ len(failing), ','.join(x.name for x in failing)
+ )