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`.
This commit is contained in:
parent
ff0d871612
commit
1f8ba53ca7
@ -22,6 +22,7 @@
|
|||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
@ -41,17 +42,26 @@ def setup_parser(subparser):
|
|||||||
sp = subparser.add_subparsers(
|
sp = subparser.add_subparsers(
|
||||||
metavar='SUBCOMMAND', dest='compiler_command')
|
metavar='SUBCOMMAND', dest='compiler_command')
|
||||||
|
|
||||||
update_parser = sp.add_parser(
|
add_parser = sp.add_parser('add', help='Add compilers to the Spack configuration.')
|
||||||
'add', help='Add compilers to the Spack configuration.')
|
add_parser.add_argument('add_paths', nargs=argparse.REMAINDER)
|
||||||
update_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 = sp.add_parser('remove', help='Remove compiler by spec.')
|
||||||
remove_parser.add_argument('path')
|
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('compiler_spec')
|
||||||
|
info_parser.add_argument('--scope', choices=spack.config.config_scopes,
|
||||||
|
help="Configuration scope to read from.")
|
||||||
|
|
||||||
|
|
||||||
def compiler_add(args):
|
def compiler_add(args):
|
||||||
@ -62,13 +72,13 @@ def compiler_add(args):
|
|||||||
paths = get_path('PATH')
|
paths = get_path('PATH')
|
||||||
|
|
||||||
compilers = [c for c in spack.compilers.find_compilers(*args.add_paths)
|
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:
|
if compilers:
|
||||||
spack.compilers.add_compilers_to_config('user', compilers)
|
spack.compilers.add_compilers_to_config(compilers, scope=args.scope)
|
||||||
n = len(compilers)
|
n = len(compilers)
|
||||||
s = 's' if n > 1 else ''
|
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))
|
tty.msg("Added %d new compiler%s to %s" % (n, s, filename))
|
||||||
colify(reversed(sorted(c.spec for c in compilers)), indent=4)
|
colify(reversed(sorted(c.spec for c in compilers)), indent=4)
|
||||||
else:
|
else:
|
||||||
@ -76,13 +86,26 @@ def compiler_add(args):
|
|||||||
|
|
||||||
|
|
||||||
def compiler_remove(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):
|
def compiler_info(args):
|
||||||
"""Print info about all compilers matching a spec."""
|
"""Print info about all compilers matching a spec."""
|
||||||
cspec = CompilerSpec(args.compiler_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:
|
if not compilers:
|
||||||
tty.error("No compilers match spec %s." % cspec)
|
tty.error("No compilers match spec %s." % cspec)
|
||||||
@ -97,7 +120,7 @@ def compiler_info(args):
|
|||||||
|
|
||||||
def compiler_list(args):
|
def compiler_list(args):
|
||||||
tty.msg("Available compilers")
|
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()):
|
for i, (name, compilers) in enumerate(index.items()):
|
||||||
if i >= 1: print
|
if i >= 1: print
|
||||||
|
|
||||||
|
@ -26,9 +26,14 @@
|
|||||||
from llnl.util.tty.colify import colify
|
from llnl.util.tty.colify import colify
|
||||||
from llnl.util.lang import index_by
|
from llnl.util.lang import index_by
|
||||||
|
|
||||||
|
import spack
|
||||||
from spack.cmd.compiler import compiler_list
|
from spack.cmd.compiler import compiler_list
|
||||||
|
|
||||||
description = "List available compilers. Same as 'spack 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):
|
def compilers(parser, args):
|
||||||
compiler_list(args)
|
compiler_list(args)
|
||||||
|
@ -49,10 +49,10 @@
|
|||||||
_default_order = ['gcc', 'intel', 'pgi', 'clang', 'xlc']
|
_default_order = ['gcc', 'intel', 'pgi', 'clang', 'xlc']
|
||||||
|
|
||||||
def _auto_compiler_spec(function):
|
def _auto_compiler_spec(function):
|
||||||
def converter(cspec_like):
|
def converter(cspec_like, *args, **kwargs):
|
||||||
if not isinstance(cspec_like, spack.spec.CompilerSpec):
|
if not isinstance(cspec_like, spack.spec.CompilerSpec):
|
||||||
cspec_like = spack.spec.CompilerSpec(cspec_like)
|
cspec_like = spack.spec.CompilerSpec(cspec_like)
|
||||||
return function(cspec_like)
|
return function(cspec_like, *args, **kwargs)
|
||||||
return converter
|
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.
|
"""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
|
# If any configuration file has compilers, just stick with the
|
||||||
# ones already configured.
|
# 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:
|
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] = {}
|
config[arch] = {}
|
||||||
compilers = find_compilers(*get_path('PATH'))
|
compilers = find_compilers(*get_path('PATH'))
|
||||||
for compiler in compilers:
|
for compiler in compilers:
|
||||||
config[arch].update(_to_dict(compiler))
|
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.
|
return {}
|
||||||
merged_config = config.get('all', {})
|
|
||||||
merged_config = spack.config._merge_yaml(merged_config, config[arch])
|
|
||||||
|
|
||||||
return merged_config
|
|
||||||
|
|
||||||
|
|
||||||
def all_compilers(arch=None):
|
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)
|
||||||
|
|
||||||
|
update = { arch : compiler_config }
|
||||||
|
spack.config.update_config('compilers', update, scope)
|
||||||
|
|
||||||
|
|
||||||
|
@_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
|
"""Return a set of specs for all the compiler versions currently
|
||||||
available to build with. These are instances of CompilerSpec.
|
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
|
_cached_default_compiler = None
|
||||||
@ -165,18 +213,18 @@ def supported(compiler_spec):
|
|||||||
|
|
||||||
|
|
||||||
@_auto_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
|
"""Return specs of available compilers that match the supplied
|
||||||
compiler spec. Return an list if nothing found."""
|
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
|
@_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.
|
"""This gets all compilers that satisfy the supplied CompilerSpec.
|
||||||
Returns an empty list if none are found.
|
Returns an empty list if none are found.
|
||||||
"""
|
"""
|
||||||
config = get_compiler_config()
|
config = get_compiler_config(arch, scope)
|
||||||
|
|
||||||
def get_compiler(cspec):
|
def get_compiler(cspec):
|
||||||
items = config[str(cspec)]
|
items = config[str(cspec)]
|
||||||
@ -195,7 +243,7 @@ def get_compiler(cspec):
|
|||||||
|
|
||||||
return cls(cspec, *compiler_paths)
|
return cls(cspec, *compiler_paths)
|
||||||
|
|
||||||
matches = find(compiler_spec)
|
matches = find(compiler_spec, arch, scope)
|
||||||
return [get_compiler(cspec) for cspec in matches]
|
return [get_compiler(cspec) for cspec in matches]
|
||||||
|
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ def substitute_spack_prefix(path):
|
|||||||
return path.replace('$spack', spack.prefix)
|
return path.replace('$spack', spack.prefix)
|
||||||
|
|
||||||
|
|
||||||
def get_config(section):
|
def get_config(section, scope=None):
|
||||||
"""Get configuration settings for a section.
|
"""Get configuration settings for a section.
|
||||||
|
|
||||||
Strips off the top-level section name from the YAML dict.
|
Strips off the top-level section name from the YAML dict.
|
||||||
@ -319,7 +319,12 @@ def get_config(section):
|
|||||||
validate_section(section)
|
validate_section(section)
|
||||||
merged_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.
|
# read potentially cached data from the scope.
|
||||||
data = scope.get_section(section)
|
data = scope.get_section(section)
|
||||||
if not data or not section in data:
|
if not data or not section in data:
|
||||||
@ -362,11 +367,11 @@ def get_config_filename(scope, section):
|
|||||||
def update_config(section, update_data, scope=None):
|
def update_config(section, update_data, scope=None):
|
||||||
"""Update the configuration file for a particular scope.
|
"""Update the configuration file for a particular scope.
|
||||||
|
|
||||||
Merges contents of update_data into the scope's data for the
|
Overwrites contents of a section in a scope with update_data,
|
||||||
specified section, then writes out the config file.
|
then writes out the config file.
|
||||||
|
|
||||||
update_data shoudl contain only the section's data, with the
|
update_data should have the top-level section name stripped off
|
||||||
top-level name stripped off. This can be a list, dict, or any
|
(it will be re-added). Data itself can be a list, dict, or any
|
||||||
other yaml-ish structure.
|
other yaml-ish structure.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -377,37 +382,7 @@ def update_config(section, update_data, scope=None):
|
|||||||
scope = validate_scope(scope) # get ConfigScope object from string.
|
scope = validate_scope(scope) # get ConfigScope object from string.
|
||||||
|
|
||||||
# read only the requested section's data.
|
# read only the requested section's data.
|
||||||
data = scope.get_section(section)
|
scope.sections[section] = { section : update_data }
|
||||||
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.write_section(section)
|
scope.write_section(section)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user