Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ghc: add support for Apple Silicon #65997

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should not need to build an unregistered build. The llvm backend should just work fine on arm64. We used to have some bare support for iphone from 8.4 onwards already even though it wasn't fully sound.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the LLVM build, you'll need to depend on a recent llvm (and can pretty safely ignore the "not supported LLVM version warnings", the llvm IR hasn't changed to the point where it breaks as far as I can tell). Make sure to set LLC and OPT to the respective tool paths.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any special requirements from the LLVM backend, or can ghc use Homebrew's LLVM? https://github.com/Homebrew/homebrew-core/blob/master/Formula/llvm.rb

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from having opt and llc and supporting the necessary targets, no there are no special requirements.

ghc will produce textual llvm Ir, feed that into opt, and then into llc. Then GHC will perform some sadly necessary assembly fixups on assembly file and feed that into as to produce the object file.


# 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