Skip to content

Commit 1c56be4

Browse files
committed
feat: support Windows on Arm
1 parent 4790617 commit 1c56be4

7 files changed

+155
-8
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
.vscode
22
.idea
3-

Dockerfile

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
ARG GO_VERSION=1.20
2+
FROM golang:${GO_VERSION}-bookworm as builder
3+
ARG GO_VERSION
4+
ARG LLVM_MINGW64_VER=20240606
5+
ARG LLVM_MINGW64_SRC="https://github.com/mstorsjo/llvm-mingw/releases/download"
6+
ENV LLVM_MINGW64_VER="${LLVM_MINGW64_VER}"
7+
ENV LLVM_MINGW64_SRC="$LLVM_MINGW64_SRC"
8+
9+
WORKDIR /tmp
10+
COPY --chmod=0755 scripts/setup-llvm-mingw64.sh /tmp/
11+
RUN /tmp/setup-llvm-mingw64.sh
12+
13+
ARG GO_VERSION
214
FROM golang:${GO_VERSION}-bookworm
315

416
RUN apt update &&\
517
apt install \
618
make mingw-w64 bash --yes
7-
ADD docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
8-
RUN chmod +x /usr/bin/docker-entrypoint.sh
19+
COPY --chmod=0755 scripts/docker-entrypoint.sh /usr/bin/docker-entrypoint.sh
20+
COPY --chmod=0755 scripts/install-llvm-mingw64.sh /tmp/install-llvm-mingw64.sh
21+
COPY --from=builder /tmp/llvm-mingw64 /tmp/llvm-mingw64
22+
RUN /tmp/install-llvm-mingw64.sh /tmp/llvm-mingw64
923
ENV PATH=/go/bin:$PATH \
1024
CGO_ENABLED=1 \
1125
GOOS=windows

Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
IMG_NAME = x1unix/go-mingw-test
2+
DOCKER_OUT_TYPE=docker
23

34
.PHONY: image
45
image:
56
@if [ -z $(GO_VERSION) ]; then echo "usage: 'make image GO_VERSION=[GO VERSION NUMBER]'" && exit 1; fi; \
67
echo ":: Building image..." &&\
7-
docker build -t $(IMG_NAME):$(GO_VERSION) -f Dockerfile . --build-arg GO_VERSION=$(GO_VERSION)
8+
docker build --output=type=$(DOCKER_OUT_TYPE) -t $(IMG_NAME):$(GO_VERSION) -f Dockerfile . --build-arg GO_VERSION=$(GO_VERSION)

README.md

+15-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ Docker image for building Go binaries for **Windows** with MinGW-w64 toolchain b
77

88
Image provides simple cross-compilation environment for windows 32 and 64bit builds.
99

10+
**Supports Windows on Arm!**
11+
1012
## Supported Architectures
1113

1214
Here is a list of supported host and target architectures:
1315

1416
| Host Architecture | Win x86 | Win x86-64 | Win Arm |
1517
| ------------------- | ------- | ---------- | ------- |
16-
| **arm64 / aarch64** ||| 🚫 |
17-
| **amd64** ||| 🚫 |
18+
| **arm64 / aarch64** ||| |
19+
| **amd64** ||| |
1820

1921
## Usage
2022

@@ -39,7 +41,17 @@ docker run --rm -it -v /YourPackageSrc:/go/work \
3941

4042
You will get compiled Windows binary.
4143

42-
**For 32-bit toolchain**
44+
#### Windows On Arm
45+
46+
Set `GOARCH=arm64` to build ARM Windows binary:
47+
48+
```shell
49+
docker run --rm -it -e GOARCH=arm64 -v /YourPackageSrc:/go/work \
50+
-w /go/work \
51+
x1unix/go-mingw go build .
52+
```
53+
54+
#### For 32-bit toolchain
4355

4456
To build a 32-bit executable, set `GOARCH=386` variable:
4557

docker-entrypoint.sh renamed to scripts/docker-entrypoint.sh

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@ amd64)
1616
export CXX=i686-w64-mingw32-g++
1717
export CC=i686-w64-mingw32-gcc
1818
;;
19+
arm64)
20+
export CXX_FOR_TARGET=aarch64-w64-mingw32-g++
21+
export CC_FOR_TARGET=aarch64-w64-mingw32-gcc
22+
export CXX=aarch64-w64-mingw32-g++
23+
export CC=aarch64-w64-mingw32-gcc
24+
;;
1925
*)
20-
echo "Unsupported GOARCH variable value '$GOARCH'. Please set GOARCH environment variable to 'amd64' or '386'"
26+
echo "Unsupported GOARCH variable value '$GOARCH'. Please set GOARCH environment variable to 'amd64', 'arm64' or '386'"
2127
exit 2
2228
;;
2329
esac

scripts/install-llvm-mingw64.sh

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
set -o pipefail
4+
5+
trap 'echo "$0: Error on line $LINENO" >&2' ERR
6+
7+
src="$1"
8+
if [ -z "$src" ]; then
9+
echo "Error: missing source dir"
10+
exit 1
11+
fi
12+
13+
base_dir='/usr'
14+
15+
echo ":: Installing llvm-mingw64..."
16+
echo "Source dir: $src"
17+
18+
cd "$src" || exit 1
19+
find . -mindepth 1 -maxdepth 1 -type d ! -name . | while read -r subdir; do
20+
dst_dir="$(basename "$subdir")"
21+
22+
case "$dst_dir" in
23+
bin)
24+
perm=755
25+
;;
26+
*)
27+
perm=644
28+
;;
29+
esac
30+
31+
find "$subdir" -type f | while read -r file; do
32+
dst="$base_dir/${file/.\//}"
33+
mkdir -p "$(dirname "$dst")"
34+
install -m $perm "$file" "$dst"
35+
done
36+
done
37+
38+
echo ":: Restoring symlinks..."
39+
while IFS= read -r line; do
40+
src=$(echo "$line" | awk '{print $1}')
41+
src="$base_dir/$src"
42+
43+
dest=$(echo "$line" | awk '{print $2}')
44+
dest="$(realpath "$base_dir/$dest")"
45+
ln -s "$dest" "$src"
46+
done <symlinks.txt
47+
48+
echo ":: Cleanup"
49+
cd ..
50+
rm -rf "$src"

scripts/setup-llvm-mingw64.sh

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
set -o pipefail
4+
5+
trap 'echo "$0: Error on line $LINENO" >&2' ERR
6+
7+
if [ -z "$LLVM_MINGW64_SRC" ]; then
8+
echo "Error: LLVM_MINGW64_SRC is undefined"
9+
env
10+
exit 1
11+
fi
12+
13+
if [ -z "$LLVM_MINGW64_VER" ]; then
14+
echo "Error: LLVM_MINGW64_VER is undefined"
15+
env
16+
exit 1
17+
fi
18+
19+
apt update && apt install xz-utils --yes
20+
21+
case "$(uname -m)" in
22+
aarch64 | arm64)
23+
m_arch="aarch64"
24+
;;
25+
x86_64 | amd64)
26+
m_arch="x86_64"
27+
;;
28+
*)
29+
echo "Error: unsupported architecture $(uname -m)"
30+
exit 1
31+
;;
32+
esac
33+
34+
pkg_dir="llvm-mingw-$LLVM_MINGW64_VER-ucrt-ubuntu-20.04-$m_arch"
35+
pkg_file="$pkg_dir.tar.xz"
36+
src_url="$LLVM_MINGW64_SRC/$LLVM_MINGW64_VER/$pkg_file"
37+
echo ":: Downloading $src_url ..."
38+
wget "$src_url"
39+
# wget -q --spider "$src_url"
40+
41+
if [ ! -f "$pkg_file" ]; then
42+
echo "Error: can't find downloaded file $pkg_file"
43+
ls -la
44+
exit 1
45+
fi
46+
47+
echo ":: Extracting file..."
48+
tar -xf "$pkg_file"
49+
rm "$pkg_file"
50+
51+
echo ":: Preparing file list..."
52+
mv "$pkg_dir" llvm-mingw64
53+
cd llvm-mingw64
54+
55+
# Keep llvm-mingw64 only for arm target to avoid conflict with gcc-mingw64
56+
rm bin/x86_64* bin/i686*
57+
rm -rf i686-w64-mingw32 x86_64-w64-mingw32
58+
59+
# Backup symlinks
60+
find . -type l | while read -r symlink; do
61+
src="${symlink/.\//}"
62+
dst="$(dirname "$src")/$(readlink "$symlink")"
63+
echo "$src $dst" >>symlinks.txt
64+
rm "$symlink"
65+
done

0 commit comments

Comments
 (0)