summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTodd Gamblin <tgamblin@llnl.gov>2015-12-28 00:33:17 -0800
committerTodd Gamblin <tgamblin@llnl.gov>2015-12-28 00:46:51 -0800
commit1f8ba53ca7767ca452f553f71d49eaf90fa19db8 (patch)
treea9b17548660828d42f7a97ed74f71276c11fe017 /lib
parentff0d871612c05d803fdabb8a5b870b7af961cdc2 (diff)
downloadspack-1f8ba53ca7767ca452f553f71d49eaf90fa19db8.tar.gz
spack-1f8ba53ca7767ca452f553f71d49eaf90fa19db8.tar.bz2
spack-1f8ba53ca7767ca452f553f71d49eaf90fa19db8.tar.xz
spack-1f8ba53ca7767ca452f553f71d49eaf90fa19db8.zip
Rework compiler configuration and simplify config.py logic.
- `spack compiler` subcommands now take an optional --scope argument. - no more `remove_from_config` in `config.py` -- `update` just overwrites b/c it's easier to just call `get_config`, modify YAML structures directly, and then call `update`. - Implemented `spack compiler remove`.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/cmd/compiler.py49
-rw-r--r--lib/spack/spack/cmd/compilers.py5
-rw-r--r--lib/spack/spack/compilers/__init__.py92
-rw-r--r--lib/spack/spack/config.py51
4 files changed, 124 insertions, 73 deletions
diff --git a/lib/spack/spack/cmd/compiler.py b/lib/spack/spack/cmd/compiler.py
index af1a22c9dd..a3860abf76 100644
--- a/lib/spack/spack/cmd/compiler.py
+++ b/lib/spack/spack/cmd/compiler.py
@@ -22,6 +22,7 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
+import sys
import argparse
import llnl.util.tty as tty
@@ -41,17 +42,26 @@ def setup_parser(subparser):
sp = subparser.add_subparsers(
metavar='SUBCOMMAND', dest='compiler_command')
- update_parser = sp.add_parser(
- 'add', help='Add compilers to the Spack configuration.')
- update_parser.add_argument('add_paths', nargs=argparse.REMAINDER)
+ add_parser = sp.add_parser('add', help='Add compilers to the Spack configuration.')
+ add_parser.add_argument('add_paths', nargs=argparse.REMAINDER)
+ add_parser.add_argument('--scope', choices=spack.config.config_scopes,
+ help="Configuration scope to modify.")
- remove_parser = sp.add_parser('remove', help='remove compiler')
- remove_parser.add_argument('path')
+ remove_parser = sp.add_parser('remove', help='Remove compiler by spec.')
+ remove_parser.add_argument(
+ '-a', '--all', action='store_true', help='Remove ALL compilers that match spec.')
+ remove_parser.add_argument('compiler_spec')
+ remove_parser.add_argument('--scope', choices=spack.config.config_scopes,
+ help="Configuration scope to modify.")
- list_parser = sp.add_parser('list', help='list available compilers')
+ list_parser = sp.add_parser('list', help='list available compilers')
+ list_parser.add_argument('--scope', choices=spack.config.config_scopes,
+ help="Configuration scope to read from.")
- info_parser = sp.add_parser('info', help='Show compiler paths.')
+ info_parser = sp.add_parser('info', help='Show compiler paths.')
info_parser.add_argument('compiler_spec')
+ info_parser.add_argument('--scope', choices=spack.config.config_scopes,
+ help="Configuration scope to read from.")
def compiler_add(args):
@@ -62,13 +72,13 @@ def compiler_add(args):
paths = get_path('PATH')
compilers = [c for c in spack.compilers.find_compilers(*args.add_paths)
- if c.spec not in spack.compilers.all_compilers()]
+ if c.spec not in spack.compilers.all_compilers(scope=args.scope)]
if compilers:
- spack.compilers.add_compilers_to_config('user', compilers)
+ spack.compilers.add_compilers_to_config(compilers, scope=args.scope)
n = len(compilers)
s = 's' if n > 1 else ''
- filename = spack.config.get_config_filename('user', 'compilers')
+ filename = spack.config.get_config_filename(args.scope, 'compilers')
tty.msg("Added %d new compiler%s to %s" % (n, s, filename))
colify(reversed(sorted(c.spec for c in compilers)), indent=4)
else:
@@ -76,13 +86,26 @@ def compiler_add(args):
def compiler_remove(args):
- pass
+ cspec = CompilerSpec(args.compiler_spec)
+ compilers = spack.compilers.compilers_for_spec(cspec, scope=args.scope)
+
+ if not compilers:
+ tty.die("No compilers match spec %s." % cspec)
+ elif not args.all and len(compilers) > 1:
+ tty.error("Multiple compilers match spec %s. Choose one:" % cspec)
+ colify(reversed(sorted([c.spec for c in compilers])), indent=4)
+ tty.msg("Or, you can use `spack compiler remove -a` to remove all of them.")
+ sys.exit(1)
+
+ for compiler in compilers:
+ spack.compilers.remove_compiler_from_config(compiler.spec, scope=args.scope)
+ tty.msg("Removed compiler %s." % compiler.spec)
def compiler_info(args):
"""Print info about all compilers matching a spec."""
cspec = CompilerSpec(args.compiler_spec)
- compilers = spack.compilers.compilers_for_spec(cspec)
+ compilers = spack.compilers.compilers_for_spec(cspec, scope=args.scope)
if not compilers:
tty.error("No compilers match spec %s." % cspec)
@@ -97,7 +120,7 @@ def compiler_info(args):
def compiler_list(args):
tty.msg("Available compilers")
- index = index_by(spack.compilers.all_compilers(), 'name')
+ index = index_by(spack.compilers.all_compilers(scope=args.scope), 'name')
for i, (name, compilers) in enumerate(index.items()):
if i >= 1: print
diff --git a/lib/spack/spack/cmd/compilers.py b/lib/spack/spack/cmd/compilers.py
index c485a910eb..7e09016f2d 100644
--- a/lib/spack/spack/cmd/compilers.py
+++ b/lib/spack/spack/cmd/compilers.py
@@ -26,9 +26,14 @@ import llnl.util.tty as tty
from llnl.util.tty.colify import colify
from llnl.util.lang import index_by
+import spack
from spack.cmd.compiler import compiler_list
description = "List available compilers. Same as 'spack compiler list'."
+def setup_parser(subparser):
+ subparser.add_argument('--scope', choices=spack.config.config_scopes,
+ help="Configuration scope to read/modify.")
+
def compilers(parser, args):
compiler_list(args)
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index a1b6d978df..67dfaa3ac9 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -49,10 +49,10 @@ _required_instance_vars = ['cc', 'cxx', 'f77', 'fc']
_default_order = ['gcc', 'intel', 'pgi', 'clang', 'xlc']
def _auto_compiler_spec(function):
- def converter(cspec_like):
+ def converter(cspec_like, *args, **kwargs):
if not isinstance(cspec_like, spack.spec.CompilerSpec):
cspec_like = spack.spec.CompilerSpec(cspec_like)
- return function(cspec_like)
+ return function(cspec_like, *args, **kwargs)
return converter
@@ -65,39 +65,87 @@ def _to_dict(compiler):
}
-def get_compiler_config(arch=None):
+def get_compiler_config(arch=None, scope=None):
"""Return the compiler configuration for the specified architecture.
-
- If the compiler configuration designates some compilers for
- 'all' architectures, those are merged into the result, as well.
-
"""
# If any configuration file has compilers, just stick with the
# ones already configured.
- config = spack.config.get_config('compilers')
+ config = spack.config.get_config('compilers', scope=scope)
+ my_arch = spack.architecture.sys_type()
if arch is None:
- arch = spack.architecture.sys_type()
+ arch = my_arch
- if arch not in config:
+ if arch in config:
+ return config[arch]
+
+ # Only for the current arch in *highest* scope: automatically try to
+ # find compilers if none are configured yet.
+ if arch == my_arch and scope == 'user':
config[arch] = {}
compilers = find_compilers(*get_path('PATH'))
for compiler in compilers:
config[arch].update(_to_dict(compiler))
- spack.config.update_config('compilers', config)
+ spack.config.update_config('compilers', config, scope=scope)
+ return config[arch]
- # Merge 'all' compilers with arch-specific ones.
- merged_config = config.get('all', {})
- merged_config = spack.config._merge_yaml(merged_config, config[arch])
+ return {}
+
+
+def add_compilers_to_config(compilers, arch=None, scope=None):
+ """Add compilers to the config for the specified architecture.
+
+ Arguments:
+ - compilers: a list of Compiler objects.
+ - arch: arch to add compilers for.
+ - scope: configuration scope to modify.
+ """
+ if arch is None:
+ arch = spack.architecture.sys_type()
+
+ compiler_config = get_compiler_config(arch, scope)
+ for compiler in compilers:
+ compiler_config[str(compiler.spec)] = dict(
+ (c, getattr(compiler, c, "None"))
+ for c in _required_instance_vars)
- return merged_config
+ update = { arch : compiler_config }
+ spack.config.update_config('compilers', update, scope)
-def all_compilers(arch=None):
+@_auto_compiler_spec
+def remove_compiler_from_config(compiler_spec, arch=None, scope=None):
+ """Remove compilers from the config, by spec.
+
+ Arguments:
+ - compiler_specs: a list of CompilerSpec objects.
+ - arch: arch to add compilers for.
+ - scope: configuration scope to modify.
+ """
+ if arch is None:
+ arch = spack.architecture.sys_type()
+
+ compiler_config = get_compiler_config(arch, scope)
+ del compiler_config[str(compiler_spec)]
+ update = { arch : compiler_config }
+
+ spack.config.update_config('compilers', update, scope)
+
+
+def all_compilers(arch=None, scope=None):
"""Return a set of specs for all the compiler versions currently
available to build with. These are instances of CompilerSpec.
"""
- return [spack.spec.CompilerSpec(s) for s in get_compiler_config(arch)]
+ # Get compilers for this architecture.
+ arch_config = get_compiler_config(arch, scope)
+
+ # Merge 'all' compilers with arch-specific ones.
+ # Arch-specific compilers have higher precedence.
+ merged_config = get_compiler_config('all', scope=scope)
+ merged_config = spack.config._merge_yaml(merged_config, arch_config)
+
+ # Return compiler specs for the result.
+ return [spack.spec.CompilerSpec(s) for s in merged_config]
_cached_default_compiler = None
@@ -165,18 +213,18 @@ def supported(compiler_spec):
@_auto_compiler_spec
-def find(compiler_spec):
+def find(compiler_spec, arch=None, scope=None):
"""Return specs of available compilers that match the supplied
compiler spec. Return an list if nothing found."""
- return [c for c in all_compilers() if c.satisfies(compiler_spec)]
+ return [c for c in all_compilers(arch, scope) if c.satisfies(compiler_spec)]
@_auto_compiler_spec
-def compilers_for_spec(compiler_spec):
+def compilers_for_spec(compiler_spec, arch=None, scope=None):
"""This gets all compilers that satisfy the supplied CompilerSpec.
Returns an empty list if none are found.
"""
- config = get_compiler_config()
+ config = get_compiler_config(arch, scope)
def get_compiler(cspec):
items = config[str(cspec)]
@@ -195,7 +243,7 @@ def compilers_for_spec(compiler_spec):
return cls(cspec, *compiler_paths)
- matches = find(compiler_spec)
+ matches = find(compiler_spec, arch, scope)
return [get_compiler(cspec) for cspec in matches]
diff --git a/lib/spack/spack/config.py b/lib/spack/spack/config.py
index 9e3b44085f..d266d2e23f 100644
--- a/lib/spack/spack/config.py
+++ b/lib/spack/spack/config.py
@@ -311,7 +311,7 @@ def substitute_spack_prefix(path):
return path.replace('$spack', spack.prefix)
-def get_config(section):
+def get_config(section, scope=None):
"""Get configuration settings for a section.
Strips off the top-level section name from the YAML dict.
@@ -319,7 +319,12 @@ def get_config(section):
validate_section(section)
merged_section = {}
- for scope in config_scopes.values():
+ if scope is None:
+ scopes = config_scopes.values()
+ else:
+ scopes = [validate_scope(scope)]
+
+ for scope in scopes:
# read potentially cached data from the scope.
data = scope.get_section(section)
if not data or not section in data:
@@ -362,52 +367,22 @@ def get_config_filename(scope, section):
def update_config(section, update_data, scope=None):
"""Update the configuration file for a particular scope.
- Merges contents of update_data into the scope's data for the
- specified section, then writes out the config file.
+ Overwrites contents of a section in a scope with update_data,
+ then writes out the config file.
- update_data shoudl contain only the section's data, with the
- top-level name stripped off. This can be a list, dict, or any
+ update_data should have the top-level section name stripped off
+ (it will be re-added). Data itself can be a list, dict, or any
other yaml-ish structure.
"""
# read in the config to ensure we've got current data
get_config(section)
- validate_section(section) # validate section name
+ validate_section(section) # validate section name
scope = validate_scope(scope) # get ConfigScope object from string.
# read only the requested section's data.
- data = scope.get_section(section)
- data = _merge_yaml(data, { section : update_data })
- scope.write_section(section)
-
-
-def remove_from_config(section, key_to_rm, scope=None):
- """Remove a configuration key and write updated configuration to disk.
-
- Return True if something was removed, False otherwise.
-
- """
- # ensure configs are current by reading in.
- get_config(section)
-
- # check args and get the objects we need.
- scope = validate_scope(scope)
- data = scope.get_section(section)
- filename = scope.get_section_filename(section)
-
- # do some checks
- if not data:
- return False
-
- if not section in data:
- raise ConfigFileError("Invalid configuration file: '%s'" % filename)
-
- if key_to_rm not in section[section]:
- return False
-
- # remove the key from the section's configuration
- del data[section][key_to_rm]
+ scope.sections[section] = { section : update_data }
scope.write_section(section)