Use frontend OS for build/run deps by default (#2292)
Packages built targeting a backend may depend on packages like cmake which can be built against the frontend. With this commit, any build dependency or child of a build dependency will target the frontend by default. In compiler concretization when packages copy compilers from nearby packages, build dependencies use compiler information from other build dependencies, and link dependencies avoid using compiler information from build dependencies.
This commit is contained in:
parent
5f01f273e0
commit
30daf95ae8
5 changed files with 91 additions and 25 deletions
|
@ -513,3 +513,8 @@ def sys_type():
|
||||||
"""
|
"""
|
||||||
arch = Arch(platform(), 'default_os', 'default_target')
|
arch = Arch(platform(), 'default_os', 'default_target')
|
||||||
return str(arch)
|
return str(arch)
|
||||||
|
|
||||||
|
|
||||||
|
@memoized
|
||||||
|
def frontend_sys_type():
|
||||||
|
return str(Arch(platform(), 'frontend', 'frontend'))
|
||||||
|
|
|
@ -251,7 +251,11 @@ 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
|
root_arch = spec.link_root().architecture
|
||||||
|
if spec.build_dep() and spec.disjoint_build_tree():
|
||||||
|
sys_arch = spack.spec.ArchSpec(
|
||||||
|
spack.architecture.frontend_sys_type())
|
||||||
|
else:
|
||||||
sys_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
|
sys_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
|
||||||
spec_changed = False
|
spec_changed = False
|
||||||
|
|
||||||
|
@ -321,14 +325,21 @@ def _proper_compiler_style(cspec, aspec):
|
||||||
spec.compiler in all_compilers):
|
spec.compiler in all_compilers):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Find the another spec that has a compiler, or the root if none do
|
if spec.compiler:
|
||||||
other_spec = spec if spec.compiler else find_spec(
|
other_spec = spec
|
||||||
spec, lambda x: x.compiler)
|
elif spec.build_dep() and spec.disjoint_build_tree():
|
||||||
|
link_root = spec.link_root()
|
||||||
|
build_subtree = list(link_root.traverse(direction='children'))
|
||||||
|
candidates = list(x for x in build_subtree if x.compiler)
|
||||||
|
other_spec = candidates[0] if candidates else link_root
|
||||||
|
else:
|
||||||
|
# Find another spec that has a compiler, or the root if none do.
|
||||||
|
# Prefer compiler info from other specs which are not build deps.
|
||||||
|
other_spec = (
|
||||||
|
find_spec(spec, lambda x: x.compiler and not x.build_dep()) or
|
||||||
|
spec.root)
|
||||||
|
|
||||||
if not other_spec:
|
|
||||||
other_spec = spec.root
|
|
||||||
other_compiler = other_spec.compiler
|
other_compiler = other_spec.compiler
|
||||||
assert(other_spec)
|
|
||||||
|
|
||||||
# Check if the compiler is already fully specified
|
# Check if the compiler is already fully specified
|
||||||
if other_compiler in all_compilers:
|
if other_compiler in all_compilers:
|
||||||
|
@ -372,16 +383,20 @@ def concretize_compiler_flags(self, spec):
|
||||||
# changes
|
# changes
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def compiler_match(spec1, spec2):
|
||||||
|
return ((spec1.compiler, spec1.architecture) ==
|
||||||
|
(spec2.compiler, spec2.architecture))
|
||||||
|
|
||||||
ret = False
|
ret = False
|
||||||
for flag in spack.spec.FlagMap.valid_compiler_flags():
|
for flag in spack.spec.FlagMap.valid_compiler_flags():
|
||||||
try:
|
try:
|
||||||
nearest = next(p for p in spec.traverse(direction='parents')
|
nearest = next(p for p in spec.traverse(direction='parents')
|
||||||
if ((p.compiler == spec.compiler and
|
if ((p is not spec) and
|
||||||
p is not spec) and
|
compiler_match(p, spec) and
|
||||||
flag in p.compiler_flags))
|
flag in p.compiler_flags))
|
||||||
if flag not in spec.compiler_flags or \
|
if (flag not in spec.compiler_flags or
|
||||||
not (sorted(spec.compiler_flags[flag]) >=
|
(set(nearest.compiler_flags[flag]) -
|
||||||
sorted(nearest.compiler_flags[flag])):
|
set(spec.compiler_flags[flag]))):
|
||||||
if flag in spec.compiler_flags:
|
if flag in spec.compiler_flags:
|
||||||
spec.compiler_flags[flag] = list(
|
spec.compiler_flags[flag] = list(
|
||||||
set(spec.compiler_flags[flag]) |
|
set(spec.compiler_flags[flag]) |
|
||||||
|
@ -392,10 +407,11 @@ def concretize_compiler_flags(self, spec):
|
||||||
ret = True
|
ret = True
|
||||||
|
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
if (flag in spec.root.compiler_flags and
|
if (compiler_match(spec.root, spec) and
|
||||||
|
flag in spec.root.compiler_flags and
|
||||||
((flag not in spec.compiler_flags) or
|
((flag not in spec.compiler_flags) or
|
||||||
sorted(spec.compiler_flags[flag]) !=
|
(set(spec.root.compiler_flags[flag]) -
|
||||||
sorted(spec.root.compiler_flags[flag]))):
|
set(spec.compiler_flags[flag])))):
|
||||||
if flag in spec.compiler_flags:
|
if flag in spec.compiler_flags:
|
||||||
spec.compiler_flags[flag] = list(
|
spec.compiler_flags[flag] = list(
|
||||||
set(spec.compiler_flags[flag]) |
|
set(spec.compiler_flags[flag]) |
|
||||||
|
@ -419,10 +435,8 @@ def concretize_compiler_flags(self, spec):
|
||||||
if compiler.flags[flag] != []:
|
if compiler.flags[flag] != []:
|
||||||
ret = True
|
ret = True
|
||||||
else:
|
else:
|
||||||
if ((sorted(spec.compiler_flags[flag]) !=
|
if (set(compiler.flags[flag]) -
|
||||||
sorted(compiler.flags[flag])) and
|
set(spec.compiler_flags[flag])):
|
||||||
(not set(spec.compiler_flags[flag]) >=
|
|
||||||
set(compiler.flags[flag]))):
|
|
||||||
ret = True
|
ret = True
|
||||||
spec.compiler_flags[flag] = list(
|
spec.compiler_flags[flag] = list(
|
||||||
set(spec.compiler_flags[flag]) |
|
set(spec.compiler_flags[flag]) |
|
||||||
|
|
|
@ -22,7 +22,7 @@ def __init__(self):
|
||||||
super(Cnl, self).__init__(name, version)
|
super(Cnl, self).__init__(name, version)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name + self.version
|
||||||
|
|
||||||
def find_compilers(self, *paths):
|
def find_compilers(self, *paths):
|
||||||
types = spack.compilers.all_compiler_types()
|
types = spack.compilers.all_compiler_types()
|
||||||
|
|
|
@ -1090,7 +1090,7 @@ def return_val(res):
|
||||||
|
|
||||||
successors = deps
|
successors = deps
|
||||||
if direction == 'parents':
|
if direction == 'parents':
|
||||||
successors = self.dependents_dict() # TODO: deptype?
|
successors = self.dependents_dict(deptype)
|
||||||
|
|
||||||
visited.add(key)
|
visited.add(key)
|
||||||
for name in sorted(successors):
|
for name in sorted(successors):
|
||||||
|
@ -1308,6 +1308,23 @@ def from_json(stream):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise sjson.SpackJSONError("error parsing JSON spec:", str(e))
|
raise sjson.SpackJSONError("error parsing JSON spec:", str(e))
|
||||||
|
|
||||||
|
def build_dep(self):
|
||||||
|
# If this spec is the root, it will automatically be included in
|
||||||
|
# traverse
|
||||||
|
return not (self.root in
|
||||||
|
self.traverse(
|
||||||
|
deptype=('link', 'run'), direction='parents'))
|
||||||
|
|
||||||
|
def link_root(self):
|
||||||
|
parents = list(self.traverse(deptype=('link',), direction='parents',
|
||||||
|
order='pre'))
|
||||||
|
return parents[-1]
|
||||||
|
|
||||||
|
def disjoint_build_tree(self):
|
||||||
|
link_root = self.link_root()
|
||||||
|
build_subtree = list(link_root.traverse(direction='children'))
|
||||||
|
return all(x.build_dep() for x in build_subtree)
|
||||||
|
|
||||||
def _concretize_helper(self, presets=None, visited=None):
|
def _concretize_helper(self, presets=None, visited=None):
|
||||||
"""Recursive helper function for concretize().
|
"""Recursive helper function for concretize().
|
||||||
This concretizes everything bottom-up. As things are
|
This concretizes everything bottom-up. As things are
|
||||||
|
@ -1326,8 +1343,8 @@ def _concretize_helper(self, presets=None, visited=None):
|
||||||
|
|
||||||
# Concretize deps first -- this is a bottom-up process.
|
# Concretize deps first -- this is a bottom-up process.
|
||||||
for name in sorted(self._dependencies.keys()):
|
for name in sorted(self._dependencies.keys()):
|
||||||
changed |= self._dependencies[
|
dep = self._dependencies[name]
|
||||||
name].spec._concretize_helper(presets, visited)
|
changed |= dep.spec._concretize_helper(presets, visited)
|
||||||
|
|
||||||
if self.name in presets:
|
if self.name in presets:
|
||||||
changed |= self.constrain(presets[self.name])
|
changed |= self.constrain(presets[self.name])
|
||||||
|
|
|
@ -85,6 +85,36 @@ def test_concretize_variant(self):
|
||||||
self.check_concretize('mpich debug=2')
|
self.check_concretize('mpich debug=2')
|
||||||
self.check_concretize('mpich')
|
self.check_concretize('mpich')
|
||||||
|
|
||||||
|
def test_concretize_with_build_dep(self):
|
||||||
|
# Set the target as the backend. Since the cmake build dependency is
|
||||||
|
# not explicitly configured to target the backend it should target
|
||||||
|
# the frontend (whatever compiler that is, it is different)
|
||||||
|
spec = self.check_concretize('cmake-client platform=test target=be')
|
||||||
|
client_compiler = spack.compilers.compiler_for_spec(
|
||||||
|
spec.compiler, spec.architecture)
|
||||||
|
cmake_spec = spec['cmake']
|
||||||
|
cmake_compiler = spack.compilers.compiler_for_spec(
|
||||||
|
cmake_spec.compiler, cmake_spec.architecture)
|
||||||
|
self.assertTrue(client_compiler.operating_system !=
|
||||||
|
cmake_compiler.operating_system)
|
||||||
|
|
||||||
|
def test_concretize_link_dep_of_build_dep(self):
|
||||||
|
# The link dep of the build dep should use the same compiler as
|
||||||
|
# the build dep, and both should be different from the root
|
||||||
|
spec = self.check_concretize('dttop platform=test target=be')
|
||||||
|
dttop_compiler = spack.compilers.compiler_for_spec(
|
||||||
|
spec.compiler, spec.architecture)
|
||||||
|
dtlink2_spec = spec['dtlink2']
|
||||||
|
dtlink2_compiler = spack.compilers.compiler_for_spec(
|
||||||
|
dtlink2_spec.compiler, dtlink2_spec.architecture)
|
||||||
|
dtbuild1_spec = spec['dtbuild1']
|
||||||
|
dtbuild1_compiler = spack.compilers.compiler_for_spec(
|
||||||
|
dtbuild1_spec.compiler, dtbuild1_spec.architecture)
|
||||||
|
self.assertTrue(dttop_compiler.operating_system !=
|
||||||
|
dtlink2_compiler.operating_system)
|
||||||
|
self.assertTrue(dtbuild1_compiler.operating_system ==
|
||||||
|
dtlink2_compiler.operating_system)
|
||||||
|
|
||||||
def test_conretize_compiler_flags(self):
|
def test_conretize_compiler_flags(self):
|
||||||
self.check_concretize('mpich cppflags="-O3"')
|
self.check_concretize('mpich cppflags="-O3"')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue