Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Compile Go for Apple Silicon (M1)

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
@kynrai
Copy link

kynrai commented Dec 1, 2020

Works perfectly for me on a M1 MacBook Pro

@sirkon
Copy link

sirkon commented Dec 1, 2020

@kynrai and so how the native compiler performance on M1?

@felipecsl
Copy link

felipecsl commented Dec 2, 2020

Worked perfectly for me too 👍
By the way, this should no longer be necessary now:

git fetch https://go.googlesource.com/go refs/changes/58/272258/1 && \
git checkout FETCH_HEAD

@bmess
Copy link

bmess commented Dec 11, 2020

thank you!

@Dids
Copy link
Author

Dids commented Dec 11, 2020

Worked perfectly for me too 👍
By the way, this should no longer be necessary now:

git fetch https://go.googlesource.com/go refs/changes/58/272258/1 && \
git checkout FETCH_HEAD

While this is true, I didn't want to use the master branch either, as this could potentially break or differ from the instructions above. I could definitely update it to a newer ref though!

@Fullstop000
Copy link

Fullstop000 commented Dec 17, 2020

Worked perfectly on my M1 MacBook Air

@vlw
Copy link

vlw commented Dec 31, 2020

Failed to build bootstrap

#### Copying to ../../go-darwin-arm64-bootstrap

#### Cleaning ../../go-darwin-arm64-bootstrap

#### Building ../../go-darwin-arm64-bootstrap

Building Go cmd/dist using /var/folders/3x/6lgl1n4d51zdddzdplnh5mgw0000gn/T/go-arm-bootstrap.wcCnw0y9/go. (go1.15.5 darwin/amd64)
Building Go toolchain1 using /var/folders/3x/6lgl1n4d51zdddzdplnh5mgw0000gn/T/go-arm-bootstrap.wcCnw0y9/go.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 using go_bootstrap and Go toolchain2.
Building packages and commands for host, darwin/amd64.
# runtime/cgo
gcc_darwin_amd64.c:62:15: error: unknown token in expression
<inline asm>:1:12: note: instantiated into assembly here
gcc_darwin_amd64.c:62:15: error: invalid operand
<inline asm>:1:12: note: instantiated into assembly here
go tool dist: FAILED: /var/folders/3x/6lgl1n4d51zdddzdplnh5mgw0000gn/T/go-arm-bootstrap.wcCnw0y9/go-darwin-arm64-bootstrap/pkg/tool/darwin_amd64/go_bootstrap install -gcflags=all= -ldflags=all= std cmd: exit status 2

MacBook Air M1, Big Sur 11.1

@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

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