summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Kosukhin <sergey.kosukhin@mpimet.mpg.de>2022-09-12 11:27:35 +0200
committerGitHub <noreply@github.com>2022-09-12 11:27:35 +0200
commit7a93eddf1c69e59a3f0f33729f9c57eb50d81df1 (patch)
tree1db0dc34e57b9706f74e7c69ef04eb8e436ee1f8
parentf7fbfc54b341b8bda3e30cb196c1b71e2ec3f68a (diff)
downloadspack-7a93eddf1c69e59a3f0f33729f9c57eb50d81df1.tar.gz
spack-7a93eddf1c69e59a3f0f33729f9c57eb50d81df1.tar.bz2
spack-7a93eddf1c69e59a3f0f33729f9c57eb50d81df1.tar.xz
spack-7a93eddf1c69e59a3f0f33729f9c57eb50d81df1.zip
gcc: add support for the D language (GDC) (#32330)
-rw-r--r--var/spack/repos/builtin/packages/gcc/package.py160
1 files changed, 157 insertions, 3 deletions
diff --git a/var/spack/repos/builtin/packages/gcc/package.py b/var/spack/repos/builtin/packages/gcc/package.py
index 44e5c8f531..c7d0b0b0bf 100644
--- a/var/spack/repos/builtin/packages/gcc/package.py
+++ b/var/spack/repos/builtin/packages/gcc/package.py
@@ -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 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
@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 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
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 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
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 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
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 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage):
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
+ ),
+ ),
+ )