Skip to content

Commit

Permalink
ghc: add support for Apple Silicon with ghc 8.10.3
Browse files Browse the repository at this point in the history
This PR adds support to ghc.rb for Apple Silicon Macs. This PR removes the
external build of gmp in favor of using the in-tree one as the in-tree one
is statically linked these days (confirmed no external gmp references). The
version in-tree is 6.1.2 which does not build on Apple Silicon so it is
replaced by the formula with 6.2.1 which does.

In order to get a full install with a working arm64 binary we currently need
to build ghc in three steps:

 1) Install the ghc binaries for x86_64 into a temporary directory (this is
    also done for x86_64).

 2) Build a cross-compiler for arm64 using the x86_64 binary to bootstrap.

 3) Use either the x86_64 binaries (on x86_64) or the cross-compiler to build
    a native ghc for the system.

This PR relies on an extensive patch based on a PR to ghc 8.10.x. These
patches add support for arm64-apple-darwin and correct some build system
confusion between the ghc target name (aarch64-apple-darwin) and the llvm
target name (arm64-apple-darwin).

Some caveats:

 - This build takes awhile (over 2 hours). This is a significant build time
   for an M1 system given it is roughly twice as fast as a Core i9.

 - We can probably shorten the build time by using integer-simple and
   disabling other libraries but this formula is a stop-gap measure until
   upstream releases official support (ghc 9.x series).

 - There is no native code generator for arm64 at this time. The resulting
   binaries will likely be slower than if there was a native code generator.

Patch updated by @SeekingMeaning

Signed-off-by: Nathan Hjelm <[email protected]>
  • Loading branch information
hjelmn committed Feb 1, 2021
1 parent 775897a commit bf1112b
Showing 1 changed file with 76 additions and 20 deletions.
96 changes: 76 additions & 20 deletions Formula/ghc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class Ghc < Formula
url "https://downloads.haskell.org/~ghc/8.10.3/ghc-8.10.3-src.tar.xz"
sha256 "ccdc8319549028a708d7163e2967382677b1a5a379ff94d948195b5cf46eb931"
license "BSD-3-Clause"
revision 1

livecheck do
url "https://www.haskell.org/ghc/download.html"
Expand All @@ -20,10 +21,10 @@ class Ghc < Formula
depends_on "sphinx-doc" => :build

resource "gmp" do
url "https://ftp.gnu.org/gnu/gmp/gmp-6.2.1.tar.xz"
mirror "https://gmplib.org/download/gmp/gmp-6.2.1.tar.xz"
mirror "https://ftpmirror.gnu.org/gmp/gmp-6.2.1.tar.xz"
sha256 "fd4829912cddd12f84181c3451cc752be224643e87fac497b69edddadc49b4f2"
url "https://ftp.gnu.org/gnu/gmp/gmp-6.2.1.tar.bz2"
mirror "https://gmplib.org/download/gmp/gmp-6.2.1.tar.bz2"
mirror "https://ftpmirror.gnu.org/gmp/gmp-6.2.1.tar.bz2"
sha256 "eae9326beb4158c386e39a356818031bd28f3124cf915f8c5b1dc4c7a36b4d7c"
end

# https://www.haskell.org/ghc/download_ghc_8_10_1.html#macosx_x86_64
Expand All @@ -41,34 +42,89 @@ class Ghc < Formula
end
end

# Fixes for macOS ARM
# https://gitlab.haskell.org/ghc/ghc/-/merge_requests/4795
patch do
url "https://raw.githubusercontent.com/Homebrew/formula-patches/f6c5879312437dd58087e4885a86ac536a128ea9/ghc/ghc-8.10.3.patch"
sha256 "7aee4d6eeb37676450c84da6205e79b5ff8c9f2d4e5763f5bbf5b1c990d002b3"
end

def install
ENV["CC"] = ENV.cc
ENV["LD"] = "ld"
ENV["PYTHON"] = Formula["[email protected]"].opt_bin/"python3"

# Build a static gmp rather than in-tree gmp, otherwise all ghc-compiled
# executables link to Homebrew's GMP.
gmp = libexec/"integer-gmp"

# GMP *does not* use PIC by default without shared libs so --with-pic
# is mandatory or else you'll get "illegal text relocs" errors.
resource("gmp").stage do
system "./configure", "--prefix=#{gmp}", "--with-pic", "--disable-shared",
"--build=#{Hardware.oldest_cpu}-apple-darwin#{OS.kernel_version.major}"
system "make"
system "make", "install"
end

args = ["--with-gmp-includes=#{gmp}/include",
"--with-gmp-libraries=#{gmp}/lib"]
args = []

resource("binary").stage do
binary = buildpath/"binary"

system "./configure", "--prefix=#{binary}", *args
ENV.deparallelize { system "make", "install" }

ENV.prepend_path "PATH", binary/"bin"
ENV["GHC"] = binary/"bin/ghc"
end

cpu = if Hardware::CPU.arm?
"arm64"
else
Hardware.oldest_cpu
end

# Replace in-tree gmp with 6.2.1 which supports arm64.
rm "libraries/integer-gmp/gmp/gmp-tarballs/gmp-6.1.2-nodoc.tar.bz2", force: true
cp resource("gmp").cached_download, "libraries/integer-gmp/gmp/gmp-tarballs/gmp-6.2.1-nodoc.tar.bz2"

# There is no native codegen for ARM64 yet.
if Hardware::CPU.arm?
args << "--enable-unregisterised"

# The Xcode compiler is a cross compiler (ARM64/x86_64) but ghc's configure script will look for
# the standard tool names. Go ahead and create the required names. We can not just use symbolic
# links for gcc, nm, or ar as this confuses the command line tools.

tmp = buildpath/"binary-cross"

tmpbin = tmp/"bin"
mkdir_p tmpbin

make_contents = lambda { |command|
<<~EOF
#!/bin/bash
/usr/bin/#{command} $@
EOF
}

File.write(tmpbin/"#{cpu}-apple-darwin-nm", make_contents.call("nm"), { perm: 0755 })
File.write(tmpbin/"#{cpu}-apple-darwin-ar", make_contents.call("ar"), { perm: 0755 })
# This gcc forces ARM64 as the target. It may be invoked by an x86_64 binary (which would have
# selected x86_64 which is not what we want.
File.write(tmpbin/"#{cpu}-apple-darwin-gcc", make_contents.call("gcc -arch arm64"), { perm: 0755 })

ENV.prepend_path "PATH", tmpbin

# Basic build setup for the cross compile. This is based on the documentation for building a
# cross compiler for targetting iOS.
(buildpath/"mk/build.mk").write <<~EOS
BuildFlavour = perf-cross
HADDOCK_DOCS = NO
EOS

ENV["CC"] = "#{cpu}-apple-darwin-gcc"

# Run configure as x86_64 to ensure it correctly detects the build host as x86_64. Otherwise it might
# not cross-compile correctly.
system "arch", "-x86_64", "./configure", "--prefix=#{tmp}", "--target=#{cpu}-apple-darwin", *args
system "make"

ENV.deparallelize { system "make", "install" }

# clean up before rebuilding
system "make", "distclean"
rm "#{buildpath}/mk/build.mk", force: true

ENV["CC"] = ENV.cc
ENV["GHC"] = tmp/"bin/ghc"
end

system "./configure", "--prefix=#{prefix}", *args
Expand Down

0 comments on commit bf1112b

Please sign in to comment.