tclmodules : added hooks to process EnvironmentModifications objects
This commit is contained in:
parent
b45ec3f04e
commit
597727f8be
@ -47,18 +47,18 @@
|
|||||||
__all__ = ['EnvModule', 'Dotkit', 'TclModule']
|
__all__ = ['EnvModule', 'Dotkit', 'TclModule']
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import os.path
|
||||||
import re
|
import re
|
||||||
import textwrap
|
|
||||||
import shutil
|
import shutil
|
||||||
|
import textwrap
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
import spack
|
||||||
|
from spack.environment import *
|
||||||
from llnl.util.filesystem import join_path, mkdirp
|
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 = {}
|
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):
|
class EnvModule(object):
|
||||||
name = 'env_module'
|
name = 'env_module'
|
||||||
|
|
||||||
@ -88,21 +114,27 @@ def __init__(cls, name, bases, dict):
|
|||||||
if cls.name != 'env_module':
|
if cls.name != 'env_module':
|
||||||
module_types[cls.name] = cls
|
module_types[cls.name] = cls
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, spec=None):
|
def __init__(self, spec=None):
|
||||||
# category in the modules system
|
# category in the modules system
|
||||||
# TODO: come up with smarter category names.
|
# TODO: come up with smarter category names.
|
||||||
self.category = "spack"
|
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
|
# dict pathname -> list of directories to be prepended to in
|
||||||
# the module file.
|
# the module file.
|
||||||
self._paths = None
|
self._paths = None
|
||||||
self.spec = spec
|
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
|
@property
|
||||||
def paths(self):
|
def paths(self):
|
||||||
@ -130,26 +162,19 @@ def add_path(path_name, directory):
|
|||||||
add_path(var, directory)
|
add_path(var, directory)
|
||||||
|
|
||||||
# Add python path unless it's an actual python installation
|
# 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':
|
if self.spec.name != 'python':
|
||||||
site_packages = glob(join_path(self.spec.prefix.lib, "python*/site-packages"))
|
site_packages = glob(join_path(self.spec.prefix.lib, "python*/site-packages"))
|
||||||
if site_packages:
|
if site_packages:
|
||||||
add_path('PYTHONPATH', site_packages[0])
|
add_path('PYTHONPATH', site_packages[0])
|
||||||
|
|
||||||
|
# FIXME : Same for GEM_PATH
|
||||||
if self.spec.package.extends(spack.spec.Spec('ruby')):
|
if self.spec.package.extends(spack.spec.Spec('ruby')):
|
||||||
add_path('GEM_PATH', self.spec.prefix)
|
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__)
|
|
||||||
|
|
||||||
return self._paths
|
return self._paths
|
||||||
|
|
||||||
|
|
||||||
def write(self):
|
def write(self):
|
||||||
"""Write out a module file for this object."""
|
"""Write out a module file for this object."""
|
||||||
module_dir = os.path.dirname(self.file_name)
|
module_dir = os.path.dirname(self.file_name)
|
||||||
@ -160,9 +185,18 @@ def write(self):
|
|||||||
if not self.paths:
|
if not self.paths:
|
||||||
return
|
return
|
||||||
|
|
||||||
with open(self.file_name, 'w') as f:
|
# Construct the changes that needs to be done on the environment for
|
||||||
self._write(f)
|
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):
|
def _write(self, stream):
|
||||||
"""To be implemented by subclasses."""
|
"""To be implemented by subclasses."""
|
||||||
@ -175,14 +209,12 @@ def file_name(self):
|
|||||||
where this module lives."""
|
where this module lives."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def use_name(self):
|
def use_name(self):
|
||||||
"""Subclasses should implement this to return the name the
|
"""Subclasses should implement this to return the name the
|
||||||
module command uses to refer to the package."""
|
module command uses to refer to the package."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
def remove(self):
|
def remove(self):
|
||||||
mod_file = self.file_name
|
mod_file = self.file_name
|
||||||
if os.path.exists(mod_file):
|
if os.path.exists(mod_file):
|
||||||
@ -205,7 +237,7 @@ def use_name(self):
|
|||||||
self.spec.compiler.version,
|
self.spec.compiler.version,
|
||||||
self.spec.dag_hash())
|
self.spec.dag_hash())
|
||||||
|
|
||||||
def _write(self, dk_file):
|
def _write(self, dk_file, env):
|
||||||
# Category
|
# Category
|
||||||
if self.category:
|
if self.category:
|
||||||
dk_file.write('#c %s\n' % self.category)
|
dk_file.write('#c %s\n' % self.category)
|
||||||
@ -231,6 +263,10 @@ def _write(self, dk_file):
|
|||||||
class TclModule(EnvModule):
|
class TclModule(EnvModule):
|
||||||
name = 'tcl'
|
name = 'tcl'
|
||||||
path = join_path(spack.share_path, "modules")
|
path = join_path(spack.share_path, "modules")
|
||||||
|
formats = {
|
||||||
|
PrependPath: 'prepend-path {0.name} \"{0.path}\"\n',
|
||||||
|
SetEnv: 'setenv {0.name} \"{0.value}\"\n'
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def file_name(self):
|
def file_name(self):
|
||||||
@ -244,25 +280,56 @@ def use_name(self):
|
|||||||
self.spec.compiler.version,
|
self.spec.compiler.version,
|
||||||
self.spec.dag_hash())
|
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):
|
def _write(self, module_file, env):
|
||||||
# TODO: cateogry?
|
"""
|
||||||
m_file.write('#%Module1.0\n')
|
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
|
# Short description
|
||||||
if self.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
|
# Long description
|
||||||
if self.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)
|
doc = re.sub(r'"', '\"', self.long_description)
|
||||||
m_file.write("puts stderr \"%s\"\n" % doc)
|
module_file.write("puts stderr \"%s\"\n" % doc)
|
||||||
m_file.write('}\n\n')
|
module_file.write('}\n\n')
|
||||||
|
|
||||||
# Path alterations
|
# Environment modifications
|
||||||
for var, dirs in self.paths.items():
|
for line in self.process_environment_command(env):
|
||||||
for directory in dirs:
|
module_file.write(line)
|
||||||
m_file.write("prepend-path %s \"%s\"\n" % (var, directory))
|
|
||||||
|
|
||||||
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 *
|
from spack import *
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class Mpich(Package):
|
class Mpich(Package):
|
||||||
"""MPICH is a high performance and widely portable implementation of
|
"""MPICH is a high performance and widely portable implementation of
|
||||||
the Message Passing Interface (MPI) standard."""
|
the Message Passing Interface (MPI) standard."""
|
||||||
@ -48,11 +49,25 @@ class Mpich(Package):
|
|||||||
|
|
||||||
def environment_modifications(self, dependent_spec):
|
def environment_modifications(self, dependent_spec):
|
||||||
env = super(Mpich, self).environment_modifications(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'])
|
if dependent_spec is None:
|
||||||
env.set_env('MPICH_F77', os.environ['F77'])
|
# We are not using compiler wrappers
|
||||||
env.set_env('MPICH_F90', os.environ['FC'])
|
cc = self.compiler.cc
|
||||||
env.set_env('MPICH_FC', os.environ['FC'])
|
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
|
return env
|
||||||
|
|
||||||
def module_modifications(self, module, spec, dep_spec):
|
def module_modifications(self, module, spec, dep_spec):
|
||||||
|
@ -91,13 +91,14 @@ def site_packages_dir(self):
|
|||||||
|
|
||||||
def environment_modifications(self, extension_spec):
|
def environment_modifications(self, extension_spec):
|
||||||
env = super(Python, self).environment_modifications(extension_spec)
|
env = super(Python, self).environment_modifications(extension_spec)
|
||||||
# Set PYTHONPATH to include site-packages dir for the
|
if extension_spec is not None:
|
||||||
# extension and any other python extensions it depends on.
|
# Set PYTHONPATH to include site-packages dir for the
|
||||||
python_paths = []
|
# extension and any other python extensions it depends on.
|
||||||
for d in extension_spec.traverse():
|
python_paths = []
|
||||||
if d.package.extends(self.spec):
|
for d in extension_spec.traverse():
|
||||||
python_paths.append(os.path.join(d.prefix, self.site_packages_dir))
|
if d.package.extends(self.spec):
|
||||||
env.set_env['PYTHONPATH'] = ':'.join(python_paths)
|
python_paths.append(os.path.join(d.prefix, self.site_packages_dir))
|
||||||
|
env.set_env['PYTHONPATH'] = ':'.join(python_paths)
|
||||||
return env
|
return env
|
||||||
|
|
||||||
def module_modifications(self, module, spec, ext_spec):
|
def module_modifications(self, module, spec, ext_spec):
|
||||||
|
Loading…
Reference in New Issue
Block a user