(WIP) Install mechanism
This commit is contained in:
parent
8c66a1699e
commit
67b04f1b8d
@ -36,7 +36,6 @@
|
|||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import stat
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import types
|
import types
|
||||||
@ -296,62 +295,10 @@ def _add_werror_handling(keep_werror, env):
|
|||||||
env.set("SPACK_COMPILER_FLAGS_REPLACE", " ".join(["|".join(item) for item in replace_flags]))
|
env.set("SPACK_COMPILER_FLAGS_REPLACE", " ".join(["|".join(item) for item in replace_flags]))
|
||||||
|
|
||||||
|
|
||||||
def set_compiler_environment_variables(pkg, env):
|
def set_wrapper_environment_variables_for_flags(pkg, env):
|
||||||
assert pkg.spec.concrete
|
assert pkg.spec.concrete
|
||||||
compiler = pkg.compiler
|
|
||||||
spec = pkg.spec
|
spec = pkg.spec
|
||||||
|
|
||||||
# Make sure the executables for this compiler exist
|
|
||||||
compiler.verify_executables()
|
|
||||||
|
|
||||||
# Set compiler variables used by CMake and autotools
|
|
||||||
assert all(key in compiler.link_paths for key in ("cc", "cxx", "f77", "fc"))
|
|
||||||
|
|
||||||
# Populate an object with the list of environment modifications
|
|
||||||
# and return it
|
|
||||||
# TODO : add additional kwargs for better diagnostics, like requestor,
|
|
||||||
# ttyout, ttyerr, etc.
|
|
||||||
link_dir = spack.paths.build_env_path
|
|
||||||
|
|
||||||
# Set SPACK compiler variables so that our wrapper knows what to
|
|
||||||
# call. If there is no compiler configured then use a default
|
|
||||||
# wrapper which will emit an error if it is used.
|
|
||||||
if compiler.cc:
|
|
||||||
env.set("SPACK_CC", compiler.cc)
|
|
||||||
env.set("CC", os.path.join(link_dir, compiler.link_paths["cc"]))
|
|
||||||
else:
|
|
||||||
env.set("CC", os.path.join(link_dir, "cc"))
|
|
||||||
if compiler.cxx:
|
|
||||||
env.set("SPACK_CXX", compiler.cxx)
|
|
||||||
env.set("CXX", os.path.join(link_dir, compiler.link_paths["cxx"]))
|
|
||||||
else:
|
|
||||||
env.set("CC", os.path.join(link_dir, "c++"))
|
|
||||||
if compiler.f77:
|
|
||||||
env.set("SPACK_F77", compiler.f77)
|
|
||||||
env.set("F77", os.path.join(link_dir, compiler.link_paths["f77"]))
|
|
||||||
else:
|
|
||||||
env.set("F77", os.path.join(link_dir, "f77"))
|
|
||||||
if compiler.fc:
|
|
||||||
env.set("SPACK_FC", compiler.fc)
|
|
||||||
env.set("FC", os.path.join(link_dir, compiler.link_paths["fc"]))
|
|
||||||
else:
|
|
||||||
env.set("FC", os.path.join(link_dir, "fc"))
|
|
||||||
|
|
||||||
# Set SPACK compiler rpath flags so that our wrapper knows what to use
|
|
||||||
env.set("SPACK_CC_RPATH_ARG", compiler.cc_rpath_arg)
|
|
||||||
env.set("SPACK_CXX_RPATH_ARG", compiler.cxx_rpath_arg)
|
|
||||||
env.set("SPACK_F77_RPATH_ARG", compiler.f77_rpath_arg)
|
|
||||||
env.set("SPACK_FC_RPATH_ARG", compiler.fc_rpath_arg)
|
|
||||||
env.set("SPACK_LINKER_ARG", compiler.linker_arg)
|
|
||||||
|
|
||||||
# Check whether we want to force RPATH or RUNPATH
|
|
||||||
if spack.config.get("config:shared_linking:type") == "rpath":
|
|
||||||
env.set("SPACK_DTAGS_TO_STRIP", compiler.enable_new_dtags)
|
|
||||||
env.set("SPACK_DTAGS_TO_ADD", compiler.disable_new_dtags)
|
|
||||||
else:
|
|
||||||
env.set("SPACK_DTAGS_TO_STRIP", compiler.disable_new_dtags)
|
|
||||||
env.set("SPACK_DTAGS_TO_ADD", compiler.enable_new_dtags)
|
|
||||||
|
|
||||||
if pkg.keep_werror is not None:
|
if pkg.keep_werror is not None:
|
||||||
keep_werror = pkg.keep_werror
|
keep_werror = pkg.keep_werror
|
||||||
else:
|
else:
|
||||||
@ -359,10 +306,6 @@ def set_compiler_environment_variables(pkg, env):
|
|||||||
|
|
||||||
_add_werror_handling(keep_werror, env)
|
_add_werror_handling(keep_werror, env)
|
||||||
|
|
||||||
# Set the target parameters that the compiler will add
|
|
||||||
isa_arg = optimization_flags(compiler, spec.target)
|
|
||||||
env.set("SPACK_TARGET_ARGS", isa_arg)
|
|
||||||
|
|
||||||
# Trap spack-tracked compiler flags as appropriate.
|
# Trap spack-tracked compiler flags as appropriate.
|
||||||
# env_flags are easy to accidentally override.
|
# env_flags are easy to accidentally override.
|
||||||
inject_flags = {}
|
inject_flags = {}
|
||||||
@ -396,74 +339,27 @@ def set_compiler_environment_variables(pkg, env):
|
|||||||
env.set(flag.upper(), " ".join(f for f in env_flags[flag]))
|
env.set(flag.upper(), " ".join(f for f in env_flags[flag]))
|
||||||
pkg.flags_to_build_system_args(build_system_flags)
|
pkg.flags_to_build_system_args(build_system_flags)
|
||||||
|
|
||||||
env.set("SPACK_COMPILER_SPEC", str(spec.compiler))
|
|
||||||
|
|
||||||
env.set("SPACK_SYSTEM_DIRS", SYSTEM_DIR_CASE_ENTRY)
|
env.set("SPACK_SYSTEM_DIRS", SYSTEM_DIR_CASE_ENTRY)
|
||||||
|
|
||||||
compiler.setup_custom_environment(pkg, env)
|
# FIXME (compiler as nodes): recover this one in the correct packages
|
||||||
|
# compiler.setup_custom_environment(pkg, env)
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
|
||||||
def optimization_flags(compiler, target):
|
def optimization_flags(compiler, target):
|
||||||
if spack.compilers.is_mixed_toolchain(compiler):
|
|
||||||
msg = (
|
|
||||||
"microarchitecture specific optimizations are not "
|
|
||||||
"supported yet on mixed compiler toolchains [check"
|
|
||||||
f" {compiler.name}@{compiler.version} for further details]"
|
|
||||||
)
|
|
||||||
tty.debug(msg)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
# Try to check if the current compiler comes with a version number or
|
# Try to check if the current compiler comes with a version number or
|
||||||
# has an unexpected suffix. If so, treat it as a compiler with a
|
# has an unexpected suffix. If so, treat it as a compiler with a
|
||||||
# custom spec.
|
# custom spec.
|
||||||
compiler_version = compiler.version
|
version_number, _ = archspec.cpu.version_components(compiler.version.dotted_numeric_string)
|
||||||
version_number, suffix = archspec.cpu.version_components(compiler.version)
|
|
||||||
if not version_number or suffix:
|
|
||||||
try:
|
|
||||||
compiler_version = compiler.real_version
|
|
||||||
except spack.util.executable.ProcessError as e:
|
|
||||||
# log this and just return compiler.version instead
|
|
||||||
tty.debug(str(e))
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = target.optimization_flags(compiler.name, compiler_version.dotted_numeric_string)
|
result = target.optimization_flags(compiler.name, version_number)
|
||||||
except (ValueError, archspec.cpu.UnsupportedMicroarchitecture):
|
except (ValueError, archspec.cpu.UnsupportedMicroarchitecture):
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class FilterDefaultDynamicLinkerSearchPaths:
|
|
||||||
"""Remove rpaths to directories that are default search paths of the dynamic linker."""
|
|
||||||
|
|
||||||
def __init__(self, dynamic_linker: Optional[str]) -> None:
|
|
||||||
# Identify directories by (inode, device) tuple, which handles symlinks too.
|
|
||||||
self.default_path_identifiers: Set[Tuple[int, int]] = set()
|
|
||||||
if not dynamic_linker:
|
|
||||||
return
|
|
||||||
for path in spack.util.libc.default_search_paths_from_dynamic_linker(dynamic_linker):
|
|
||||||
try:
|
|
||||||
s = os.stat(path)
|
|
||||||
if stat.S_ISDIR(s.st_mode):
|
|
||||||
self.default_path_identifiers.add((s.st_ino, s.st_dev))
|
|
||||||
except OSError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
def is_dynamic_loader_default_path(self, p: str) -> bool:
|
|
||||||
try:
|
|
||||||
s = os.stat(p)
|
|
||||||
return (s.st_ino, s.st_dev) in self.default_path_identifiers
|
|
||||||
except OSError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __call__(self, dirs: List[str]) -> List[str]:
|
|
||||||
if not self.default_path_identifiers:
|
|
||||||
return dirs
|
|
||||||
return [p for p in dirs if not self.is_dynamic_loader_default_path(p)]
|
|
||||||
|
|
||||||
|
|
||||||
def set_wrapper_variables(pkg, env):
|
def set_wrapper_variables(pkg, env):
|
||||||
"""Set environment variables used by the Spack compiler wrapper (which have the prefix
|
"""Set environment variables used by the Spack compiler wrapper (which have the prefix
|
||||||
`SPACK_`) and also add the compiler wrappers to PATH.
|
`SPACK_`) and also add the compiler wrappers to PATH.
|
||||||
@ -472,39 +368,8 @@ def set_wrapper_variables(pkg, env):
|
|||||||
this function computes these options in a manner that is intended to match the DAG traversal
|
this function computes these options in a manner that is intended to match the DAG traversal
|
||||||
order in `SetupContext`. TODO: this is not the case yet, we're using post order, SetupContext
|
order in `SetupContext`. TODO: this is not the case yet, we're using post order, SetupContext
|
||||||
is using topo order."""
|
is using topo order."""
|
||||||
# Set environment variables if specified for
|
# Set compiler flags injected from the spec
|
||||||
# the given compiler
|
set_wrapper_environment_variables_for_flags(pkg, env)
|
||||||
compiler = pkg.compiler
|
|
||||||
env.extend(spack.schema.environment.parse(compiler.environment))
|
|
||||||
|
|
||||||
if compiler.extra_rpaths:
|
|
||||||
extra_rpaths = ":".join(compiler.extra_rpaths)
|
|
||||||
env.set("SPACK_COMPILER_EXTRA_RPATHS", extra_rpaths)
|
|
||||||
|
|
||||||
# Add spack build environment path with compiler wrappers first in
|
|
||||||
# the path. We add the compiler wrapper path, which includes default
|
|
||||||
# wrappers (cc, c++, f77, f90), AND a subdirectory containing
|
|
||||||
# compiler-specific symlinks. The latter ensures that builds that
|
|
||||||
# are sensitive to the *name* of the compiler see the right name when
|
|
||||||
# we're building with the wrappers.
|
|
||||||
#
|
|
||||||
# Conflicts on case-insensitive systems (like "CC" and "cc") are
|
|
||||||
# handled by putting one in the <build_env_path>/case-insensitive
|
|
||||||
# directory. Add that to the path too.
|
|
||||||
env_paths = []
|
|
||||||
compiler_specific = os.path.join(
|
|
||||||
spack.paths.build_env_path, os.path.dirname(pkg.compiler.link_paths["cc"])
|
|
||||||
)
|
|
||||||
for item in [spack.paths.build_env_path, compiler_specific]:
|
|
||||||
env_paths.append(item)
|
|
||||||
ci = os.path.join(item, "case-insensitive")
|
|
||||||
if os.path.isdir(ci):
|
|
||||||
env_paths.append(ci)
|
|
||||||
|
|
||||||
tty.debug("Adding compiler bin/ paths: " + " ".join(env_paths))
|
|
||||||
for item in env_paths:
|
|
||||||
env.prepend_path("PATH", item)
|
|
||||||
env.set_path(SPACK_ENV_PATH, env_paths)
|
|
||||||
|
|
||||||
# Working directory for the spack command itself, for debug logs.
|
# Working directory for the spack command itself, for debug logs.
|
||||||
if spack.config.get("config:debug"):
|
if spack.config.get("config:debug"):
|
||||||
@ -570,22 +435,17 @@ def set_wrapper_variables(pkg, env):
|
|||||||
lib_path = os.path.join(pkg.prefix, libdir)
|
lib_path = os.path.join(pkg.prefix, libdir)
|
||||||
rpath_dirs.insert(0, lib_path)
|
rpath_dirs.insert(0, lib_path)
|
||||||
|
|
||||||
filter_default_dynamic_linker_search_paths = FilterDefaultDynamicLinkerSearchPaths(
|
# FIXME (compiler as nodes): recover this filter
|
||||||
pkg.compiler.default_dynamic_linker
|
# filter_default_dynamic_linker_search_paths = FilterDefaultDynamicLinkerSearchPaths(
|
||||||
)
|
# pkg.compiler.default_dynamic_linker
|
||||||
|
# )
|
||||||
|
|
||||||
# TODO: filter_system_paths is again wrong (and probably unnecessary due to the is_system_path
|
# TODO: filter_system_paths is again wrong (and probably unnecessary due to the is_system_path
|
||||||
# branch above). link_dirs should be filtered with entries from _parse_link_paths.
|
# branch above). link_dirs should be filtered with entries from _parse_link_paths.
|
||||||
link_dirs = list(dedupe(filter_system_paths(link_dirs)))
|
link_dirs = list(dedupe(filter_system_paths(link_dirs)))
|
||||||
include_dirs = list(dedupe(filter_system_paths(include_dirs)))
|
include_dirs = list(dedupe(filter_system_paths(include_dirs)))
|
||||||
rpath_dirs = list(dedupe(filter_system_paths(rpath_dirs)))
|
rpath_dirs = list(dedupe(filter_system_paths(rpath_dirs)))
|
||||||
rpath_dirs = filter_default_dynamic_linker_search_paths(rpath_dirs)
|
# rpath_dirs = filter_default_dynamic_linker_search_paths(rpath_dirs)
|
||||||
|
|
||||||
# TODO: implicit_rpaths is prefiltered by is_system_path, that should be removed in favor of
|
|
||||||
# just this filter.
|
|
||||||
implicit_rpaths = filter_default_dynamic_linker_search_paths(pkg.compiler.implicit_rpaths())
|
|
||||||
if implicit_rpaths:
|
|
||||||
env.set("SPACK_COMPILER_IMPLICIT_RPATHS", ":".join(implicit_rpaths))
|
|
||||||
|
|
||||||
# Spack managed directories include the stage, store and upstream stores. We extend this with
|
# Spack managed directories include the stage, store and upstream stores. We extend this with
|
||||||
# their real paths to make it more robust (e.g. /tmp vs /private/tmp on macOS).
|
# their real paths to make it more robust (e.g. /tmp vs /private/tmp on macOS).
|
||||||
@ -641,22 +501,19 @@ def set_package_py_globals(pkg, context: Context = Context.BUILD):
|
|||||||
# Put spack compiler paths in module scope. (Some packages use it
|
# Put spack compiler paths in module scope. (Some packages use it
|
||||||
# in setup_run_environment etc, so don't put it context == build)
|
# in setup_run_environment etc, so don't put it context == build)
|
||||||
link_dir = spack.paths.build_env_path
|
link_dir = spack.paths.build_env_path
|
||||||
pkg_compiler = None
|
|
||||||
try:
|
|
||||||
pkg_compiler = pkg.compiler
|
|
||||||
except spack.compilers.NoCompilerForSpecError as e:
|
|
||||||
tty.debug(f"cannot set 'spack_cc': {str(e)}")
|
|
||||||
|
|
||||||
if pkg_compiler is not None:
|
# FIXME (compiler as nodes): make this more general, and not tied to three languages
|
||||||
module.spack_cc = os.path.join(link_dir, pkg_compiler.link_paths["cc"])
|
# Maybe add a callback?
|
||||||
module.spack_cxx = os.path.join(link_dir, pkg_compiler.link_paths["cxx"])
|
global_names = {
|
||||||
module.spack_f77 = os.path.join(link_dir, pkg_compiler.link_paths["f77"])
|
"c": ("spack_cc",),
|
||||||
module.spack_fc = os.path.join(link_dir, pkg_compiler.link_paths["fc"])
|
"cxx": ("spack_cxx",),
|
||||||
else:
|
"fortran": ("spack_fc", "spack_f77"),
|
||||||
module.spack_cc = None
|
}
|
||||||
module.spack_cxx = None
|
for language in ("c", "cxx", "fortran"):
|
||||||
module.spack_f77 = None
|
spec = pkg.spec.dependencies(virtuals=[language])
|
||||||
module.spack_fc = None
|
value = None if not spec else os.path.join(link_dir, spec[0].package.link_paths[language])
|
||||||
|
for name in global_names[language]:
|
||||||
|
setattr(module, name, value)
|
||||||
|
|
||||||
# Useful directories within the prefix are encapsulated in
|
# Useful directories within the prefix are encapsulated in
|
||||||
# a Prefix object.
|
# a Prefix object.
|
||||||
@ -823,7 +680,6 @@ def setup_package(pkg, dirty, context: Context = Context.BUILD):
|
|||||||
context == Context.TEST and pkg.test_requires_compiler
|
context == Context.TEST and pkg.test_requires_compiler
|
||||||
)
|
)
|
||||||
if need_compiler:
|
if need_compiler:
|
||||||
set_compiler_environment_variables(pkg, env_mods)
|
|
||||||
set_wrapper_variables(pkg, env_mods)
|
set_wrapper_variables(pkg, env_mods)
|
||||||
|
|
||||||
# Platform specific setup goes before package specific setup. This is for setting
|
# Platform specific setup goes before package specific setup. This is for setting
|
||||||
@ -848,11 +704,6 @@ def setup_package(pkg, dirty, context: Context = Context.BUILD):
|
|||||||
|
|
||||||
# Load modules on an already clean environment, just before applying Spack's
|
# Load modules on an already clean environment, just before applying Spack's
|
||||||
# own environment modifications. This ensures Spack controls CC/CXX/... variables.
|
# own environment modifications. This ensures Spack controls CC/CXX/... variables.
|
||||||
if need_compiler:
|
|
||||||
tty.debug("setup_package: loading compiler modules")
|
|
||||||
for mod in pkg.compiler.modules:
|
|
||||||
load_module(mod)
|
|
||||||
|
|
||||||
load_external_modules(pkg)
|
load_external_modules(pkg)
|
||||||
|
|
||||||
# Make sure nothing's strange about the Spack environment.
|
# Make sure nothing's strange about the Spack environment.
|
||||||
|
@ -4,15 +4,18 @@
|
|||||||
import itertools
|
import itertools
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import platform
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict, List, Sequence, Tuple, Union
|
from typing import Dict, List, Optional, Sequence, Tuple, Union
|
||||||
|
|
||||||
|
import archspec.cpu
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.lang import classproperty
|
from llnl.util.lang import classproperty, memoized
|
||||||
|
|
||||||
import spack.compiler
|
|
||||||
import spack.package_base
|
import spack.package_base
|
||||||
|
import spack.paths
|
||||||
import spack.util.executable
|
import spack.util.executable
|
||||||
|
|
||||||
# Local "type" for type hints
|
# Local "type" for type hints
|
||||||
@ -43,6 +46,9 @@ class CompilerPackage(spack.package_base.PackageBase):
|
|||||||
#: Static definition of languages supported by this class
|
#: Static definition of languages supported by this class
|
||||||
compiler_languages: Sequence[str] = ["c", "cxx", "fortran"]
|
compiler_languages: Sequence[str] = ["c", "cxx", "fortran"]
|
||||||
|
|
||||||
|
#: Relative path to compiler wrappers
|
||||||
|
link_paths: Dict[str, str] = {}
|
||||||
|
|
||||||
def __init__(self, spec: "spack.spec.Spec"):
|
def __init__(self, spec: "spack.spec.Spec"):
|
||||||
super().__init__(spec)
|
super().__init__(spec)
|
||||||
msg = f"Supported languages for {spec} are not a subset of possible supported languages"
|
msg = f"Supported languages for {spec} are not a subset of possible supported languages"
|
||||||
@ -77,14 +83,14 @@ def executables(cls) -> Sequence[str]:
|
|||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def determine_version(cls, exe: Path):
|
def determine_version(cls, exe: Path) -> str:
|
||||||
version_argument = cls.compiler_version_argument
|
version_argument = cls.compiler_version_argument
|
||||||
if isinstance(version_argument, str):
|
if isinstance(version_argument, str):
|
||||||
version_argument = (version_argument,)
|
version_argument = (version_argument,)
|
||||||
|
|
||||||
for va in version_argument:
|
for va in version_argument:
|
||||||
try:
|
try:
|
||||||
output = spack.compiler.get_compiler_version_output(exe, va)
|
output = compiler_output(exe, version_argument=va)
|
||||||
match = re.search(cls.compiler_version_regex, output)
|
match = re.search(cls.compiler_version_regex, output)
|
||||||
if match:
|
if match:
|
||||||
return ".".join(match.groups())
|
return ".".join(match.groups())
|
||||||
@ -142,3 +148,167 @@ def determine_compiler_paths(cls, exes: Sequence[Path]) -> Dict[str, Path]:
|
|||||||
def determine_variants(cls, exes: Sequence[Path], version_str: str) -> Tuple:
|
def determine_variants(cls, exes: Sequence[Path], version_str: str) -> Tuple:
|
||||||
# path determination is separated so it can be reused in subclasses
|
# path determination is separated so it can be reused in subclasses
|
||||||
return "", {"compilers": cls.determine_compiler_paths(exes=exes)}
|
return "", {"compilers": cls.determine_compiler_paths(exes=exes)}
|
||||||
|
|
||||||
|
#: Returns the argument needed to set the RPATH, or None if it does not exist
|
||||||
|
rpath_arg: Optional[str] = "-Wl,-rpath,"
|
||||||
|
#: Flag that needs to be used to pass an argument to the linker
|
||||||
|
linker_arg: str = "-Wl,"
|
||||||
|
#: Flag used to produce Position Independent Code
|
||||||
|
pic_flag: str = "-fPIC"
|
||||||
|
#: Flag used to get verbose output
|
||||||
|
verbose_flags: str = "-v"
|
||||||
|
#: Flag to activate OpenMP support
|
||||||
|
openmp_flag: str = "-fopenmp"
|
||||||
|
|
||||||
|
def standard_flag(self, *, language: str, standard: str) -> str:
|
||||||
|
"""Returns the flag used to enforce a given standard for a language"""
|
||||||
|
if language not in self.supported_languages:
|
||||||
|
# FIXME (compiler as nodes): Use UnsupportedCompilerFlag ?
|
||||||
|
raise RuntimeError(f"{self.spec} does not provide the '{language}' language")
|
||||||
|
try:
|
||||||
|
return self._standard_flag(language=language, standard=standard)
|
||||||
|
except (KeyError, RuntimeError) as e:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"{self.spec} does not provide the '{language}' standard {standard}"
|
||||||
|
) from e
|
||||||
|
|
||||||
|
def _standard_flag(self, *, language: str, standard: str) -> str:
|
||||||
|
raise NotImplementedError("Must be implemented by derived classes")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def disable_new_dtags(self) -> str:
|
||||||
|
if platform.system() == "Darwin":
|
||||||
|
return ""
|
||||||
|
return "--disable-new-dtags"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enable_new_dtags(self) -> str:
|
||||||
|
if platform.system() == "Darwin":
|
||||||
|
return ""
|
||||||
|
return "--enable-new-dtags"
|
||||||
|
|
||||||
|
def setup_dependent_build_environment(self, env, dependent_spec):
|
||||||
|
# FIXME (compiler as nodes): check if this is good enough or should be made more general
|
||||||
|
|
||||||
|
# Populate an object with the list of environment modifications and return it
|
||||||
|
link_dir = pathlib.Path(spack.paths.build_env_path)
|
||||||
|
|
||||||
|
for language, attr_name, wrapper_var_name, spack_var_name in [
|
||||||
|
("c", "cc", "CC", "SPACK_CC"),
|
||||||
|
("cxx", "cxx", "CXX", "SPACK_CXX"),
|
||||||
|
("fortran", "fortran", "F77", "SPACK_F77"),
|
||||||
|
("fortran", "fortran", "FC", "SPACK_FC"),
|
||||||
|
]:
|
||||||
|
if not hasattr(self, attr_name):
|
||||||
|
continue
|
||||||
|
|
||||||
|
compiler = getattr(self, attr_name)
|
||||||
|
env.set(spack_var_name, compiler)
|
||||||
|
|
||||||
|
if language not in self.link_paths:
|
||||||
|
continue
|
||||||
|
|
||||||
|
wrapper_path = link_dir / self.link_paths.get(language)
|
||||||
|
env.set(wrapper_var_name, str(wrapper_path))
|
||||||
|
|
||||||
|
env.set("SPACK_CC_RPATH_ARG", self.rpath_arg)
|
||||||
|
env.set("SPACK_CXX_RPATH_ARG", self.rpath_arg)
|
||||||
|
env.set("SPACK_F77_RPATH_ARG", self.rpath_arg)
|
||||||
|
env.set("SPACK_FC_RPATH_ARG", self.rpath_arg)
|
||||||
|
env.set("SPACK_LINKER_ARG", self.linker_arg)
|
||||||
|
|
||||||
|
# Check whether we want to force RPATH or RUNPATH
|
||||||
|
if spack.config.CONFIG.get("config:shared_linking:type") == "rpath":
|
||||||
|
env.set("SPACK_DTAGS_TO_STRIP", self.enable_new_dtags)
|
||||||
|
env.set("SPACK_DTAGS_TO_ADD", self.disable_new_dtags)
|
||||||
|
else:
|
||||||
|
env.set("SPACK_DTAGS_TO_STRIP", self.disable_new_dtags)
|
||||||
|
env.set("SPACK_DTAGS_TO_ADD", self.enable_new_dtags)
|
||||||
|
|
||||||
|
spec = self.spec
|
||||||
|
uarch = spec.architecture.target
|
||||||
|
version_number, _ = archspec.cpu.version_components(spec.version.dotted_numeric_string)
|
||||||
|
try:
|
||||||
|
isa_arg = uarch.optimization_flags(spec.name, version_number)
|
||||||
|
except (ValueError, archspec.cpu.UnsupportedMicroarchitecture):
|
||||||
|
isa_arg = ""
|
||||||
|
|
||||||
|
if isa_arg:
|
||||||
|
env.set("SPACK_TARGET_ARGS", isa_arg)
|
||||||
|
|
||||||
|
env.set("SPACK_COMPILER_SPEC", spec.format("{name}{@version}{variants}{/hash:7}"))
|
||||||
|
|
||||||
|
if spec.extra_attributes:
|
||||||
|
environment = spec.extra_attributes.get("environment")
|
||||||
|
if environment:
|
||||||
|
env.extend(spack.schema.environment.parse(environment))
|
||||||
|
|
||||||
|
extra_rpaths = spec.extra_attributes.get("extra_rpaths")
|
||||||
|
if extra_rpaths:
|
||||||
|
extra_rpaths = ":".join(compiler.extra_rpaths)
|
||||||
|
env.set("SPACK_COMPILER_EXTRA_RPATHS", extra_rpaths)
|
||||||
|
|
||||||
|
# Add spack build environment path with compiler wrappers first in
|
||||||
|
# the path. We add the compiler wrapper path, which includes default
|
||||||
|
# wrappers (cc, c++, f77, f90), AND a subdirectory containing
|
||||||
|
# compiler-specific symlinks. The latter ensures that builds that
|
||||||
|
# are sensitive to the *name* of the compiler see the right name when
|
||||||
|
# we're building with the wrappers.
|
||||||
|
#
|
||||||
|
# Conflicts on case-insensitive systems (like "CC" and "cc") are
|
||||||
|
# handled by putting one in the <build_env_path>/case-insensitive
|
||||||
|
# directory. Add that to the path too.
|
||||||
|
env_paths = []
|
||||||
|
compiler_specific = os.path.join(
|
||||||
|
spack.paths.build_env_path, os.path.dirname(self.link_paths["c"])
|
||||||
|
)
|
||||||
|
for item in [spack.paths.build_env_path, compiler_specific]:
|
||||||
|
env_paths.append(item)
|
||||||
|
ci = os.path.join(item, "case-insensitive")
|
||||||
|
if os.path.isdir(ci):
|
||||||
|
env_paths.append(ci)
|
||||||
|
|
||||||
|
tty.debug("Adding compiler bin/ paths: " + " ".join(env_paths))
|
||||||
|
for item in env_paths:
|
||||||
|
env.prepend_path("PATH", item)
|
||||||
|
env.set_path("SPACK_ENV_PATH", env_paths)
|
||||||
|
|
||||||
|
|
||||||
|
@memoized
|
||||||
|
def _compiler_output(
|
||||||
|
compiler_path: Path, *, version_argument: str, ignore_errors: Tuple[int, ...] = ()
|
||||||
|
) -> str:
|
||||||
|
"""Returns the output from the compiler invoked with the given version argument.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
compiler_path: path of the compiler to be invoked
|
||||||
|
version_argument: the argument used to extract version information
|
||||||
|
"""
|
||||||
|
compiler = spack.util.executable.Executable(compiler_path)
|
||||||
|
compiler_invocation_args = {
|
||||||
|
"output": str,
|
||||||
|
"error": str,
|
||||||
|
"ignore_errors": ignore_errors,
|
||||||
|
"timeout": 120,
|
||||||
|
"fail_on_error": True,
|
||||||
|
}
|
||||||
|
if version_argument:
|
||||||
|
output = compiler(version_argument, **compiler_invocation_args)
|
||||||
|
else:
|
||||||
|
output = compiler(**compiler_invocation_args)
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
def compiler_output(
|
||||||
|
compiler_path: Path, *, version_argument: str, ignore_errors: Tuple[int, ...] = ()
|
||||||
|
) -> str:
|
||||||
|
"""Wrapper for _get_compiler_version_output()."""
|
||||||
|
# This ensures that we memoize compiler output by *absolute path*,
|
||||||
|
# not just executable name. If we don't do this, and the path changes
|
||||||
|
# (e.g., during testing), we can get incorrect results.
|
||||||
|
if not os.path.isabs(compiler_path):
|
||||||
|
compiler_path = spack.util.executable.which_string(compiler_path, required=True)
|
||||||
|
|
||||||
|
return _compiler_output(
|
||||||
|
compiler_path, version_argument=version_argument, ignore_errors=ignore_errors
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user