gcc: add support for the D language (GDC) (#32330)
This commit is contained in:
parent
f7fbfc54b3
commit
7a93eddf1c
@ -87,13 +87,17 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
||||
version("4.5.4", sha256="eef3f0456db8c3d992cbb51d5d32558190bc14f3bc19383dd93acc27acc6befc")
|
||||
|
||||
# We specifically do not add 'all' variant here because:
|
||||
# (i) Ada, Go, Jit, and Objective-C++ are not default languages.
|
||||
# (i) Ada, D, Go, Jit, and Objective-C++ are not default languages.
|
||||
# In that respect, the name 'all' is rather misleading.
|
||||
# (ii) Languages other than c,c++,fortran are prone to configure bug in GCC
|
||||
# For example, 'java' appears to ignore custom location of zlib
|
||||
# (iii) meaning of 'all' changes with GCC version, i.e. 'java' is not part
|
||||
# of gcc7. Correctly specifying conflicts() and depends_on() in such a
|
||||
# case is a PITA.
|
||||
#
|
||||
# Also note that some languages get enabled by the configure scripts even if not listed in the
|
||||
# arguments. For example, c++ is enabled when the bootstrapping is enabled and lto is enabled
|
||||
# when the link time optimization support is enabled.
|
||||
variant(
|
||||
"languages",
|
||||
default="c,c++,fortran",
|
||||
@ -102,6 +106,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
||||
"brig",
|
||||
"c",
|
||||
"c++",
|
||||
"d",
|
||||
"fortran",
|
||||
"go",
|
||||
"java",
|
||||
@ -234,6 +239,45 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
||||
# See https://gcc.gnu.org/gcc-5/changes.html
|
||||
conflicts("languages=jit", when="@:4")
|
||||
|
||||
with when("languages=d"):
|
||||
# The very first version of GDC that became part of GCC already supported version 2.076 of
|
||||
# the language and runtime.
|
||||
# See https://wiki.dlang.org/GDC#Status
|
||||
provides("D@2")
|
||||
|
||||
# Support for the D programming language has been added to GCC 9.
|
||||
# See https://gcc.gnu.org/gcc-9/changes.html#d
|
||||
conflicts("@:8", msg="support for D has been added in GCC 9.1")
|
||||
|
||||
# Versions of GDC prior to 12 can be built with an ISO C++11 compiler. Starting version 12,
|
||||
# the D frontend requires a working GDC. Moreover, it is strongly recommended to use an
|
||||
# older version of GDC to build GDC.
|
||||
# See https://gcc.gnu.org/install/prerequisites.html#GDC-prerequisite
|
||||
with when("@12:"):
|
||||
# All versions starting 12 have to be built GCC:
|
||||
for c in spack.compilers.supported_compilers():
|
||||
if c != "gcc":
|
||||
conflicts("%{0}".format(c))
|
||||
|
||||
# And it has to be GCC older than the version we build:
|
||||
vv = ["11", "12.1.0", "12.2.0"]
|
||||
for prev_v, curr_v in zip(vv, vv[1:]):
|
||||
conflicts(
|
||||
"%gcc@{0}:".format(curr_v),
|
||||
when="@{0}".format(curr_v),
|
||||
msg="'gcc@{0} languages=d' requires '%gcc@:{1}' "
|
||||
"with the D language support".format(curr_v, prev_v),
|
||||
)
|
||||
|
||||
# In principle, it is possible to have GDC even with GCC 5.
|
||||
# See https://github.com/D-Programming-GDC/gdc
|
||||
# We, however, require at least the oldest version that officially supports GDC. It is
|
||||
# also a good opportunity to tell the users that they need a working GDC:
|
||||
conflicts(
|
||||
"%gcc@:8",
|
||||
msg="'gcc@12: languages=d' requires '%gcc@9:' with the D language support",
|
||||
)
|
||||
|
||||
with when("+nvptx"):
|
||||
depends_on("cuda")
|
||||
resource(
|
||||
@ -260,6 +304,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
||||
conflicts("languages=jit")
|
||||
conflicts("languages=objc")
|
||||
conflicts("languages=obj-c++")
|
||||
conflicts("languages=d")
|
||||
# NVPTX build disables bootstrap
|
||||
conflicts("+bootstrap")
|
||||
|
||||
@ -383,7 +428,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
||||
|
||||
@classproperty
|
||||
def executables(cls):
|
||||
names = [r"gcc", r"[^\w]?g\+\+", r"gfortran"]
|
||||
names = [r"gcc", r"[^\w]?g\+\+", r"gfortran", r"gdc"]
|
||||
suffixes = [r"", r"-mp-\d+\.\d", r"-\d+\.\d", r"-\d+", r"\d\d"]
|
||||
return [r"".join(x) for x in itertools.product(names, suffixes)]
|
||||
|
||||
@ -443,7 +488,14 @@ def determine_version(cls, exe):
|
||||
@classmethod
|
||||
def determine_variants(cls, exes, version_str):
|
||||
languages, compilers = set(), {}
|
||||
for exe in exes:
|
||||
# There are often at least two copies (not symlinks) of each compiler executable in the
|
||||
# same directory: one with a canonical name, e.g. "gfortran", and another one with the
|
||||
# target prefix, e.g. "x86_64-pc-linux-gnu-gfortran". There also might be a copy of "gcc"
|
||||
# with the version suffix, e.g. "x86_64-pc-linux-gnu-gcc-6.3.0". To ensure the consistency
|
||||
# of values in the "compilers" dictionary (i.e. we prefer all of them to reference copies
|
||||
# with canonical names if possible), we iterate over the executables in the reversed sorted
|
||||
# order:
|
||||
for exe in sorted(exes, reverse=True):
|
||||
basename = os.path.basename(exe)
|
||||
if "g++" in basename:
|
||||
languages.add("c++")
|
||||
@ -454,6 +506,9 @@ def determine_variants(cls, exes, version_str):
|
||||
elif "gcc" in basename:
|
||||
languages.add("c")
|
||||
compilers["c"] = exe
|
||||
elif "gdc" in basename:
|
||||
languages.add("d")
|
||||
compilers["d"] = exe
|
||||
variant_str = "languages={0}".format(",".join(languages))
|
||||
return variant_str, {"compilers": compilers}
|
||||
|
||||
@ -469,6 +524,7 @@ def validate_detected_spec(cls, spec, extra_attributes):
|
||||
for constraint, key in {
|
||||
"languages=c": "c",
|
||||
"languages=c++": "cxx",
|
||||
"languages=d": "d",
|
||||
"languages=fortran": "fortran",
|
||||
}.items():
|
||||
if spec.satisfies(constraint, strict=True):
|
||||
@ -720,6 +776,18 @@ def configure_args(self):
|
||||
options.append("--with-boot-ldflags=" + boot_ldflags)
|
||||
options.append("--with-build-config=spack")
|
||||
|
||||
if "languages=d" in spec:
|
||||
# Phobos is the standard library for the D Programming Language. The documentation says
|
||||
# that on some targets, 'libphobos' is not enabled by default, but compiles and works
|
||||
# if '--enable-libphobos' is used. Specifics are documented for affected targets.
|
||||
# See https://gcc.gnu.org/install/prerequisites.html#GDC-prerequisite
|
||||
# Unfortunately, it is unclear where exactly the aforementioned specifics are
|
||||
# documented but GDC seems to be unusable without the library, therefore we enable it
|
||||
# explicitly:
|
||||
options.append("--enable-libphobos")
|
||||
if spec.satisfies("@12:"):
|
||||
options.append("GDC={0}".format(self.detect_gdc()))
|
||||
|
||||
return options
|
||||
|
||||
# run configure/make/make(install) for the nvptx-none target
|
||||
@ -893,3 +961,89 @@ def setup_run_environment(self, env):
|
||||
env.set(lang.upper(), abspath)
|
||||
# Stop searching filename/regex combos for this language
|
||||
break
|
||||
|
||||
def detect_gdc(self):
|
||||
"""Detect and return the path to GDC that belongs to the same instance of GCC that is used
|
||||
by self.compiler.
|
||||
|
||||
If the path cannot be detected, raise InstallError with recommendations for the users on
|
||||
how to circumvent the problem.
|
||||
|
||||
Should be use only if self.spec.satisfies("@12: languages=d")
|
||||
"""
|
||||
# Detect GCC package in the directory of the GCC compiler
|
||||
# or in the $PATH if self.compiler.cc is not an absolute path:
|
||||
from spack.detection import by_executable
|
||||
|
||||
compiler_dir = os.path.dirname(self.compiler.cc)
|
||||
detected_packages = by_executable(
|
||||
[self.__class__], path_hints=([compiler_dir] if os.path.isdir(compiler_dir) else None)
|
||||
)
|
||||
|
||||
# We consider only packages that satisfy the following constraint:
|
||||
required_spec = Spec("languages=c,c++,d")
|
||||
candidate_specs = [
|
||||
p.spec
|
||||
for p in filter(
|
||||
lambda p: p.spec.satisfies(required_spec), detected_packages.get(self.name, ())
|
||||
)
|
||||
]
|
||||
|
||||
if candidate_specs:
|
||||
# We now need to filter specs that match the compiler version:
|
||||
compiler_spec = Spec(repr(self.compiler.spec))
|
||||
|
||||
# First, try to filter specs that satisfy the compiler spec:
|
||||
new_candidate_specs = list(
|
||||
filter(lambda s: s.satisfies(compiler_spec), candidate_specs)
|
||||
)
|
||||
|
||||
# The compiler version might be more specific than what we can detect. For example, the
|
||||
# user might have "gcc@10.2.1-sys" as the compiler spec in compilers.yaml. In that
|
||||
# case, we end up with an empty list of candidates. To circumvent the problem, we try
|
||||
# to filter specs that are satisfied by the compiler spec:
|
||||
if not new_candidate_specs:
|
||||
new_candidate_specs = list(
|
||||
filter(lambda s: compiler_spec.satisfies(s), candidate_specs)
|
||||
)
|
||||
|
||||
candidate_specs = new_candidate_specs
|
||||
|
||||
error_nl = "\n " # see SpackError.__str__()
|
||||
|
||||
if not candidate_specs:
|
||||
raise InstallError(
|
||||
"Cannot detect GDC",
|
||||
long_msg="Starting version 12, the D frontend requires a working GDC."
|
||||
"{0}You can install it with Spack by running:"
|
||||
"{0}{0}spack install gcc@9:11 languages=c,c++,d"
|
||||
"{0}{0}Once that has finished, you will need to add it to your compilers.yaml file"
|
||||
"{0}and use it to install this spec (i.e. {1} ...).".format(
|
||||
error_nl, self.spec.format("{name}{@version} {variants.languages}")
|
||||
),
|
||||
)
|
||||
elif len(candidate_specs) == 0:
|
||||
return candidate_specs[0].extra_attributes["compilers"]["d"]
|
||||
else:
|
||||
# It is rather unlikely to end up here but let us try to resolve the ambiguity:
|
||||
candidate_gdc = candidate_specs[0].extra_attributes["compilers"]["d"]
|
||||
if all(
|
||||
candidate_gdc == s.extra_attributes["compilers"]["d"] for s in candidate_specs[1:]
|
||||
):
|
||||
# It does not matter which one we take if they are all the same:
|
||||
return candidate_gdc
|
||||
else:
|
||||
raise InstallError(
|
||||
"Cannot resolve ambiguity when detecting GDC that belongs to "
|
||||
"%{0}".format(self.compiler.spec),
|
||||
long_msg="The candidates are:{0}{0}{1}{0}".format(
|
||||
error_nl,
|
||||
error_nl.join(
|
||||
"{0} (cc: {1})".format(
|
||||
s.extra_attributes["compilers"]["d"],
|
||||
s.extra_attributes["compilers"]["c"],
|
||||
)
|
||||
for s in candidate_specs
|
||||
),
|
||||
),
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user