Golang là một ngôn ngữ mạnh mẽ, được đánh giá là khá trong sáng và dễ học hơn nhiều so với một số ngôn ngữ khác như C/C++. Kèm theo đó là một số tính năng “đặc sản” nhà Go như goroutines, garbage collection, bộ packages phong phú đi kèm, v.v.. Thế nên Go luôn là sự lựa chọn đầu tiên đối với các developers cần một ngôn ngữ build app nhanh chóng nhưng đảm bảo được performance
Thêm vào đó, Go có thể build trên hầu hết các nền tảng Linux, Windows, MacOS và cả WebAssembly, trên hầu hết các kiến trúc i386, arm, amd64, mips,.. Một số anh em dev gọi đó là cross-platform hay multi-platform
Tuy nhiên, mặc định Go sẽ build binary file dựa trên cấu hình của máy host. Nghĩa là khi build trên máy với OS=linux Arch=amd64, thì bạn không thể vác file đó chạy trên máy OS=linux Arch=arm như Raspberry Pi chẳng hạn. Muốn build cho mạch nhúng như Raspberry Pi, chúng ta phải set 2 biến môi trường là GOOS
và GOARCH
để Go compiler hiểu chúng ta muốn build cho một platform cụ thể nào đó. Ví dụ: GOOS=linux GOARCH=arm go build .
Khá là phiền phức và rắc rối nếu chúng ta muốn build hàng loạt cho tất cả các platforms mà chúng ta muốn hỗ trợ. Script sau đây sẽ giúp bạn đơn giản hóa vấn đề đó
1. Platforms file
Trước tiên, chúng ta cần define một file như platforms.txt
bao gồm các platforms mà chương trình của chúng ta support. Để lấy được list các platform mà Go support chúng ta chạy lệnh go tool dist list
, bạn sẽ nhận được danh sách như sau
# >go tool dist list
aix/ppc64
android/amd64
android/arm64
linux/386
linux/amd64
linux/arm64
# ...
windows/386
windows/amd64
windows/arm
Notes: Tuy Go có hỗ trợ build cho Android tuy nhiên nó yêu cầu bạn phải cài đặt Android NDK để làm việc
File platforms.txt
của mình sẽ support một số platforms phổ biến, nội dung nó như sau:
darwin/amd64
darwin/arm64
linux/amd64
linux/arm
windows/386
windows/amd64
windows/arm
2. Scripting
Mình sẽ thực hiện viết bash script, mình cũng comment trong code để giải thích
#!/bin/bash
# Chúng ta sẽ pass tên ứng dụng thông qua cli, vd: bash ./build.sh hello-world
APP_NAME_ARG=$1
APP_NAME="${APP_NAME_ARG:-go-app}"
WORKING_DIR="${PWD}"
PLATFORMS_FILE="platforms.txt"
FULL_PATH_PLATFORMS_FILE=$WORKING_DIR/$PLATFORMS_FILE
# check file platforms.txt
if [ ! -f $FULL_PATH_PLATFORMS_FILE ]; then
echo "Platforms file: $FULL_PATH_PLATFORMS_FILE does not exist"
exit 1
fi
# Xóa folder build
echo "Clean build folder"
rm -rf ./build
# Tạo folder build
echo "Create build folder"
mkdir -p build
# install dependencies
echo "Install dependencies"
go mod download
# Đọc file platforms.txt
while read line; do
platform_split=(${line//\// }) # Tương tự "linux/arm".split("/") Javascript
GOOS=${platform_split[0]}
GOARCH=${platform_split[1]}
output_name=$APP_NAME
# Đối với OS=windows thì sẽ thêm đuôi .exe
if [ $GOOS = "windows" ]; then
output_name+='.exe'
fi
mkdir -p build/$GOOS/$GOARCH
output_path="$WORKING_DIR/build/$GOOS/$GOARCH/$output_name"
echo "====================================================" #Separator
echo "Building for OS=$GOOS Architecture=$GOARCH"
# Cờ -ldflags="-s -w" được đặt để giảm dung lượng file
env GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="-s -w" -o $output_path
if [ ! -f $output_path ]; then
echo "Failed when build for OS=$GOOS Architecture=$GOARCH"
else
fileSize=$(find "$output_path" -printf "%s")
echo "Done with output file: $output_path ($fileSize bytes)"
fi
if [ $? -ne 0 ]; then
echo 'An error has occurred! Aborting the script execution...'
exit 1
fi
done < $PLATFORMS_FILE
echo "DONE"
3. Done
Thực hiện chạy lệnh: bash ./build.sh hello-world
cấu trúc folder dự án sau khi build sẽ như sau. Các binary files sẽ nằm trong các folder OS/Architecture tương ứng
.
├── build
│ ├── darwin
│ │ ├── amd64
│ │ │ └── hello-world
│ │ └── arm64
│ │ └── hello-world
│ ├── linux
│ │ ├── amd64
│ │ │ └── hello-world
│ │ └── arm
│ │ └── hello-world
│ └── windows
│ ├── 386
│ │ └── hello-world.exe
│ └── amd64
│ └── hello-world.exe
├── build.sh
├── go.mod
├── main.go
└── platforms.txt
Đến đây bạn có thể deploy ứng dụng của mình được rồi. Chúc các bạn thành công!
Toàn bộ source code của mình tại đây github.com/tranphuquy19/golang-build-cross-platform