Allow unit test to work on Apple M1/M2 (#43363)

This commit is contained in:
Massimiliano Culpo 2024-03-26 16:20:42 +01:00 committed by Harmen Stoppels
parent 0c766f2e9b
commit d2096e8fc1
16 changed files with 306 additions and 456 deletions

View file

@ -789,7 +789,7 @@ def setup_package(pkg, dirty, context: Context = Context.BUILD):
for mod in ["cray-mpich", "cray-libsci"]: for mod in ["cray-mpich", "cray-libsci"]:
module("unload", mod) module("unload", mod)
if target.module_name: if target and target.module_name:
load_module(target.module_name) load_module(target.module_name)
load_external_modules(pkg) load_external_modules(pkg)

View file

@ -112,16 +112,16 @@ def _to_dict(compiler):
def get_compiler_config(scope=None, init_config=True): def get_compiler_config(scope=None, init_config=True):
"""Return the compiler configuration for the specified architecture.""" """Return the compiler configuration for the specified architecture."""
config = spack.config.get("compilers", scope=scope) or [] config = spack.config.CONFIG.get("compilers", scope=scope) or []
if config or not init_config: if config or not init_config:
return config return config
merged_config = spack.config.get("compilers") merged_config = spack.config.CONFIG.get("compilers")
if merged_config: if merged_config:
return config return config
_init_compiler_config(scope=scope) _init_compiler_config(scope=scope)
config = spack.config.get("compilers", scope=scope) config = spack.config.CONFIG.get("compilers", scope=scope)
return config return config

View file

@ -8,13 +8,16 @@
import pytest import pytest
import archspec.cpu
import llnl.util.filesystem as fs import llnl.util.filesystem as fs
import spack.compilers
import spack.concretize import spack.concretize
import spack.operating_systems import spack.operating_systems
import spack.platforms import spack.platforms
import spack.target import spack.target
from spack.spec import ArchSpec, CompilerSpec, Spec from spack.spec import ArchSpec, Spec
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
@ -121,52 +124,60 @@ def test_arch_spec_container_semantic(item, architecture_str):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"compiler_spec,target_name,expected_flags", "compiler_spec,target_name,expected_flags",
[ [
# Check compilers with version numbers from a single toolchain # Homogeneous compilers
("gcc@4.7.2", "ivybridge", "-march=core-avx-i -mtune=core-avx-i"), ("gcc@4.7.2", "ivybridge", "-march=core-avx-i -mtune=core-avx-i"),
# Check mixed toolchains
("clang@8.0.0", "broadwell", ""),
("clang@3.5", "x86_64", "-march=x86-64 -mtune=generic"), ("clang@3.5", "x86_64", "-march=x86-64 -mtune=generic"),
# Check Apple's Clang compilers
("apple-clang@9.1.0", "x86_64", "-march=x86-64"), ("apple-clang@9.1.0", "x86_64", "-march=x86-64"),
# Mixed toolchain
("clang@8.0.0", "broadwell", ""),
], ],
) )
@pytest.mark.filterwarnings("ignore:microarchitecture specific") @pytest.mark.filterwarnings("ignore:microarchitecture specific")
def test_optimization_flags(compiler_spec, target_name, expected_flags, config): def test_optimization_flags(compiler_spec, target_name, expected_flags, compiler_factory):
target = spack.target.Target(target_name) target = spack.target.Target(target_name)
compiler = spack.compilers.compilers_for_spec(compiler_spec).pop() compiler_dict = compiler_factory(spec=compiler_spec, operating_system="")["compiler"]
if compiler_spec == "clang@8.0.0":
compiler_dict["paths"] = {
"cc": "/path/to/clang-8",
"cxx": "/path/to/clang++-8",
"f77": "/path/to/gfortran-9",
"fc": "/path/to/gfortran-9",
}
compiler = spack.compilers.compiler_from_dict(compiler_dict)
opt_flags = target.optimization_flags(compiler) opt_flags = target.optimization_flags(compiler)
assert opt_flags == expected_flags assert opt_flags == expected_flags
@pytest.mark.parametrize( @pytest.mark.parametrize(
"compiler,real_version,target_str,expected_flags", "compiler_str,real_version,target_str,expected_flags",
[ [
(CompilerSpec("gcc@=9.2.0"), None, "haswell", "-march=haswell -mtune=haswell"), ("gcc@=9.2.0", None, "haswell", "-march=haswell -mtune=haswell"),
# Check that custom string versions are accepted # Check that custom string versions are accepted
( ("gcc@=10foo", "9.2.0", "icelake", "-march=icelake-client -mtune=icelake-client"),
CompilerSpec("gcc@=10foo"),
"9.2.0",
"icelake",
"-march=icelake-client -mtune=icelake-client",
),
# Check that we run version detection (4.4.0 doesn't support icelake) # Check that we run version detection (4.4.0 doesn't support icelake)
( ("gcc@=4.4.0-special", "9.2.0", "icelake", "-march=icelake-client -mtune=icelake-client"),
CompilerSpec("gcc@=4.4.0-special"),
"9.2.0",
"icelake",
"-march=icelake-client -mtune=icelake-client",
),
# Check that the special case for Apple's clang is treated correctly # Check that the special case for Apple's clang is treated correctly
# i.e. it won't try to detect the version again # i.e. it won't try to detect the version again
(CompilerSpec("apple-clang@=9.1.0"), None, "x86_64", "-march=x86-64"), ("apple-clang@=9.1.0", None, "x86_64", "-march=x86-64"),
], ],
) )
def test_optimization_flags_with_custom_versions( def test_optimization_flags_with_custom_versions(
compiler, real_version, target_str, expected_flags, monkeypatch, config compiler_str,
real_version,
target_str,
expected_flags,
monkeypatch,
mutable_config,
compiler_factory,
): ):
target = spack.target.Target(target_str) target = spack.target.Target(target_str)
compiler_dict = compiler_factory(spec=compiler_str, operating_system="redhat6")
mutable_config.set("compilers", [compiler_dict])
if real_version: if real_version:
monkeypatch.setattr(spack.compiler.Compiler, "get_real_version", lambda x: real_version) monkeypatch.setattr(spack.compiler.Compiler, "get_real_version", lambda x: real_version)
compiler = spack.compilers.compiler_from_dict(compiler_dict["compiler"])
opt_flags = target.optimization_flags(compiler) opt_flags = target.optimization_flags(compiler)
assert opt_flags == expected_flags assert opt_flags == expected_flags
@ -201,9 +212,10 @@ def test_satisfy_strict_constraint_when_not_concrete(architecture_tuple, constra
) )
@pytest.mark.usefixtures("mock_packages", "config") @pytest.mark.usefixtures("mock_packages", "config")
@pytest.mark.only_clingo("Fixing the parser broke this test for the original concretizer.") @pytest.mark.only_clingo("Fixing the parser broke this test for the original concretizer.")
@pytest.mark.skipif(
str(archspec.cpu.host().family) != "x86_64", reason="tests are for x86_64 uarch ranges"
)
def test_concretize_target_ranges(root_target_range, dep_target_range, result, monkeypatch): def test_concretize_target_ranges(root_target_range, dep_target_range, result, monkeypatch):
# Monkeypatch so that all concretization is done as if the machine is core2
monkeypatch.setattr(spack.platforms.test.Test, "default", "core2")
spec = Spec(f"a %gcc@10 foobar=bar target={root_target_range} ^b target={dep_target_range}") spec = Spec(f"a %gcc@10 foobar=bar target={root_target_range} ^b target={dep_target_range}")
with spack.concretize.disable_compiler_existence_check(): with spack.concretize.disable_compiler_existence_check():
spec.concretize() spec.concretize()

View file

@ -19,6 +19,8 @@
import py import py
import pytest import pytest
import archspec.cpu
from llnl.util.filesystem import join_path, visit_directory_tree from llnl.util.filesystem import join_path, visit_directory_tree
import spack.binary_distribution as bindist import spack.binary_distribution as bindist
@ -573,11 +575,20 @@ def test_update_sbang(tmpdir, test_mirror):
uninstall_cmd("-y", "/%s" % new_spec.dag_hash()) uninstall_cmd("-y", "/%s" % new_spec.dag_hash())
def test_install_legacy_buildcache_layout(install_mockery_mutable_config): @pytest.mark.skipif(
str(archspec.cpu.host().family) != "x86_64",
reason="test data uses gcc 4.5.0 which does not support aarch64",
)
def test_install_legacy_buildcache_layout(
mutable_config, compiler_factory, install_mockery_mutable_config
):
"""Legacy buildcache layout involved a nested archive structure """Legacy buildcache layout involved a nested archive structure
where the .spack file contained a repeated spec.json and another where the .spack file contained a repeated spec.json and another
compressed archive file containing the install tree. This test compressed archive file containing the install tree. This test
makes sure we can still read that layout.""" makes sure we can still read that layout."""
mutable_config.set(
"compilers", [compiler_factory(spec="gcc@4.5.0", operating_system="debian6")]
)
legacy_layout_dir = os.path.join(test_path, "data", "mirrors", "legacy_layout") legacy_layout_dir = os.path.join(test_path, "data", "mirrors", "legacy_layout")
mirror_url = "file://{0}".format(legacy_layout_dir) mirror_url = "file://{0}".format(legacy_layout_dir)
filename = ( filename = (

View file

@ -9,6 +9,8 @@
import py.path import py.path
import pytest import pytest
import archspec.cpu
import llnl.util.filesystem as fs import llnl.util.filesystem as fs
import spack.build_systems.autotools import spack.build_systems.autotools
@ -209,6 +211,9 @@ def test_autotools_gnuconfig_replacement_disabled(
assert "gnuconfig version of config.guess" not in f.read() assert "gnuconfig version of config.guess" not in f.read()
@pytest.mark.disable_clean_stage_check @pytest.mark.disable_clean_stage_check
@pytest.mark.skipif(
str(archspec.cpu.host().family) != "x86_64", reason="test data is specific for x86_64"
)
def test_autotools_gnuconfig_replacement_no_gnuconfig(self, mutable_database, monkeypatch): def test_autotools_gnuconfig_replacement_no_gnuconfig(self, mutable_database, monkeypatch):
""" """
Tests whether a useful error message is shown when patch_config_files is Tests whether a useful error message is shown when patch_config_files is

View file

@ -111,10 +111,10 @@ def test_compiler_find_no_apple_gcc(no_compilers_yaml, working_env, mock_executa
@pytest.mark.regression("37996") @pytest.mark.regression("37996")
def test_compiler_remove(mutable_config, mock_packages): def test_compiler_remove(mutable_config, mock_packages):
"""Tests that we can remove a compiler from configuration.""" """Tests that we can remove a compiler from configuration."""
assert spack.spec.CompilerSpec("gcc@=4.5.0") in spack.compilers.all_compiler_specs() assert spack.spec.CompilerSpec("gcc@=4.8.0") in spack.compilers.all_compiler_specs()
args = spack.util.pattern.Bunch(all=True, compiler_spec="gcc@4.5.0", add_paths=[], scope=None) args = spack.util.pattern.Bunch(all=True, compiler_spec="gcc@4.8.0", add_paths=[], scope=None)
spack.cmd.compiler.compiler_remove(args) spack.cmd.compiler.compiler_remove(args)
assert spack.spec.CompilerSpec("gcc@=4.5.0") not in spack.compilers.all_compiler_specs() assert spack.spec.CompilerSpec("gcc@=4.8.0") not in spack.compilers.all_compiler_specs()
@pytest.mark.regression("37996") @pytest.mark.regression("37996")
@ -123,10 +123,10 @@ def test_removing_compilers_from_multiple_scopes(mutable_config, mock_packages):
site_config = spack.config.get("compilers", scope="site") site_config = spack.config.get("compilers", scope="site")
spack.config.set("compilers", site_config, scope="user") spack.config.set("compilers", site_config, scope="user")
assert spack.spec.CompilerSpec("gcc@=4.5.0") in spack.compilers.all_compiler_specs() assert spack.spec.CompilerSpec("gcc@=4.8.0") in spack.compilers.all_compiler_specs()
args = spack.util.pattern.Bunch(all=True, compiler_spec="gcc@4.5.0", add_paths=[], scope=None) args = spack.util.pattern.Bunch(all=True, compiler_spec="gcc@4.8.0", add_paths=[], scope=None)
spack.cmd.compiler.compiler_remove(args) spack.cmd.compiler.compiler_remove(args)
assert spack.spec.CompilerSpec("gcc@=4.5.0") not in spack.compilers.all_compiler_specs() assert spack.spec.CompilerSpec("gcc@=4.8.0") not in spack.compilers.all_compiler_specs()
@pytest.mark.not_on_windows("Cannot execute bash script on Windows") @pytest.mark.not_on_windows("Cannot execute bash script on Windows")

View file

@ -62,10 +62,16 @@ def test_multiple_conflicting_compiler_definitions(mutable_config):
assert cmp.f77 == "f77" assert cmp.f77 == "f77"
def test_get_compiler_duplicates(config): def test_get_compiler_duplicates(mutable_config, compiler_factory):
# In this case there is only one instance of the specified compiler in # In this case there is only one instance of the specified compiler in
# the test configuration (so it is not actually a duplicate), but the # the test configuration (so it is not actually a duplicate), but the
# method behaves the same. # method behaves the same.
cnl_compiler = compiler_factory(spec="gcc@4.5.0", operating_system="CNL")
# CNL compiler has no target attribute, and this is essential to make detection pass
del cnl_compiler["compiler"]["target"]
mutable_config.set(
"compilers", [compiler_factory(spec="gcc@4.5.0", operating_system="SuSE11"), cnl_compiler]
)
cfg_file_to_duplicates = spack.compilers.get_compiler_duplicates( cfg_file_to_duplicates = spack.compilers.get_compiler_duplicates(
"gcc@4.5.0", spack.spec.ArchSpec("cray-CNL-xeon") "gcc@4.5.0", spack.spec.ArchSpec("cray-CNL-xeon")
) )
@ -75,13 +81,6 @@ def test_get_compiler_duplicates(config):
assert len(duplicates) == 1 assert len(duplicates) == 1
def test_all_compilers(config):
all_compilers = spack.compilers.all_compilers()
filtered = [x for x in all_compilers if str(x.spec) == "clang@=3.3"]
filtered = [x for x in filtered if x.operating_system == "SuSE11"]
assert len(filtered) == 1
@pytest.mark.parametrize( @pytest.mark.parametrize(
"input_version,expected_version,expected_error", "input_version,expected_version,expected_error",
[(None, None, "Couldn't get version for compiler /usr/bin/gcc"), ("4.9", "4.9", None)], [(None, None, "Couldn't get version for compiler /usr/bin/gcc"), ("4.9", "4.9", None)],
@ -660,7 +659,25 @@ def test_xl_r_flags():
"compiler_spec,expected_result", "compiler_spec,expected_result",
[("gcc@4.7.2", False), ("clang@3.3", False), ("clang@8.0.0", True)], [("gcc@4.7.2", False), ("clang@3.3", False), ("clang@8.0.0", True)],
) )
def test_detecting_mixed_toolchains(compiler_spec, expected_result, config): def test_detecting_mixed_toolchains(
compiler_spec, expected_result, mutable_config, compiler_factory
):
mixed_c = compiler_factory(spec="clang@8.0.0", operating_system="debian6")
mixed_c["compiler"]["paths"] = {
"cc": "/path/to/clang-8",
"cxx": "/path/to/clang++-8",
"f77": "/path/to/gfortran-9",
"fc": "/path/to/gfortran-9",
}
mutable_config.set(
"compilers",
[
compiler_factory(spec="gcc@4.7.2", operating_system="debian6"),
compiler_factory(spec="clang@3.3", operating_system="debian6"),
mixed_c,
],
)
compiler = spack.compilers.compilers_for_spec(compiler_spec).pop() compiler = spack.compilers.compilers_for_spec(compiler_spec).pop()
assert spack.compilers.is_mixed_toolchain(compiler) is expected_result assert spack.compilers.is_mixed_toolchain(compiler) is expected_result

View file

@ -224,6 +224,20 @@ def change(self, changes=None):
yield _changing_pkg yield _changing_pkg
@pytest.fixture()
def clang12_with_flags(compiler_factory):
c = compiler_factory(spec="clang@12.2.0", operating_system="redhat6")
c["compiler"]["flags"] = {"cflags": "-O3", "cxxflags": "-O3"}
return c
@pytest.fixture()
def gcc11_with_flags(compiler_factory):
c = compiler_factory(spec="gcc@11.1.0", operating_system="redhat6")
c["compiler"]["flags"] = {"cflags": "-O0 -g", "cxxflags": "-O0 -g", "fflags": "-O0 -g"}
return c
# This must use the mutable_config fixture because the test # This must use the mutable_config fixture because the test
# adjusting_default_target_based_on_compiler uses the current_host fixture, # adjusting_default_target_based_on_compiler uses the current_host fixture,
# which changes the config. # which changes the config.
@ -316,18 +330,35 @@ def test_provides_handles_multiple_providers_of_same_version(self):
assert Spec("builtin.mock.multi-provider-mpi@1.10.0") in providers assert Spec("builtin.mock.multi-provider-mpi@1.10.0") in providers
assert Spec("builtin.mock.multi-provider-mpi@1.8.8") in providers assert Spec("builtin.mock.multi-provider-mpi@1.8.8") in providers
def test_different_compilers_get_different_flags(self): def test_different_compilers_get_different_flags(
self, mutable_config, clang12_with_flags, gcc11_with_flags
):
"""Tests that nodes get the flags of the associated compiler."""
mutable_config.set("compilers", [clang12_with_flags, gcc11_with_flags])
client = Spec( client = Spec(
"cmake-client %gcc@11.1.0 platform=test os=fe target=fe" "cmake-client %gcc@11.1.0 platform=test os=fe target=fe"
+ " ^cmake %clang@12.2.0 platform=test os=fe target=fe" " ^cmake %clang@12.2.0 platform=test os=fe target=fe"
) ).concretized()
client.concretize()
cmake = client["cmake"] cmake = client["cmake"]
assert set(client.compiler_flags["cflags"]) == set(["-O0", "-g"]) assert set(client.compiler_flags["cflags"]) == {"-O0", "-g"}
assert set(cmake.compiler_flags["cflags"]) == set(["-O3"]) assert set(cmake.compiler_flags["cflags"]) == {"-O3"}
assert set(client.compiler_flags["fflags"]) == set(["-O0", "-g"]) assert set(client.compiler_flags["fflags"]) == {"-O0", "-g"}
assert not set(cmake.compiler_flags["fflags"]) assert not set(cmake.compiler_flags["fflags"])
@pytest.mark.regression("9908")
def test_spec_flags_maintain_order(self, mutable_config, gcc11_with_flags):
"""Tests that Spack assembles flags in a consistent way (i.e. with the same ordering),
for successive concretizations.
"""
mutable_config.set("compilers", [gcc11_with_flags])
spec_str = "libelf %gcc@11.1.0 os=redhat6"
for _ in range(3):
s = Spec(spec_str).concretized()
assert all(
s.compiler_flags[x] == ["-O0", "-g"] for x in ("cflags", "cxxflags", "fflags")
)
@pytest.mark.xfail(reason="Broken, needs to be fixed")
def test_compiler_flags_from_compiler_and_dependent(self): def test_compiler_flags_from_compiler_and_dependent(self):
client = Spec("cmake-client %clang@12.2.0 platform=test os=fe target=fe cflags==-g") client = Spec("cmake-client %clang@12.2.0 platform=test os=fe target=fe cflags==-g")
client.concretize() client.concretize()
@ -335,7 +366,8 @@ def test_compiler_flags_from_compiler_and_dependent(self):
for spec in [client, cmake]: for spec in [client, cmake]:
assert spec.compiler_flags["cflags"] == ["-O3", "-g"] assert spec.compiler_flags["cflags"] == ["-O3", "-g"]
def test_compiler_flags_differ_identical_compilers(self): def test_compiler_flags_differ_identical_compilers(self, mutable_config, clang12_with_flags):
mutable_config.set("compilers", [clang12_with_flags])
# Correct arch to use test compiler that has flags # Correct arch to use test compiler that has flags
spec = Spec("a %clang@12.2.0 platform=test os=fe target=fe") spec = Spec("a %clang@12.2.0 platform=test os=fe target=fe")
@ -390,22 +422,17 @@ def test_compiler_inherited_upwards(self):
for dep in spec.traverse(): for dep in spec.traverse():
assert "%clang" in dep assert "%clang" in dep
def test_architecture_inheritance(self):
"""test_architecture_inheritance is likely to fail with an
UnavailableCompilerVersionError if the architecture is concretized
incorrectly.
"""
spec = Spec("cmake-client %gcc@11.1.0 os=fe ^ cmake")
spec.concretize()
assert spec["cmake"].architecture == spec.architecture
@pytest.mark.only_clingo("Fixing the parser broke this test for the original concretizer") @pytest.mark.only_clingo("Fixing the parser broke this test for the original concretizer")
def test_architecture_deep_inheritance(self, mock_targets): def test_architecture_deep_inheritance(self, mock_targets, compiler_factory):
"""Make sure that indirect dependencies receive architecture """Make sure that indirect dependencies receive architecture
information from the root even when partial architecture information information from the root even when partial architecture information
is provided by an intermediate dependency. is provided by an intermediate dependency.
""" """
spec_str = "mpileaks %gcc@4.5.0 os=CNL target=nocona" " ^dyninst os=CNL ^callpath os=CNL" cnl_compiler = compiler_factory(spec="gcc@4.5.0", operating_system="CNL")
# CNL compiler has no target attribute, and this is essential to make detection pass
del cnl_compiler["compiler"]["target"]
with spack.config.override("compilers", [cnl_compiler]):
spec_str = "mpileaks %gcc@4.5.0 os=CNL target=nocona ^dyninst os=CNL ^callpath os=CNL"
spec = Spec(spec_str).concretized() spec = Spec(spec_str).concretized()
for s in spec.traverse(root=False): for s in spec.traverse(root=False):
assert s.architecture.target == spec.architecture.target assert s.architecture.target == spec.architecture.target
@ -843,7 +870,10 @@ def test_concretize_anonymous_dep(self, spec_str):
], ],
) )
@pytest.mark.only_clingo("Original concretizer cannot work around conflicts") @pytest.mark.only_clingo("Original concretizer cannot work around conflicts")
def test_compiler_conflicts_in_package_py(self, spec_str, expected_str): def test_compiler_conflicts_in_package_py(
self, spec_str, expected_str, clang12_with_flags, gcc11_with_flags
):
with spack.config.override("compilers", [clang12_with_flags, gcc11_with_flags]):
s = Spec(spec_str).concretized() s = Spec(spec_str).concretized()
assert s.satisfies(expected_str) assert s.satisfies(expected_str)
@ -1135,14 +1165,16 @@ def test_activating_test_dependencies(self, spec_str, tests_arg, with_dep, witho
@pytest.mark.regression("20019") @pytest.mark.regression("20019")
@pytest.mark.only_clingo("Use case not supported by the original concretizer") @pytest.mark.only_clingo("Use case not supported by the original concretizer")
def test_compiler_match_is_preferred_to_newer_version(self): def test_compiler_match_is_preferred_to_newer_version(self, compiler_factory):
# This spec depends on openblas. Openblas has a conflict # This spec depends on openblas. Openblas has a conflict
# that doesn't allow newer versions with gcc@4.4.0. Check # that doesn't allow newer versions with gcc@4.4.0. Check
# that an old version of openblas is selected, rather than # that an old version of openblas is selected, rather than
# a different compiler for just that node. # a different compiler for just that node.
with spack.config.override(
"compilers", [compiler_factory(spec="gcc@10.1.0", operating_system="redhat6")]
):
spec_str = "simple-inheritance+openblas %gcc@10.1.0 os=redhat6" spec_str = "simple-inheritance+openblas %gcc@10.1.0 os=redhat6"
s = Spec(spec_str).concretized() s = Spec(spec_str).concretized()
assert "openblas@0.2.15" in s assert "openblas@0.2.15" in s
assert s["openblas"].satisfies("%gcc@10.1.0") assert s["openblas"].satisfies("%gcc@10.1.0")
@ -1169,7 +1201,10 @@ def test_variant_not_default(self):
@pytest.mark.regression("20055") @pytest.mark.regression("20055")
@pytest.mark.only_clingo("Use case not supported by the original concretizer") @pytest.mark.only_clingo("Use case not supported by the original concretizer")
def test_custom_compiler_version(self): def test_custom_compiler_version(self, mutable_config, compiler_factory):
mutable_config.set(
"compilers", [compiler_factory(spec="gcc@10foo", operating_system="redhat6")]
)
s = Spec("a %gcc@10foo os=redhat6").concretized() s = Spec("a %gcc@10foo os=redhat6").concretized()
assert "%gcc@10foo" in s assert "%gcc@10foo" in s
@ -1369,9 +1404,14 @@ def test_external_with_non_default_variant_as_dependency(self):
("mpileaks%gcc@10.2.1 platform=test os=redhat6", "os=redhat6"), ("mpileaks%gcc@10.2.1 platform=test os=redhat6", "os=redhat6"),
], ],
) )
def test_os_selection_when_multiple_choices_are_possible(self, spec_str, expected_os): def test_os_selection_when_multiple_choices_are_possible(
self, spec_str, expected_os, compiler_factory
):
# GCC 10.2.1 is defined both for debian and for redhat
with spack.config.override(
"compilers", [compiler_factory(spec="gcc@10.2.1", operating_system="redhat6")]
):
s = Spec(spec_str).concretized() s = Spec(spec_str).concretized()
for node in s.traverse(): for node in s.traverse():
assert node.satisfies(expected_os) assert node.satisfies(expected_os)

View file

@ -105,7 +105,7 @@ def test_preferred_variants_from_wildcard(self):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"compiler_str,spec_str", "compiler_str,spec_str",
[("gcc@=4.5.0", "mpileaks"), ("clang@=12.0.0", "mpileaks"), ("gcc@=4.5.0", "openmpi")], [("gcc@=4.8.0", "mpileaks"), ("clang@=12.0.0", "mpileaks"), ("gcc@=4.8.0", "openmpi")],
) )
def test_preferred_compilers(self, compiler_str, spec_str): def test_preferred_compilers(self, compiler_str, spec_str):
"""Test preferred compilers are applied correctly""" """Test preferred compilers are applied correctly"""

View file

@ -21,6 +21,7 @@
import py import py
import pytest import pytest
import archspec.cpu
import archspec.cpu.microarchitecture import archspec.cpu.microarchitecture
import archspec.cpu.schema import archspec.cpu.schema
@ -708,7 +709,9 @@ def configuration_dir(tmpdir_factory, linux_os):
t.write(content) t.write(content)
compilers_yaml = test_config.join("compilers.yaml") compilers_yaml = test_config.join("compilers.yaml")
content = "".join(compilers_yaml.read()).format(linux_os) content = "".join(compilers_yaml.read()).format(
linux_os=linux_os, target=str(archspec.cpu.host().family)
)
t = tmpdir.join("site", "compilers.yaml") t = tmpdir.join("site", "compilers.yaml")
t.write(content) t.write(content)
yield tmpdir yield tmpdir
@ -1952,3 +1955,48 @@ def pytest_runtest_setup(item):
def disable_parallel_buildcache_push(monkeypatch): def disable_parallel_buildcache_push(monkeypatch):
"""Disable process pools in tests.""" """Disable process pools in tests."""
monkeypatch.setattr(spack.cmd.buildcache, "_make_pool", spack.cmd.buildcache.NoPool) monkeypatch.setattr(spack.cmd.buildcache, "_make_pool", spack.cmd.buildcache.NoPool)
def create_test_repo(tmpdir, pkg_name_content_tuples):
repo_path = str(tmpdir)
repo_yaml = tmpdir.join("repo.yaml")
with open(str(repo_yaml), "w") as f:
f.write(
"""\
repo:
namespace: testcfgrequirements
"""
)
packages_dir = tmpdir.join("packages")
for pkg_name, pkg_str in pkg_name_content_tuples:
pkg_dir = packages_dir.ensure(pkg_name, dir=True)
pkg_file = pkg_dir.join("package.py")
with open(str(pkg_file), "w") as f:
f.write(pkg_str)
return spack.repo.Repo(repo_path)
@pytest.fixture()
def compiler_factory():
"""Factory for a compiler dict, taking a spec and an OS as arguments."""
def _factory(*, spec, operating_system):
return {
"compiler": {
"spec": spec,
"operating_system": operating_system,
"paths": {"cc": "/path/to/cc", "cxx": "/path/to/cxx", "f77": None, "fc": None},
"modules": [],
"target": str(archspec.cpu.host().family),
}
}
return _factory
@pytest.fixture()
def host_architecture_str():
"""Returns the broad architecture family (x86_64, aarch64, etc.)"""
return str(archspec.cpu.host().family)

View file

@ -1,353 +1,41 @@
compilers: compilers:
- compiler: - compiler:
spec: clang@3.3 spec: gcc@=4.8.0
operating_system: {0.name}{0.version} operating_system: {linux_os.name}{linux_os.version}
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: []
target: {target}
- compiler:
spec: gcc@=4.8.0
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: []
target: {target}
- compiler:
spec: clang@=12.0.0
operating_system: {linux_os.name}{linux_os.version}
paths: paths:
cc: /path/to/clang cc: /path/to/clang
cxx: /path/to/clang++ cxx: /path/to/clang++
f77: None f77: None
fc: None fc: None
modules: 'None' modules: []
target: x86_64 target: {target}
- compiler: - compiler:
spec: gcc@4.5.0 spec: gcc@=10.2.1
operating_system: {0.name}{0.version} operating_system: {linux_os.name}{linux_os.version}
paths: paths:
cc: /path/to/gcc cc: /path/to/gcc
cxx: /path/to/g++ cxx: /path/to/g++
f77: None f77: None
fc: None fc: None
modules: 'None' modules: []
target: x86_64 target: {target}
- compiler:
spec: gcc@4.5.0
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: clang@3.3
operating_system: CNL
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
- compiler:
spec: clang@3.3
operating_system: SuSE11
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: clang@3.3
operating_system: yosemite
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: /path/to/gfortran
fc: /path/to/gfortran
operating_system: CNL
spec: gcc@4.5.0
modules: 'None'
- compiler:
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: /path/to/gfortran
fc: /path/to/gfortran
operating_system: SuSE11
spec: gcc@4.5.0
modules: 'None'
target: x86_64
- compiler:
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: /path/to/gfortran
fc: /path/to/gfortran
operating_system: yosemite
spec: gcc@4.5.0
modules: 'None'
target: x86_64
- compiler:
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: /path/to/gfortran
fc: /path/to/gfortran
operating_system: elcapitan
spec: gcc@4.5.0
modules: 'None'
target: x86_64
- compiler:
spec: clang@3.3
operating_system: elcapitan
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: gcc@4.7.2
operating_system: redhat6
paths:
cc: /path/to/gcc472
cxx: /path/to/g++472
f77: /path/to/gfortran472
fc: /path/to/gfortran472
flags:
cflags: -O0 -g
cxxflags: -O0 -g
fflags: -O0 -g
modules: 'None'
target: x86_64
- compiler:
spec: gcc@4.4.0
operating_system: redhat6
paths:
cc: /path/to/gcc440
cxx: /path/to/g++440
f77: /path/to/gfortran440
fc: /path/to/gfortran440
modules: 'None'
target: x86_64
- compiler:
spec: clang@3.5
operating_system: redhat6
paths:
cc: /path/to/clang35
cxx: /path/to/clang++35
f77: None
fc: None
flags:
cflags: -O3
cxxflags: -O3
modules: 'None'
target: x86_64
- compiler:
spec: clang@8.0.0
operating_system: redhat7
paths:
cc: /path/to/clang-8
cxx: /path/to/clang++-8
f77: /path/to/gfortran-9
fc: /path/to/gfortran-9
flags:
cflags: -O3
cxxflags: -O3
modules: 'None'
target: x86_64
- compiler:
spec: apple-clang@9.1.0
operating_system: elcapitan
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: gcc@10foo
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: /path/to/gfortran
fc: /path/to/gfortran
modules: 'None'
target: x86_64
- compiler:
spec: gcc@4.4.0-special
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: /path/to/gfortran
fc: /path/to/gfortran
modules: 'None'
target: x86_64
- compiler:
spec: clang@12.0.0
operating_system: {0.name}{0.version}
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
target: aarch64
- compiler:
spec: gcc@10.2.1
operating_system: {0.name}{0.version}
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: 'None'
target: aarch64
- compiler:
spec: clang@12.0.0
operating_system: redhat6
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
target: aarch64
- compiler:
spec: gcc@10.2.1
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: 'None'
target: aarch64
- compiler:
spec: gcc@10.1.0
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: 'None'
target: aarch64
- compiler:
spec: gcc@11.1.0
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
flags:
cflags: -O0 -g
cxxflags: -O0 -g
fflags: -O0 -g
modules: 'None'
target: aarch64
- compiler:
spec: clang@12.2.0
operating_system: redhat6
paths:
cc: /path/to/clang35
cxx: /path/to/clang++35
f77: None
fc: None
flags:
cflags: -O3
cxxflags: -O3
modules: 'None'
target: aarch64
- compiler:
spec: gcc@10foo
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: /path/to/gfortran
fc: /path/to/gfortran
modules: 'None'
target: aarch64
- compiler:
spec: clang@12.0.0
operating_system: {0.name}{0.version}
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: gcc@10.2.1
operating_system: {0.name}{0.version}
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: clang@12.0.0
operating_system: redhat6
paths:
cc: /path/to/clang
cxx: /path/to/clang++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: gcc@10.2.1
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: gcc@10.1.0
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
modules: 'None'
target: x86_64
- compiler:
spec: gcc@11.1.0
operating_system: redhat6
paths:
cc: /path/to/gcc
cxx: /path/to/g++
f77: None
fc: None
flags:
cflags: -O0 -g
cxxflags: -O0 -g
fflags: -O0 -g
modules: 'None'
target: x86_64
- compiler:
spec: clang@12.2.0
operating_system: redhat6
paths:
cc: /path/to/clang35
cxx: /path/to/clang++35
f77: None
fc: None
flags:
cflags: -O3
cxxflags: -O3
modules: 'None'
target: x86_64

View file

@ -11,6 +11,8 @@
import py import py
import pytest import pytest
import archspec.cpu
import llnl.util.filesystem as fs import llnl.util.filesystem as fs
import llnl.util.lock as ulk import llnl.util.lock as ulk
import llnl.util.tty as tty import llnl.util.tty as tty
@ -528,6 +530,10 @@ def fake_package_list(compiler, architecture, pkgs):
assert installer.build_pq[0][1].compiler assert installer.build_pq[0][1].compiler
@pytest.mark.skipif(
str(archspec.cpu.host().family) != "x86_64",
reason="OneAPI compiler is not supported on other architectures",
)
def test_bootstrapping_compilers_with_different_names_from_spec( def test_bootstrapping_compilers_with_different_names_from_spec(
install_mockery, mutable_config, mock_fetch, archspec_host_is_spack_test_host install_mockery, mutable_config, mock_fetch, archspec_host_is_spack_test_host
): ):

View file

@ -7,6 +7,8 @@
import pytest import pytest
import archspec.cpu
import spack.environment as ev import spack.environment as ev
import spack.main import spack.main
import spack.modules.lmod import spack.modules.lmod
@ -100,7 +102,12 @@ def test_file_layout(self, compiler, provider, factory, module_configuration):
else: else:
assert repetitions == 1 assert repetitions == 1
def test_compilers_provided_different_name(self, factory, module_configuration): def test_compilers_provided_different_name(
self, factory, module_configuration, compiler_factory
):
with spack.config.override(
"compilers", [compiler_factory(spec="clang@3.3", operating_system="debian6")]
):
module_configuration("complex_hierarchy") module_configuration("complex_hierarchy")
module, spec = factory("intel-oneapi-compilers%clang@3.3") module, spec = factory("intel-oneapi-compilers%clang@3.3")
@ -136,6 +143,9 @@ def test_autoload_all(self, modulefile_content, module_configuration):
assert len([x for x in content if "depends_on(" in x]) == 5 assert len([x for x in content if "depends_on(" in x]) == 5
@pytest.mark.skipif(
str(archspec.cpu.host().family) != "x86_64", reason="test data is specific for x86_64"
)
def test_alter_environment(self, modulefile_content, module_configuration): def test_alter_environment(self, modulefile_content, module_configuration):
"""Tests modifications to run-time environment.""" """Tests modifications to run-time environment."""
@ -207,6 +217,9 @@ def test_setenv_raw_value(self, modulefile_content, module_configuration):
assert len([x for x in content if 'setenv("FOO", "{{name}}, {name}, {{}}, {}")' in x]) == 1 assert len([x for x in content if 'setenv("FOO", "{{name}}, {name}, {{}}, {}")' in x]) == 1
@pytest.mark.skipif(
str(archspec.cpu.host().family) != "x86_64", reason="test data is specific for x86_64"
)
def test_help_message(self, modulefile_content, module_configuration): def test_help_message(self, modulefile_content, module_configuration):
"""Tests the generation of module help message.""" """Tests the generation of module help message."""
@ -330,14 +343,16 @@ def test_override_template_in_package(self, modulefile_content, module_configura
assert "Override successful!" in content assert "Override successful!" in content
def test_override_template_in_modules_yaml(self, modulefile_content, module_configuration): def test_override_template_in_modules_yaml(
self, modulefile_content, module_configuration, host_architecture_str
):
"""Tests overriding a template from `modules.yaml`""" """Tests overriding a template from `modules.yaml`"""
module_configuration("override_template") module_configuration("override_template")
content = modulefile_content("override-module-templates") content = modulefile_content("override-module-templates")
assert "Override even better!" in content assert "Override even better!" in content
content = modulefile_content("mpileaks target=x86_64") content = modulefile_content(f"mpileaks target={host_architecture_str}")
assert "Override even better!" in content assert "Override even better!" in content
@pytest.mark.usefixtures("config") @pytest.mark.usefixtures("config")

View file

@ -7,6 +7,8 @@
import pytest import pytest
import archspec.cpu
import spack.modules.common import spack.modules.common
import spack.modules.tcl import spack.modules.tcl
import spack.spec import spack.spec
@ -89,22 +91,29 @@ def test_autoload_all(self, modulefile_content, module_configuration):
assert len([x for x in content if "depends-on " in x]) == 2 assert len([x for x in content if "depends-on " in x]) == 2
assert len([x for x in content if "module load " in x]) == 2 assert len([x for x in content if "module load " in x]) == 2
def test_prerequisites_direct(self, modulefile_content, module_configuration): def test_prerequisites_direct(
self, modulefile_content, module_configuration, host_architecture_str
):
"""Tests asking direct dependencies as prerequisites.""" """Tests asking direct dependencies as prerequisites."""
module_configuration("prerequisites_direct") module_configuration("prerequisites_direct")
content = modulefile_content("mpileaks target=x86_64") content = modulefile_content(f"mpileaks target={host_architecture_str}")
assert len([x for x in content if "prereq" in x]) == 2 assert len([x for x in content if "prereq" in x]) == 2
def test_prerequisites_all(self, modulefile_content, module_configuration): def test_prerequisites_all(
self, modulefile_content, module_configuration, host_architecture_str
):
"""Tests asking all dependencies as prerequisites.""" """Tests asking all dependencies as prerequisites."""
module_configuration("prerequisites_all") module_configuration("prerequisites_all")
content = modulefile_content("mpileaks target=x86_64") content = modulefile_content(f"mpileaks target={host_architecture_str}")
assert len([x for x in content if "prereq" in x]) == 5 assert len([x for x in content if "prereq" in x]) == 5
@pytest.mark.skipif(
str(archspec.cpu.host().family) != "x86_64", reason="test data is specific for x86_64"
)
def test_alter_environment(self, modulefile_content, module_configuration): def test_alter_environment(self, modulefile_content, module_configuration):
"""Tests modifications to run-time environment.""" """Tests modifications to run-time environment."""
@ -177,6 +186,9 @@ def test_setenv_raw_value(self, modulefile_content, module_configuration):
assert len([x for x in content if "setenv FOO {{{name}}, {name}, {{}}, {}}" in x]) == 1 assert len([x for x in content if "setenv FOO {{{name}}, {name}, {{}}, {}}" in x]) == 1
@pytest.mark.skipif(
str(archspec.cpu.host().family) != "x86_64", reason="test data is specific for x86_64"
)
def test_help_message(self, modulefile_content, module_configuration): def test_help_message(self, modulefile_content, module_configuration):
"""Tests the generation of module help message.""" """Tests the generation of module help message."""
@ -219,7 +231,7 @@ def test_help_message(self, modulefile_content, module_configuration):
) )
assert help_msg in "".join(content) assert help_msg in "".join(content)
def test_exclude(self, modulefile_content, module_configuration): def test_exclude(self, modulefile_content, module_configuration, host_architecture_str):
"""Tests excluding the generation of selected modules.""" """Tests excluding the generation of selected modules."""
module_configuration("exclude") module_configuration("exclude")
@ -231,9 +243,9 @@ def test_exclude(self, modulefile_content, module_configuration):
# and IOError on Python 2 or common bases like EnvironmentError # and IOError on Python 2 or common bases like EnvironmentError
# which are not officially documented # which are not officially documented
with pytest.raises(Exception): with pytest.raises(Exception):
modulefile_content("callpath target=x86_64") modulefile_content(f"callpath target={host_architecture_str}")
content = modulefile_content("zmpi target=x86_64") content = modulefile_content(f"zmpi target={host_architecture_str}")
assert len([x for x in content if "module load " in x]) == 1 assert len([x for x in content if "module load " in x]) == 1
@ -403,14 +415,16 @@ def test_override_template_in_package(self, modulefile_content, module_configura
assert "Override successful!" in content assert "Override successful!" in content
def test_override_template_in_modules_yaml(self, modulefile_content, module_configuration): def test_override_template_in_modules_yaml(
self, modulefile_content, module_configuration, host_architecture_str
):
"""Tests overriding a template from `modules.yaml`""" """Tests overriding a template from `modules.yaml`"""
module_configuration("override_template") module_configuration("override_template")
content = modulefile_content("override-module-templates") content = modulefile_content("override-module-templates")
assert "Override even better!" in content assert "Override even better!" in content
content = modulefile_content("mpileaks target=x86_64") content = modulefile_content(f"mpileaks target={host_architecture_str}")
assert "Override even better!" in content assert "Override even better!" in content
def test_extend_context(self, modulefile_content, module_configuration): def test_extend_context(self, modulefile_content, module_configuration):

View file

@ -69,9 +69,15 @@ def test_no_version_match(pkg_name):
("", "boolean_false_first", "True"), ("", "boolean_false_first", "True"),
], ],
) )
def test_multimethod_calls(pkg_name, constraint_str, method_name, expected_result): def test_multimethod_calls(
pkg_name, constraint_str, method_name, expected_result, compiler_factory
):
# Add apple-clang, as it is required by one of the tests
with spack.config.override(
"compilers", [compiler_factory(spec="apple-clang@9.1.0", operating_system="elcapitan")]
):
s = spack.spec.Spec(pkg_name + constraint_str).concretized() s = spack.spec.Spec(pkg_name + constraint_str).concretized()
msg = "Method {0} from {1} is giving a wrong result".format(method_name, s) msg = f"Method {method_name} from {s} is giving a wrong result"
assert getattr(s.package, method_name)() == expected_result, msg assert getattr(s.package, method_name)() == expected_result, msg

View file

@ -734,18 +734,6 @@ def test_spec_formatting_escapes(self, default_mock_concretization):
with pytest.raises(SpecFormatStringError): with pytest.raises(SpecFormatStringError):
spec.format(fmt_str) spec.format(fmt_str)
@pytest.mark.regression("9908")
def test_spec_flags_maintain_order(self):
# Spack was assembling flags in a manner that could result in
# different orderings for repeated concretizations of the same
# spec and config
spec_str = "libelf %gcc@11.1.0 os=redhat6"
for _ in range(3):
s = Spec(spec_str).concretized()
assert all(
s.compiler_flags[x] == ["-O0", "-g"] for x in ("cflags", "cxxflags", "fflags")
)
def test_combination_of_wildcard_or_none(self): def test_combination_of_wildcard_or_none(self):
# Test that using 'none' and another value raises # Test that using 'none' and another value raises
with pytest.raises(spack.variant.InvalidVariantValueCombinationError): with pytest.raises(spack.variant.InvalidVariantValueCombinationError):