summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/llnl/util/filesystem.py30
-rw-r--r--lib/spack/llnl/util/lang.py6
-rw-r--r--lib/spack/spack/build_environment.py52
-rw-r--r--lib/spack/spack/cmd/info.py4
-rw-r--r--lib/spack/spack/concretize.py4
-rw-r--r--lib/spack/spack/config.py28
-rw-r--r--lib/spack/spack/modules.py19
-rw-r--r--lib/spack/spack/package.py2
-rw-r--r--lib/spack/spack/test/concretize.py9
9 files changed, 123 insertions, 31 deletions
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index c4665c284c..46ca03bec4 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -27,9 +27,10 @@ __all__ = ['set_install_permissions', 'install', 'install_tree', 'traverse_tree'
'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file',
'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink',
'set_executable', 'copy_mode', 'unset_executable_mode',
- 'remove_dead_links', 'remove_linked_tree']
+ 'remove_dead_links', 'remove_linked_tree', 'fix_darwin_install_name']
import os
+import glob
import sys
import re
import shutil
@@ -38,6 +39,7 @@ import errno
import getpass
from contextlib import contextmanager, closing
from tempfile import NamedTemporaryFile
+import subprocess
import llnl.util.tty as tty
from spack.util.compression import ALLOWED_ARCHIVE_TYPES
@@ -392,3 +394,29 @@ def remove_linked_tree(path):
os.unlink(path)
else:
shutil.rmtree(path, True)
+
+def fix_darwin_install_name(path):
+ """
+ Fix install name of dynamic libraries on Darwin to have full path.
+ There are two parts of this task:
+ (i) use install_name('-id',...) to change install name of a single lib;
+ (ii) use install_name('-change',...) to change the cross linking between libs.
+ The function assumes that all libraries are in one folder and currently won't
+ follow subfolders.
+
+ Args:
+ path: directory in which .dylib files are alocated
+
+ """
+ libs = glob.glob(join_path(path,"*.dylib"))
+ for lib in libs:
+ # fix install name first:
+ subprocess.Popen(["install_name_tool", "-id",lib,lib], stdout=subprocess.PIPE).communicate()[0]
+ long_deps = subprocess.Popen(["otool", "-L",lib], stdout=subprocess.PIPE).communicate()[0].split('\n')
+ deps = [dep.partition(' ')[0][1::] for dep in long_deps[2:-1]]
+ # fix all dependencies:
+ for dep in deps:
+ for loc in libs:
+ if dep == os.path.basename(loc):
+ subprocess.Popen(["install_name_tool", "-change",dep,loc,lib], stdout=subprocess.PIPE).communicate()[0]
+ break
diff --git a/lib/spack/llnl/util/lang.py b/lib/spack/llnl/util/lang.py
index 13d301f84e..3b4e2c8352 100644
--- a/lib/spack/llnl/util/lang.py
+++ b/lib/spack/llnl/util/lang.py
@@ -117,7 +117,8 @@ def caller_locals():
scope. Yes, this is some black magic, and yes it's useful
for implementing things like depends_on and provides.
"""
- stack = inspect.stack()
+ # Passing zero here skips line context for speed.
+ stack = inspect.stack(0)
try:
return stack[2][0].f_locals
finally:
@@ -128,7 +129,8 @@ def get_calling_module_name():
"""Make sure that the caller is a class definition, and return the
enclosing module's name.
"""
- stack = inspect.stack()
+ # Passing zero here skips line context for speed.
+ stack = inspect.stack(0)
try:
# Make sure locals contain __module__
caller_locals = stack[2][0].f_locals
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index fc5b7d6207..119a255a34 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -225,7 +225,7 @@ def set_module_variables_for_package(pkg, module):
m.spack_cc = join_path(link_dir, pkg.compiler.link_paths['cc'])
m.spack_cxx = join_path(link_dir, pkg.compiler.link_paths['cxx'])
m.spack_f77 = join_path(link_dir, pkg.compiler.link_paths['f77'])
- m.spack_f90 = join_path(link_dir, pkg.compiler.link_paths['fc'])
+ m.spack_fc = join_path(link_dir, pkg.compiler.link_paths['fc'])
# Emulate some shell commands for convenience
m.pwd = os.getcwd
@@ -270,32 +270,56 @@ def parent_class_modules(cls):
return result
+def setup_module_variables_for_dag(pkg):
+ """Set module-scope variables for all packages in the DAG."""
+ for spec in pkg.spec.traverse(order='post'):
+ # If a user makes their own package repo, e.g.
+ # spack.repos.mystuff.libelf.Libelf, and they inherit from
+ # an existing class like spack.repos.original.libelf.Libelf,
+ # then set the module variables for both classes so the
+ # parent class can still use them if it gets called.
+ spkg = spec.package
+ modules = parent_class_modules(spkg.__class__)
+ for mod in modules:
+ set_module_variables_for_package(spkg, mod)
+ set_module_variables_for_package(spkg, spkg.module)
+
+
def setup_package(pkg):
"""Execute all environment setup routines."""
spack_env = EnvironmentModifications()
run_env = EnvironmentModifications()
+ # Before proceeding, ensure that specs and packages are consistent
+ #
+ # This is a confusing behavior due to how packages are
+ # constructed. `setup_dependent_package` may set attributes on
+ # specs in the DAG for use by other packages' install
+ # method. However, spec.package will look up a package via
+ # spack.repo, which defensively copies specs into packages. This
+ # code ensures that all packages in the DAG have pieces of the
+ # same spec object at build time.
+ #
+ # This is safe for the build process, b/c the build process is a
+ # throwaway environment, but it is kind of dirty.
+ #
+ # TODO: Think about how to avoid this fix and do something cleaner.
+ for s in pkg.spec.traverse(): s.package.spec = s
+
set_compiler_environment_variables(pkg, spack_env)
set_build_environment_variables(pkg, spack_env)
-
- # If a user makes their own package repo, e.g.
- # spack.repos.mystuff.libelf.Libelf, and they inherit from
- # an existing class like spack.repos.original.libelf.Libelf,
- # then set the module variables for both classes so the
- # parent class can still use them if it gets called.
- modules = parent_class_modules(pkg.__class__)
- for mod in modules:
- set_module_variables_for_package(pkg, mod)
+ setup_module_variables_for_dag(pkg)
# Allow dependencies to modify the module
- for dependency_spec in pkg.spec.traverse(root=False):
+ spec = pkg.spec
+ for dependency_spec in spec.traverse(root=False):
dpkg = dependency_spec.package
- dpkg.setup_dependent_python_module(pkg.module, pkg.spec)
+ dpkg.setup_dependent_package(pkg.module, spec)
# Allow dependencies to set up environment as well
- for dependency_spec in pkg.spec.traverse(root=False):
+ for dependency_spec in spec.traverse(root=False):
dpkg = dependency_spec.package
- dpkg.setup_dependent_environment(spack_env, run_env, pkg.spec)
+ dpkg.setup_dependent_environment(spack_env, run_env, spec)
# Allow the package to apply some settings.
pkg.setup_environment(spack_env, run_env)
diff --git a/lib/spack/spack/cmd/info.py b/lib/spack/spack/cmd/info.py
index e7abe7f4a5..c93db55c63 100644
--- a/lib/spack/spack/cmd/info.py
+++ b/lib/spack/spack/cmd/info.py
@@ -52,7 +52,7 @@ def print_text_info(pkg):
print "Safe versions: "
if not pkg.versions:
- print("None")
+ print(" None")
else:
pad = padder(pkg.versions, 4)
for v in reversed(sorted(pkg.versions)):
@@ -62,7 +62,7 @@ def print_text_info(pkg):
print
print "Variants:"
if not pkg.variants:
- print "None"
+ print " None"
else:
pad = padder(pkg.variants, 4)
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
index 2e576743ec..ed9bf79868 100644
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -159,6 +159,10 @@ class DefaultConcretizer(object):
if any(v.satisfies(sv) for sv in spec.versions)],
cmp=cmp_versions)
+ def prefer_key(v):
+ return pkg.versions.get(Version(v)).get('preferred', False)
+ valid_versions.sort(key=prefer_key, reverse=True)
+
if valid_versions:
spec.versions = ver([valid_versions[0]])
else:
diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index 6afd69b3ac..14e5aaf4fb 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -237,7 +237,29 @@ section_schemas = {
'type' : 'object',
'default' : {},
}
- },},},},},}
+ },},},},},},
+ 'modules': {
+ '$schema': 'http://json-schema.org/schema#',
+ 'title': 'Spack module file configuration file schema',
+ 'type': 'object',
+ 'additionalProperties': False,
+ 'patternProperties': {
+ r'modules:?': {
+ 'type': 'object',
+ 'default': {},
+ 'additionalProperties': False,
+ 'properties': {
+ 'enable': {
+ 'type': 'array',
+ 'default': [],
+ 'items': {
+ 'type': 'string'
+ }
+ }
+ }
+ },
+ },
+ },
}
"""OrderedDict of config scopes keyed by name.
@@ -405,11 +427,11 @@ def _read_config_file(filename, schema):
validate_section(data, schema)
return data
- except MarkedYAMLError, e:
+ except MarkedYAMLError as e:
raise ConfigFileError(
"Error parsing yaml%s: %s" % (str(e.context_mark), e.problem))
- except IOError, e:
+ except IOError as e:
raise ConfigFileError(
"Error reading configuration file %s: %s" % (filename, str(e)))
diff --git a/lib/spack/spack/modules.py b/lib/spack/spack/modules.py
index 05c93cd3e6..f6a11c92e3 100644
--- a/lib/spack/spack/modules.py
+++ b/lib/spack/spack/modules.py
@@ -48,6 +48,7 @@ import textwrap
import llnl.util.tty as tty
import spack
+import spack.config
from llnl.util.filesystem import join_path, mkdirp
from spack.environment import *
@@ -56,6 +57,8 @@ __all__ = ['EnvModule', 'Dotkit', 'TclModule']
# Registry of all types of modules. Entries created by EnvModule's metaclass
module_types = {}
+CONFIGURATION = spack.config.get_config('modules')
+
def print_help():
"""For use by commands to tell user how to activate shell support."""
@@ -115,7 +118,7 @@ class EnvModule(object):
class __metaclass__(type):
def __init__(cls, name, bases, dict):
type.__init__(cls, name, bases, dict)
- if cls.name != 'env_module':
+ if cls.name != 'env_module' and cls.name in CONFIGURATION['enable']:
module_types[cls.name] = cls
def __init__(self, spec=None):
@@ -158,13 +161,13 @@ class EnvModule(object):
# Let the extendee modify their extensions before asking for
# package-specific modifications
- for extendee in self.pkg.extendees:
- extendee_spec = self.spec[extendee]
- extendee_spec.package.modify_module(
- self.pkg.module, extendee_spec, self.spec)
+ spack_env = EnvironmentModifications()
+ for item in self.pkg.extendees:
+ package = self.spec[item].package
+ package.setup_dependent_package(self.pkg.module, self.spec)
+ package.setup_dependent_environment(spack_env, env, self.spec)
# Package-specific environment modifications
- spack_env = EnvironmentModifications()
self.spec.package.setup_environment(spack_env, env)
# TODO : implement site-specific modifications and filters
@@ -275,6 +278,6 @@ class TclModule(EnvModule):
# Long description
if self.long_description:
module_file.write('proc ModulesHelp { } {\n')
- doc = re.sub(r'"', '\"', self.long_description)
- module_file.write("puts stderr \"%s\"\n" % doc)
+ for line in textwrap.wrap(self.long_description, 72):
+ module_file.write("puts stderr \"%s\"\n" % line)
module_file.write('}\n\n')
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 9d8ac87bd7..9af3221837 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -1075,7 +1075,7 @@ class Package(object):
self.setup_environment(spack_env, run_env)
- def setup_dependent_python_module(self, module, dependent_spec):
+ def setup_dependent_package(self, module, dependent_spec):
"""Set up Python module-scope variables for dependent packages.
Called before the install() method of dependents.
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 08cce09674..9cd8c969ae 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -24,6 +24,7 @@
##############################################################################
import spack
from spack.spec import Spec, CompilerSpec
+from spack.version import ver
from spack.concretize import find_spec
from spack.test.mock_packages_test import *
@@ -77,6 +78,14 @@ class ConcretizeTest(MockPackagesTest):
self.check_concretize('mpich')
+ def test_concretize_preferred_version(self):
+ spec = self.check_concretize('python')
+ self.assertEqual(spec.versions, ver('2.7.11'))
+
+ spec = self.check_concretize('python@3.5.1')
+ self.assertEqual(spec.versions, ver('3.5.1'))
+
+
def test_concretize_with_virtual(self):
self.check_concretize('mpileaks ^mpi')
self.check_concretize('mpileaks ^mpi@:1.1')