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")
|
version("4.5.4", sha256="eef3f0456db8c3d992cbb51d5d32558190bc14f3bc19383dd93acc27acc6befc")
|
||||||
|
|
||||||
# We specifically do not add 'all' variant here because:
|
# 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.
|
# In that respect, the name 'all' is rather misleading.
|
||||||
# (ii) Languages other than c,c++,fortran are prone to configure bug in GCC
|
# (ii) Languages other than c,c++,fortran are prone to configure bug in GCC
|
||||||
# For example, 'java' appears to ignore custom location of zlib
|
# For example, 'java' appears to ignore custom location of zlib
|
||||||
# (iii) meaning of 'all' changes with GCC version, i.e. 'java' is not part
|
# (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
|
# of gcc7. Correctly specifying conflicts() and depends_on() in such a
|
||||||
# case is a PITA.
|
# 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(
|
variant(
|
||||||
"languages",
|
"languages",
|
||||||
default="c,c++,fortran",
|
default="c,c++,fortran",
|
||||||
@ -102,6 +106,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
|||||||
"brig",
|
"brig",
|
||||||
"c",
|
"c",
|
||||||
"c++",
|
"c++",
|
||||||
|
"d",
|
||||||
"fortran",
|
"fortran",
|
||||||
"go",
|
"go",
|
||||||
"java",
|
"java",
|
||||||
@ -234,6 +239,45 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
|||||||
# See https://gcc.gnu.org/gcc-5/changes.html
|
# See https://gcc.gnu.org/gcc-5/changes.html
|
||||||
conflicts("languages=jit", when="@:4")
|
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"):
|
with when("+nvptx"):
|
||||||
depends_on("cuda")
|
depends_on("cuda")
|
||||||
resource(
|
resource(
|
||||||
@ -260,6 +304,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
|||||||
conflicts("languages=jit")
|
conflicts("languages=jit")
|
||||||
conflicts("languages=objc")
|
conflicts("languages=objc")
|
||||||
conflicts("languages=obj-c++")
|
conflicts("languages=obj-c++")
|
||||||
|
conflicts("languages=d")
|
||||||
# NVPTX build disables bootstrap
|
# NVPTX build disables bootstrap
|
||||||
conflicts("+bootstrap")
|
conflicts("+bootstrap")
|
||||||
|
|
||||||
@ -383,7 +428,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
|
|||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
def executables(cls):
|
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"]
|
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)]
|
return [r"".join(x) for x in itertools.product(names, suffixes)]
|
||||||
|
|
||||||
@ -443,7 +488,14 @@ def determine_version(cls, exe):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def determine_variants(cls, exes, version_str):
|
def determine_variants(cls, exes, version_str):
|
||||||
languages, compilers = set(), {}
|
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)
|
basename = os.path.basename(exe)
|
||||||
if "g++" in basename:
|
if "g++" in basename:
|
||||||
languages.add("c++")
|
languages.add("c++")
|
||||||
@ -454,6 +506,9 @@ def determine_variants(cls, exes, version_str):
|
|||||||
elif "gcc" in basename:
|
elif "gcc" in basename:
|
||||||
languages.add("c")
|
languages.add("c")
|
||||||
compilers["c"] = exe
|
compilers["c"] = exe
|
||||||
|
elif "gdc" in basename:
|
||||||
|
languages.add("d")
|
||||||
|
compilers["d"] = exe
|
||||||
variant_str = "languages={0}".format(",".join(languages))
|
variant_str = "languages={0}".format(",".join(languages))
|
||||||
return variant_str, {"compilers": compilers}
|
return variant_str, {"compilers": compilers}
|
||||||
|
|
||||||
@ -469,6 +524,7 @@ def validate_detected_spec(cls, spec, extra_attributes):
|
|||||||
for constraint, key in {
|
for constraint, key in {
|
||||||
"languages=c": "c",
|
"languages=c": "c",
|
||||||
"languages=c++": "cxx",
|
"languages=c++": "cxx",
|
||||||
|
"languages=d": "d",
|
||||||
"languages=fortran": "fortran",
|
"languages=fortran": "fortran",
|
||||||
}.items():
|
}.items():
|
||||||
if spec.satisfies(constraint, strict=True):
|
if spec.satisfies(constraint, strict=True):
|
||||||
@ -720,6 +776,18 @@ def configure_args(self):
|
|||||||
options.append("--with-boot-ldflags=" + boot_ldflags)
|
options.append("--with-boot-ldflags=" + boot_ldflags)
|
||||||
options.append("--with-build-config=spack")
|
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
|
return options
|
||||||
|
|
||||||
# run configure/make/make(install) for the nvptx-none target
|
# 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)
|
env.set(lang.upper(), abspath)
|
||||||
# Stop searching filename/regex combos for this language
|
# Stop searching filename/regex combos for this language
|
||||||
break
|
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