Go的執行原理以及Go的命令

qfliweimin發表於2019-04-18

一、Go的原始碼檔案

Go 的原始碼檔案分類:

Go的執行原理以及Go的命令

如上圖,分為三類:

1、命令原始碼檔案:

宣告自己屬於 main 程式碼包、包含無引數宣告和結果宣告的 main 函式。

命令原始碼檔案被安裝以後,GOPATH 如果只有一個工作區,那麼相應的可執行檔案會被存放當前工作區的 bin 資料夾下;如果有多個工作區,就會安裝到 GOBIN 指向的目錄下。

命令原始碼檔案是 Go 程式的入口。

同一個程式碼包中最好也不要放多個命令原始碼檔案。多個命令原始碼檔案雖然可以分開單獨 go run 執行起來,但是無法通過 go build 和 go install。

我們先開啟上次課的hello目錄,然後複製helloworld.go為helloworld2.go檔案,並修改裡面的內容:

package mainimport "fmt"func main(){    fmt.Println("我是第二個helloworld檔案")    fmt.Print("Go Go Go !!!")}複製程式碼

hello目錄下有兩個go檔案了,一個是helloworld.go,一個是helloworld2.go。先說明一下,在上述資料夾中放了兩個命令原始碼檔案,同時都宣告自己屬於 main 程式碼包。

Go的執行原理以及Go的命令

開啟終端,進入hello這個目錄,也可以看到這兩個檔案:

localhost:~ ruby cd go/src/hellolocalhost:hello ruby lshelloworld.go   helloworld2.go複製程式碼

然後我們分別執行go run命令,可以看到兩個go檔案都可以被執行:

localhost:hello ruby$ go run helloworld.goHelloWorldGo Go Go !!!localhost:hello ruby$ go run helloworld2.go我是第二個helloworld檔案Go Go Go !!!複製程式碼

Go的執行原理以及Go的命令

接下來執行 go build 和 go install ,看看會發生什麼:

localhost:hello ruby$ go build # hello./helloworld2.go:3:6: main redeclared in this block    previous declaration at ./helloworld.go:3:6localhost:hello ruby$ go install# hello./helloworld2.go:3:6: main redeclared in this block    previous declaration at ./helloworld.go:3:6localhost:hello ruby$ 複製程式碼

執行效果圖:

Go的執行原理以及Go的命令

這也就證明了多個命令原始碼檔案雖然可以分開單獨 go run 執行起來,但是無法通過 go build 和 go install。

同理,如果命令原始碼檔案和庫原始碼檔案也會出現這樣的問題,庫原始碼檔案不能通過 go build 和 go install 這種常規的方法編譯和安裝。具體例子和上述類似,這裡就不再貼程式碼了。

所以命令原始碼檔案應該是被單獨放在一個程式碼包中。

2、庫原始碼檔案

庫原始碼檔案就是不具備命令原始碼檔案上述兩個特徵的原始碼檔案。存在於某個程式碼包中的普通的原始碼檔案。

庫原始碼檔案被安裝後,相應的歸檔檔案(.a 檔案)會被存放到當前工作區的 pkg 的平臺相關目錄下。

3、測試原始碼檔案

名稱以 _test.go 為字尾的程式碼檔案,並且必須包含 Test 或者 Benchmark 名稱字首的函式:

func TestXXX( t *testing.T) {​}複製程式碼

名稱以 Test 為名稱字首的函式,只能接受 *testing.T 的引數,這種測試函式是功能測試函式。

func BenchmarkXXX( b *testing.B) {​}​複製程式碼

名稱以 Benchmark 為名稱字首的函式,只能接受 *testing.B 的引數,這種測試函式是效能測試函式。

現在答案就很明顯了:

命令原始碼檔案是可以單獨執行的。可以使用 go run 命令直接執行,也可以通過 go build 或 go install 命令得到相應的可執行檔案。所以命令原始碼檔案是可以在機器的任何目錄下執行的。

舉個栗子:

比如平時我們在 LeetCode 上刷演算法題,這時候寫的就是一個程式,這就是命令原始碼檔案,可以在電腦的任意一個資料夾新建一個 go 檔案就可以開始刷題了,寫完就可以執行,對比執行結果,答案對了就可以提交程式碼。

但是公司專案裡面的程式碼就不能這樣了,只能存放在 GOPATH 目錄下。因為公司專案不可能只有命令原始碼檔案的,肯定是包含庫原始碼檔案,甚至包含測試原始碼檔案的。

二、Go的命令

目前Go的最新版1.12裡面基本命令有以下17個。

我們可以開啟終端輸入:go help即可看到Go的這些命令以及簡介。

    bug         start a bug report    build       compile packages and dependencies    clean       remove object files and cached files    doc         show documentation for package or symbol    env         print Go environment information    fix         update packages to use new APIs    fmt         gofmt (reformat) package sources    generate    generate Go files by processing source    get         download and install packages and dependencies    install     compile and install packages and dependencies    list        list packages or modules    mod         module maintenance    run         compile and run Go program    test        test packages    tool        run specified go tool    version     print Go version    vet         report likely mistakes in packages複製程式碼

其中和編譯相關的有build、get、install、run這4個。接下來就依次看看這四個的作用。

在詳細分析這4個命令之前,先羅列一下通用的命令標記,以下這些命令都可適用的:

名稱說明
-a用於強制重新編譯所有涉及的 Go 語言程式碼包(包括 Go 語言標準庫中的程式碼包),即使它們已經是最新的了。該標記可以讓我們有機會通過改動底層的程式碼包做一些實驗。
-n使命令僅列印其執行過程中用到的所有命令,而不去真正執行它們。如果不只想檢視或者驗證命令的執行過程,而不想改變任何東西,使用它正好合適。
-race用於檢測並報告指定 Go 語言程式中存在的資料競爭問題。當用 Go 語言編寫併發程式的時候,這是很重要的檢測手段之一。
-v用於列印命令執行過程中涉及的程式碼包。這一定包括我們指定的目的碼包,並且有時還會包括該程式碼包直接或間接依賴的那些程式碼包。這會讓你知道哪些程式碼包被執行過了。
-work用於列印命令執行時生成和使用的臨時工作目錄的名字,且命令執行完成後不刪除它。這個目錄下的檔案可能會對你有用,也可以從側面瞭解命令的執行過程。如果不新增此標記,那麼臨時工作目錄會在命令執行完畢前刪除。
-x使命令列印其執行過程中用到的所有命令,並同時執行它們。

1. go run

專門用來執行命令原始碼檔案的命令,注意,這個命令不是用來執行所有 Go 的原始碼檔案的!

go run 命令只能接受一個命令原始碼檔案以及若干個庫原始碼檔案(必須同屬於 main 包)作為檔案引數,且不能接受測試原始碼檔案。它在執行時會檢查原始碼檔案的型別。如果引數中有多個或者沒有命令原始碼檔案,那麼 go run 命令就只會列印錯誤提示資訊並退出,而不會繼續執行。

這個命令具體幹了些什麼事情呢?來分析分析,我們先重新建立一個新檔案:mytest.go,並加入以下程式碼:

package mainimport "fmt"func main(){    fmt.Println("HelloWorld")    fmt.Println("你好,Go!!!")}複製程式碼

執行go run 配合-n:

localhost:hello ruby$ go run -n mytest.go ​## command-line-arguments#​mkdir -p $WORK/b001/cat >$WORK/b001/importcfg << 'EOF' # internal# import configpackagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.apackagefile runtime=/usr/local/go/pkg/darwin_amd64/runtime.aEOFcd /Users/ruby/go/src/hello/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001 -p main -complete -buildid ieg41NOobNF0eqq3xgnP/ieg41NOobNF0eqq3xgnP -dwarf=false -goversion go1.12.1 -D _/Users/ruby/go/src/hello -importcfg $WORK/b001/importcfg -pack -c=4 ./mytest.go/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/_pkg_.a # internalcat >$WORK/b001/importcfg.link << 'EOF' # internal... # 此處省略EOFmkdir -p $WORK/b001/exe/cd ./usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/mytest -importcfg $WORK/b001/importcfg.link -s -w -buildmode=exe -buildid=vpgT856LhbZPXp6WeHib/ieg41NOobNF0eqq3xgnP/ieg41NOobNF0eqq3xgnP/vpgT856LhbZPXp6WeHib -extld=clang $WORK/b001/_pkg_.a$WORK/b001/exe/mytestlocalhost:hello ruby$ ​複製程式碼

執行效果圖:

Go的執行原理以及Go的命令

這裡可以看到建立了兩個臨時資料夾 b001 和 exe,先執行了 compile 命令,然後 link,生成了歸檔檔案.a 和 最終可執行檔案,最終的可執行檔案放在 exe 資料夾裡面。命令的最後一步就是執行了可執行檔案。

總結一下如下圖:

Go的執行原理以及Go的命令

舉個例子,生成的臨時檔案可以用go run -work看到,比如當前生成的臨時資料夾是如下的路徑:

localhost:hello ruby$ go run -work mytest.go WORK=/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build593750496HelloWorld你好,Go!!!localhost:hello ruby$ 複製程式碼

我們進入:/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build593750496目錄,可以看到如下目錄結構:

Go的執行原理以及Go的命令

可以看到,最終go run命令是生成了2個檔案,一個是歸檔檔案,一個是可執行檔案。

go run 命令在第二次執行的時候,如果發現匯入的程式碼包沒有發生變化,那麼 go run 不會再次編譯這個匯入的程式碼包。直接靜態連結進來。

localhost:hello ruby$ go run -n mytest.go mkdir -p $WORK/b001/cat >$WORK/b001/importcfg.link << 'EOF' # internalpackagefile command-line-arguments=/Users/ruby/Library/Caches/go-build/6b/6b9577027c8da20b0ae6da790267f558b3b71eea1feb44039fb933b35eaef6f9-dpackagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a...EOFmkdir -p $WORK/b001/exe/cd ./usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/mytest -importcfg $WORK/b001/importcfg.link -s -w -buildmode=exe -buildid=goiqf_1cemqljgOYzSRA/ieg41NOobNF0eqq3xgnP/MVbHdxOky1BGK6Aq_4bM/goiqf_1cemqljgOYzSRA -extld=clang /Users/ruby/Library/Caches/go-build/6b/6b9577027c8da20b0ae6da790267f558b3b71eea1feb44039fb933b35eaef6f9-d$WORK/b001/exe/mytestlocalhost:hello ruby$ ​複製程式碼

2. go build

go build 命令主要是用於測試編譯。在包的編譯過程中,若有必要,會同時編譯與之相關聯的包。

  1. 如果是普通包,當你執行go build命令後,不會產生任何檔案。

  2. 如果是main包,當只執行go build命令後,會在當前目錄下生成一個可執行檔案。如果需要在$GOPATH/bin目錄下生成相應的exe檔案,需要執行go install 或者使用 go build -o 路徑/可執行檔案。

  3. 如果某個資料夾下有多個檔案,而你只想編譯其中某一個檔案,可以在 go build 之後加上檔名,例如 go build a.go;go build 命令預設會編譯當前目錄下的所有go檔案。

  4. 你也可以指定編譯輸出的檔名。比如,我們可以指定go build -o 可執行檔名,預設情況是你的package名(非main包),或者是第一個原始檔的檔名(main包)。

  5. go build 會忽略目錄下以”_”或者”.”開頭的go檔案。

  6. 如果你的原始碼針對不同的作業系統需要不同的處理,那麼你可以根據不同的作業系統字尾來命名檔案。

當程式碼包中有且僅有一個命令原始碼檔案的時候,在資料夾所在目錄中執行 go build 命令,會在該目錄下生成一個與目錄同名的可執行檔案。

// 假設當前資料夾名叫 hellolocalhost:hello ruby$ pwd/Users/ruby/go/src/hellolocalhost:hello ruby$ lshelloworld.golocalhost:hello ruby$ go buildlocalhost:hello ruby$ lshello       helloworld.golocalhost:hello ruby$ 複製程式碼

於是在當前目錄直接生成了以當前資料夾為名的可執行檔案( 在 Mac 平臺下是 Unix executable 檔案,在 Windows 平臺下是 exe 檔案)

Go的執行原理以及Go的命令

但是這種情況下,如果使用 go install 命令,如果 GOPATH 裡面只有一個工作區,就會在當前工作區的 bin 目錄下生成相應的可執行檔案。如果 GOPATH 下有多個工作區,則是在 GOBIN 下生成對應的可執行檔案。

localhost:hello ruby$ go installgo install hello: open /usr/local/go/bin/hello: permission deniedlocalhost:hello ruby$ 複製程式碼

Go的執行原理以及Go的命令

這個問題是因為它需要建立bin目錄,然後把可剛才的可執行檔案放進去,而目前我們在gopath下還沒有bin目錄,那麼就需要先建立這個檔案,而普通使用者沒有直接建立資料夾的許可權,這個和Go語言的命令是沒有關係的。我們可以加上sodu 來執行這個命令,表示使用管理員的身份執行,然後輸入密碼,那麼就可以建立bin這個資料夾了。

再次執行:

localhost:hello ruby$ sudo go installPassword:localhost:hello ruby$ ​複製程式碼

執行完 go install 會發現可執行檔案不見了!去哪裡了呢?其實是被移動到了 bin 目錄下了(如果 GOPATH 下有多個工作區,就會放在GOBIN 目錄下)。

檢視目錄:

Go的執行原理以及Go的命令

那 go build 和 go install 究竟幹了些什麼呢?

先來說說 go build。go build 用於編譯我們指定的原始碼檔案或程式碼包以及它們的依賴包。但是注意如果用來編譯非命令原始碼檔案,即庫原始碼檔案,go build 執行完是不會產生任何結果的。這種情況下,go build 命令只是檢查庫原始碼檔案的有效性,只會做檢查性的編譯,而不會輸出任何結果檔案。

go build 編譯命令原始碼檔案,則會在該命令的執行目錄中生成一個可執行檔案,上面的例子也印證了這個過程。

go build 後面不追加目錄路徑的話,它就把當前目錄作為程式碼包並進行編譯。go build 命令後面如果跟了程式碼包匯入路徑作為引數,那麼該程式碼包及其依賴都會被編譯。

go build 命令究竟做了些什麼呢?我們可以執行-n這個命令來檢視:

localhost:hello ruby$ go build -n​## hello#​mkdir -p $WORK/b001/cat >$WORK/b001/importcfg << 'EOF' # internal# import configpackagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.apackagefile runtime=/usr/local/go/pkg/darwin_amd64/runtime.aEOFcd /Users/ruby/go/src/hello/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001 -p main -complete -buildid PXDetO1R1NhLFMK5QGUc/PXDetO1R1NhLFMK5QGUc -goversion go1.12.1 -D "" -importcfg $WORK/b001/importcfg -pack -c=4 ./helloworld.go/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/_pkg_.a # internalcat >$WORK/b001/importcfg.link << 'EOF' # internalpackagefile hello=$WORK/b001/_pkg_.a...EOFmkdir -p $WORK/b001/exe/cd ./usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=diTh1q6kcbGRIX3aj3mU/PXDetO1R1NhLFMK5QGUc/PXDetO1R1NhLFMK5QGUc/diTh1q6kcbGRIX3aj3mU -extld=clang $WORK/b001/_pkg_.a/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/exe/a.out # internalmv $WORK/b001/exe/a.out hellolocalhost:hello ruby$ ​複製程式碼

可以看到,執行過程和 go run 大體相同,唯一不同的就是在最後一步,go run 是執行了可執行檔案,但是 go build 命令,只是把庫原始碼檔案編譯了一遍,然後把可執行檔案移動到了當前目錄的資料夾中。

總結一下如下圖:

Go的執行原理以及Go的命令

3. go install

go install 命令是用來編譯並安裝程式碼包或者原始碼檔案的。

go install 命令在內部實際上分成了兩步操作:第一步是生成結果檔案(可執行檔案或者.a包),第二步會把編譯好的結果移到$GOPATH/pkg或者​$GOPATH/bin

可執行檔案: 一般是 go install 帶main函式的go檔案產生的,有函式入口,所有可以直接執行。

.a應用包: 一般是 go install 不包含main函式的go檔案產生的,沒有函式入口,只能被呼叫。

go install 用於編譯並安裝指定的程式碼包及它們的依賴包。當指定的程式碼包的依賴包還沒有被編譯和安裝時,該命令會先去處理依賴包。與 go build 命令一樣,傳給 go install 命令的程式碼包引數應該以匯入路徑的形式提供。並且,go build 命令的絕大多數標記也都可以用於 實際上,go install 命令只比 go build 命令多做了一件事,即:安裝編譯後的結果檔案到指定目錄。

安裝程式碼包會在當前工作區的 pkg 的平臺相關目錄下生成歸檔檔案(即 .a 檔案)。 安裝命令原始碼檔案會在當前工作區的 bin 目錄(如果 GOPATH 下有多個工作區,就會放在 GOBIN 目錄下)生成可執行檔案。

同樣,go install 命令如果後面不追加任何引數,它會把當前目錄作為程式碼包並安裝。這和 go build 命令是完全一樣的。

go install 命令後面如果跟了程式碼包匯入路徑作為引數,那麼該程式碼包及其依賴都會被安裝。

go install 命令後面如果跟了命令原始碼檔案以及相關庫原始碼檔案作為引數的話,只有這些檔案會被編譯並安裝。

go install 命令究竟做了些什麼呢?

localhost:hello ruby$ go install -n​## hello#​mkdir -p $WORK/b001/cat >$WORK/b001/importcfg << 'EOF' # internal# import configpackagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.apackagefile runtime=/usr/local/go/pkg/darwin_amd64/runtime.aEOFcd /Users/ruby/go/src/hello/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001 -p main -complete -buildid E1CTs4eXkD5M28s_FQXT/E1CTs4eXkD5M28s_FQXT -goversion go1.12.1 -D "" -importcfg $WORK/b001/importcfg -pack -c=4 ./helloworld.go/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/_pkg_.a # internalcat >$WORK/b001/importcfg.link << 'EOF' # internalpackagefile hello=$WORK/b001/_pkg_.apackagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a...EOFmkdir -p $WORK/b001/exe/cd ./usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=FJ6kJTmN9rcWcwLhqfiQ/E1CTs4eXkD5M28s_FQXT/E1CTs4eXkD5M28s_FQXT/FJ6kJTmN9rcWcwLhqfiQ -extld=clang $WORK/b001/_pkg_.a/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/exe/a.out # internalmkdir -p /usr/local/go/bin/mv $WORK/b001/exe/a.out /usr/local/go/bin/hellolocalhost:hello ruby$ ​複製程式碼

前面幾步依舊和 go run 、go build 完全一致,只是最後一步的差別,go install 會把命令原始碼檔案安裝到當前工作區的 bin 目錄(如果 GOPATH 下有多個工作區,就會放在 GOBIN 目錄下)。如果是庫原始碼檔案,就會被安裝到當前工作區的 pkg 的平臺相關目錄下。

總結一下如下圖:

Go的執行原理以及Go的命令

在安裝多個庫原始碼檔案時有可能遇到如下的問題:

localhost:hello ruby$  go install envir.go fpath.go ipath.go pnode.go util.gogo install: no install location for .go files listed on command line (GOBIN not set)複製程式碼

而且,在我們為環境變數 GOBIN 設定了正確的值之後,這個錯誤提示資訊仍然會出現。這是因為,只有在安裝命令原始碼檔案的時候,命令程式才會將環境變數 GOBIN 的值作為結果檔案的存放目錄。而在安裝庫原始碼檔案時,在命令程式內部的代表結果檔案存放目錄路徑的那個變數不會被賦值。最後,命令程式會發現它依然是個無效的空值。所以,命令程式會同樣返回一個關於“無安裝位置”的錯誤。這就引出一個結論,我們只能使用安裝程式碼包的方式來安裝庫原始碼檔案,而不能在 go install 命令羅列並安裝它們。另外,go install 命令目前無法接受標記-o以自定義結果檔案的存放位置。這也從側面說明了 go install 命令不支援針對庫原始碼檔案的安裝操作。

4. go get

go get 命令用於從遠端程式碼倉庫(比如 Github )上下載並安裝程式碼包。注意,go get 命令會把當前的程式碼包下載到 $GOPATH 中的第一個工作區的 src 目錄中,並安裝。

使用 go get 下載第三方包的時候,依舊會下載到 $GOPATH 的第一個工作空間,而非 vendor 目錄。當前工作鏈中並沒有真正意義上的包依賴管理,不過好在有不少第三方工具可選。

如果在 go get 下載過程中加入-d 標記,那麼下載操作只會執行下載動作,而不執行安裝動作。比如有些非常特殊的程式碼包在安裝過程中需要有特殊的處理,所以我們需要先下載下來,所以就會用到-d 標記。

還有一個很有用的標記是-u標記,加上它可以利用網路來更新已有的程式碼包及其依賴包。如果已經下載過一個程式碼包,但是這個程式碼包又有更新了,那麼這時候可以直接用-u標記來更新本地的對應的程式碼包。如果不加這個-u標記,執行 go get 一個已有的程式碼包,會發現命令什麼都不執行。只有加了-u標記,命令會去執行 git pull 命令拉取最新的程式碼包的最新版本,下載並安裝。

命令 go get 還有一個很值得稱道的功能——智慧下載。在使用它檢出或更新程式碼包之後,它會尋找與本地已安裝 Go 語言的版本號相對應的標籤(tag)或分支(branch)。比如,本機安裝 Go 語言的版本是1.x,那麼 go get 命令會在該程式碼包的遠端倉庫中尋找名為 “go1” 的標籤或者分支。如果找到指定的標籤或者分支,則將原生程式碼包的版本切換到此標籤或者分支。如果沒有找到指定的標籤或者分支,則將原生程式碼包的版本切換到主幹的最新版本。

go get 常用的一些標記如下:

標記名稱標記描述
-d讓命令程式只執行下載動作,而不執行安裝動作。
-f僅在使用-u標記時才有效。該標記會讓命令程式忽略掉對已下載程式碼包的匯入路徑的檢查。如果下載並安裝的程式碼包所屬的專案是你從別人那裡 Fork 過來的,那麼這樣做就尤為重要了。
-fix讓命令程式在下載程式碼包後先執行修正動作,而後再進行編譯和安裝。
-insecure允許命令程式使用非安全的 scheme(如 HTTP )去下載指定的程式碼包。如果你用的程式碼倉庫(如公司內部的 Gitlab )沒有HTTPS 支援,可以新增此標記。請在確定安全的情況下使用它。
-t讓命令程式同時下載並安裝指定的程式碼包中的測試原始碼檔案中依賴的程式碼包。
-u讓命令利用網路來更新已有程式碼包及其依賴包。預設情況下,該命令只會從網路上下載本地不存在的程式碼包,而不會更新已有的程式碼包。

go get 命令究竟做了些什麼呢?我們還是來列印一下每一步的執行過程。

localhost:hello ruby$ go get -x github.com/go-errors/errorscd .git clone https://github.com/go-errors/errors /Users/ruby/go/src/github.com/go-errors/errorscd /Users/ruby/go/src/github.com/go-errors/errorsgit submodule update --init --recursivecd /Users/ruby/go/src/github.com/go-errors/errorsgit show-refcd /Users/ruby/go/src/github.com/go-errors/errorsgit submodule update --init --recursiveWORK=/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build188558329localhost:hello ruby$ 複製程式碼

效果圖:

Go的執行原理以及Go的命令

這裡可以很明顯的看到,執行完 go get 命令以後,會呼叫 git clone 方法下載原始碼,並編譯,最終會把庫原始碼檔案編譯成歸檔檔案安裝到 pkg 對應的相關平臺目錄下。

Go的執行原理以及Go的命令

總結一下如下圖:

Go的執行原理以及Go的命令

5. 其他命令

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產生

go fmt

go fmt 命令主要是用來幫你格式化所寫好的程式碼檔案。

比如我們寫了一個格式很糟糕的 test.go 檔案,我們只需要使用 fmt go test.go 命令,就可以讓go幫我們格式化我們的程式碼檔案。但是我們一般很少使用這個命令,因為我們的開發工具一般都帶有儲存時自動格式化功能,這個功能底層其實就是呼叫了 go fmt 命令而已。

使用go fmt命令,更多時候是用gofmt,而且需要引數-w,否則格式化結果不會寫入檔案。gofmt -w src,可以格式化整個專案。

go test

go test 命令,會自動讀取原始碼目錄下面名為*_test.go的檔案,生成並執行測試用的可執行檔案。預設的情況下,不需要任何的引數,它會自動把你原始碼包下面所有test檔案測試完畢,當然你也可以帶上引數,詳情請參考go help testflag

go doc

go doc 命令其實就是一個很強大的文件工具。

如何檢視相應package的文件呢? 例如builtin包,那麼執行go doc builtin;如果是http包,那麼執行go doc net/http;檢視某一個包裡面的函式,那麼執行go doc fmt Printf;也可以檢視相應的程式碼,執行go doc -src fmt Printf;

# 檢視net/http包localhost:hello ruby$ go doc net/http# 檢視time包localhost:hello ruby$ go doc time# 檢視某個包裡的指定函式localhost:hello ruby$ go doc fmt Printf複製程式碼

通過命令在命令列執行 go doc -http=:埠號,比如godoc -http=:8080。然後在瀏覽器中開啟127.0.0.1:8080,你將會看到一個golang.org的本地copy版本,通過它你可以查詢pkg文件等其它內容。如果你設定了GOPATH,在pkg分類下,不但會列出標準包的文件,還會列出你本地GOPATH中所有專案的相關文件,這對於經常被限制訪問的使用者來說是一個不錯的選擇。

localhost:hello ruby$ godoc -http=:9527複製程式碼

go fix 用來修復以前老版本的程式碼到新版本,例如go1之前老版本的程式碼轉化到go1

go version 檢視go當前的版本

go env 檢視當前go的環境變數

go list 列出當前全部安裝的package



相關文章