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
on the platform.
"""
root_arch = spec.root.architecture
sys_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
try:
# 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
# ensure type safety for the architecture
if spec.architecture is None:
spec.architecture = spack.spec.ArchSpec(sys_arch)
spec.architecture = spack.spec.ArchSpec()
spec_changed = True
default_archs = list(x for x in [root_arch, sys_arch] if x)
for arch in default_archs:
if spec.architecture.concrete:
break
replacement_fields = [k for k, v in iteritems(arch.to_cmp_dict())
if v and not getattr(spec.architecture, k)]
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)
# replace each of the fields (platform, os, target) separately
nearest_dict = nearest_arch.to_cmp_dict()
replacement_fields = [k for k, v in iteritems(nearest_dict)
if v and not getattr(spec.architecture, k)]
for field in replacement_fields:
setattr(spec.architecture, field, getattr(nearest_arch, field))
spec_changed = True
return spec_changed

View file

@ -1,4 +1,4 @@
##############################################################################
#############################################################################
# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
@ -31,6 +31,7 @@
from spack.spec import Spec, CompilerSpec
from spack.spec import ConflictsInSpecError, SpecError
from spack.version import ver
from spack.test.conftest import MockPackage, MockPackageMultiRepo
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 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):
spec = Spec('a%gcc cflags="-O -foo-flag foo-val" platform=test')
spec.concretize()
@ -216,6 +253,7 @@ def concretize_multi_provider(self):
assert s['mpi'].version == ver('1.10.3')
def test_concretize_two_virtuals(self):
"""Test a package with multiple virtual dependencies."""
Spec('hypre').concretize()