diff --git a/etc/spack/defaults/packages.yaml b/etc/spack/defaults/packages.yaml index ead2d872c7..f0596b0fe1 100644 --- a/etc/spack/defaults/packages.yaml +++ b/etc/spack/defaults/packages.yaml @@ -27,7 +27,8 @@ packages: fuse: [libfuse] gl: [glx, osmesa] glu: [mesa-glu, openglu] - golang: [gcc] + golang: [go, gcc] + go-external-or-gccgo-bootstrap: [go-bootstrap, gcc] iconv: [libiconv] ipp: [intel-ipp] java: [openjdk, jdk, ibm-java] diff --git a/var/spack/repos/builtin/packages/gcc/package.py b/var/spack/repos/builtin/packages/gcc/package.py index 67b065a107..f36980d8e7 100644 --- a/var/spack/repos/builtin/packages/gcc/package.py +++ b/var/spack/repos/builtin/packages/gcc/package.py @@ -206,9 +206,24 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage): provides("golang@:1.4", when="@5:") provides("golang@:1.6.1", when="@6:") provides("golang@:1.8", when="@7:") + provides("golang@:1.10", when="@8:") + provides("golang@:1.12", when="@9:") + provides("golang@:1.14", when="@10:") + provides("golang@:1.16", when="@11:") + provides("golang@:1.18", when="@11:") # GCC 4.6 added support for the Go programming language. # See https://gcc.gnu.org/gcc-4.6/changes.html conflicts("@:4.5", msg="support for Go has been added in GCC 4.6") + # aarch64 machines (including Macs with Apple silicon) can't use + # go-bootstrap because it pre-dates aarch64 support in Go. When not + # using an external go bootstrap go, These machines have to rely on + # Go support in gcc (which may require compiling a version of gcc + # with Go support just to satisfy this requirement). However, + # there's also a bug in some versions of GCC's Go front-end that prevents + # these versions from properly bootstrapping Go. (See issue #47771 + # https://github.com/golang/go/issues/47771 ) On the 10.x branch, we need + # at least 10.4. On the 11.x branch, we need at least 11.3: + provides("go-external-or-gccgo-bootstrap", when="gcc@10.4.0:10,11.3.0:target=aarch64:") # Go is not supported on macOS conflicts("platform=darwin", msg="Go not supported on MacOS") @@ -442,7 +457,7 @@ class Gcc(AutotoolsPackage, GNUMirrorPackage): @classproperty def executables(cls): - names = [r"gcc", r"[^\w]?g\+\+", r"gfortran", r"gdc"] + names = [r"gcc", r"[^\w]?g\+\+", r"gfortran", r"gdc", r"gccgo"] 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)] @@ -520,6 +535,9 @@ def determine_variants(cls, exes, version_str): elif "gcc" in basename: languages.add("c") compilers["c"] = exe + elif "gccgo" in basename: + languages.add("go") + compilers["go"] = exe elif "gdc" in basename: languages.add("d") compilers["d"] = exe diff --git a/var/spack/repos/builtin/packages/go-bootstrap/package.py b/var/spack/repos/builtin/packages/go-bootstrap/package.py index 7068a44c93..a622ffd72a 100644 --- a/var/spack/repos/builtin/packages/go-bootstrap/package.py +++ b/var/spack/repos/builtin/packages/go-bootstrap/package.py @@ -3,6 +3,8 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import re + from spack.package import * # THIS PACKAGE SHOULD NOT EXIST @@ -47,6 +49,25 @@ class GoBootstrap(Package): conflicts("os=monterey", msg="go-bootstrap won't build on new macOS") conflicts("target=aarch64:", msg="Go bootstrap doesn't support aarch64 architectures") + # This virtual package allows a fallback to gccgo for aarch64, + # where go-bootstrap cannot be built(aarch64 was added with Go 1.5) + provides("go-external-or-gccgo-bootstrap") + + # Support for aarch64 was added in Go 1.5, use an external package or gccgo instead: + conflicts("@:1.4", when="target=aarch64:") + + executables = ["^go$"] + + # When the user adds a go compiler using ``spack external find go-bootstrap``, + # this lets us get the version for packages.yaml. Then, the solver can avoid + # to build the bootstrap go compiler(for aarch64, it's only gccgo) from source: + @classmethod + def determine_version(cls, exe): + """Return the version of an externally provided go executable or ``None``""" + output = Executable(exe)("version", output=str, error=str) + match = re.search(r"go version go(\S+)", output) + return match.group(1) if match else None + def patch(self): if self.spec.satisfies("@:1.4.3"): # NOTE: Older versions of Go attempt to download external files that have @@ -72,7 +93,13 @@ def install(self, spec, prefix): install_tree(".", prefix) def setup_dependent_build_environment(self, env, dependent_spec): - env.set("GOROOT_BOOTSTRAP", self.spec.prefix) + """Set GOROOT_BOOTSTRAP: When using an external compiler, get its GOROOT env""" + if self.spec.external: + # Use the go compiler added by ``spack external find go-bootstrap``: + goroot = Executable(self.spec.prefix.bin.go)("env", "GOROOT", output=str) + else: + goroot = self.spec.prefix + env.set("GOROOT_BOOTSTRAP", goroot) def setup_build_environment(self, env): env.set("GOROOT_FINAL", self.spec.prefix) diff --git a/var/spack/repos/builtin/packages/go/package.py b/var/spack/repos/builtin/packages/go/package.py index e1425f06c8..b4f2c76959 100644 --- a/var/spack/repos/builtin/packages/go/package.py +++ b/var/spack/repos/builtin/packages/go/package.py @@ -152,14 +152,13 @@ class Go(Package): # aarch64 machines (including Macs with Apple silicon) can't use # go-bootstrap because it pre-dates aarch64 support in Go. These machines # have to rely on Go support in gcc (which may require compiling a version - # of gcc with Go support just to satisfy this requirement). However, - # there's also a bug in some versions of GCC's Go front-end that prevents - # these versions from properly bootstrapping Go. (See issue #47771 - # https://github.com/golang/go/issues/47771 ) On the 10.x branch, we need - # at least 10.4. On the 11.x branch, we need at least 11.3. + # of gcc with Go support just to satisfy this requirement) or external go: - if platform.machine() == "aarch64": - depends_on("gcc@10.4.0:10,11.3.0: languages=go", type="build") + # #27769: On M1/MacOS, platform.machine() may return arm64: + if platform.machine() in ["arm64", "aarch64"]: + # Use an external go compiler from packages.yaml/`spack external find go-bootstrap`, + # but fallback to build go-bootstrap@1.4 or to gcc with languages=go (for aarch64): + depends_on("go-external-or-gccgo-bootstrap", type="build") else: depends_on("go-bootstrap", type="build")