How to cross-compile Go app for Apple Silicon (M1)
Tags: go, crosscompile, applesilicon, m1
Published: 2021-05-27 19:41:17

This is the first part in the series on how we prepared our application to run on M1 (Apple Silicon).

At [Tidal Migrations](https://tidalmigrations.com/) we build our CLI application — [Tidal Tools](https://get.tidal.sh/) — to make it easier for our customers to deal with all sorts of data necessary for their cloud migrations journey. The CLI app could be run anywhere — on a manager’s Microsoft Windows workstation, on a developer’s Apple MacBook Pro, or even on a Linux server since *a long time ago in a datacenter far, far away…* Because of this, having the ability to build the app for different operating systems was the top priority for us since the beginning of the development. That’s why we choose Go programming language for our CLI application development.

[Go](https://golang.org/) (sometimes referred as _Golang_) is a statically typed, compiled programming language designed at Google. Among other awesome features of Go, there is one which was crucial for us — the ability to cross-compile code for different operating systems and architectures. In other words, it is possible for a developer running, for example, macOS on her laptop to build an application suitable for running on Windows or Linux, or any other operating system which is supported by the Go compiler.

The following short walkthrough will guide you through the process of creating a simple Hello world application and building it for Linux, Windows and macOS on M1.

Let’s start with writing the actual code for our application:

```go
// hello.go

package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Printf(
		"Hello world from %s/%s\n",
		runtime.GOOS,
		runtime.GOARCH,
	)
}
```

If we build it (with `go build hello.go` command) and run the binary (`./hello`) it should display something like the following:

```
Hello world from linux/amd64
```

```
Hello world from windows/amd64
```

or

```
Hello world from darwin/arm64
```

That depends on the OS and architecture of the computer where we build our app. But as I mentioned earlier, it is possible to build Go applications for operating systems and architectures different than the one where we run the build process. With modern Go tools it is pretty straightforward. All we need to do is to set some specific environment variables — `GOOS` and `GOARCH` — and voilà, we build binaries for different operating systems and architectures.

At first, let's build our “Hello world” app for Microsoft Windows:

```
GOOS=windows GOARCH=amd64 go build hello.go
```

If we run `ls`, we'd see that a new file (`hello.exe`) appeared in the current directory:

```
$ ls
hello.exe  hello.go
```

Let's determine a type of the `hello.exe` file using `file` command:

```
$ file hello.exe
hello.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows
```

Now, let's build our application for some old (32-bit) Linux:

```
GOOS=linux GOARCH=386 go build -o hello-linux-386 hello.go
```

A new file (`hello-linux-386`) should appear:

```
$ ls
hello.exe  hello.go  hello-linux-386
```

And it should be of 32-bit executable type:

```
file hello-linux-386 
hello-linux-386: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, ..., not stripped
```

And finally, let's build the same application for Apple Silicon:

```
GOOS=darwin GOARCH=arm64 go build -o hello-macos-arm64 hello.go
```

Running that `go build` command should create the third binary in our folder:

```
$ ls
hello.exe  hello.go  hello-linux-386  hello-macos-arm64
```

The type of the file is the following:

```
$ file hello-macos-arm64 
hello-macos-arm64: Mach-O 64-bit arm64 executable, flags:<|DYLDLINK|PIE>
```

![Hello world](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sv73xkxrtaik65xgidwc.png)

That's it! With this simple trick you can build Go applications for different operating systems and architectures on your laptop or a single build server.

I hope you enjoyed this post! Stay tuned to learn more about our journey towards M1 version release!