Cách tạo Go Executables cho nhiều nền tảng trên Ubuntu 16.04
Ngôn ngữ lập trình Go đi kèm với một chuỗi công cụ phong phú giúp việc lấy các gói và xây dựng các file thực thi trở nên vô cùng dễ dàng. Một trong những tính năng mạnh mẽ nhất của Go là khả năng xây dựng chéo các file thi hành cho bất kỳ nền tảng nước ngoài nào được Go hỗ trợ. Điều này làm cho việc kiểm tra và phân phối gói dễ dàng hơn nhiều, vì bạn không cần phải có quyền truy cập vào một nền tảng cụ thể để phân phối gói của bạn cho nó.Trong hướng dẫn này, bạn sẽ sử dụng các công cụ của Go để lấy một gói từ kiểm soát version và tự động cài đặt file thực thi của nó. Sau đó, bạn sẽ xây dựng và cài đặt file thi hành theo cách thủ công để bạn có thể làm quen với quy trình. Sau đó, bạn sẽ xây dựng một file thực thi cho một kiến trúc khác và tự động hóa quá trình xây dựng để tạo file thực thi cho nhiều nền tảng. Khi hoàn tất, bạn sẽ biết cách xây dựng file thực thi cho Windows và macOS, cũng như các nền tảng khác mà bạn muốn hỗ trợ.
Yêu cầu
Để làm theo hướng dẫn này, bạn cần :
- Một server Ubuntu 16.04 được cài đặt theo hướng dẫn cài đặt server ban đầu Ubuntu 16.04 , bao gồm user không phải root có quyền sudo và firewall .
- Bắt đầu cài đặt, như được mô tả trong Cách cài đặt Go 1.6 trên Ubuntu 16.04 .
Bước 1 - Cài đặt chương trình Go từ Kiểm soát version
Trước khi có thể tạo file thực thi từ gói Go, ta phải lấy mã nguồn của nó. Công cụ go get
có thể tìm nạp các gói từ hệ thống kiểm soát version như GitHub. Dưới mui xe, go get
các gói sao chép vào folder con của folder $GOPATH/src/
. Sau đó, nếu có thể, nó sẽ cài đặt gói bằng cách xây dựng file thực thi của nó và đặt nó trong folder $GOPATH/bin
. Nếu bạn đã cấu hình Go như được mô tả trong hướng dẫn yêu cầu , thì folder $GOPATH/bin
có trong biến môi trường $PATH
của bạn, điều này đảm bảo bạn có thể sử dụng các gói đã cài đặt từ bất kỳ đâu trên hệ thống của bạn .
Cú pháp của lệnh go get
là go get package-import-path
. package-import-path
là một chuỗi xác định một gói duy nhất. Đó thường là vị trí của gói trong một repository từ xa như Github hoặc một folder trong folder $GOPATH/src/
trên máy của bạn.
Người ta thường sử dụng cờ go get
với cờ -u
, nó hướng dẫn go get
để lấy gói và các phần phụ thuộc của nó hoặc cập nhật các phần phụ thuộc đó nếu chúng đã có trên máy.
Trong hướng dẫn này, ta sẽ cài đặt Caddy , một web server được viết bằng Go. Theo hướng dẫn của Caddy x, ta sẽ sử dụng github.com/mholt/caddy/caddy
cho đường dẫn nhập gói. Sử dụng go get
để tìm nạp và cài đặt Caddy:
- go get -u github.com/mholt/caddy/caddy
Lệnh sẽ mất một chút thời gian để hoàn thành, nhưng bạn sẽ không thấy bất kỳ tiến trình nào trong khi nó tìm nạp gói và cài đặt. Không có kết quả nào thực sự cho biết lệnh được thực thi thành công.
Khi lệnh hoàn tất, bạn sẽ thấy mã nguồn của Caddy có sẵn tại $GOPATH/src/github.com/mholt/caddy
. Ngoài ra, vì Caddy có file thực thi, nó được tạo tự động và lưu trữ trong folder $GOPATH/bin
. Xác minh điều này bằng cách sử dụng which
để in các vị trí của thực thi:
- which caddy
Bạn sẽ thấy kết quả sau:
Output/home/sammy/work/bin/caddy
Lưu ý : Lệnh go get
cài đặt các gói từ nhánh mặc định của repository Git, trong nhiều trường hợp là nhánh master
hoặc nhánh đang phát triển. Đảm bảo xem lại các hướng dẫn, thường nằm trong file README
của repository , trước khi sử dụng go get
.
Bạn có thể sử dụng các lệnh Git như git checkout
để chọn một nhánh khác trên các nguồn thu được bằng lệnh go get
. Xem lại hướng dẫn Cách sử dụng Git Nhánh để tìm hiểu thêm về cách chuyển đổi các nhánh.
Ta hãy xem xét quá trình cài đặt gói Go một cách chi tiết hơn, bắt đầu bằng việc tạo file thực thi từ các gói mà ta đã có được.
Bước 2 - Xây dựng một thực thi
Lệnh go get
download nguồn và cài đặt file thực thi của Caddy cho ta trong một lệnh duy nhất. Nhưng bạn có thể cần tự mình xây dựng lại file thực thi hoặc xây dựng file thực thi từ mã của bạn . Lệnh go build
dựng các file thực thi.
Mặc dù ta đã cài đặt Caddy, hãy xây dựng lại nó theo cách thủ công để ta có thể thoải mái với quá trình này. Thực thi go build
và chỉ định đường dẫn nhập gói:
- go build github.com/mholt/caddy/caddy
Như trước đây, không có kết quả nào cho biết hoạt động thành công. Tệp thực thi sẽ được tạo trong folder hiện tại của bạn, có cùng tên với folder chứa gói. Trong trường hợp này, file thực thi sẽ được đặt tên là caddy
.
Nếu bạn đang ở trong folder gói, bạn có thể bỏ qua đường dẫn đến gói và chỉ cần chạy go build
.
Để chỉ định một tên hoặc vị trí khác cho file thực thi, hãy sử dụng cờ -o
. Hãy xây dựng một file thực thi có tên là caddy-server
và đặt nó vào folder build
trong folder làm việc hiện tại:
- go build -o build/caddy-server github.com/mholt/caddy/caddy
Lệnh này tạo file thực thi và cũng tạo folder ./build
nếu nó không tồn tại.
Bây giờ ta hãy xem xét cài đặt các file thực thi.
Bước 3 - Cài đặt một Executable
Xây dựng file thực thi sẽ tạo file thực thi trong folder hiện tại hoặc folder bạn chọn. Cài đặt file thực thi là quá trình tạo file thực thi và lưu trữ file đó trong $GOPATH/bin
. Lệnh go install
hoạt động giống như go build
, nhưng go install
sẽ quan tâm đến việc đặt file kết quả vào đúng nơi dành cho bạn.
Để cài đặt file thực thi, go install
sử dụng go install
, theo sau là đường dẫn nhập gói. , hãy sử dụng Caddy để thử điều này:
- go install github.com/mholt/caddy/caddy
Giống như với go build
, bạn sẽ không thấy kết quả nếu lệnh thành công. Và giống như trước đây, file thực thi được tạo cùng tên với folder chứa gói. Nhưng lần này, file thực thi được lưu trữ trong $GOPATH/bin
. Nếu $GOPATH/bin
là một phần của biến môi trường $PATH
của bạn, thì file thực thi sẽ có sẵn từ mọi nơi trên hệ điều hành của bạn. Bạn có thể xác minh vị trí của nó sử dụng which
lệnh:
- which caddy
Bạn sẽ thấy kết quả sau:
Output of which/home/sammy/work/bin/caddy
Đến đây bạn đã hiểu cách go get
, go build
và go install
công việc và chúng liên quan như thế nào, hãy cùng khám phá một trong những tính năng phổ biến nhất của Go: tạo file thực thi cho các nền tảng mục tiêu khác.
Bước 4 - Xây dựng các thực thi cho các kiến trúc khác nhau
Lệnh go build
cho phép bạn tạo một file thực thi cho bất kỳ nền tảng đích nào được Go hỗ trợ, trên nền tảng của bạn . Điều này nghĩa là bạn có thể kiểm tra, phát hành và phân phối ứng dụng của bạn mà không cần xây dựng các file thực thi đó trên nền tảng mục tiêu mà bạn muốn sử dụng.
Việc biên dịch chéo hoạt động bằng cách cài đặt các biến môi trường bắt buộc chỉ định hệ điều hành và kiến trúc đích. Ta sử dụng GOOS
biến cho hệ điều hành đích và GOARCH
cho kiến trúc đích. Để xây dựng một file thực thi, lệnh sẽ có dạng sau:
- env GOOS=target-OS GOARCH=target-architecture go build package-import-path
Lệnh env
chạy chương trình trong môi trường đã sửa đổi. Điều này cho phép bạn sử dụng các biến môi trường chỉ để thực hiện lệnh hiện tại. Các biến không được đặt hoặc đặt lại sau khi lệnh thực thi.
Bảng sau đây cho thấy các kết hợp có thể có của GOOS
và GOARCH
mà bạn có thể sử dụng:
GOOS - Hệ điều hành đích | GOARCH - Nền tảng mục tiêu |
---|---|
android | arm |
darwin | 386 |
darwin | amd64 |
darwin | arm |
darwin | arm64 |
dragonfly | amd64 |
freebsd | 386 |
freebsd | amd64 |
freebsd | arm |
linux | 386 |
linux | amd64 |
linux | arm |
linux | arm64 |
linux | ppc64 |
linux | ppc64le |
linux | mips |
linux | mipsle |
linux | mips64 |
linux | mips64le |
netbsd | 386 |
netbsd | amd64 |
netbsd | arm |
openbsd | 386 |
openbsd | amd64 |
openbsd | arm |
plan9 | 386 |
plan9 | amd64 |
solaris | amd64 |
windows | 386 |
windows | amd64 |
Cảnh báo: Các file thực thi biên dịch chéo dành cho Android yêu cầu Android NDK và một số cài đặt bổ sung nằm ngoài phạm vi của hướng dẫn này.
Sử dụng các giá trị trong bảng, ta có thể tạo Caddy cho Windows 64-bit như sau:
- env GOOS=windows GOARCH=amd64 go build github.com/mholt/caddy/caddy
, không có kết quả nào cho biết hoạt động đã thành công. Tệp thực thi sẽ được tạo trong folder hiện tại, sử dụng tên gói làm tên của nó. Tuy nhiên, vì ta đã xây dựng file thực thi này cho Windows nên tên kết thúc bằng hậu tố .exe
.
Bạn nên có file caddy.exe
trong folder hiện tại của bạn , bạn có thể xác minh file này bằng ls
.
- ls caddy.exe
Bạn sẽ thấy file caddy.exe
được liệt kê trong kết quả :
Outputcaddy.exe
Lưu ý : Bạn có thể sử dụng cờ -o
để đổi tên file thực thi hoặc đặt file đó ở một vị trí khác. Tuy nhiên, khi xây dựng file thực thi cho Windows và cung cấp một tên khác, hãy đảm bảo chỉ định rõ ràng hậu tố .exe
khi đặt tên file thực thi.
Hãy xem kịch bản của quá trình này để giúp phát hành phần mềm cho nhiều môi trường mục tiêu dễ dàng hơn.
Bước 5 - Tạo tập lệnh để tự động biên dịch chéo
Quá trình tạo file thực thi cho nhiều nền tảng có thể hơi tẻ nhạt, nhưng ta có thể tạo một tập lệnh để làm mọi thứ dễ dàng hơn.
Tập lệnh sẽ lấy đường dẫn nhập gói làm đối số, lặp qua danh sách các cặp nền tảng và hệ điều hành được định nghĩa , đồng thời tạo file thực thi cho mỗi cặp, đặt kết quả vào folder hiện tại. Mỗi file thực thi sẽ được đặt tên với tên gói, theo sau là nền tảng và kiến trúc đích, ở dạng package-OS-architecture
. Đây sẽ là một script phổ quát mà bạn có thể sử dụng cho bất kỳ dự án nào.
Chuyển sang folder chính của bạn và tạo một file mới có tên go-executable-build.bash
trong editor của bạn:
- cd ~
- nano go-executable-build.bash
Ta sẽ bắt đầu kịch bản của bạn bằng một dòng shebang . Dòng này xác định trình thông dịch nào sẽ phân tích cú pháp tập lệnh này khi nó chạy dưới dạng file thực thi. Thêm dòng sau để chỉ định rằng bash
sẽ thực thi tập lệnh này:
#!/usr/bin/env bash
Ta muốn lấy đường dẫn nhập gói làm đối số dòng lệnh. Để làm điều này, ta sẽ sử dụng biến $ n
, với n
là một số không âm. Biến $0
chứa tên của tập lệnh bạn đã thực thi, trong khi $1
sẽ chứa các đối số do user cung cấp. Thêm dòng này vào tập lệnh, sẽ lấy đối số đầu tiên từ dòng lệnh và lưu trữ nó trong một biến được gọi là package
:
... package=$1
Tiếp theo, hãy đảm bảo user đã cung cấp giá trị này. Nếu giá trị không được cung cấp, hãy thoát khỏi tập lệnh với thông báo giải thích cách sử dụng tập lệnh:
... if [[ -z "$package" ]]; then echo "usage: $0 <package-name>" exit 1 fi
Câu lệnh if
này kiểm tra giá trị của biến $package
. Nếu nó không được đặt, ta sử dụng echo
để in cách sử dụng chính xác và sau đó kết thúc tập lệnh bằng cách sử dụng exit
. exit
lấy giá trị trả về làm đối số, giá trị này phải là 0
cho các thực thi thành công và bất kỳ giá trị nào khác 0 cho các thực thi không thành công. Ta sử dụng 1
ở đây vì tập lệnh không thành công.
Lưu ý : Nếu bạn muốn làm cho tập lệnh này hoạt động với một gói được định nghĩa , hãy thay đổi biến package
để trỏ đến đường dẫn nhập đó:
... package="github.com/user/hello"
Tiếp theo, ta muốn extract tên gói từ đường dẫn. Đường dẫn nhập gói được phân cách bằng /
ký tự, với tên gói nằm ở cuối đường dẫn. Đầu tiên, ta sẽ chia đường dẫn nhập gói thành một mảng, sử dụng /
làm dấu phân cách:
package_split=(${package//\// })
Tên gói phải là phần tử cuối cùng của mảng $package_split
mới này. Trong Bash, bạn có thể sử dụng index mảng âm để truy cập một mảng từ cuối thay vì đầu. Thêm dòng này để lấy tên gói từ mảng và lưu trữ nó trong một biến có tên là package_name
:
... package_name=${package_split[-1]}
Bây giờ, bạn cần phải quyết định nền tảng và kiến trúc nào bạn muốn xây dựng các file thực thi. Trong hướng dẫn này, ta sẽ xây dựng các file thực thi cho Windows 64-bit, Windows 32-bit và 64-bit macOS. Ta sẽ đặt các mục tiêu này trong một mảng có định dạng OS / Platform
, vì vậy ta có thể chia từng cặp thành các biến GOOS
và GOARCH
bằng cách sử dụng cùng một phương pháp ta đã sử dụng để extract tên gói từ đường dẫn. Thêm các nền tảng vào tập lệnh:
... platforms=("windows/amd64" "windows/386" "darwin/amd64")
Tiếp theo, ta sẽ lặp qua mảng nền tảng, chia từng mục nhập nền tảng thành các giá trị cho các biến môi trường GOOS
và GOARCH
và sử dụng chúng để xây dựng file thực thi. Ta có thể làm điều đó với vòng lặp for
sau:
... for platform in "${platforms[@]}" do ... done
Biến platform
sẽ chứa một mục nhập từ mảng platforms
trong mỗi lần lặp. Ta cần chia platform
thành hai biến - GOOS
và GOARCH
. Thêm các dòng sau vào vòng lặp for
:
for platform in "${platforms[@]}" do platform_split=(${platform//\// }) GOOS=${platform_split[0]} GOARCH=${platform_split[1]} done
Tiếp theo, ta sẽ tạo tên file thực thi bằng cách kết hợp tên gói với hệ điều hành và kiến trúc. Khi ta đang xây dựng cho Windows, ta cũng cần thêm hậu tố .exe
vào tên file . Thêm mã này vào vòng lặp for
:
for platform in "${platforms[@]}" do platform_split=(${platform//\// }) GOOS=${platform_split[0]} GOARCH=${platform_split[1]} output_name=$package_name'-'$GOOS'-'$GOARCH if [ $GOOS = "windows" ]; then output_name+='.exe' fi done
Với các biến được đặt, ta sử dụng go build
để tạo file thực thi. Thêm dòng này vào phần nội dung của vòng lặp for
, ngay phía trên từ khóa done
:
... if [ $GOOS = "windows" ]; then output_name+='.exe' fi env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package done
Cuối cùng, ta nên kiểm tra xem có lỗi khi xây dựng file thực thi hay không. Ví dụ: ta có thể gặp lỗi nếu ta cố gắng tạo một gói mà ta không có nguồn. Ta có thể kiểm tra mã trả về của lệnh go build
để tìm giá trị khác 0. Biến $?
chứa mã trả về từ việc thực hiện lệnh trước đó. Nếu go build
trả về bất kỳ thứ gì khác 0
, thì đã xảy ra sự cố và ta sẽ muốn thoát tập lệnh. Thêm mã này vào vòng lặp for
, sau lệnh go build
và bên trên từ khóa done
.
... env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package if [ $? -ne 0 ]; then echo 'An error has occurred! Aborting the script execution...' exit 1 fi
Như vậy, bây giờ ta có một tập lệnh sẽ xây dựng nhiều file thực thi từ gói Go của ta . Đây là tập lệnh đã hoàn thành:
#!/usr/bin/env bash package=$1 if [[ -z "$package" ]]; then echo "usage: $0 <package-name>" exit 1 fi package_split=(${package//\// }) package_name=${package_split[-1]} platforms=("windows/amd64" "windows/386" "darwin/amd64") for platform in "${platforms[@]}" do platform_split=(${platform//\// }) GOOS=${platform_split[0]} GOARCH=${platform_split[1]} output_name=$package_name'-'$GOOS'-'$GOARCH if [ $GOOS = "windows" ]; then output_name+='.exe' fi env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package if [ $? -ne 0 ]; then echo 'An error has occurred! Aborting the script execution...' exit 1 fi done
Xác minh file của bạn trùng với mã trước đó. Sau đó, lưu file và thoát khỏi editor .
Trước khi có thể sử dụng tập lệnh, ta phải làm cho nó có thể thực thi được bằng chmod
:
- chmod +x go-executable-build.bash
Cuối cùng, kiểm tra tập lệnh bằng cách xây dựng các file thực thi cho Caddy:
- ./go-executable-build.bash github.com/mholt/caddy/caddy
Nếu mọi thứ suôn sẻ, bạn sẽ có các file thực thi trong folder hiện tại của bạn . Không có kết quả cho biết thực thi tập lệnh thành công. Bạn có thể xác minh là các file thực thi được tạo bằng ls
:
- ls caddy*
Bạn sẽ thấy cả ba version :
Example ls outputcaddy-darwin-amd64 caddy-windows-386.exe caddy-windows-amd64.exe
Để thay đổi nền tảng mục tiêu, chỉ cần thay đổi biến platforms
trong tập lệnh của bạn.
Kết luận
Trong hướng dẫn này, bạn đã học cách sử dụng công cụ của Go để lấy các gói từ hệ thống kiểm soát version , cũng như xây dựng và biên dịch chéo các file thực thi cho các nền tảng khác nhau.
Bạn cũng đã tạo một tập lệnh mà bạn có thể sử dụng để biên dịch chéo một gói duy nhất cho nhiều nền tảng.
Để đảm bảo ứng dụng của bạn hoạt động chính xác, bạn có thể xem thử nghiệm và tích hợp liên tục như Travis-CI và AppVeyor để thử nghiệm trên Windows.
Nếu bạn quan tâm đến Caddy và cách sử dụng nó, hãy xem Cách lưu trữ trang web bằng Caddy trên Ubuntu 16.04 .
Các tin liên quan
Cách cài đặt Concourse CI trên Ubuntu 16.042017-05-26
Cách giám sát server và dịch vụ bằng Icinga trên Ubuntu 16.04
2017-05-05
Cách thiết lập đồng bộ hóa thời gian trên Ubuntu 16.04
2017-04-28
Cách quản lý log với Graylog 2 trên Ubuntu 16.04
2017-04-25
Cách cài đặt Webmin trên Ubuntu 16.04
2017-04-21
Cách cài đặt và cấu hình OrientDB trên Ubuntu 16.04
2017-03-24
how-to-monitor-system-metrics-with-the-tick-stack-on-ubuntu-16-04
2017-03-16
Cách cài đặt và cấu hình Postfix trên Ubuntu 16.04
2017-03-16
Cách cấu hình client FreeIPA trên Ubuntu 16.04
2017-03-08
Cách cài đặt Moodle trên Ubuntu 16.04
2017-03-02