Consistent docs and usage of env mod methods (#3351)

This commit is contained in:
Adam J. Stewart 2017-03-15 00:26:44 -05:00 committed by Todd Gamblin
parent 560d28ac7f
commit dca4d2b15e
26 changed files with 123 additions and 143 deletions

View File

@ -1523,23 +1523,23 @@ properties to be used by dependents.
The function declaration should look like this:
.. code-block:: python
class Qt(Package):
...
def setup_dependent_environment(self, module, spec, dep_spec):
"""Dependencies of Qt find it using the QTDIR environment variable."""
os.environ['QTDIR'] = self.prefix
.. literalinclude:: ../../../var/spack/repos/builtin/packages/qt/package.py
:pyobject: Qt.setup_dependent_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:
* **module**: the module of the dependent package, where global
properties can be assigned.
* **spec**: the spec of the *dependency package* (the one the function is called on).
* **dep_spec**: the spec of the dependent package (i.e. dep_spec depends on spec).
* **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``.
A good example of using these is in the Python package:
@ -2805,11 +2805,8 @@ the one passed to install, only the MPI implementations all set some
additional properties on it to help you out. E.g., in mvapich2, you'll
find this:
.. code-block:: python
def setup_dependent_package(self, module, dep_spec):
self.spec.mpicc = join_path(self.prefix.bin, 'mpicc')
# … etc …
.. literalinclude:: ../../../var/spack/repos/builtin/packages/mvapich2/package.py
:pyobject: Mvapich2.setup_dependent_package
That code allows the mvapich2 package to associate an ``mpicc`` property
with the ``mvapich2`` node in the DAG, so that dependents can access it.

View File

@ -1393,32 +1393,29 @@ def module(self):
def setup_environment(self, spack_env, run_env):
"""Set up the compile and runtime environments for a package.
`spack_env` and `run_env` are `EnvironmentModifications`
objects. Package authors can call methods on them to alter
``spack_env`` and ``run_env`` are ``EnvironmentModifications``
objects. Package authors can call methods on them to alter
the environment within Spack and at runtime.
Both `spack_env` and `run_env` are applied within the build
process, before this package's `install()` method is called.
Both ``spack_env`` and ``run_env`` are applied within the build
process, before this package's ``install()`` method is called.
Modifications in `run_env` will *also* be added to the
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.
Examples:
Example:
1. Qt extensions need `QTDIR` set.
Args:
spack_env (EnvironmentModifications): list of
modifications to be applied when this package is built
within Spack.
run_env (EnvironmentModifications): list of environment
changes to be applied when this package is run outside
of Spack.
1. Qt extensions need ``QTDIR`` set.
:param EnvironmentModifications spack_env: List of environment
modifications to be applied when this package is built
within Spack.
:param EnvironmentModifications run_env: List of environment
modifications to be applied when this package is run outside
of Spack. These are added to the resulting module file.
"""
pass
@ -1431,32 +1428,26 @@ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
others that follow the extension model a way to implement
common environment or compile-time settings for dependencies.
By default, this delegates to ``self.setup_environment()``
This is useful if there are some common steps to installing
all extensions for a certain package.
Example:
1. Installing python modules generally requires
`PYTHONPATH` to point to the lib/pythonX.Y/site-packages
directory in the module's install prefix. This could
set that variable.
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
modifications to be applied when the dependent package
is bulit within Spack.
run_env (EnvironmentModifications): list of environment
changes to be applied when the dependent package is
run outside of Spack.
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`.
This is useful if there are some common steps to installing
all extensions for a certain package.
:param EnvironmentModifications spack_env: List of environment
modifications to be applied when the dependent package is
built within Spack.
:param EnvironmentModifications 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.
:param Spec 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``.
"""
pass
@ -1470,37 +1461,29 @@ def setup_dependent_package(self, module, dependent_spec):
its extensions. This is useful if there are some common steps
to installing all extensions for a certain package.
Example :
Examples:
1. Extensions often need to invoke the `python`
interpreter from the Python installation being
extended. This routine can put a 'python' Executable
object in the module scope for the extension package to
simplify extension installs.
1. Extensions often need to invoke the ``python`` interpreter
from the Python installation being extended. This routine
can put a ``python()`` Executable object in the module scope
for the extension package to simplify extension installs.
2. MPI compilers could set some variables in the
dependent's scope that point to `mpicc`, `mpicxx`,
etc., allowing them to be called by common names
regardless of which MPI is used.
2. MPI compilers could set some variables in the dependent's
scope that point to ``mpicc``, ``mpicxx``, etc., allowing
them to be called by common name regardless of which MPI is used.
3. BLAS/LAPACK implementations can set some variables
indicating the path to their libraries, since these
paths differ by BLAS/LAPACK implementation.
3. BLAS/LAPACK implementations can set some variables
indicating the path to their libraries, since these
paths differ by BLAS/LAPACK implementation.
Args:
module (module): The Python `module` object of the
dependent package. Packages can use this to set
module-scope variables for the dependent to use.
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`.
This is useful if there are some common steps to installing
all extensions for a certain package.
:param spack.package.PackageBase.module module: The Python ``module``
object of the dependent package. Packages can use this to set
module-scope variables for the dependent to use.
:param Spec 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``.
"""
pass

View File

@ -53,7 +53,7 @@ def install(self, spec, prefix):
mkdir(prefix.bin)
install('output/bazel', prefix.bin)
def setup_dependent_package(self, module, dep_spec):
def setup_dependent_package(self, module, dependent_spec):
class BazelExecutable(Executable):
"""Special callable executable object for bazel so the user can
specify parallel or not on a per-invocation basis. Using
@ -84,8 +84,8 @@ def __call__(self, *args, **kwargs):
return super(BazelExecutable, self).__call__(*args, **kwargs)
jobs = cpu_count()
if not dep_spec.package.parallel:
if not dependent_spec.package.parallel:
jobs = 1
elif dep_spec.package.make_jobs:
jobs = dep_spec.package.make_jobs
elif dependent_spec.package.make_jobs:
jobs = dependent_spec.package.make_jobs
module.bazel = BazelExecutable('bazel', 'build', jobs)

View File

@ -287,5 +287,5 @@ def cmake_args(self):
return options
def setup_environment(self, spack_env, env):
env.set('DEAL_II_DIR', self.prefix)
def setup_environment(self, spack_env, run_env):
run_env.set('DEAL_II_DIR', self.prefix)

View File

@ -42,7 +42,7 @@ def install(self, spec, prefix):
else:
install(src, dst)
def setup_dependent_environment(self, spack_env, run_env, extension_spec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
catalog = os.path.join(self.spec.prefix, 'catalog.xml')
spack_env.set('XML_CATALOG_FILES', catalog, separator=' ')

View File

@ -44,7 +44,7 @@ def install(self, spec, prefix):
else:
install(src, dst)
def setup_dependent_environment(self, spack_env, run_env, extension_spec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
catalog = os.path.join(self.spec.prefix, 'catalog.xml')
spack_env.set('XML_CATALOG_FILES', catalog, separator=' ')

View File

@ -38,5 +38,5 @@ class EverytraceExample(CMakePackage):
# Currently the only MPI this everytrace works with.
depends_on('openmpi')
def setup_environment(self, spack_env, env):
env.prepend_path('PATH', join_path(self.prefix, 'bin'))
def setup_environment(self, spack_env, run_env):
run_env.prepend_path('PATH', join_path(self.prefix, 'bin'))

View File

@ -47,5 +47,5 @@ def cmake_args(self):
'-DUSE_MPI=%s' % ('YES' if '+mpi' in spec else 'NO'),
'-DUSE_FORTRAN=%s' % ('YES' if '+fortran' in spec else 'NO')]
def setup_environment(self, spack_env, env):
env.prepend_path('PATH', join_path(self.prefix, 'bin'))
def setup_environment(self, spack_env, run_env):
run_env.prepend_path('PATH', join_path(self.prefix, 'bin'))

View File

@ -53,8 +53,8 @@ def install(self, spec, prefix):
# In theory the 'run' dependency on 'jdk' above should take
# care of this for me. In practice, it does not.
def setup_environment(self, spack_env, env):
def setup_environment(self, spack_env, run_env):
"""Add <prefix> to the path; the package has a script at the
top level.
"""
env.prepend_path('PATH', join_path(self.spec['jdk'].prefix, 'bin'))
run_env.prepend_path('PATH', join_path(self.spec['jdk'].prefix, 'bin'))

View File

@ -87,7 +87,7 @@ def install(self, spec, prefix):
else:
shutil.copy2(f, os.path.join(prefix, f))
def setup_dependent_environment(self, spack_env, run_env, dep_spec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
spack_env.set('GOROOT_BOOTSTRAP', self.spec.prefix)
def setup_environment(self, spack_env, run_env):

View File

@ -114,7 +114,7 @@ def install(self, spec, prefix):
def setup_environment(self, spack_env, run_env):
spack_env.set('GOROOT_FINAL', self.spec.prefix)
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
"""Called before go modules' install() methods.
In most cases, extensions will only need to set GOPATH and use go::
@ -127,13 +127,13 @@ def setup_dependent_package(self, module, ext_spec):
# Add a go command/compiler for extensions
module.go = Executable(join_path(self.spec.prefix.bin, 'go'))
def setup_dependent_environment(self, spack_env, run_env, ext_spec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
if os.environ.get('GOROOT', False):
tty.warn('GOROOT is set, this is not recommended')
path_components = []
# Set GOPATH to include paths of dependencies
for d in ext_spec.traverse():
for d in dependent_spec.traverse():
if d.package.extends(self.spec):
path_components.append(d.prefix)
@ -142,4 +142,4 @@ def setup_dependent_environment(self, spack_env, run_env, ext_spec):
# Allow packages to find this when using module or dotkit
run_env.prepend_path('GOPATH', ':'.join(
[ext_spec.prefix] + path_components))
[dependent_spec.prefix] + path_components))

View File

@ -125,5 +125,5 @@ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
# set up MKLROOT for everyone using MKL package
spack_env.set('MKLROOT', self.prefix)
def setup_environment(self, spack_env, env):
env.set('MKLROOT', self.prefix)
def setup_environment(self, spack_env, run_env):
run_env.set('MKLROOT', self.prefix)

View File

@ -86,9 +86,9 @@ def append_paths(self, paths, cpaths, path):
paths.append(os.path.join(path, '?', 'init.lua'))
cpaths.append(os.path.join(path, '?.so'))
def setup_dependent_environment(self, spack_env, run_env, extension_spec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
lua_paths = []
for d in extension_spec.traverse(
for d in dependent_spec.traverse(
deptypes=('build', 'run'), deptype_query='run'):
if d.package.extends(self.spec):
lua_paths.append(os.path.join(d.prefix, self.lua_lib_dir))
@ -111,9 +111,9 @@ def setup_dependent_environment(self, spack_env, run_env, extension_spec):
# Add LUA to PATH for dependent packages
spack_env.prepend_path('PATH', self.prefix.bin)
# For run time environment set only the path for extension_spec and
# For run time environment set only the path for dependent_spec and
# prepend it to LUAPATH
if extension_spec.package.extends(self.spec):
if dependent_spec.package.extends(self.spec):
run_env.prepend_path('LUA_PATH', ';'.join(lua_patterns),
separator=';')
run_env.prepend_path('LUA_CPATH', ';'.join(lua_cpatterns),
@ -149,7 +149,7 @@ def lua_lib_dir(self):
def lua_share_dir(self):
return os.path.join('share', 'lua', self.version.up_to(2))
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
"""
Called before lua modules's install() methods.

View File

@ -69,7 +69,7 @@ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
spack_env.set('MPICH_F90', spack_fc)
spack_env.set('MPICH_FC', spack_fc)
def setup_dependent_package(self, module, dep_spec):
def setup_dependent_package(self, module, dependent_spec):
if 'platform=cray' in self.spec:
self.spec.mpicc = spack_cc
self.spec.mpicxx = spack_cxx

View File

@ -209,7 +209,7 @@ def setup_environment(self, spack_env, run_env):
self.version > Version('2.0'):
run_env.set('SLURM_MPI_TYPE', 'pmi2')
def setup_dependent_environment(self, spack_env, run_env, extension_spec):
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, 'mpicxx'))
spack_env.set('MPIF77', join_path(self.prefix.bin, 'mpif77'))
@ -221,7 +221,7 @@ def setup_dependent_environment(self, spack_env, run_env, extension_spec):
spack_env.set('MPICH_F90', spack_fc)
spack_env.set('MPICH_FC', spack_fc)
def setup_dependent_package(self, module, dep_spec):
def setup_dependent_package(self, module, dependent_spec):
self.spec.mpicc = join_path(self.prefix.bin, 'mpicc')
self.spec.mpicxx = join_path(self.prefix.bin, 'mpicxx')
self.spec.mpifc = join_path(self.prefix.bin, 'mpif90')

View File

@ -88,7 +88,7 @@ class Octave(AutotoolsPackage):
depends_on('gnuplot', when='+gnuplot')
depends_on('image-magick', when='+magick')
depends_on('hdf5', when='+hdf5')
depends_on('jdk', when='+jdk') # TODO: requires Java 6 ?
depends_on('jdk', when='+jdk') # TODO: requires Java 6 ?
depends_on('llvm', when='+llvm')
# depends_on('opengl', when='+opengl') # TODO: add package
depends_on('qhull', when='+qhull')
@ -225,7 +225,7 @@ def configure_args(self):
# Set up environment to make install easy for Octave extensions.
# ========================================================================
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
"""Called before Octave modules' install() methods.
In most cases, extensions will only need to have one line:

View File

@ -139,7 +139,7 @@ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
spack_env.set('OMPI_FC', spack_fc)
spack_env.set('OMPI_F77', spack_f77)
def setup_dependent_package(self, module, dep_spec):
def setup_dependent_package(self, module, dependent_spec):
self.spec.mpicc = join_path(self.prefix.bin, 'mpicc')
self.spec.mpicxx = join_path(self.prefix.bin, 'mpic++')
self.spec.mpifc = join_path(self.prefix.bin, 'mpif90')

View File

@ -99,7 +99,7 @@ def apply_patch(self, other):
plumed.stdin.write(choice)
plumed.wait()
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
# Make plumed visible from dependent packages
module.plumed = Executable(join_path(self.spec.prefix.bin, 'plumed'))

View File

@ -53,7 +53,7 @@ class PyNumpy(PythonPackage):
depends_on('blas', when='+blas')
depends_on('lapack', when='+lapack')
def setup_dependent_package(self, module, dep_spec):
def setup_dependent_package(self, module, dependent_spec):
python_version = self.spec['python'].version.up_to(2)
arch = '{0}-{1}'.format(platform.system().lower(), platform.machine())

View File

@ -335,7 +335,7 @@ def python_include_dir(self):
def site_packages_dir(self):
return join_path(self.python_lib_dir, 'site-packages')
def setup_dependent_environment(self, spack_env, run_env, extension_spec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
"""Set PYTHONPATH to include site-packages dir for the
extension and any other python extensions it depends on."""
# The python executable for version 3 may be python3 or python
@ -361,7 +361,7 @@ def setup_dependent_environment(self, spack_env, run_env, extension_spec):
spack_env.set('PYTHONHOME', prefix.strip('\n'))
python_paths = []
for d in extension_spec.traverse(
for d in dependent_spec.traverse(
deptype=('build', 'run'), deptype_query='run'):
if d.package.extends(self.spec):
python_paths.append(join_path(d.prefix,
@ -371,12 +371,12 @@ def setup_dependent_environment(self, spack_env, run_env, extension_spec):
spack_env.set('PYTHONPATH', pythonpath)
# For run time environment set only the path for
# extension_spec and prepend it to PYTHONPATH
if extension_spec.package.extends(self.spec):
# dependent_spec and prepend it to PYTHONPATH
if dependent_spec.package.extends(self.spec):
run_env.prepend_path('PYTHONPATH', join_path(
extension_spec.prefix, self.site_packages_dir))
dependent_spec.prefix, self.site_packages_dir))
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
"""Called before python modules' install() methods.
In most cases, extensions will only need to have one line::
@ -398,15 +398,15 @@ def setup_dependent_package(self, module, ext_spec):
module.setup_py.add_default_env(key, value)
# Add variables for lib/pythonX.Y and lib/pythonX.Y/site-packages dirs.
module.python_lib_dir = join_path(ext_spec.prefix,
module.python_lib_dir = join_path(dependent_spec.prefix,
self.python_lib_dir)
module.python_include_dir = join_path(ext_spec.prefix,
module.python_include_dir = join_path(dependent_spec.prefix,
self.python_include_dir)
module.site_packages_dir = join_path(ext_spec.prefix,
module.site_packages_dir = join_path(dependent_spec.prefix,
self.site_packages_dir)
# Make the site packages directory for extensions
if ext_spec.package.is_extension:
if dependent_spec.package.is_extension:
mkdirp(module.site_packages_dir)
# ========================================================================

View File

@ -128,10 +128,10 @@ def url_for_version(self, version):
def setup_environment(self, spack_env, run_env):
run_env.set('QTDIR', self.prefix)
def setup_dependent_environment(self, spack_env, run_env, dspec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
spack_env.set('QTDIR', self.prefix)
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
module.qmake = Executable(join_path(self.spec.prefix.bin, 'qmake'))
def patch(self):

View File

@ -149,11 +149,11 @@ def filter_compilers(self):
def r_lib_dir(self):
return join_path('rlib', 'R', 'library')
def setup_dependent_environment(self, spack_env, run_env, extension_spec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
# Set R_LIBS to include the library dir for the
# extension and any other R extensions it depends on.
r_libs_path = []
for d in extension_spec.traverse(
for d in dependent_spec.traverse(
deptype=('build', 'run'), deptype_query='run'):
if d.package.extends(self.spec):
r_libs_path.append(join_path(d.prefix, self.r_lib_dir))
@ -167,11 +167,11 @@ def setup_dependent_environment(self, spack_env, run_env, extension_spec):
# determine how many jobs can actually be started.
spack_env.set('MAKEFLAGS', '-j{0}'.format(make_jobs))
# For run time environment set only the path for extension_spec and
# For run time environment set only the path for dependent_spec and
# prepend it to R_LIBS
if extension_spec.package.extends(self.spec):
if dependent_spec.package.extends(self.spec):
run_env.prepend_path('R_LIBS', join_path(
extension_spec.prefix, self.r_lib_dir))
dependent_spec.prefix, self.r_lib_dir))
def setup_environment(self, spack_env, run_env):
run_env.prepend_path('LIBRARY_PATH',
@ -181,7 +181,7 @@ def setup_environment(self, spack_env, run_env):
run_env.prepend_path('CPATH',
join_path(self.prefix, 'rlib', 'R', 'include'))
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
"""Called before R modules' install() methods. In most cases,
extensions will only need to have one line:
R('CMD', 'INSTALL', '--library={0}'.format(self.module.r_lib_dir),
@ -191,9 +191,9 @@ def setup_dependent_package(self, module, ext_spec):
module.R = Executable(join_path(self.spec.prefix.bin, 'R'))
# Add variable for library directry
module.r_lib_dir = join_path(ext_spec.prefix, self.r_lib_dir)
module.r_lib_dir = join_path(dependent_spec.prefix, self.r_lib_dir)
# Make the site packages directory for extensions, if it does not exist
# already.
if ext_spec.package.is_extension:
if dependent_spec.package.is_extension:
mkdirp(module.r_lib_dir)

View File

@ -79,7 +79,7 @@ def install(self, spec, prefix):
make()
make("install")
def setup_dependent_environment(self, spack_env, run_env, dspec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
spack_env.set('ROOTSYS', self.prefix)
spack_env.set('ROOT_VERSION', 'v6')
spack_env.prepend_path('PYTHONPATH', self.prefix.lib)

View File

@ -52,20 +52,20 @@ def install(self, spec, prefix):
make()
make("install")
def setup_dependent_environment(self, spack_env, run_env, extension_spec):
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
# TODO: do this only for actual extensions.
# Set GEM_PATH to include dependent gem directories
ruby_paths = []
for d in extension_spec.traverse():
for d in dependent_spec.traverse():
if d.package.extends(self.spec):
ruby_paths.append(d.prefix)
spack_env.set_path('GEM_PATH', ruby_paths)
# The actual installation path for this gem
spack_env.set('GEM_HOME', extension_spec.prefix)
spack_env.set('GEM_HOME', dependent_spec.prefix)
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
"""Called before ruby modules' install() methods. Sets GEM_HOME
and GEM_PATH to values appropriate for the package being built.

View File

@ -71,7 +71,7 @@ def install(self, spec, prefix):
make()
make("install")
def setup_dependent_package(self, module, ext_spec):
def setup_dependent_package(self, module, dependent_spec):
"""
Called before python modules' install() methods.

View File

@ -49,11 +49,11 @@ def url_for_version(self, version):
base_url = 'http://prdownloads.sourceforge.net/tcl'
return '{0}/tcl{1}-src.tar.gz'.format(base_url, version)
def setup_environment(self, spack_env, env):
def setup_environment(self, spack_env, run_env):
# When using Tkinter from within spack provided python+tk, python
# will not be able to find Tcl/Tk unless TCL_LIBRARY is set.
env.set('TCL_LIBRARY', join_path(self.prefix.lib, 'tcl{0}'.format(
self.spec.version.up_to(2))))
run_env.set('TCL_LIBRARY', join_path(self.prefix.lib, 'tcl{0}'.format(
self.spec.version.up_to(2))))
@run_after('install')
def symlink_tclsh(self):