Bootstrap should search for compilers after switching config scopes (#26029)
fixes #25992 Currently the bootstrapping process may need a compiler. When bootstrapping from sources the need is obvious, while when bootstrapping from binaries it's currently needed in case patchelf is not on the system (since it will be then bootstrapped from sources). Before this PR we were searching for compilers as the first operation, in case they were not declared in the configuration. This fails in case we start bootstrapping from within an environment. The fix is to defer the search until we have swapped configuration.
This commit is contained in:
parent
4d36c40cfb
commit
b847bb72f0
@ -490,18 +490,20 @@ def _bootstrap_config_scopes():
|
|||||||
return config_scopes
|
return config_scopes
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
def _add_compilers_if_missing():
|
||||||
def ensure_bootstrap_configuration():
|
# Do not use spack.architecture.default_arch() since it memoize the result
|
||||||
# We may need to compile code from sources, so ensure we have compilers
|
arch = spack.architecture.Arch(
|
||||||
# for the current platform before switching parts.
|
spack.architecture.real_platform(), 'default_os', 'default_target'
|
||||||
arch = spack.architecture.default_arch()
|
)
|
||||||
arch = spack.spec.ArchSpec(str(arch)) # The call below expects an ArchSpec object
|
arch = spack.spec.ArchSpec(str(arch)) # The call below expects an ArchSpec object
|
||||||
if not spack.compilers.compilers_for_arch(arch):
|
if not spack.compilers.compilers_for_arch(arch):
|
||||||
compiler_cmd = spack.main.SpackCommand('compiler')
|
new_compilers = spack.compilers.find_new_compilers()
|
||||||
compiler_cmd(
|
if new_compilers:
|
||||||
'find', output=os.devnull, error=os.devnull, fail_on_error=False
|
spack.compilers.add_compilers_to_config(new_compilers, init_config=False)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def ensure_bootstrap_configuration():
|
||||||
bootstrap_store_path = store_path()
|
bootstrap_store_path = store_path()
|
||||||
with spack.environment.deactivate_environment():
|
with spack.environment.deactivate_environment():
|
||||||
with spack.architecture.use_platform(spack.architecture.real_platform()):
|
with spack.architecture.use_platform(spack.architecture.real_platform()):
|
||||||
@ -511,6 +513,9 @@ def ensure_bootstrap_configuration():
|
|||||||
# and builtin but accounting for platform specific scopes
|
# and builtin but accounting for platform specific scopes
|
||||||
config_scopes = _bootstrap_config_scopes()
|
config_scopes = _bootstrap_config_scopes()
|
||||||
with spack.config.use_configuration(*config_scopes):
|
with spack.config.use_configuration(*config_scopes):
|
||||||
|
# We may need to compile code from sources, so ensure we have
|
||||||
|
# compilers for the current platform before switching parts.
|
||||||
|
_add_compilers_if_missing()
|
||||||
with spack.modules.disable_modules():
|
with spack.modules.disable_modules():
|
||||||
with spack_python_interpreter():
|
with spack_python_interpreter():
|
||||||
yield
|
yield
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
import spack.compilers
|
import spack.compilers
|
||||||
import spack.config
|
import spack.config
|
||||||
import spack.spec
|
import spack.spec
|
||||||
from spack.spec import ArchSpec, CompilerSpec
|
|
||||||
|
|
||||||
description = "manage compilers"
|
description = "manage compilers"
|
||||||
section = "system"
|
section = "system"
|
||||||
@ -78,24 +77,13 @@ def compiler_find(args):
|
|||||||
# None signals spack.compiler.find_compilers to use its default logic
|
# None signals spack.compiler.find_compilers to use its default logic
|
||||||
paths = args.add_paths or None
|
paths = args.add_paths or None
|
||||||
|
|
||||||
# Don't initialize compilers config via compilers.get_compiler_config.
|
# Below scope=None because we want new compilers that don't appear
|
||||||
# Just let compiler_find do the
|
# in any other configuration.
|
||||||
# entire process and return an empty config from all_compilers
|
new_compilers = spack.compilers.find_new_compilers(paths, scope=None)
|
||||||
# Default for any other process is init_config=True
|
|
||||||
compilers = [c for c in spack.compilers.find_compilers(paths)]
|
|
||||||
new_compilers = []
|
|
||||||
for c in compilers:
|
|
||||||
arch_spec = ArchSpec((None, c.operating_system, c.target))
|
|
||||||
same_specs = spack.compilers.compilers_for_spec(
|
|
||||||
c.spec, arch_spec, init_config=False)
|
|
||||||
|
|
||||||
if not same_specs:
|
|
||||||
new_compilers.append(c)
|
|
||||||
|
|
||||||
if new_compilers:
|
if new_compilers:
|
||||||
spack.compilers.add_compilers_to_config(new_compilers,
|
spack.compilers.add_compilers_to_config(
|
||||||
scope=args.scope,
|
new_compilers, scope=args.scope, init_config=False
|
||||||
init_config=False)
|
)
|
||||||
n = len(new_compilers)
|
n = len(new_compilers)
|
||||||
s = 's' if n > 1 else ''
|
s = 's' if n > 1 else ''
|
||||||
|
|
||||||
@ -110,7 +98,7 @@ def compiler_find(args):
|
|||||||
|
|
||||||
|
|
||||||
def compiler_remove(args):
|
def compiler_remove(args):
|
||||||
cspec = CompilerSpec(args.compiler_spec)
|
cspec = spack.spec.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)
|
||||||
@ -128,7 +116,7 @@ def compiler_remove(args):
|
|||||||
|
|
||||||
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 = spack.spec.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:
|
||||||
|
@ -192,15 +192,12 @@ def all_compiler_specs(scope=None, init_config=True):
|
|||||||
|
|
||||||
|
|
||||||
def find_compilers(path_hints=None):
|
def find_compilers(path_hints=None):
|
||||||
"""Returns the list of compilers found in the paths given as arguments.
|
"""Return the list of compilers found in the paths given as arguments.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path_hints (list or None): list of path hints where to look for.
|
path_hints (list or None): list of path hints where to look for.
|
||||||
A sensible default based on the ``PATH`` environment variable
|
A sensible default based on the ``PATH`` environment variable
|
||||||
will be used if the value is None
|
will be used if the value is None
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of compilers found
|
|
||||||
"""
|
"""
|
||||||
if path_hints is None:
|
if path_hints is None:
|
||||||
path_hints = get_path('PATH')
|
path_hints = get_path('PATH')
|
||||||
@ -242,6 +239,30 @@ def remove_errors(item):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def find_new_compilers(path_hints=None, scope=None):
|
||||||
|
"""Same as ``find_compilers`` but return only the compilers that are not
|
||||||
|
already in compilers.yaml.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path_hints (list or None): list of path hints where to look for.
|
||||||
|
A sensible default based on the ``PATH`` environment variable
|
||||||
|
will be used if the value is None
|
||||||
|
scope (str): scope to look for a compiler. If None consider the
|
||||||
|
merged configuration.
|
||||||
|
"""
|
||||||
|
compilers = find_compilers(path_hints)
|
||||||
|
compilers_not_in_config = []
|
||||||
|
for c in compilers:
|
||||||
|
arch_spec = spack.spec.ArchSpec((None, c.operating_system, c.target))
|
||||||
|
same_specs = compilers_for_spec(
|
||||||
|
c.spec, arch_spec, scope=scope, init_config=False
|
||||||
|
)
|
||||||
|
if not same_specs:
|
||||||
|
compilers_not_in_config.append(c)
|
||||||
|
|
||||||
|
return compilers_not_in_config
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@ -289,8 +310,9 @@ def all_compilers(scope=None):
|
|||||||
|
|
||||||
|
|
||||||
@_auto_compiler_spec
|
@_auto_compiler_spec
|
||||||
def compilers_for_spec(compiler_spec, arch_spec=None, scope=None,
|
def compilers_for_spec(
|
||||||
use_cache=True, init_config=True):
|
compiler_spec, arch_spec=None, scope=None, use_cache=True, init_config=True
|
||||||
|
):
|
||||||
"""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.
|
||||||
"""
|
"""
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import spack.bootstrap
|
import spack.bootstrap
|
||||||
|
import spack.compilers
|
||||||
import spack.environment
|
import spack.environment
|
||||||
import spack.store
|
import spack.store
|
||||||
import spack.util.path
|
import spack.util.path
|
||||||
@ -78,3 +79,23 @@ def test_bootstrap_disables_modulefile_generation(mutable_config):
|
|||||||
assert 'lmod' not in spack.config.get('modules:enable')
|
assert 'lmod' not in spack.config.get('modules:enable')
|
||||||
assert 'tcl' in spack.config.get('modules:enable')
|
assert 'tcl' in spack.config.get('modules:enable')
|
||||||
assert 'lmod' in spack.config.get('modules:enable')
|
assert 'lmod' in spack.config.get('modules:enable')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.regression('25992')
|
||||||
|
@pytest.mark.requires_executables('gcc')
|
||||||
|
def test_bootstrap_search_for_compilers_with_no_environment(no_compilers_yaml):
|
||||||
|
assert not spack.compilers.all_compiler_specs(init_config=False)
|
||||||
|
with spack.bootstrap.ensure_bootstrap_configuration():
|
||||||
|
assert spack.compilers.all_compiler_specs(init_config=False)
|
||||||
|
assert not spack.compilers.all_compiler_specs(init_config=False)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.regression('25992')
|
||||||
|
@pytest.mark.requires_executables('gcc')
|
||||||
|
def test_bootstrap_search_for_compilers_with_environment_active(
|
||||||
|
no_compilers_yaml, active_mock_environment
|
||||||
|
):
|
||||||
|
assert not spack.compilers.all_compiler_specs(init_config=False)
|
||||||
|
with spack.bootstrap.ensure_bootstrap_configuration():
|
||||||
|
assert spack.compilers.all_compiler_specs(init_config=False)
|
||||||
|
assert not spack.compilers.all_compiler_specs(init_config=False)
|
||||||
|
@ -16,18 +16,6 @@
|
|||||||
compiler = spack.main.SpackCommand('compiler')
|
compiler = spack.main.SpackCommand('compiler')
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def no_compilers_yaml(mutable_config):
|
|
||||||
"""Creates a temporary configuration without compilers.yaml"""
|
|
||||||
|
|
||||||
for scope, local_config in mutable_config.scopes.items():
|
|
||||||
compilers_yaml = os.path.join(
|
|
||||||
local_config.path, scope, 'compilers.yaml'
|
|
||||||
)
|
|
||||||
if os.path.exists(compilers_yaml):
|
|
||||||
os.remove(compilers_yaml)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_compiler_version():
|
def mock_compiler_version():
|
||||||
return '4.5.3'
|
return '4.5.3'
|
||||||
|
@ -652,6 +652,15 @@ def mutable_empty_config(tmpdir_factory, configuration_dir):
|
|||||||
yield cfg
|
yield cfg
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def no_compilers_yaml(mutable_config):
|
||||||
|
"""Creates a temporary configuration without compilers.yaml"""
|
||||||
|
for scope, local_config in mutable_config.scopes.items():
|
||||||
|
compilers_yaml = os.path.join(local_config.path, 'compilers.yaml')
|
||||||
|
if os.path.exists(compilers_yaml):
|
||||||
|
os.remove(compilers_yaml)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def mock_low_high_config(tmpdir):
|
def mock_low_high_config(tmpdir):
|
||||||
"""Mocks two configuration scopes: 'low' and 'high'."""
|
"""Mocks two configuration scopes: 'low' and 'high'."""
|
||||||
|
Loading…
Reference in New Issue
Block a user