活用 Go 命令列工具:Build Web Application with Golang 第一章實戰指南
活用 Go 命令列工具:Build Web Application with Golang 第一章實戰指南
Go 語言自帶一套完整、統一的命令列工具鏈,從編譯、格式化、測試到產生文件,都能在終端機中一氣呵成。本篇以《Build Web Application with Golang》第一章「Go 命令」為主體,完整講解 go build、go clean、go fmt、go get、go install、go test、go generate 等常用指令的用法與參數,並結合本倉庫中的 mymath 套件與 mathapp 應用範例程式碼,讓讀者掌握從編譯單一套件、構建可執行檔,到自動化產生程式碼的完整實戰能力。
Go 命令總覽
在命令列中直接執行 go,即可檢視 Go 語言自帶的整套命令列工具。這些命令涵蓋了日常開發所需的幾乎全部操作:編譯(go build)、安裝(go install)、測試(go test)、格式化(go fmt)、取得遠端套件(go get)、產生程式碼(go generate)等。以下各節逐一深入介紹常用命令及其參數。
go build:編譯套件與可執行檔
go build 主要用於編譯程式碼。在套件的編譯過程中,若有必要,會同時編譯與之關聯的套件。其行為會因套件類型而異:
- 普通套件:例如上一節(GOPATH 與工作空間)編寫的
mymath套件,執行go build之後不會產生任何檔案;若需要在$GOPATH/pkg下產生相應的.a檔案,必須執行go install。 - main 套件:執行
go build之後會在當前目錄產生一個可執行檔案;若希望在$GOPATH/bin下產生檔案,需執行go install,或使用go build -o 路徑/檔名。 - 指定單檔編譯:若專案資料夾內有多個檔案而只想編譯某一個,可在
go build後加上檔名,例如go build a.go;預設情況下go build會編譯當前目錄下的所有 go 檔案。 - 指定輸出檔名:例如針對
mathapp應用可執行go build -o astaxie.exe。預設的輸出名稱是非 main 套件的 package 名稱,或是 main 套件的第一個原始檔檔名。
補充說明:實際上 package 名稱是指程式碼中
package關鍵字後使用的名稱(依 [Go 語言規範]定義),可以與資料夾名稱不同;預設產生的可執行檔名稱是資料夾名稱。
go build 還有兩個重要的檔案篩選規則:
- 忽略目錄下以
_或.開頭的 go 檔案; - 若原始碼針對不同作業系統需要不同處理,可依作業系統字尾命名檔案,例如:
array_linux.go
array_darwin.go
array_windows.go
array_freebsd.go
go build 會選擇性地編譯以系統名(Linux、Darwin、Windows、Freebsd)結尾的檔案。例如在 Linux 系統下編譯只會選擇 array_linux.go,其餘系統字尾的檔案全部忽略——這是 Go 內建建置約束(Build Constraints)的一種形式。
go build 參數一覽
| 參數 | 說明 |
|---|---|
-o |
指定輸出的檔名,可帶路徑,例如 go build -o a/b/c |
-i |
安裝相應的套件,等同「編譯 + go install」 |
-a |
強制更新所有已經是最新的套件(對標準套件不適用) |
-n |
僅印出需要執行的編譯命令但不執行,可觀察底層運作方式 |
-p n |
指定並行可執行的編譯數目,預設為 CPU 數目 |
-race |
編譯時自動偵測資料競爭(Data Race),目前僅支援 64 位元機器 |
-v |
印出目前正在編譯的套件名稱 |
-work |
印出編譯時使用的暫存資料夾名稱,若已存在則不刪除 |
-x |
印出實際執行的命令(與 -n 類似,但會真的執行) |
-ccflags 'arg list' |
傳遞參數給 5c、6c、8c 呼叫 |
-compiler name |
指定相應的編譯器:gccgo 或 gc |
-gccgoflags 'arg list' |
傳遞參數給 gccgo 編譯連結呼叫 |
-gcflags 'arg list' |
傳遞參數給 5g、6g、8g 呼叫 |
-installsuffix suffix |
為了與預設安裝套件區別,用此前綴重新安裝依賴套件;-race 時預設即為 -installsuffix race,可用 -n 驗證 |
-ldflags 'flag list' |
傳遞參數給 5l、6l、8l 呼叫 |
-tags 'tag list' |
設定編譯時可適配的 tag,詳細限制參考 Build Constraints |
實際對照:mymath 套件與 mathapp 應用
本倉庫的範例程式碼完整重現了 1.2 節的套件與應用結構,可用來親身體驗 go build 與 go install 的行為差異:
- 套件原始碼 en/code/src/mymath/sqrt.go:宣告
package mymath,以牛頓法迭代 1000 次求平方根,屬普通套件; - 應用原始碼 en/code/src/apps/ch.1.2/main.go:宣告
package main,import引入mymath並在main()中呼叫mymath.Sqrt(2)。
若將 GOPATH 指向 en/code(依 en/code/readme.md 的說明設定),在 ch.1.2 目錄執行 go run main.go 可看到 Hello, world. Sqrt(2) = 1.414213562373095;對 mymath 執行 go install 則會在 $GOPATH/pkg 下產生 mymath.a,對 ch.1.2 執行 go install 則會在 $GOPATH/bin 產生可執行檔——正好印證本節對普通套件與 main 套件的區分。
go clean:清除編譯產物
go clean 用於移除當前原始碼套件及關聯套件中編譯產生的檔案,包括:
_obj/ 舊的 object 目錄,由 Makefiles 遺留
_test/ 舊的 test 目錄,由 Makefiles 遺留
_testmain.go 舊的 gotest 檔案,由 Makefiles 遺留
test.out 舊的 test 記錄,由 Makefiles 遺留
build.out 舊的 test 記錄,由 Makefiles 遺留
*.[568ao] object 檔案,由 Makefiles 遺留
DIR(.exe) 由 go build 產生
DIR.test(.exe) 由 go test -c 產生
MAINFILE(.exe) 由 go build MAINFILE.go 產生
*.so 由 SWIG 產生
實務上常用此命令清除編譯檔案後再提交原始碼:編譯產物與作業系統相關,對原始碼管理沒有意義。例如執行 go clean -i -n(-n 表示只印出不執行):
$ go clean -i -n
cd /Users/astaxie/develop/gopath/src/mathapp
rm -f mathapp mathapp.exe mathapp.test mathapp.test.exe app app.exe
rm -f /Users/astaxie/develop/gopath/bin/mathapp
go clean 參數一覽
| 參數 | 說明 |
|---|---|
-i |
同時清除透過 go install 安裝的關聯套件與可執行檔 |
-n |
印出需要執行的清除命令但不執行,便於了解底層運作 |
-r |
迴圈清除在 import 中引入的套件 |
-x |
印出執行的詳細命令,即 -n 所印內容的實際執行版本 |
go fmt:統一的程式碼格式
有 C/C++ 經驗的讀者知道,程式碼風格(如 K&R 與 ANSI)常引發爭論。Go 則有標準統一的風格,並強制要求(例如左大括號必須放在行尾),不遵循格式的程式碼無法編譯通過。go fmt 命令可自動格式化程式碼:寫完程式後執行 go fmt <檔名>.go,程式碼即被修改為標準格式。許多開發工具在儲存時自動格式化,底層正是呼叫 go fmt。
需要注意:go fmt 本質上是 gofmt 的上層封裝,且必須帶 -w 參數,否則格式化結果不會寫入檔案。例如 gofmt -w -l src 可以格式化整個專案。若需要更多自訂格式化能力,可直接使用 gofmt 工具。
gofmt 參數一覽
| 參數 | 說明 |
|---|---|
-l |
顯示那些需要格式化的檔案 |
-w |
將改寫後的內容直接寫入檔案,而非列印到標準輸出 |
-r |
新增形如 a[b:len(a)] -> a[b:] 的重寫規則,方便批量替換 |
-s |
簡化檔案中的程式碼 |
-d |
顯示格式化前後的 diff 而不寫入檔案,預設為 false |
-e |
將所有語法錯誤列印到標準輸出;不使用時只會列印前 10 個錯誤 |
-cpuprofile |
支援除錯模式,將 cpufile 寫入指定檔案 |
go get:動態取得遠端套件
go get 用於動態取得遠端程式碼套件,支援 BitBucket、GitHub、Google Code 與 Launchpad 等平台。命令內部分成兩步:第一步下載原始碼套件,第二步執行 go install。下載時 go 工具會依不同域名呼叫不同的原始碼工具:
BitBucket (Mercurial Git)
GitHub (Git)
Google Code Project Hosting (Git, Mercurial, Subversion)
Launchpad (Bazaar)
因此要讓 go get 正常運作,必須先安裝合適的原始碼管理工具,並將其加入 PATH。go get 也支援自訂域名,詳見 go help remote。
go get 參數一覽
| 參數 | 說明 |
|---|---|
-d |
只下載不安裝 |
-f |
僅在搭配 -u 時有效,不讓 -u 驗證 import 中的每個套件都已取得,對本地 fork 的套件特別有用 |
-fix |
取得原始碼之後先執行 fix,再進行後續操作 |
-t |
同時下載執行測試所需的套件 |
-u |
強制使用網路更新套件及其依賴套件 |
-v |
顯示執行的命令 |
實際對照:1.2 節的遠端套件流程
在 GOPATH 與工作空間一節中,go get github.com/astaxie/beedb 正是 go get 的典型應用:先透過 git 將原始碼 clone 到 $GOPATH/src/github.com/astaxie/beedb,再執行 go install 在 $GOPATH/pkg 下產生 beedb.a。之後在程式中只需 import "github.com/astaxie/beedb" 即可像使用本地套件一樣使用它。
go install:編譯並安裝
go install 內部同樣分兩步:第一步產生結果檔案(可執行檔或 .a 套件),第二步將編譯好的結果移到 $GOPATH/pkg 或 $GOPATH/bin。它支援 go build 的所有編譯參數,其中最常使用的是 -v,可隨時查看底層執行資訊。
go test:執行測試
執行 go test 會自動讀取原始碼目錄下所有名為 *_test.go 的檔案,產生並執行測試用可執行檔,輸出類似:
ok archive/tar 0.011s
FAIL archive/zip 0.022s
ok compress/gzip 0.033s
...
預設不需要任何參數,會自動把原始碼套件下所有 test 檔案測試完畢;也可帶參數,詳情參考 go help testflag。
常用測試參數
| 參數 | 說明 |
|---|---|
-bench regexp |
執行相應的 benchmarks,例如 -bench=. |
-cover |
開啟測試覆蓋率統計 |
-run regexp |
只執行 regexp 匹配的函式,例如 -run=Array 只執行以 Array 開頭的函式 |
-v |
顯示測試的詳細命令 |
go tool:fix 與 vet
go tool 下聚集了很多子命令,這裡重點介紹兩個:
go tool fix .:修復舊版程式碼到新版本,例如 go1 之前老版本程式碼的 API 變化遷移;go tool vet directory|files:分析當前目錄程式碼是否正確,例如偵測fmt.Printf的參數型別不正確、函式內提前 return 導致的無用程式碼等問題。
go generate:編譯前自動產生程式碼
go generate 自 Go 1.4 起提供,用於在編譯前自動化產生某類程式碼。它與 go build 完全不同:透過分析原始碼中特殊的註釋,執行相應的命令。這些命令必須明確、無依賴。使用前應建立正確的觀念:go generate 是給開發者自己用的,不是給使用套件的人用的,主要用於方便自動產生程式碼。
例如用 yacc 產生程式碼的典型命令:
go tool yacc -o gopher.go -p parser gopher.y
-o 指定輸出檔名,-p 指定 package 名稱。若要讓 go generate 觸發此命令,可在當前目錄任一個 xxx.go 檔案中任意位置加入一行註釋:
//go:generate go tool yacc -o gopher.go -p parser gopher.y
注意 //go:generate 之間沒有任何空格,這是固定格式,掃描原始碼時即依此判斷。之後即可依序產生、編譯、測試:
$ go generate
$ go build
$ go test
若 gopher.y 檔案有修改,只需重新執行 go generate 重新產生檔案即可。以本倉庫而言,若以 go generate 搭配建置腳本(參考 zh/build_new.sh 的建置流程),可將「產生程式碼 → 編譯 → 測試」自動化整合進日常工作流。
godoc:查閱與伺服套件文件
在 Go 1.2 之前有 go doc 命令,之後全部移到 godoc 命令,需安裝:go get golang.org/x/tools/cmd/godoc。Go 內建強大的文件工具,不依賴任何第三方文件:
- 查看套件文件:
godoc builtin - 查看 http 套件:
godoc net/http - 查看某套件內的函式:
godoc fmt Printf - 查看函式原始碼:
godoc -src fmt Printf
還可啟動本機文件伺服器:執行 godoc -http=:8080,然後在瀏覽器開啟 127.0.0.1:8080,即可看到 golang.org 的本地版本,查詢 pkg 文件等內容。若設定了 GOPATH,在 pkg 分類下不僅會列出標準套件文件,還會列出本地 GOPATH 中所有專案的文件,對網路受限的使用者尤其方便。
其他常用命令
Go 還提供其他實用工具:
go version 檢視 Go 目前的版本
go env 檢視目前 Go 的環境變數
go list 列出目前全部安裝的 package
go run 編譯並執行 Go 程式
以上工具還有許多參數未逐一介紹,讀者隨時可用 go help 命令 取得更詳細的幫助資訊。例如 go help build、go help testflag 都是探索參數細節的入口。
小結與後續閱讀
掌握 Go 命令列工具是開發 Go 專案的基本功:go build / go install 負責建置與安裝,go clean 保持工作區乾淨,go fmt / gofmt 統一程式碼風格,go get 管理遠端依賴,go test 保證品質,go generate 自動化產生程式碼,godoc 則提供完整的文件查閱能力。配合 en/code/src/mymath/sqrt.go 與 en/code/src/apps/ch.1.2/main.go 實作練習,即可完整掌握這套工具鏈。
下一篇將介紹帶有儲存自動格式化功能的 Go 開發工具,進一步提升開發效率。
- 目錄
- 上一節:GOPATH 與工作空間
- 下一節:Go 開發工具

