Skip to content

Instantly share code, notes, and snippets.

@Dids
Last active September 25, 2023 01:55
Show Gist options
  • Star 41 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Dids/dbe6356377e2a0b0dc8eacb0101dc3a7 to your computer and use it in GitHub Desktop.
Save Dids/dbe6356377e2a0b0dc8eacb0101dc3a7 to your computer and use it in GitHub Desktop.
Compile Go for Apple Silicon (M1)

NOTICE: This guide is no longer relevant, as a lot has changed over time and Go supports Apple Silicon natively just fine now!

Compile Go for Apple Silicon (M1)

Follow these short instructions on how to compile Go for Apple Silicon (M1). From here on out, we may simply refer to it as the "ARM device".

This entire process should only take about 5-10 minutes, but please read through everything carefully, in order to avoid any potential issues along the way.

Note that at the time of writing this, Go was not yet officially available for Apple's ARM.

Additionally it should be noted that this guide expects you to only be working on the ARM device, and not to have Go installed (yet).

Brief introduction

In order to compile the Go runtime, we will first need the Go toolchain. Since neither the Go runtime nor the toolchain exists for our target platform yet, we will have to compile both ourselves.

We will begin by using an x86 version of the Go runtime, which we will use to "bootstrap" (compile) our ARM toolchain.

Finally, we will finish it all off by compiling the Go runtime for ARM, using our previously compiled ARM toolchain.

Initial preparations

We will need to prepare a working directory, which will contain all of our temporary files.

Start by running the following command:

export GO_TMP=$(mktemp -udt go-arm-bootstrap) && \
  mkdir -p $GO_TMP && \
  echo $GO_TMP

Verify that the output of the last command is similar to the following:

/var/folders/8x/8n5pkxt51f3c4qxgc1f00qyh0000gn/T/go-arm-bootstrap.iHw5D8RG

Next we will install the x86 version of the Go runtime, which will be used as our compiler for the custom toolchain (runs with Rosetta):

cd $GO_TMP && \
  curl -Ls https://golang.org/dl/go1.15.5.darwin-amd64.tar.gz | tar -xjf -

Now we can move on to bootstrapping/compiling the toolchain, then finally compiling the Go runtime.

Bootstrapping the toolchain

The following commands will download an Apple Silicon specific patch/commit of Go, then bootstrap the toolchain using the x86 Go runtime as the compiler, ultimately creating our custom ARM toolchain in a new directory:

git clone https://go.googlesource.com/go $GO_TMP/go-bootstrap && \
  cd $GO_TMP/go-bootstrap && \
  git fetch https://go.googlesource.com/go refs/changes/58/272258/1 && \
  git checkout FETCH_HEAD && \
  cd $GO_TMP/go-bootstrap/src && \
  arch --x86_64 env GOROOT_BOOTSTRAP=$GO_TMP/go GODEBUG=asyncpreemptoff=1 GOOS=darwin GOARCH=arm64 ./bootstrap.bash

Compiling the runtime

NOTE: We're running make.bash instead of all.bash, as at the time of writing this, the tests that are part of the building process partially fail.

Now that we have our custom ARM toolchain, we can compile our custom ARM runtime with similar commands (note that we're running the "installation" as root):

export GO_RUNTIME=$GO_TMP/go-runtime && \
  git clone https://go.googlesource.com/go $GO_RUNTIME && \
  cd $GO_RUNTIME && \
  git fetch https://go.googlesource.com/go refs/changes/58/272258/1 && \
  git checkout FETCH_HEAD && \
  cd $GO_RUNTIME/src && \
  arch --arm64e env GOROOT_BOOTSTRAP=$GO_TMP/go-darwin-arm64-bootstrap ./make.bash && \
  sudo --preserve-env=GO_RUNTIME zsh -c '\
    mv $GO_RUNTIME /usr/local/opt/go && \
    chown -R root:wheel /usr/local/opt/go'

At this point, all you need to do is add /usr/local/opt/go/bin to your PATH environment variable, eg. through your ~/.zshrc configuration file. You may also need to set additional environment variables that are Go specific, such as GOROOT or GOPATH.

Here is an example of how you might set the path environment variables:

export GOPATH=$HOME/go
export PATH=$PATH:/usr/local/opt/go/bin:$GOPATH/bin
@webcpu
Copy link

webcpu commented Jun 30, 2021

There is a bug. Arm64 compiler can't use all of your CPU cores.
Workaround:
export GOMAXPROCS=8

before
go build ./cmd/saas/main.go 1.39s user 0.58s system 118% cpu 1.662 total
after
go build ./cmd/saas/main.go 0.43s user 0.51s system 335% cpu 0.283 total

@davidrenne
Copy link

@Dids hey Pauli, shouldnt this be deleted as a public gist? I compile to m1 now with just GOOS=darwin GOARCH=arm64 and it can run on an M1.

I found this when searching how to do it, but that works fine in latest go version. Isnt this just a misleading gist now? Please delete or make private if so, so the search engines cannot find it.

ty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment