go run biên dịch và chạy chương trình trong một bước, không giữ lại tệp thực thi. go build biên dịch và để lại một tệp thực thi trong thư mục hiện tại. go install biên dịch và đặt tệp thực thi vào $HOME/go/bin. Cả ba đều biên dịch ra mã máy gốc; không lệnh nào thông dịch cả.
| Lệnh | Biên dịch | Chạy | Giữ tệp thực thi | Tệp thực thi nằm ở đâu |
|---|---|---|---|---|
go run . | có | có | không | thư mục tạm, bị xóa sau đó |
go build | có | không | có | thư mục hiện tại (hoặc -o path) |
go install | có | không | có | $GOBIN, nếu không thì $GOPATH/bin |
Chương trình dưới đây được dùng trong các ví dụ trên trang này. Trình soạn thảo chạy nó giống như go run.
go run
go run nhận một package (thường là ., thư mục hiện tại) hoặc một danh sách tệp .go:
go run .
go run main.go
go run ./cmd/server
Mọi thứ phía sau package được truyền cho chương trình của bạn làm đối số:
go run . --port 8080 verbose
version: dev
built for: linux/amd64
args: [--port 8080 verbose]
Nên dùng go run . thay vì go run main.go. Chỉ định tên tệp sẽ chỉ biên dịch đúng tệp đó, nên ngay khi package có tệp thứ hai, các hàm định nghĩa ở đó sẽ bị báo là undefined. Trang package và import trình bày chi tiết lỗi này.
go run còn chạy được một chương trình từ xa ở một phiên bản cụ thể mà không cần cài đặt, rất tiện cho các trình sinh code:
go run golang.org/x/tools/cmd/stringer@v0.30.0 -type=Color
go build
go build biên dịch package trong thư mục hiện tại. Với package main, nó ghi ra một tệp thực thi; với package thư viện, nó biên dịch, báo lỗi nếu có, rồi bỏ kết quả đi.
go mod init example.com/hello
go build
ls
go.mod hello main.go
Tên tệp thực thi tuân theo các quy tắc sau:
| Bạn chạy | Tên tệp thực thi |
|---|---|
go build trong module example.com/hello | hello |
go build ./cmd/server | server |
go build main.go | main (đặt theo tên tệp đầu tiên) |
go build -o bin/app . | bin/app |
bất kỳ lệnh nào ở trên với GOOS=windows | cùng tên, thêm .exe |
Hai dạng khác mà bạn sẽ dùng thường xuyên:
go build ./... # compile every package in the module
go vet ./... # static checks, covered below
./... nghĩa là "thư mục này và mọi thư mục bên dưới nó". go build ./... với nhiều package main không ghi ra tệp thực thi nào; đây là cách kiểm tra nhanh xem "mọi thứ có biên dịch được không".
Các flag build hữu ích
| Flag | Tác dụng |
|---|---|
-o name | tệp hoặc thư mục đầu ra |
-v | in tên package khi chúng được biên dịch |
-race | build kèm bộ phát hiện data race (chậm hơn, tệp lớn hơn; dùng khi kiểm thử) |
-trimpath | xóa các đường dẫn hệ thống tệp cục bộ khỏi tệp thực thi, để build có thể tái lập |
-ldflags "-s -w" | bỏ bảng ký hiệu và thông tin gỡ lỗi DWARF, giúp tệp thực thi nhỏ hơn |
-ldflags "-X main.version=1.4.0" | gán giá trị cho một biến chuỗi lúc liên kết |
-tags name | đưa vào các tệp được bảo vệ bởi ràng buộc //go:build name |
Flag -X là cách hầu hết dự án Go đóng dấu phiên bản vào tệp thực thi. Nó chỉ hoạt động với các biến string cấp package (không áp dụng cho hằng số):
go build -o app -ldflags "-X main.version=1.4.0" .
./app
version: 1.4.0
built for: linux/amd64
args: []
Tệp thực thi còn ghi lại phiên bản các module của nó và, từ Go 1.18, commit VCS mà nó được build từ đó. go version -m ./app in ra những thông tin này, và chương trình có thể đọc chúng bằng runtime/debug.ReadBuildInfo.
go install
go install build y hệt go build rồi chuyển tệp thực thi vào $GOBIN, hoặc $GOPATH/bin khi GOBIN chưa được đặt (mặc định là $HOME/go/bin):
go install .
go env GOPATH
Cách dùng phổ biến nhất của nó là cài đặt các công cụ viết bằng Go. Với @version, nó cài một chương trình mà không động tới go.mod của bạn:
go install golang.org/x/tools/gopls@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
Nếu sau đó shell không tìm thấy công cụ, nghĩa là $HOME/go/bin chưa nằm trong PATH. Hãy thêm export PATH=$PATH:$(go env GOPATH)/bin vào profile của shell.
Biên dịch chéo với GOOS và GOARCH
Go có thể build cho hệ điều hành hoặc CPU khác từ bất kỳ máy nào, không cần thêm toolchain. Đặt hai biến môi trường cho lệnh build:
GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 .
GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 .
GOOS=darwin GOARCH=arm64 go build -o app-macos .
GOOS=windows GOARCH=amd64 go build -o app.exe .
Trong PowerShell, biến môi trường được đặt theo cách khác:
$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -o app-linux .
Các cặp phổ biến nhất:
| GOOS | GOARCH | Nền tảng đích |
|---|---|---|
linux | amd64 | hầu hết máy chủ và container |
linux | arm64 | AWS Graviton, Raspberry Pi chạy hệ điều hành 64-bit |
darwin | arm64 | máy Mac dùng Apple Silicon |
darwin | amd64 | máy Mac dùng chip Intel |
windows | amd64 | Windows 64-bit |
js | wasm | WebAssembly trong trình duyệt |
go tool dist list in ra mọi cặp được hỗ trợ (48 cặp trong Go 1.24).
Biên dịch chéo chỉ dễ như vậy với code Go thuần. Một package dùng cgo (code C, chẳng hạn một số driver SQLite) cần trình biên dịch chéo C cho nền tảng đích. Khi biên dịch chéo, cgo bị tắt theo mặc định, và đặt CGO_ENABLED=0 một cách tường minh cũng cho bạn một tệp thực thi Linux hoàn toàn tĩnh, đúng thứ bạn cần trong một container image tối giản scratch hoặc distroless.
go fmt và go vet
Hai bước kiểm tra này nên có trong mọi quy trình làm việc, và trong CI.
go fmt viết lại các tệp theo một phong cách chính thức duy nhất: tab, các trường được căn thẳng hàng, khoảng trắng được chuẩn hóa. Đây là lớp bọc quanh gofmt -l -w:
go fmt ./...
gofmt -l . # list files that are not formatted; empty output means clean
go vet báo những đoạn code biên dịch được nhưng gần như chắc chắn là sai. Sai lệch định dạng của Printf là trường hợp kinh điển:
package main
import "fmt"
func main() {
count := 3
fmt.Printf("%s items\n", count)
}
go vet ./...
# example.com/hello
# [example.com/hello]
./main.go:7:2: fmt.Printf format %s has arg count of wrong type int
Chương trình biên dịch được và in ra %!s(int=3) items, đúng loại bug mà vet sinh ra để bắt. Các kiểm tra khác của vet gồm sao chép sync.Mutex theo giá trị, code không bao giờ chạy tới, struct tag sai cú pháp, và một context.CancelFunc không bao giờ được gọi. go test tự động chạy một phần các kiểm tra này; go build không chạy kiểm tra nào.
Các lệnh con khác của go
| Lệnh | Mục đích |
|---|---|
go test ./... | chạy test |
go mod tidy | thêm dependency còn thiếu và xóa dependency không dùng |
go get pkg@version | thêm hoặc thay đổi một dependency |
go clean -cache | xóa sạch build cache |
go env | in cấu hình của Go |
go doc fmt.Println | hiển thị tài liệu ngay trong terminal |
go list -m all | liệt kê mọi module trong bản build |
Vì sao build lần thứ hai lại nhanh
Go lưu các package đã biên dịch trong build cache (go env GOCACHE). Một lần build lại chỉ biên dịch lại những package có mã nguồn hoặc dependency thay đổi, nên go run . trên một dự án không đổi gần như khởi động ngay lập tức. Nếu một bản build hoạt động bất thường sau khi đổi phiên bản Go hoặc biến môi trường, go clean -cache sẽ xóa cache; bạn hiếm khi cần đến lệnh này.
Câu hỏi thường gặp
go run và go build khác nhau thế nào?
go run biên dịch chương trình vào một thư mục tạm, chạy nó, rồi bỏ tệp thực thi đi. go build biên dịch chương trình và ghi tệp thực thi vào thư mục hiện tại để bạn có thể chạy lại hoặc sao chép đi nơi khác. Dùng go run khi đang phát triển và go build khi bạn cần tệp thực thi.
Làm sao đặt tên tệp đầu ra cho go build?
Dùng -o: go build -o myapp . ghi ra myapp (trên Windows, bạn tự viết -o myapp.exe). Không có -o, go build đặt tên tệp thực thi theo phần cuối của đường dẫn import của package, hoặc theo tệp đầu tiên khi bạn truyền các tệp .go, và thêm .exe khi build cho Windows.
Làm sao biên dịch chéo Go cho Linux hoặc Windows?
Đặt GOOS và GOARCH cho lệnh build: GOOS=linux GOARCH=amd64 go build -o app-linux . hoặc GOOS=windows GOARCH=amd64 go build . (lệnh này tạo ra một tệp .exe). Code Go thuần không cần thêm toolchain nào. go tool dist list in ra mọi cặp được hỗ trợ.
go install đặt tệp thực thi ở đâu?
Trong $GOBIN nếu biến này được đặt, nếu không thì trong $GOPATH/bin, mặc định là $HOME/go/bin. Thêm thư mục đó vào PATH để chạy các công cụ đã cài bằng tên. go install example.com/tool@latest cài một công cụ mà không thêm nó vào module của bạn.
go build có chạy go vet không?
Không. go build chỉ biên dịch. go test tự động chạy một phần các kiểm tra của go vet, nhưng để có đầy đủ, hãy tự chạy go vet ./..., thường là trong CI cùng với gofmt -l ..