summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMassimiliano Culpo <massimiliano.culpo@gmail.com>2021-09-18 02:28:48 +0200
committerGitHub <noreply@github.com>2021-09-17 18:28:48 -0600
commitb847bb72f0db53f8741876d7633cc46b5f855759 (patch)
treea0104edae8306c0f0e093b374bf5afbf0682b04c /lib
parent4d36c40cfb5225a27d25af444d0fc3dbb9e8791d (diff)
downloadspack-b847bb72f0db53f8741876d7633cc46b5f855759.tar.gz
spack-b847bb72f0db53f8741876d7633cc46b5f855759.tar.bz2
spack-b847bb72f0db53f8741876d7633cc46b5f855759.tar.xz
spack-b847bb72f0db53f8741876d7633cc46b5f855759.zip
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/bootstrap.py23
-rw-r--r--lib/spack/spack/cmd/compiler.py28
-rw-r--r--lib/spack/spack/compilers/__init__.py34
-rw-r--r--lib/spack/spack/test/bootstrap.py21
-rw-r--r--lib/spack/spack/test/cmd/compiler.py12
-rw-r--r--lib/spack/spack/test/conftest.py9
6 files changed, 80 insertions, 47 deletions
diff --git a/lib/spack/spack/bootstrap.py b/lib/spack/spack/bootstrap.py
index 5d1a494065..fbfeefe92f 100644
--- a/lib/spack/spack/bootstrap.py
+++ b/lib/spack/spack/bootstrap.py
@@ -490,18 +490,20 @@ def _bootstrap_config_scopes():
return config_scopes
-@contextlib.contextmanager
-def ensure_bootstrap_configuration():
- # We may need to compile code from sources, so ensure we have compilers
- # for the current platform before switching parts.
- arch = spack.architecture.default_arch()
+def _add_compilers_if_missing():
+ # Do not use spack.architecture.default_arch() since it memoize the result
+ arch = spack.architecture.Arch(
+ spack.architecture.real_platform(), 'default_os', 'default_target'
+ )
arch = spack.spec.ArchSpec(str(arch)) # The call below expects an ArchSpec object
if not spack.compilers.compilers_for_arch(arch):
- compiler_cmd = spack.main.SpackCommand('compiler')
- compiler_cmd(
- 'find', output=os.devnull, error=os.devnull, fail_on_error=False
- )
+ new_compilers = spack.compilers.find_new_compilers()
+ if new_compilers:
+ spack.compilers.add_compilers_to_config(new_compilers, init_config=False)
+
+@contextlib.contextmanager
+def ensure_bootstrap_configuration():
bootstrap_store_path = store_path()
with spack.environment.deactivate_environment():
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
config_scopes = _bootstrap_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_python_interpreter():
yield
diff --git a/lib/spack/spack/cmd/compiler.py b/lib/spack/spack/cmd/compiler.py
index 51d3dcced3..3543025cc0 100644
--- a/lib/spack/spack/cmd/compiler.py
+++ b/lib/spack/spack/cmd/compiler.py
@@ -18,7 +18,6 @@ from llnl.util.tty.color import colorize
import spack.compilers
import spack.config
import spack.spec
-from spack.spec import ArchSpec, CompilerSpec
description = "manage compilers"
section = "system"
@@ -78,24 +77,13 @@ def compiler_find(args):
# None signals spack.compiler.find_compilers to use its default logic
paths = args.add_paths or None
- # Don't initialize compilers config via compilers.get_compiler_config.
- # Just let compiler_find do the
- # entire process and return an empty config from all_compilers
- # 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)
-
+ # Below scope=None because we want new compilers that don't appear
+ # in any other configuration.
+ new_compilers = spack.compilers.find_new_compilers(paths, scope=None)
if new_compilers:
- spack.compilers.add_compilers_to_config(new_compilers,
- scope=args.scope,
- init_config=False)
+ spack.compilers.add_compilers_to_config(
+ new_compilers, scope=args.scope, init_config=False
+ )
n = len(new_compilers)
s = 's' if n > 1 else ''
@@ -110,7 +98,7 @@ def compiler_find(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)
if not compilers:
tty.die("No compilers match spec %s" % cspec)
@@ -128,7 +116,7 @@ def compiler_remove(args):
def compiler_info(args):
"""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)
if not compilers:
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index 7959dad25b..9ecfa69393 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -192,15 +192,12 @@ def all_compiler_specs(scope=None, init_config=True):
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:
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
-
- Returns:
- List of compilers found
"""
if path_hints is None:
path_hints = get_path('PATH')
@@ -242,6 +239,30 @@ def find_compilers(path_hints=None):
)
+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():
"""Return a set of names of compilers supported by Spack.
@@ -289,8 +310,9 @@ def all_compilers(scope=None):
@_auto_compiler_spec
-def compilers_for_spec(compiler_spec, arch_spec=None, scope=None,
- use_cache=True, init_config=True):
+def compilers_for_spec(
+ compiler_spec, arch_spec=None, scope=None, use_cache=True, init_config=True
+):
"""This gets all compilers that satisfy the supplied CompilerSpec.
Returns an empty list if none are found.
"""
diff --git a/lib/spack/spack/test/bootstrap.py b/lib/spack/spack/test/bootstrap.py
index bb03df3aae..3aed7231f3 100644
--- a/lib/spack/spack/test/bootstrap.py
+++ b/lib/spack/spack/test/bootstrap.py
@@ -5,6 +5,7 @@
import pytest
import spack.bootstrap
+import spack.compilers
import spack.environment
import spack.store
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 'tcl' 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)
diff --git a/lib/spack/spack/test/cmd/compiler.py b/lib/spack/spack/test/cmd/compiler.py
index 2d554c2474..cb04e9bd27 100644
--- a/lib/spack/spack/test/cmd/compiler.py
+++ b/lib/spack/spack/test/cmd/compiler.py
@@ -17,18 +17,6 @@ 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
def mock_compiler_version():
return '4.5.3'
diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py
index 456624127a..7ef3429383 100644
--- a/lib/spack/spack/test/conftest.py
+++ b/lib/spack/spack/test/conftest.py
@@ -652,6 +652,15 @@ def mutable_empty_config(tmpdir_factory, configuration_dir):
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()
def mock_low_high_config(tmpdir):
"""Mocks two configuration scopes: 'low' and 'high'."""