252 lines
7.4 KiB
Python
252 lines
7.4 KiB
Python
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
|
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
|
#
|
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
import pathlib
|
|
|
|
import pytest
|
|
|
|
import spack.config
|
|
import spack.environment as ev
|
|
import spack.repo
|
|
import spack.util.spack_yaml as syaml
|
|
from spack.spec import Spec
|
|
|
|
"""
|
|
These tests include the following package DAGs:
|
|
|
|
Firstly, w, x, y where w and x apply cflags to y.
|
|
|
|
w
|
|
|\
|
|
x |
|
|
|/
|
|
y
|
|
|
|
Secondly, v, y which where v does not apply cflags to y - this is for testing
|
|
mixing with compiler flag propagation in the absence of compiler flags applied
|
|
by dependents.
|
|
|
|
v
|
|
|
|
|
y
|
|
|
|
Finally, a diamond dag to check that the topological order is resolved into
|
|
a total order:
|
|
|
|
t
|
|
|\
|
|
u x
|
|
|/
|
|
y
|
|
"""
|
|
|
|
|
|
@pytest.fixture
|
|
def test_repo(mutable_config, monkeypatch, mock_stage):
|
|
repo_dir = pathlib.Path(spack.paths.repos_path) / "flags.test"
|
|
with spack.repo.use_repositories(str(repo_dir)) as mock_repo_path:
|
|
yield mock_repo_path
|
|
|
|
|
|
def update_concretize_scope(conf_str, section):
|
|
conf = syaml.load_config(conf_str)
|
|
spack.config.set(section, conf[section], scope="concretize")
|
|
|
|
|
|
def test_mix_spec_and_requirements(concretize_scope, test_repo):
|
|
conf_str = """\
|
|
packages:
|
|
y:
|
|
require: cflags="-c"
|
|
"""
|
|
update_concretize_scope(conf_str, "packages")
|
|
|
|
s1 = Spec('y cflags="-a"').concretized()
|
|
assert s1.satisfies('cflags="-a -c"')
|
|
|
|
|
|
def test_mix_spec_and_dependent(concretize_scope, test_repo):
|
|
s1 = Spec('x ^y cflags="-a"').concretized()
|
|
assert s1["y"].satisfies('cflags="-a -d1"')
|
|
|
|
|
|
def _compiler_cfg_one_entry_with_cflags(cflags):
|
|
return f"""\
|
|
compilers::
|
|
- compiler:
|
|
spec: gcc@12.100.100
|
|
paths:
|
|
cc: /usr/bin/fake-gcc
|
|
cxx: /usr/bin/fake-g++
|
|
f77: null
|
|
fc: null
|
|
flags:
|
|
cflags: {cflags}
|
|
operating_system: debian6
|
|
modules: []
|
|
"""
|
|
|
|
|
|
def test_mix_spec_and_compiler_cfg(concretize_scope, test_repo):
|
|
conf_str = _compiler_cfg_one_entry_with_cflags("-Wall")
|
|
update_concretize_scope(conf_str, "compilers")
|
|
|
|
s1 = Spec('y %gcc@12.100.100 cflags="-O2"').concretized()
|
|
assert s1.satisfies('cflags="-Wall -O2"')
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"cmd_flags,req_flags,cmp_flags,dflags,expected_order",
|
|
[
|
|
("-a -b", "-c", None, False, "-c -a -b"),
|
|
("-x7 -x4", "-x5 -x6", None, False, "-x5 -x6 -x7 -x4"),
|
|
("-x7 -x4", "-x5 -x6", "-x3 -x8", False, "-x3 -x8 -x5 -x6 -x7 -x4"),
|
|
("-x7 -x4", "-x5 -x6", "-x3 -x8", True, "-x3 -x8 -d1 -d2 -x5 -x6 -x7 -x4"),
|
|
("-x7 -x4", None, "-x3 -x8", False, "-x3 -x8 -x7 -x4"),
|
|
("-x7 -x4", None, "-x3 -x8", True, "-x3 -x8 -d1 -d2 -x7 -x4"),
|
|
# The remaining test cover cases of intersection
|
|
("-a -b", "-a -c", None, False, "-c -a -b"),
|
|
("-a -b", None, "-a -c", False, "-c -a -b"),
|
|
("-a -b", "-a -c", "-a -d", False, "-d -c -a -b"),
|
|
("-a -d2 -d1", "-d2 -c", "-d1 -b", True, "-b -c -a -d2 -d1"),
|
|
("-a", "-d0 -d2 -c", "-d1 -b", True, "-b -d1 -d0 -d2 -c -a"),
|
|
],
|
|
)
|
|
def test_flag_order_and_grouping(
|
|
concretize_scope, test_repo, cmd_flags, req_flags, cmp_flags, dflags, expected_order
|
|
):
|
|
"""Check consistent flag ordering and grouping on a package "y"
|
|
with flags introduced from a variety of sources.
|
|
|
|
The ordering rules are explained in ``asp.SpecBuilder.reorder_flags``.
|
|
"""
|
|
if req_flags:
|
|
conf_str = f"""\
|
|
packages:
|
|
y:
|
|
require: cflags="{req_flags}"
|
|
"""
|
|
update_concretize_scope(conf_str, "packages")
|
|
|
|
if cmp_flags:
|
|
conf_str = _compiler_cfg_one_entry_with_cflags(cmp_flags)
|
|
update_concretize_scope(conf_str, "compilers")
|
|
|
|
compiler_spec = ""
|
|
if cmp_flags:
|
|
compiler_spec = "%gcc@12.100.100"
|
|
|
|
if dflags:
|
|
spec_str = f"x+activatemultiflag {compiler_spec} ^y"
|
|
expected_dflags = "-d1 -d2"
|
|
else:
|
|
spec_str = f"y {compiler_spec}"
|
|
expected_dflags = None
|
|
|
|
if cmd_flags:
|
|
spec_str += f' cflags="{cmd_flags}"'
|
|
|
|
root_spec = Spec(spec_str).concretized()
|
|
spec = root_spec["y"]
|
|
satisfy_flags = " ".join(x for x in [cmd_flags, req_flags, cmp_flags, expected_dflags] if x)
|
|
assert spec.satisfies(f'cflags="{satisfy_flags}"')
|
|
assert spec.compiler_flags["cflags"] == expected_order.split()
|
|
|
|
|
|
def test_two_dependents_flag_mixing(concretize_scope, test_repo):
|
|
root_spec1 = Spec("w~moveflaglater").concretized()
|
|
spec1 = root_spec1["y"]
|
|
assert spec1.compiler_flags["cflags"] == "-d0 -d1 -d2".split()
|
|
|
|
root_spec2 = Spec("w+moveflaglater").concretized()
|
|
spec2 = root_spec2["y"]
|
|
assert spec2.compiler_flags["cflags"] == "-d3 -d1 -d2".split()
|
|
|
|
|
|
def test_propagate_and_compiler_cfg(concretize_scope, test_repo):
|
|
conf_str = _compiler_cfg_one_entry_with_cflags("-f2")
|
|
update_concretize_scope(conf_str, "compilers")
|
|
|
|
root_spec = Spec("v %gcc@12.100.100 cflags=='-f1'").concretized()
|
|
assert root_spec["y"].satisfies("cflags='-f1 -f2'")
|
|
|
|
|
|
# Note: setting flags on a dependency overrides propagation, which
|
|
# is tested in test/concretize.py:test_compiler_flag_propagation
|
|
|
|
|
|
def test_propagate_and_pkg_dep(concretize_scope, test_repo):
|
|
root_spec1 = Spec("x ~activatemultiflag cflags=='-f1'").concretized()
|
|
assert root_spec1["y"].satisfies("cflags='-f1 -d1'")
|
|
|
|
|
|
def test_propagate_and_require(concretize_scope, test_repo):
|
|
conf_str = """\
|
|
packages:
|
|
y:
|
|
require: cflags="-f2"
|
|
"""
|
|
update_concretize_scope(conf_str, "packages")
|
|
|
|
root_spec1 = Spec("v cflags=='-f1'").concretized()
|
|
assert root_spec1["y"].satisfies("cflags='-f1 -f2'")
|
|
|
|
# Next, check that a requirement does not "undo" a request for
|
|
# propagation from the command-line spec
|
|
conf_str = """\
|
|
packages:
|
|
v:
|
|
require: cflags="-f1"
|
|
"""
|
|
update_concretize_scope(conf_str, "packages")
|
|
|
|
root_spec2 = Spec("v cflags=='-f1'").concretized()
|
|
assert root_spec2["y"].satisfies("cflags='-f1'")
|
|
|
|
# Note: requirements cannot enforce propagation: any attempt to do
|
|
# so will generate a concretization error; this likely relates to
|
|
# the note about #37180 in concretize.lp
|
|
|
|
|
|
def test_dev_mix_flags(tmp_path, concretize_scope, mutable_mock_env_path, test_repo):
|
|
src_dir = tmp_path / "x-src"
|
|
|
|
env_content = f"""\
|
|
spack:
|
|
specs:
|
|
- y %gcc@12.100.100 cflags=='-fsanitize=address'
|
|
develop:
|
|
y:
|
|
spec: y cflags=='-fsanitize=address'
|
|
path: {src_dir}
|
|
"""
|
|
|
|
conf_str = _compiler_cfg_one_entry_with_cflags("-f1")
|
|
update_concretize_scope(conf_str, "compilers")
|
|
|
|
manifest_file = tmp_path / ev.manifest_name
|
|
manifest_file.write_text(env_content)
|
|
e = ev.create("test", manifest_file)
|
|
with e:
|
|
e.concretize()
|
|
e.write()
|
|
|
|
(result,) = list(j for i, j in e.concretized_specs() if j.name == "y")
|
|
|
|
assert result["y"].satisfies("cflags='-fsanitize=address -f1'")
|
|
|
|
|
|
def test_diamond_dep_flag_mixing(concretize_scope, test_repo):
|
|
"""A diamond where each dependent applies flags to the bottom
|
|
dependency. The goal is to ensure that the flag ordering is
|
|
(a) topological and (b) repeatable for elements not subject to
|
|
this partial ordering (i.e. the flags for the left and right
|
|
nodes of the diamond always appear in the same order).
|
|
`Spec.traverse` is responsible for handling both of these needs.
|
|
"""
|
|
root_spec1 = Spec("t").concretized()
|
|
spec1 = root_spec1["y"]
|
|
assert spec1.satisfies('cflags="-c1 -c2 -d1 -d2 -e1 -e2"')
|
|
assert spec1.compiler_flags["cflags"] == "-c1 -c2 -e1 -e2 -d1 -d2".split()
|