This is the first part in the series on how we prepared our application to run on M1 (Apple Silicon).
At Tidal Migrations we build our CLI application — Tidal Tools — 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 (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:
// 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>
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!
Top comments (2)
Do I need an Apple developer account (paid)?
No, you don't.