tclmodules : added hooks to process EnvironmentModifications objects
This commit is contained in:
parent
b45ec3f04e
commit
597727f8be
@ -47,18 +47,18 @@
|
||||
__all__ = ['EnvModule', 'Dotkit', 'TclModule']
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import textwrap
|
||||
import shutil
|
||||
import textwrap
|
||||
from glob import glob
|
||||
|
||||
import llnl.util.tty as tty
|
||||
import spack
|
||||
from spack.environment import *
|
||||
from llnl.util.filesystem import join_path, mkdirp
|
||||
|
||||
import spack
|
||||
|
||||
"""Registry of all types of modules. Entries created by EnvModule's
|
||||
metaclass."""
|
||||
# Registry of all types of modules. Entries created by EnvModule's metaclass
|
||||
module_types = {}
|
||||
|
||||
|
||||
@ -79,6 +79,32 @@ def print_help():
|
||||
"")
|
||||
|
||||
|
||||
class PathInspector(object):
|
||||
dirname2varname = {
|
||||
'bin': ('PATH',),
|
||||
'man': ('MANPATH',),
|
||||
'lib': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'),
|
||||
'lib64': ('LIBRARY_PATH', 'LD_LIBRARY_PATH'),
|
||||
'include': ('CPATH',),
|
||||
'pkgconfig': ('PKG_CONFIG_PATH',)
|
||||
}
|
||||
|
||||
def __call__(self, env, directory, names):
|
||||
for name in names:
|
||||
variables = PathInspector.dirname2varname.get(name, None)
|
||||
if variables is None:
|
||||
continue
|
||||
absolute_path = join_path(os.path.abspath(directory), name)
|
||||
for variable in variables:
|
||||
env.prepend_path(variable, absolute_path)
|
||||
|
||||
|
||||
def inspect_path(path):
|
||||
env, inspector = EnvironmentModifications(), PathInspector()
|
||||
os.path.walk(path, inspector, env)
|
||||
return env
|
||||
|
||||
|
||||
class EnvModule(object):
|
||||
name = 'env_module'
|
||||
|
||||
@ -88,21 +114,27 @@ def __init__(cls, name, bases, dict):
|
||||
if cls.name != 'env_module':
|
||||
module_types[cls.name] = cls
|
||||
|
||||
|
||||
def __init__(self, spec=None):
|
||||
# category in the modules system
|
||||
# TODO: come up with smarter category names.
|
||||
self.category = "spack"
|
||||
|
||||
# Descriptions for the module system's UI
|
||||
self.short_description = ""
|
||||
self.long_description = ""
|
||||
|
||||
# dict pathname -> list of directories to be prepended to in
|
||||
# the module file.
|
||||
self._paths = None
|
||||
self.spec = spec
|
||||
self.pkg = spec.package # Just stored for convenience
|
||||
|
||||
# short description default is just the package + version
|
||||
# packages can provide this optional attribute
|
||||
self.short_description = spec.format("$_ $@")
|
||||
if hasattr(self.pkg, 'short_description'):
|
||||
self.short_description = self.pkg.short_description
|
||||
|
||||
# long description is the docstring with reduced whitespace.
|
||||
self.long_description = None
|
||||
if self.spec.package.__doc__:
|
||||
self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__)
|
||||
|
||||
@property
|
||||
def paths(self):
|
||||
@ -130,26 +162,19 @@ def add_path(path_name, directory):
|
||||
add_path(var, directory)
|
||||
|
||||
# Add python path unless it's an actual python installation
|
||||
# TODO: is there a better way to do this?
|
||||
# TODO : is there a better way to do this?
|
||||
# FIXME : add PYTHONPATH to every python package
|
||||
if self.spec.name != 'python':
|
||||
site_packages = glob(join_path(self.spec.prefix.lib, "python*/site-packages"))
|
||||
if site_packages:
|
||||
add_path('PYTHONPATH', site_packages[0])
|
||||
|
||||
# FIXME : Same for GEM_PATH
|
||||
if self.spec.package.extends(spack.spec.Spec('ruby')):
|
||||
add_path('GEM_PATH', self.spec.prefix)
|
||||
|
||||
# short description is just the package + version
|
||||
# TODO: maybe packages can optionally provide it.
|
||||
self.short_description = self.spec.format("$_ $@")
|
||||
|
||||
# long description is the docstring with reduced whitespace.
|
||||
if self.spec.package.__doc__:
|
||||
self.long_description = re.sub(r'\s+', ' ', self.spec.package.__doc__)
|
||||
add_path('GEM_PATH', self.spec.prefix)
|
||||
|
||||
return self._paths
|
||||
|
||||
|
||||
def write(self):
|
||||
"""Write out a module file for this object."""
|
||||
module_dir = os.path.dirname(self.file_name)
|
||||
@ -160,9 +185,18 @@ def write(self):
|
||||
if not self.paths:
|
||||
return
|
||||
|
||||
with open(self.file_name, 'w') as f:
|
||||
self._write(f)
|
||||
# Construct the changes that needs to be done on the environment for
|
||||
env = inspect_path(self.spec.prefix)
|
||||
# FIXME : move the logic to inspection
|
||||
env.prepend_path('CMAKE_PREFIX_PATH', self.spec.prefix)
|
||||
# FIXME : decide how to distinguish between calls done in the installation and elsewhere
|
||||
env.extend(self.spec.package.environment_modifications(None))
|
||||
# site_specific = ...`
|
||||
if not env:
|
||||
return
|
||||
|
||||
with open(self.file_name, 'w') as f:
|
||||
self._write(f, env)
|
||||
|
||||
def _write(self, stream):
|
||||
"""To be implemented by subclasses."""
|
||||
@ -175,14 +209,12 @@ def file_name(self):
|
||||
where this module lives."""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
@property
|
||||
def use_name(self):
|
||||
"""Subclasses should implement this to return the name the
|
||||
module command uses to refer to the package."""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def remove(self):
|
||||
mod_file = self.file_name
|
||||
if os.path.exists(mod_file):
|
||||
@ -205,7 +237,7 @@ def use_name(self):
|
||||
self.spec.compiler.version,
|
||||
self.spec.dag_hash())
|
||||
|
||||
def _write(self, dk_file):
|
||||
def _write(self, dk_file, env):
|
||||
# Category
|
||||
if self.category:
|
||||
dk_file.write('#c %s\n' % self.category)
|
||||
@ -231,6 +263,10 @@ def _write(self, dk_file):
|
||||
class TclModule(EnvModule):
|
||||
name = 'tcl'
|
||||
path = join_path(spack.share_path, "modules")
|
||||
formats = {
|
||||
PrependPath: 'prepend-path {0.name} \"{0.path}\"\n',
|
||||
SetEnv: 'setenv {0.name} \"{0.value}\"\n'
|
||||
}
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
@ -244,25 +280,56 @@ def use_name(self):
|
||||
self.spec.compiler.version,
|
||||
self.spec.dag_hash())
|
||||
|
||||
def process_environment_command(self, env):
|
||||
for command in env:
|
||||
# FIXME : how should we handle errors here?
|
||||
yield self.formats[type(command)].format(command)
|
||||
|
||||
def _write(self, m_file):
|
||||
# TODO: cateogry?
|
||||
m_file.write('#%Module1.0\n')
|
||||
def _write(self, module_file, env):
|
||||
"""
|
||||
Writes a TCL module file for this package
|
||||
|
||||
Args:
|
||||
module_file: module file stream
|
||||
env: list of environment modifications to be written in the module file
|
||||
"""
|
||||
# TCL Modulefile header
|
||||
module_file.write('#%Module1.0\n')
|
||||
# TODO : category ?
|
||||
# Short description
|
||||
if self.short_description:
|
||||
m_file.write('module-whatis \"%s\"\n\n' % self.short_description)
|
||||
module_file.write('module-whatis \"%s\"\n\n' % self.short_description)
|
||||
|
||||
# Long description
|
||||
if self.long_description:
|
||||
m_file.write('proc ModulesHelp { } {\n')
|
||||
module_file.write('proc ModulesHelp { } {\n')
|
||||
doc = re.sub(r'"', '\"', self.long_description)
|
||||
m_file.write("puts stderr \"%s\"\n" % doc)
|
||||
m_file.write('}\n\n')
|
||||
module_file.write("puts stderr \"%s\"\n" % doc)
|
||||
module_file.write('}\n\n')
|
||||
|
||||
# Path alterations
|
||||
for var, dirs in self.paths.items():
|
||||
for directory in dirs:
|
||||
m_file.write("prepend-path %s \"%s\"\n" % (var, directory))
|
||||
# Environment modifications
|
||||
for line in self.process_environment_command(env):
|
||||
module_file.write(line)
|
||||
|
||||
m_file.write("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % self.spec.prefix)
|
||||
# FIXME : REMOVE
|
||||
# def _write(self, m_file):
|
||||
# # TODO: cateogry?
|
||||
# m_file.write('#%Module1.0\n')
|
||||
#
|
||||
# # Short description
|
||||
# if self.short_description:
|
||||
# m_file.write('module-whatis \"%s\"\n\n' % self.short_description)
|
||||
#
|
||||
# # Long description
|
||||
# if self.long_description:
|
||||
# m_file.write('proc ModulesHelp { } {\n')
|
||||
# doc = re.sub(r'"', '\"', self.long_description)
|
||||
# m_file.write("puts stderr \"%s\"\n" % doc)
|
||||
# m_file.write('}\n\n')
|
||||
#
|
||||
# # Path alterations
|
||||
# for var, dirs in self.paths.items():
|
||||
# for directory in dirs:
|
||||
# m_file.write("prepend-path %s \"%s\"\n" % (var, directory))
|
||||
#
|
||||
# m_file.write("prepend-path CMAKE_PREFIX_PATH \"%s\"\n" % self.spec.prefix)
|
||||
|
@ -25,6 +25,7 @@
|
||||
from spack import *
|
||||
import os
|
||||
|
||||
|
||||
class Mpich(Package):
|
||||
"""MPICH is a high performance and widely portable implementation of
|
||||
the Message Passing Interface (MPI) standard."""
|
||||
@ -48,11 +49,25 @@ class Mpich(Package):
|
||||
|
||||
def environment_modifications(self, dependent_spec):
|
||||
env = super(Mpich, self).environment_modifications(dependent_spec)
|
||||
env.set_env('MPICH_CC', os.environ['CC'])
|
||||
env.set_env('MPICH_CXX', os.environ['CXX'])
|
||||
env.set_env('MPICH_F77', os.environ['F77'])
|
||||
env.set_env('MPICH_F90', os.environ['FC'])
|
||||
env.set_env('MPICH_FC', os.environ['FC'])
|
||||
|
||||
if dependent_spec is None:
|
||||
# We are not using compiler wrappers
|
||||
cc = self.compiler.cc
|
||||
cxx = self.compiler.cxx
|
||||
f77 = self.compiler.f77
|
||||
f90 = fc = self.compiler.fc
|
||||
else:
|
||||
# Spack compiler wrappers
|
||||
cc = os.environ['CC']
|
||||
cxx = os.environ['CXX']
|
||||
f77 = os.environ['F77']
|
||||
f90 = fc = os.environ['FC']
|
||||
|
||||
env.set_env('MPICH_CC', cc)
|
||||
env.set_env('MPICH_CXX', cxx)
|
||||
env.set_env('MPICH_F77', f77)
|
||||
env.set_env('MPICH_F90', f90)
|
||||
env.set_env('MPICH_FC', fc)
|
||||
return env
|
||||
|
||||
def module_modifications(self, module, spec, dep_spec):
|
||||
|
@ -91,13 +91,14 @@ def site_packages_dir(self):
|
||||
|
||||
def environment_modifications(self, extension_spec):
|
||||
env = super(Python, self).environment_modifications(extension_spec)
|
||||
# Set PYTHONPATH to include site-packages dir for the
|
||||
# extension and any other python extensions it depends on.
|
||||
python_paths = []
|
||||
for d in extension_spec.traverse():
|
||||
if d.package.extends(self.spec):
|
||||
python_paths.append(os.path.join(d.prefix, self.site_packages_dir))
|
||||
env.set_env['PYTHONPATH'] = ':'.join(python_paths)
|
||||
if extension_spec is not None:
|
||||
# Set PYTHONPATH to include site-packages dir for the
|
||||
# extension and any other python extensions it depends on.
|
||||
python_paths = []
|
||||
for d in extension_spec.traverse():
|
||||
if d.package.extends(self.spec):
|
||||
python_paths.append(os.path.join(d.prefix, self.site_packages_dir))
|
||||
env.set_env['PYTHONPATH'] = ':'.join(python_paths)
|
||||
return env
|
||||
|
||||
def module_modifications(self, module, spec, ext_spec):
|
||||
|
Loading…
Reference in New Issue
Block a user