Merge branch 'bugfix/compiler_find' into develop

This commit is contained in:
Todd Gamblin 2016-06-20 09:34:25 -07:00
commit ce105e9bbe
4 changed files with 112 additions and 29 deletions

View File

@ -69,7 +69,7 @@ def setup_parser(subparser):
help="Configuration scope to read from.") help="Configuration scope to read from.")
def compiler_add(args): def compiler_find(args):
"""Search either $PATH or a list of paths OR MODULES for compilers and add them """Search either $PATH or a list of paths OR MODULES for compilers and add them
to Spack's configuration.""" to Spack's configuration."""
paths = args.add_paths paths = args.add_paths
@ -78,7 +78,6 @@ def compiler_add(args):
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(scope=args.scope)] if c.spec not in spack.compilers.all_compilers(scope=args.scope)]
if compilers: if compilers:
spack.compilers.add_compilers_to_config(compilers, scope=args.scope) spack.compilers.add_compilers_to_config(compilers, scope=args.scope)
n = len(compilers) n = len(compilers)
@ -93,7 +92,6 @@ def compiler_add(args):
def compiler_remove(args): def compiler_remove(args):
cspec = CompilerSpec(args.compiler_spec) cspec = CompilerSpec(args.compiler_spec)
compilers = spack.compilers.compilers_for_spec(cspec, scope=args.scope) compilers = spack.compilers.compilers_for_spec(cspec, scope=args.scope)
if not compilers: if not compilers:
tty.die("No compilers match spec %s" % cspec) tty.die("No compilers match spec %s" % cspec)
elif not args.all and len(compilers) > 1: elif not args.all and len(compilers) > 1:
@ -137,7 +135,8 @@ def compiler_list(args):
def compiler(parser, args): def compiler(parser, args):
action = { 'add' : compiler_add, action = {'add' : compiler_find,
'find' : compiler_find,
'remove' : compiler_remove, 'remove' : compiler_remove,
'rm' : compiler_remove, 'rm' : compiler_remove,
'info' : compiler_info, 'info' : compiler_info,

View File

@ -52,6 +52,7 @@
_imported_compilers_module = 'spack.compilers' _imported_compilers_module = 'spack.compilers'
_path_instance_vars = ['cc', 'cxx', 'f77', 'fc'] _path_instance_vars = ['cc', 'cxx', 'f77', 'fc']
_other_instance_vars = ['modules', 'operating_system'] _other_instance_vars = ['modules', 'operating_system']
_cache_config_file = []
# TODO: customize order in config file # TODO: customize order in config file
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
@ -79,9 +80,7 @@ def _to_dict(compiler):
if compiler.alias: if compiler.alias:
d['alias'] = compiler.alias d['alias'] = compiler.alias
return { return {'compiler': d}
'compiler': d
}
def get_compiler_config(scope=None): def get_compiler_config(scope=None):
@ -99,7 +98,6 @@ def init_compiler_config():
# Update the configuration if there are currently no compilers # Update the configuration if there are currently no compilers
# configured. Avoid updating automatically if there ARE site # configured. Avoid updating automatically if there ARE site
# compilers configured but no user ones. # compilers configured but no user ones.
# if (isinstance(arch, basestring) or arch == my_arch) and arch not in config:
if not config: if not config:
if scope is None: if scope is None:
# We know no compilers were configured in any scope. # We know no compilers were configured in any scope.
@ -112,8 +110,11 @@ def init_compiler_config():
if not site_config: if not site_config:
init_compiler_config() init_compiler_config()
config = spack.config.get_config('compilers', scope=scope) config = spack.config.get_config('compilers', scope=scope)
return config return config
elif config:
return config
else:
return [] # Return empty list which we will later append to.
def add_compilers_to_config(compilers, scope=None): def add_compilers_to_config(compilers, scope=None):
@ -126,7 +127,8 @@ def add_compilers_to_config(compilers, scope=None):
compiler_config = get_compiler_config(scope) compiler_config = get_compiler_config(scope)
for compiler in compilers: for compiler in compilers:
compiler_config.append(_to_dict(compiler)) compiler_config.append(_to_dict(compiler))
global _cache_config_file
_cache_config_file = compiler_config
spack.config.update_config('compilers', compiler_config, scope) spack.config.update_config('compilers', compiler_config, scope)
@ -139,15 +141,17 @@ def remove_compiler_from_config(compiler_spec, scope=None):
- scope: configuration scope to modify. - scope: configuration scope to modify.
""" """
compiler_config = get_compiler_config(scope) compiler_config = get_compiler_config(scope)
matches = [(a,c) for (a,c) in compiler_config.items() if c['spec'] == compiler_spec] config_length = len(compiler_config)
if len(matches) == 1:
del compiler_config[matches[0][0]] filtered_compiler_config = [comp for comp in compiler_config
else: if spack.spec.CompilerSpec(comp['compiler']['spec']) != compiler_spec]
# Need a better way for this
global _cache_config_file
_cache_config_file = filtered_compiler_config # Update the cache for changes
if len(filtered_compiler_config) == config_length: # No items removed
CompilerSpecInsufficientlySpecificError(compiler_spec) CompilerSpecInsufficientlySpecificError(compiler_spec)
spack.config.update_config('compilers', filtered_compiler_config, scope)
spack.config.update_config('compilers', compiler_config, scope)
_cache_config_file = {}
def all_compilers_config(scope=None): def all_compilers_config(scope=None):
"""Return a set of specs for all the compiler versions currently """Return a set of specs for all the compiler versions currently
@ -155,14 +159,13 @@ def all_compilers_config(scope=None):
""" """
# Get compilers for this architecture. # Get compilers for this architecture.
global _cache_config_file #Create a cache of the config file so we don't load all the time. global _cache_config_file #Create a cache of the config file so we don't load all the time.
if not _cache_config_file: if not _cache_config_file:
_cache_config_file = get_compiler_config(scope) _cache_config_file = get_compiler_config(scope)
return _cache_config_file return _cache_config_file
else: else:
return _cache_config_file return _cache_config_file
def all_compilers(scope=None): def all_compilers(scope=None):
# Return compiler specs from the merged config. # Return compiler specs from the merged config.
return [spack.spec.CompilerSpec(s['compiler']['spec']) return [spack.spec.CompilerSpec(s['compiler']['spec'])
@ -181,7 +184,7 @@ def default_compiler():
return sorted(versions)[-1] return sorted(versions)[-1]
def find_compilers(): def find_compilers(*paths):
"""Return a list of compilers found in the suppied paths. """Return a list of compilers found in the suppied paths.
This invokes the find_compilers() method for each operating This invokes the find_compilers() method for each operating
system associated with the host platform, and appends system associated with the host platform, and appends
@ -190,11 +193,11 @@ def find_compilers():
# Find compilers for each operating system class # Find compilers for each operating system class
oss = all_os_classes() oss = all_os_classes()
compiler_lists = [] compiler_lists = []
for os in oss: for o in oss:
compiler_lists.extend(os.find_compilers()) compiler_lists.extend(o.find_compilers(*paths))
return compiler_lists return compiler_lists
def supported_compilers(): def supported_compilers():
"""Return a set of names of compilers supported by Spack. """Return a set of names of compilers supported by Spack.

View File

@ -40,7 +40,7 @@
'cc', 'link_tree', 'spec_yaml', 'optional_deps', 'cc', 'link_tree', 'spec_yaml', 'optional_deps',
'make_executable', 'configure_guess', 'lock', 'database', 'make_executable', 'configure_guess', 'lock', 'database',
'namespace_trie', 'yaml', 'sbang', 'environment', 'cmd.find', 'namespace_trie', 'yaml', 'sbang', 'environment', 'cmd.find',
'cmd.uninstall', 'cmd.test_install'] 'cmd.uninstall', 'cmd.test_install', 'cmd.test_compiler_cmd']
def list_tests(): def list_tests():

View File

@ -0,0 +1,81 @@
import os
import shutil
from tempfile import mkdtemp
from llnl.util.filesystem import set_executable, mkdirp
import spack.spec
import spack.cmd.compiler
import spack.compilers
from spack.version import Version
from spack.test.mock_packages_test import *
test_version = '4.5-spacktest'
class MockArgs(object):
def __init__(self, add_paths=[], scope=None, compiler_spec=None, all=None):
self.add_paths = add_paths
self.scope = scope
self.compiler_spec = compiler_spec
self.all = all
def make_mock_compiler():
"""Make a directory containing a fake, but detectable compiler."""
mock_compiler_dir = mkdtemp()
bin_dir = os.path.join(mock_compiler_dir, 'bin')
mkdirp(bin_dir)
gcc_path = os.path.join(bin_dir, 'gcc')
gxx_path = os.path.join(bin_dir, 'g++')
gfortran_path = os.path.join(bin_dir, 'gfortran')
with open(gcc_path, 'w') as f:
f.write("""\
#!/bin/sh
for arg in "$@"; do
if [ "$arg" = -dumpversion ]; then
echo '%s'
fi
done
""" % test_version)
# Create some mock compilers in the temporary directory
set_executable(gcc_path)
shutil.copy(gcc_path, gxx_path)
shutil.copy(gcc_path, gfortran_path)
return mock_compiler_dir
class CompilerCmdTest(MockPackagesTest):
""" Test compiler commands for add and remove """
def test_compiler_remove(self):
args = MockArgs(all=True, compiler_spec='gcc@4.5.0')
spack.cmd.compiler.compiler_remove(args)
compilers = spack.compilers.all_compilers()
self.assertTrue(spack.spec.CompilerSpec("gcc@4.5.0") not in compilers)
def test_compiler_add(self):
# compilers available by default.
old_compilers = set(spack.compilers.all_compilers())
# add our new compiler and find again.
compiler_dir = make_mock_compiler()
try:
args = MockArgs(add_paths=[compiler_dir])
spack.cmd.compiler.compiler_find(args)
# ensure new compiler is in there
new_compilers = set(spack.compilers.all_compilers())
new_compiler = new_compilers - old_compilers
self.assertTrue(new_compiler)
self.assertTrue(new_compiler.pop().version == Version(test_version))
finally:
shutil.rmtree(compiler_dir, ignore_errors=True)