diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py index 4d1ddf7ac9..c722a5506c 100644 --- a/lib/spack/spack/concretize.py +++ b/lib/spack/spack/concretize.py @@ -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 diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 7885ca279f..87a4e03b4d 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -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()