DEV Community

Cover image for Building Go packages for Windows on ARM
Denis Sedchenko
Denis Sedchenko

Posted on

Building Go packages for Windows on ARM

Intro

Recently, Qualcomm announced list of laptops that will have their new Snapdragon X Elite chip which claim to have the same performance as Apple's M3 processor.

This means that in a near future, market will see more and more Windows on ARM laptops and we as developers should be prepared to that.

This article is structured in Q&A sections to briefly explain the topic.

WoA can emulate x86, isn't it?

Although Windows on ARM (WoA) supports x86 and x86-64 emulation, some features like vector instructions (like AVX2) might be not supported, also emulation brings some performance penalty.

People who use libraries like simdjson might be at risk.

Doesn't Go already support cross compilation?

Go offers out-of-box cross compilation support, including ARM64 for Windows, but this doesn't cover CGO.

That means, any program that uses CGO libraries like sqlite3 will require C and/or C++ toolchain for cross-compilation.

Okay, isn't MinGW already cover that?

Most popular solution for cross-compilation from Windows and Linux is MinGW.

Unfortunately, MinGW doesn't support ARM64 target.

MSYS2 toolchain provide ARM support but available only for Windows.

That means that in order to build programs for Windows on ARM on a Linux machine, a different option should be considered as MinGW doesn't support arm64 target.

So how do I build a program with CGO for WoA?

Don't worry, this case is already covered.

There is a llvm-based alternative toolchain that supports WoA - llvm-mingw.

Unfortunately it's not available in most distros except Arch Linux, but you still can download prebuilt binaries from releases page.

Is there a more convenient way to use llvm-mingw?

Yes, sure!

There is a special Docker image with toolchain for all Windows architectures - amd64, x86 and arm64.

Image is called x1unix/go-mingw and offers arm64 target support since go 1.21.

Image uses MinGW for x86 and llvm-mingw for arm64 target.

How to use it?

It's quite simple, just pull the image and call go build command with GOARCH=arm64 environment variable.

For example, let's take a simple WinAPI CGO example from here and build it using Docker image:

Go code
package main

/*
#cgo LDFLAGS: -lkernel32
#include <windows.h>
#include <stdio.h>

// Function to show a MessageBox using WinAPI
void hello() {
  SYSTEM_INFO si;
  ZeroMemory( & si, sizeof(SYSTEM_INFO));
  GetSystemInfo( & si);
  char * arch;
  switch (si.wProcessorArchitecture) {
  case PROCESSOR_ARCHITECTURE_AMD64:
    arch = "AMD64";
    break;
  case PROCESSOR_ARCHITECTURE_INTEL:
    arch = "x86";
    break;
  case PROCESSOR_ARCHITECTURE_ARM:
    arch = "ARM";
    break;
  case PROCESSOR_ARCHITECTURE_ARM64:
    arch = "ARM64";
    break;
  case PROCESSOR_ARCHITECTURE_IA64:
    arch = "IA";
    break;
  default:
    arch = "Unknown";
    break;
  }

  char message[30];
  sprintf(message, "Hello from CGO on %s", arch);

  MessageBox(NULL, message, "Hello World", MB_OK);
}
*/
import "C"
import "fmt"

func main() {
    fmt.Println("Calling C function to open a MessageBox...")
    C.hello()
}
Enter fullscreen mode Exit fullscreen mode

# Go version to use. WoA supported since Go 1.21.
export GO_VERSION=1.22

docker run --rm -it -e GOARCH=arm64 \
    -v .:/go/work -w /go/work \
    x1unix/go-mingw:$GO_VERSION \
    go build -o hello.exe .
Enter fullscreen mode Exit fullscreen mode

Result

After building a program, let's try to run it inside any VM with Windows on Arm.

Parallels Workstation is used for this example.

Image description

How can I integrate this into my CI?

As this is a plain Docker image, it can be easily used both in GitHub Actions and Gitlab CI.

Please check CI templates here.

Top comments (0)