lmod : added support for the creation of hierarchical lua module files (#1723)

Includes :
- treatment of a generic hierarchy (i.e. lapack + mpi + compiler)
- possibility to specify which compilers are to be considered Core
- correct treatment of the 'family' directive
- unit tests for most new features
This commit is contained in:
Massimiliano Culpo 2016-09-20 11:26:25 +02:00 committed by Todd Gamblin
parent efadc0e299
commit ea446c0f0e
10 changed files with 560 additions and 149 deletions

1
.gitignore vendored
View file

@ -12,6 +12,7 @@
/etc/spackconfig
/share/spack/dotkit
/share/spack/modules
/share/spack/lmod
/TAGS
/htmlcov
.coverage

View file

@ -69,8 +69,8 @@ def get_cmd_function_name(name):
def get_module(name):
"""Imports the module for a particular command name and returns it."""
module_name = "%s.%s" % (__name__, name)
module = __import__(
module_name, fromlist=[name, SETUP_PARSER, DESCRIPTION],
module = __import__(module_name,
fromlist=[name, SETUP_PARSER, DESCRIPTION],
level=0)
attr_setdefault(module, SETUP_PARSER, lambda *args: None) # null-op
@ -78,8 +78,8 @@ def get_module(name):
fn_name = get_cmd_function_name(name)
if not hasattr(module, fn_name):
tty.die("Command module %s (%s) must define function '%s'."
% (module.__name__, module.__file__, fn_name))
tty.die("Command module %s (%s) must define function '%s'." %
(module.__name__, module.__file__, fn_name))
return module

View file

@ -29,10 +29,10 @@
import shutil
import sys
import llnl.util.filesystem as filesystem
import llnl.util.tty as tty
import spack.cmd
import spack.cmd.common.arguments as arguments
import llnl.util.filesystem as filesystem
from spack.modules import module_types
description = "Manipulate module files"

View file

@ -24,7 +24,7 @@
##############################################################################
"""This package contains modules with hooks for various stages in the
Spack install process. You can add modules here and they'll be
executaed by package at various times during the package lifecycle.
executed by package at various times during the package lifecycle.
Each hook is just a function that takes a package as a parameter.
Hooks are not executed in any particular order.
@ -41,9 +41,10 @@
features.
"""
import imp
from llnl.util.lang import memoized, list_modules
from llnl.util.filesystem import join_path
import spack
from llnl.util.filesystem import join_path
from llnl.util.lang import memoized, list_modules
@memoized
@ -70,7 +71,6 @@ def __call__(self, pkg):
if hasattr(hook, '__call__'):
hook(pkg)
#
# Define some functions that can be called to fire off hooks.
#

View file

@ -0,0 +1,35 @@
##############################################################################
# Copyright (c) 2013, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://scalability-llnl.github.io/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License (as published by
# the Free Software Foundation) version 2.1 dated February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
import spack.modules
def post_install(pkg):
dk = spack.modules.LmodModule(pkg.spec)
dk.write()
def post_uninstall(pkg):
dk = spack.modules.LmodModule(pkg.spec)
dk.remove()

View file

@ -40,6 +40,7 @@
"""
import copy
import datetime
import itertools
import os
import os.path
import re
@ -48,6 +49,7 @@
import llnl.util.tty as tty
import spack
import spack.compilers # Needed by LmodModules
import spack.config
from llnl.util.filesystem import join_path, mkdirp
from spack.build_environment import parent_class_modules
@ -56,7 +58,8 @@
__all__ = ['EnvModule', 'Dotkit', 'TclModule']
# 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 = {}
CONFIGURATION = spack.config.get_config('modules')
@ -633,3 +636,237 @@ def module_specific_content(self, configuration):
raise SystemExit('Module generation aborted.')
line = line.format(**naming_tokens)
yield line
# To construct an arbitrary hierarchy of module files:
# 1. Parse the configuration file and check that all the items in
# hierarchical_scheme are indeed virtual packages
# This needs to be done only once at start-up
# 2. Order the stack as `hierarchical_scheme + ['mpi, 'compiler']
# 3. Check which of the services are provided by the package
# -> may be more than one
# 4. Check which of the services are needed by the package
# -> this determines where to write the module file
# 5. For each combination of services in which we have at least one provider
# here add the appropriate conditional MODULEPATH modifications
class LmodModule(EnvModule):
name = 'lmod'
path = join_path(spack.share_path, "lmod")
environment_modifications_formats = {
PrependPath: 'prepend_path("{name}", "{value}")\n',
AppendPath: 'append_path("{name}", "{value}")\n',
RemovePath: 'remove_path("{name}", "{value}")\n',
SetEnv: 'setenv("{name}", "{value}")\n',
UnsetEnv: 'unsetenv("{name}")\n'
}
autoload_format = ('if not isloaded("{module_file}") then\n'
' LmodMessage("Autoloading {module_file}")\n'
' load("{module_file}")\n'
'end\n\n')
prerequisite_format = 'prereq("{module_file}")\n'
family_format = 'family("{family}")\n'
path_part_with_hash = join_path('{token.name}', '{token.version}-{token.hash}') # NOQA: ignore=E501
path_part_without_hash = join_path('{token.name}', '{token.version}')
# TODO : Check that extra tokens specified in configuration file
# TODO : are actually virtual dependencies
configuration = CONFIGURATION.get('lmod', {})
hierarchy_tokens = configuration.get('hierarchical_scheme', [])
hierarchy_tokens = hierarchy_tokens + ['mpi', 'compiler']
def __init__(self, spec=None):
super(LmodModule, self).__init__(spec)
# Sets the root directory for this architecture
self.modules_root = join_path(LmodModule.path, self.spec.architecture)
# Retrieve core compilers
self.core_compilers = self.configuration.get('core_compilers', [])
# Keep track of the requirements that this package has in terms
# of virtual packages
# that participate in the hierarchical structure
self.requires = {'compiler': self.spec.compiler}
# For each virtual dependency in the hierarchy
for x in self.hierarchy_tokens:
if x in self.spec and not self.spec.package.provides(
x): # if I depend on it
self.requires[x] = self.spec[x] # record the actual provider
# Check what are the services I need (this will determine where the
# module file will be written)
self.substitutions = {}
self.substitutions.update(self.requires)
# TODO : complete substitutions
# Check what service I provide to others
self.provides = {}
# If it is in the list of supported compilers family -> compiler
if self.spec.name in spack.compilers.supported_compilers():
self.provides['compiler'] = spack.spec.CompilerSpec(str(self.spec))
# Special case for llvm
if self.spec.name == 'llvm':
self.provides['compiler'] = spack.spec.CompilerSpec(str(self.spec))
self.provides['compiler'].name = 'clang'
for x in self.hierarchy_tokens:
if self.spec.package.provides(x):
self.provides[x] = self.spec[x]
def _hierarchy_token_combinations(self):
"""
Yields all the relevant combinations that could appear in the hierarchy
"""
for ii in range(len(self.hierarchy_tokens) + 1):
for item in itertools.combinations(self.hierarchy_tokens, ii):
if 'compiler' in item:
yield item
def _hierarchy_to_be_provided(self):
"""
Filters a list of hierarchy tokens and yields only the one that we
need to provide
"""
for item in self._hierarchy_token_combinations():
if any(x in self.provides for x in item):
yield item
def token_to_path(self, name, value):
# If we are dealing with a core compiler, return 'Core'
if name == 'compiler' and str(value) in self.core_compilers:
return 'Core'
# CompilerSpec does not have an hash
if name == 'compiler':
return self.path_part_without_hash.format(token=value)
# For virtual providers add a small part of the hash
# to distinguish among different variants in a directory hierarchy
value.hash = value.dag_hash(length=6)
return self.path_part_with_hash.format(token=value)
@property
def file_name(self):
parts = [self.token_to_path(x, self.requires[x])
for x in self.hierarchy_tokens if x in self.requires]
hierarchy_name = join_path(*parts)
fullname = join_path(self.modules_root, hierarchy_name,
self.use_name + '.lua')
return fullname
@property
def use_name(self):
return self.token_to_path('', self.spec)
def modulepath_modifications(self):
# What is available is what we require plus what we provide
entry = ''
available = {}
available.update(self.requires)
available.update(self.provides)
available_parts = [self.token_to_path(x, available[x])
for x in self.hierarchy_tokens if x in available]
# Missing parts
missing = [x for x in self.hierarchy_tokens if x not in available]
# Direct path we provide on top of compilers
modulepath = join_path(self.modules_root, *available_parts)
env = EnvironmentModifications()
env.prepend_path('MODULEPATH', modulepath)
for line in self.process_environment_command(env):
entry += line
def local_variable(x):
lower, upper = x.lower(), x.upper()
fmt = 'local {lower}_name = os.getenv("LMOD_{upper}_NAME")\n'
fmt += 'local {lower}_version = os.getenv("LMOD_{upper}_VERSION")\n' # NOQA: ignore=501
return fmt.format(lower=lower, upper=upper)
def set_variables_for_service(env, x):
upper = x.upper()
s = self.provides[x]
name, version = os.path.split(self.token_to_path(x, s))
env.set('LMOD_{upper}_NAME'.format(upper=upper), name)
env.set('LMOD_{upper}_VERSION'.format(upper=upper), version)
def conditional_modulepath_modifications(item):
entry = 'if '
needed = []
for x in self.hierarchy_tokens:
if x in missing:
needed.append('{x}_name '.format(x=x))
entry += 'and '.join(needed) + 'then\n'
entry += ' local t = pathJoin("{root}"'.format(
root=self.modules_root)
for x in item:
if x in missing:
entry += ', {lower}_name, {lower}_version'.format(
lower=x.lower())
else:
entry += ', "{x}"'.format(
x=self.token_to_path(x, available[x]))
entry += ')\n'
entry += ' prepend_path("MODULEPATH", t)\n'
entry += 'end\n\n'
return entry
if 'compiler' not in self.provides:
# Retrieve variables
entry += '\n'
for x in missing:
entry += local_variable(x)
entry += '\n'
# Conditional modifications
conditionals = [x
for x in self._hierarchy_to_be_provided()
if any(t in missing for t in x)]
for item in conditionals:
entry += conditional_modulepath_modifications(item)
# Set environment variables for the services we provide
env = EnvironmentModifications()
for x in self.provides:
set_variables_for_service(env, x)
for line in self.process_environment_command(env):
entry += line
return entry
@property
def header(self):
timestamp = datetime.datetime.now()
# Header as in
# https://www.tacc.utexas.edu/research-development/tacc-projects/lmod/advanced-user-guide/more-about-writing-module-files
header = "-- -*- lua -*-\n"
header += '-- Module file created by spack (https://github.com/LLNL/spack) on %s\n' % timestamp # NOQA: ignore=E501
header += '--\n'
header += '-- %s\n' % self.spec.short_spec
header += '--\n'
# Short description -> whatis()
if self.short_description:
header += "whatis([[Name : {name}]])\n".format(name=self.spec.name)
header += "whatis([[Version : {version}]])\n".format(
version=self.spec.version)
# Long description -> help()
if self.long_description:
doc = re.sub(r'"', '\"', self.long_description)
header += "help([[{documentation}]])\n".format(documentation=doc)
# Certain things need to be done only if we provide a service
if self.provides:
# Add family directives
header += '\n'
for x in self.provides:
header += self.family_format.format(family=x)
header += '\n'
header += '-- MODULEPATH modifications\n'
header += '\n'
# Modify MODULEPATH
header += self.modulepath_modifications()
# Set environment variables for services we provide
header += '\n'
header += '-- END MODULEPATH modifications\n'
header += '\n'
return header

View file

@ -139,7 +139,20 @@
'default': [],
'items': {
'type': 'string',
'enum': ['tcl', 'dotkit']}},
'enum': ['tcl', 'dotkit', 'lmod']}},
'lmod': {
'allOf': [
# Base configuration
{'$ref': '#/definitions/module_type_configuration'},
{
'core_compilers': {
'$ref': '#/definitions/array_of_strings'
},
'hierarchical_scheme': {
'$ref': '#/definitions/array_of_strings'
}
} # Specific lmod extensions
]},
'tcl': {
'allOf': [
# Base configuration

View file

@ -26,8 +26,8 @@
These tests check the database is functioning properly,
both in memory and in its file
"""
import os.path
import multiprocessing
import os.path
import spack
from llnl.util.filesystem import join_path

View file

@ -49,6 +49,82 @@ def mock_open(filename, mode):
handle.close()
# Spec strings that will be used throughout the tests
mpich_spec_string = 'mpich@3.0.4'
mpileaks_spec_string = 'mpileaks'
libdwarf_spec_string = 'libdwarf arch=x64-linux'
class HelperFunctionsTests(MockPackagesTest):
def test_update_dictionary_extending_list(self):
target = {
'foo': {
'a': 1,
'b': 2,
'd': 4
},
'bar': [1, 2, 4],
'baz': 'foobar'
}
update = {
'foo': {
'c': 3,
},
'bar': [3],
'baz': 'foobaz',
'newkey': {
'd': 4
}
}
spack.modules.update_dictionary_extending_lists(target, update)
self.assertTrue(len(target) == 4)
self.assertTrue(len(target['foo']) == 4)
self.assertTrue(len(target['bar']) == 4)
self.assertEqual(target['baz'], 'foobaz')
def test_inspect_path(self):
env = spack.modules.inspect_path('/usr')
names = [item.name for item in env]
self.assertTrue('PATH' in names)
self.assertTrue('LIBRARY_PATH' in names)
self.assertTrue('LD_LIBRARY_PATH' in names)
self.assertTrue('CPATH' in names)
class ModuleFileGeneratorTests(MockPackagesTest):
"""
Base class to test module file generators. Relies on child having defined
a 'factory' attribute to create an instance of the generator to be tested.
"""
def setUp(self):
super(ModuleFileGeneratorTests, self).setUp()
self.configuration_instance = spack.modules.CONFIGURATION
self.module_types_instance = spack.modules.module_types
spack.modules.open = mock_open
# Make sure that a non-mocked configuration will trigger an error
spack.modules.CONFIGURATION = None
spack.modules.module_types = {self.factory.name: self.factory}
def tearDown(self):
del spack.modules.open
spack.modules.module_types = self.module_types_instance
spack.modules.CONFIGURATION = self.configuration_instance
super(ModuleFileGeneratorTests, self).tearDown()
def get_modulefile_content(self, spec):
spec.concretize()
generator = self.factory(spec)
generator.write()
content = FILE_REGISTRY[generator.file_name].split('\n')
return content
class TclTests(ModuleFileGeneratorTests):
factory = spack.modules.TclModule
configuration_autoload_direct = {
'enable': ['tcl'],
'tcl': {
@ -149,82 +225,23 @@ def mock_open(filename, mode):
}
}
class HelperFunctionsTests(MockPackagesTest):
def test_update_dictionary_extending_list(self):
target = {
'foo': {
'a': 1,
'b': 2,
'd': 4
},
'bar': [1, 2, 4],
'baz': 'foobar'
}
update = {
'foo': {
'c': 3,
},
'bar': [3],
'baz': 'foobaz',
'newkey': {
'd': 4
}
}
spack.modules.update_dictionary_extending_lists(target, update)
self.assertTrue(len(target) == 4)
self.assertTrue(len(target['foo']) == 4)
self.assertTrue(len(target['bar']) == 4)
self.assertEqual(target['baz'], 'foobaz')
def test_inspect_path(self):
env = spack.modules.inspect_path('/usr')
names = [item.name for item in env]
self.assertTrue('PATH' in names)
self.assertTrue('LIBRARY_PATH' in names)
self.assertTrue('LD_LIBRARY_PATH' in names)
self.assertTrue('CPATH' in names)
class TclTests(MockPackagesTest):
def setUp(self):
super(TclTests, self).setUp()
self.configuration_obj = spack.modules.CONFIGURATION
spack.modules.open = mock_open
# Make sure that a non-mocked configuration will trigger an error
spack.modules.CONFIGURATION = None
def tearDown(self):
del spack.modules.open
spack.modules.CONFIGURATION = self.configuration_obj
super(TclTests, self).tearDown()
def get_modulefile_content(self, spec):
spec.concretize()
generator = spack.modules.TclModule(spec)
generator.write()
content = FILE_REGISTRY[generator.file_name].split('\n')
return content
def test_simple_case(self):
spack.modules.CONFIGURATION = configuration_autoload_direct
spec = spack.spec.Spec('mpich@3.0.4')
spack.modules.CONFIGURATION = self.configuration_autoload_direct
spec = spack.spec.Spec(mpich_spec_string)
content = self.get_modulefile_content(spec)
self.assertTrue('module-whatis "mpich @3.0.4"' in content)
self.assertRaises(TypeError, spack.modules.dependencies,
spec, 'non-existing-tag')
def test_autoload(self):
spack.modules.CONFIGURATION = configuration_autoload_direct
spec = spack.spec.Spec('mpileaks')
spack.modules.CONFIGURATION = self.configuration_autoload_direct
spec = spack.spec.Spec(mpileaks_spec_string)
content = self.get_modulefile_content(spec)
self.assertEqual(len([x for x in content if 'is-loaded' in x]), 2)
self.assertEqual(len([x for x in content if 'module load ' in x]), 2)
spack.modules.CONFIGURATION = configuration_autoload_all
spec = spack.spec.Spec('mpileaks')
spack.modules.CONFIGURATION = self.configuration_autoload_all
spec = spack.spec.Spec(mpileaks_spec_string)
content = self.get_modulefile_content(spec)
self.assertEqual(len([x for x in content if 'is-loaded' in x]), 5)
self.assertEqual(len([x for x in content if 'module load ' in x]), 5)
@ -252,18 +269,18 @@ def test_autoload(self):
self.assertEqual(len([x for x in content if 'module load ' in x]), 2)
def test_prerequisites(self):
spack.modules.CONFIGURATION = configuration_prerequisites_direct
spack.modules.CONFIGURATION = self.configuration_prerequisites_direct
spec = spack.spec.Spec('mpileaks arch=x86-linux')
content = self.get_modulefile_content(spec)
self.assertEqual(len([x for x in content if 'prereq' in x]), 2)
spack.modules.CONFIGURATION = configuration_prerequisites_all
spack.modules.CONFIGURATION = self.configuration_prerequisites_all
spec = spack.spec.Spec('mpileaks arch=x86-linux')
content = self.get_modulefile_content(spec)
self.assertEqual(len([x for x in content if 'prereq' in x]), 5)
def test_alter_environment(self):
spack.modules.CONFIGURATION = configuration_alter_environment
spack.modules.CONFIGURATION = self.configuration_alter_environment
spec = spack.spec.Spec('mpileaks platform=test target=x86_64')
content = self.get_modulefile_content(spec)
self.assertEqual(
@ -293,7 +310,7 @@ def test_alter_environment(self):
len([x for x in content if 'setenv LIBDWARF_ROOT' in x]), 1)
def test_blacklist(self):
spack.modules.CONFIGURATION = configuration_blacklist
spack.modules.CONFIGURATION = self.configuration_blacklist
spec = spack.spec.Spec('mpileaks ^zmpi')
content = self.get_modulefile_content(spec)
self.assertEqual(len([x for x in content if 'is-loaded' in x]), 1)
@ -307,7 +324,7 @@ def test_blacklist(self):
self.assertEqual(len([x for x in content if 'module load ' in x]), 1)
def test_conflicts(self):
spack.modules.CONFIGURATION = configuration_conflicts
spack.modules.CONFIGURATION = self.configuration_conflicts
spec = spack.spec.Spec('mpileaks')
content = self.get_modulefile_content(spec)
self.assertEqual(
@ -317,11 +334,11 @@ def test_conflicts(self):
self.assertEqual(
len([x for x in content if x == 'conflict intel/14.0.1']), 1)
spack.modules.CONFIGURATION = configuration_wrong_conflicts
spack.modules.CONFIGURATION = self.configuration_wrong_conflicts
self.assertRaises(SystemExit, self.get_modulefile_content, spec)
def test_suffixes(self):
spack.modules.CONFIGURATION = configuration_suffix
spack.modules.CONFIGURATION = self.configuration_suffix
spec = spack.spec.Spec('mpileaks+debug arch=x86-linux')
spec.concretize()
generator = spack.modules.TclModule(spec)
@ -333,6 +350,114 @@ def test_suffixes(self):
self.assertTrue('bar' in generator.use_name)
class LmodTests(ModuleFileGeneratorTests):
factory = spack.modules.LmodModule
configuration_autoload_direct = {
'enable': ['lmod'],
'lmod': {
'all': {
'autoload': 'direct'
}
}
}
configuration_autoload_all = {
'enable': ['lmod'],
'lmod': {
'all': {
'autoload': 'all'
}
}
}
configuration_alter_environment = {
'enable': ['lmod'],
'lmod': {
'all': {
'filter': {'environment_blacklist': ['CMAKE_PREFIX_PATH']}
},
'platform=test target=x86_64': {
'environment': {
'set': {'FOO': 'foo'},
'unset': ['BAR']
}
},
'platform=test target=x86_32': {
'load': ['foo/bar']
}
}
}
configuration_blacklist = {
'enable': ['lmod'],
'lmod': {
'blacklist': ['callpath'],
'all': {
'autoload': 'direct'
}
}
}
def test_simple_case(self):
spack.modules.CONFIGURATION = self.configuration_autoload_direct
spec = spack.spec.Spec(mpich_spec_string)
content = self.get_modulefile_content(spec)
self.assertTrue('-- -*- lua -*-' in content)
self.assertTrue('whatis([[Name : mpich]])' in content)
self.assertTrue('whatis([[Version : 3.0.4]])' in content)
def test_autoload(self):
spack.modules.CONFIGURATION = self.configuration_autoload_direct
spec = spack.spec.Spec(mpileaks_spec_string)
content = self.get_modulefile_content(spec)
self.assertEqual(
len([x for x in content if 'if not isloaded(' in x]), 2)
self.assertEqual(len([x for x in content if 'load(' in x]), 2)
spack.modules.CONFIGURATION = self.configuration_autoload_all
spec = spack.spec.Spec(mpileaks_spec_string)
content = self.get_modulefile_content(spec)
self.assertEqual(
len([x for x in content if 'if not isloaded(' in x]), 5)
self.assertEqual(len([x for x in content if 'load(' in x]), 5)
def test_alter_environment(self):
spack.modules.CONFIGURATION = self.configuration_alter_environment
spec = spack.spec.Spec('mpileaks platform=test target=x86_64')
content = self.get_modulefile_content(spec)
self.assertEqual(
len([x
for x in content
if x.startswith('prepend_path("CMAKE_PREFIX_PATH"')]), 0)
self.assertEqual(
len([x for x in content if 'setenv("FOO", "foo")' in x]), 1)
self.assertEqual(
len([x for x in content if 'unsetenv("BAR")' in x]), 1)
spec = spack.spec.Spec('libdwarf %clang platform=test target=x86_32')
content = self.get_modulefile_content(spec)
print('\n'.join(content))
self.assertEqual(
len([x
for x in content
if x.startswith('prepend-path("CMAKE_PREFIX_PATH"')]), 0)
self.assertEqual(
len([x for x in content if 'setenv("FOO", "foo")' in x]), 0)
self.assertEqual(
len([x for x in content if 'unsetenv("BAR")' in x]), 0)
def test_blacklist(self):
spack.modules.CONFIGURATION = self.configuration_blacklist
spec = spack.spec.Spec(mpileaks_spec_string)
content = self.get_modulefile_content(spec)
self.assertEqual(
len([x for x in content if 'if not isloaded(' in x]), 1)
self.assertEqual(len([x for x in content if 'load(' in x]), 1)
class DotkitTests(MockPackagesTest):
configuration_dotkit = {
'enable': ['dotkit'],
'dotkit': {
@ -342,9 +467,6 @@ def test_suffixes(self):
}
}
class DotkitTests(MockPackagesTest):
def setUp(self):
super(DotkitTests, self).setUp()
self.configuration_obj = spack.modules.CONFIGURATION
@ -365,7 +487,7 @@ def get_modulefile_content(self, spec):
return content
def test_dotkit(self):
spack.modules.CONFIGURATION = configuration_dotkit
spack.modules.CONFIGURATION = self.configuration_dotkit
spec = spack.spec.Spec('mpileaks arch=x86-linux')
content = self.get_modulefile_content(spec)
self.assertTrue('#c spack' in content)

View file

@ -22,9 +22,10 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
import os
from spack import *
class Llvm(Package):
"""The LLVM Project is a collection of modular and reusable compiler and
@ -37,9 +38,11 @@ class Llvm(Package):
homepage = 'http://llvm.org/'
url = 'http://llvm.org/releases/3.7.1/llvm-3.7.1.src.tar.xz'
family = 'compiler' # Used by lmod
# currently required by mesa package
version('3.0', 'a8e5f5f1c1adebae7b4a654c376a6005',
url='http://llvm.org/releases/3.0/llvm-3.0.tar.gz')
url='http://llvm.org/releases/3.0/llvm-3.0.tar.gz') # currently required by mesa package
variant('debug', default=False,
description="Build a debug version of LLVM, this increases "