Propagate architecture information during concretization (#7412)

This updates architecture concretization to

* Search for the nearest parent in the DAG for architecture information
  rather than defaulting to the root of the DAG
* Propagate architecture settings transitively, such that if for
  example the target is set at the root of the dag it will set the
  same target on indirect dependencies (assuming no intermediate
  dependency specifies a separate target). Previously this occurred
  in general but under some conditions did not, for example if an
  intermediate dependency specified some subset of architecture
  properties.
This commit is contained in:
becker33 2018-03-21 18:14:01 -07:00 committed by scheibelp
parent 726c7e0f06
commit f8657e3fd9
2 changed files with 57 additions and 17 deletions

View file

@ -222,27 +222,29 @@ def concretize_architecture(self, spec):
DAG has an architecture, then use the root otherwise use the defaults DAG has an architecture, then use the root otherwise use the defaults
on the platform. on the platform.
""" """
root_arch = spec.root.architecture try:
sys_arch = spack.spec.ArchSpec(spack.architecture.sys_type()) # Get the nearest architecture with any fields set
nearest = next(p for p in spec.traverse(direction='parents')
if (p.architecture and p is not spec))
nearest_arch = nearest.architecture
except StopIteration:
# Default to the system architecture if nothing set
nearest_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
spec_changed = False spec_changed = False
# ensure type safety for the architecture
if spec.architecture is None: if spec.architecture is None:
spec.architecture = spack.spec.ArchSpec(sys_arch) spec.architecture = spack.spec.ArchSpec()
spec_changed = True spec_changed = True
default_archs = list(x for x in [root_arch, sys_arch] if x) # replace each of the fields (platform, os, target) separately
for arch in default_archs: nearest_dict = nearest_arch.to_cmp_dict()
if spec.architecture.concrete: replacement_fields = [k for k, v in iteritems(nearest_dict)
break if v and not getattr(spec.architecture, k)]
for field in replacement_fields:
replacement_fields = [k for k, v in iteritems(arch.to_cmp_dict()) setattr(spec.architecture, field, getattr(nearest_arch, field))
if v and not getattr(spec.architecture, k)] spec_changed = True
for field in replacement_fields:
setattr(spec.architecture, field, getattr(arch, field))
spec_changed = True
if not spec.architecture.concrete:
raise InsufficientArchitectureInfoError(spec, default_archs)
return spec_changed return spec_changed

View file

@ -1,4 +1,4 @@
############################################################################## #############################################################################
# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC. # Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory. # Produced at the Lawrence Livermore National Laboratory.
# #
@ -31,6 +31,7 @@
from spack.spec import Spec, CompilerSpec from spack.spec import Spec, CompilerSpec
from spack.spec import ConflictsInSpecError, SpecError from spack.spec import ConflictsInSpecError, SpecError
from spack.version import ver from spack.version import ver
from spack.test.conftest import MockPackage, MockPackageMultiRepo
def check_spec(abstract, concrete): def check_spec(abstract, concrete):
@ -204,6 +205,42 @@ def test_different_compilers_get_different_flags(self):
assert set(client.compiler_flags['fflags']) == set(['-O0']) assert set(client.compiler_flags['fflags']) == set(['-O0'])
assert not set(cmake.compiler_flags['fflags']) assert not set(cmake.compiler_flags['fflags'])
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@4.7.2 os=fe ^ cmake')
spec.concretize()
assert spec['cmake'].architecture == spec.architecture
def test_architecture_deep_inheritance(self):
"""Make sure that indirect dependencies receive architecture
information from the root even when partial architecture information
is provided by an intermediate dependency.
"""
saved_repo = spack.repo
default_dep = ('link', 'build')
bazpkg = MockPackage('bazpkg', [], [])
barpkg = MockPackage('barpkg', [bazpkg], [default_dep])
foopkg = MockPackage('foopkg', [barpkg], [default_dep])
mock_repo = MockPackageMultiRepo([foopkg, barpkg, bazpkg])
spack.repo = mock_repo
try:
spec = Spec('foopkg %clang@3.3 os=CNL target=footar' +
' ^barpkg os=SuSE11 ^bazpkg os=be')
spec.concretize()
for s in spec.traverse(root=False):
assert s.architecture.target == spec.architecture.target
finally:
spack.repo = saved_repo
def test_compiler_flags_from_user_are_grouped(self): def test_compiler_flags_from_user_are_grouped(self):
spec = Spec('a%gcc cflags="-O -foo-flag foo-val" platform=test') spec = Spec('a%gcc cflags="-O -foo-flag foo-val" platform=test')
spec.concretize() spec.concretize()
@ -216,6 +253,7 @@ def concretize_multi_provider(self):
assert s['mpi'].version == ver('1.10.3') assert s['mpi'].version == ver('1.10.3')
def test_concretize_two_virtuals(self): def test_concretize_two_virtuals(self):
"""Test a package with multiple virtual dependencies.""" """Test a package with multiple virtual dependencies."""
Spec('hypre').concretize() Spec('hypre').concretize()