Go的執(zhí)行原理以及Go的命令

一成畦、Go的源碼文件

Go 的源碼文件分類:

如上圖取试,分為三類:

1、命令源碼文件:

聲明自己屬于 main 代碼包悔常、包含無參數(shù)聲明和結(jié)果聲明的 main 函數(shù)影斑。

命令源碼文件被安裝以后,GOPATH 如果只有一個(gè)工作區(qū)机打,那么相應(yīng)的可執(zhí)行文件會被存放當(dāng)前工作區(qū)的 bin 文件夾下矫户;如果有多個(gè)工作區(qū),就會安裝到 GOBIN 指向的目錄下残邀。

命令源碼文件是 Go 程序的入口皆辽。

同一個(gè)代碼包中最好也不要放多個(gè)命令源碼文件。多個(gè)命令源碼文件雖然可以分開單獨(dú) go run 運(yùn)行起來罐旗,但是無法通過 go build 和 go install膳汪。

我們先打開上次課的hello目錄,然后復(fù)制helloworld.go為helloworld2.go文件九秀,并修改里面的內(nèi)容:

packagemain

import"fmt"

funcmain(){

? ? fmt.Println("我是第二個(gè)helloworld文件")

? ? fmt.Print("Go Go Go !!!")

}

hello目錄下有兩個(gè)go文件了遗嗽,一個(gè)是helloworld.go,一個(gè)是helloworld2.go鼓蜒。先說明一下痹换,在上述文件夾中放了兩個(gè)命令源碼文件,同時(shí)都聲明自己屬于 main 代碼包都弹。

打開終端娇豫,進(jìn)入hello這個(gè)目錄,也可以看到這兩個(gè)文件:

localhost:~ rubycdgo/src/hello

localhost:hello rubyls

helloworld.go? helloworld2.go

然后我們分別執(zhí)行g(shù)o run命令畅厢,可以看到兩個(gè)go文件都可以被執(zhí)行:

localhost:hello ruby$ gorun helloworld.go

HelloWorld

Go Go Go !!!localhost:hello ruby$ gorun helloworld2.go

我是第二個(gè)helloworld文件

Go Go Go !!!

接下來執(zhí)行 go build 和 go install 冯痢,看看會發(fā)生什么:

localhost:hello ruby$ gobuild

# hello

./helloworld2.go:3:6: main redeclaredinthis block

? ? previous declaration at ./helloworld.go:3:6

localhost:hello ruby$ goinstall

# hello

./helloworld2.go:3:6: main redeclaredinthis block

? ? previous declaration at ./helloworld.go:3:6

localhost:hello ruby$

運(yùn)行效果圖:

這也就證明了多個(gè)命令源碼文件雖然可以分開單獨(dú) go run 運(yùn)行起來,但是無法通過 go build 和 go install。

同理浦楣,如果命令源碼文件和庫源碼文件也會出現(xiàn)這樣的問題袖肥,庫源碼文件不能通過 go build 和 go install 這種常規(guī)的方法編譯和安裝。具體例子和上述類似振劳,這里就不再貼代碼了椎组。

所以命令源碼文件應(yīng)該是被單獨(dú)放在一個(gè)代碼包中。

2历恐、庫源碼文件

庫源碼文件就是不具備命令源碼文件上述兩個(gè)特征的源碼文件寸癌。存在于某個(gè)代碼包中的普通的源碼文件。

庫源碼文件被安裝后弱贼,相應(yīng)的歸檔文件(.a 文件)會被存放到當(dāng)前工作區(qū)的 pkg 的平臺相關(guān)目錄下蒸苇。

3、測試源碼文件

名稱以 _test.go 為后綴的代碼文件哮洽,并且必須包含 Test 或者 Benchmark 名稱前綴的函數(shù):

funcTestXXX(t*testing.T) {

?

}

名稱以 Test 為名稱前綴的函數(shù)填渠,只能接受 *testing.T 的參數(shù),這種測試函數(shù)是功能測試函數(shù)鸟辅。

funcBenchmarkXXX(b*testing.B) {

?

}

?

名稱以 Benchmark 為名稱前綴的函數(shù),只能接受 *testing.B 的參數(shù)莺葫,這種測試函數(shù)是性能測試函數(shù)匪凉。

現(xiàn)在答案就很明顯了:

命令源碼文件是可以單獨(dú)運(yùn)行的∞嗝剩可以使用 go run 命令直接運(yùn)行再层,也可以通過 go build 或 go install 命令得到相應(yīng)的可執(zhí)行文件。所以命令源碼文件是可以在機(jī)器的任何目錄下運(yùn)行的堡纬。

舉個(gè)栗子:

比如平時(shí)我們在 LeetCode 上刷算法題聂受,這時(shí)候?qū)懙木褪且粋€(gè)程序,這就是命令源碼文件烤镐,可以在電腦的任意一個(gè)文件夾新建一個(gè) go 文件就可以開始刷題了蛋济,寫完就可以運(yùn)行,對比執(zhí)行結(jié)果炮叶,答案對了就可以提交代碼碗旅。

但是公司項(xiàng)目里面的代碼就不能這樣了,只能存放在 GOPATH 目錄下镜悉。因?yàn)楣卷?xiàng)目不可能只有命令源碼文件的祟辟,肯定是包含庫源碼文件,甚至包含測試源碼文件的侣肄。

二旧困、Go的命令

目前Go的最新版1.12里面基本命令有以下17個(gè)。

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

? ? bugstarta bug report

? ? build ? ? ? compile packages and dependencies

? ? clean ? ? ? remove object files and cached files

? ? doc ? ? ? ? show documentationforpackage or symbol

? ? env ? ? ? ? print Go environment information

? ? fix ? ? ? ? update packages to use new APIs

? ? fmt ? ? ? ? gofmt (reformat) package sources

? ? generate ?? generate Go files by processingsource

? ? getdownload 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 mistakesinpackages

其中和編譯相關(guān)的有build吼具、get僚纷、install、run這4個(gè)馍悟。接下來就依次看看這四個(gè)的作用畔濒。

在詳細(xì)分析這4個(gè)命令之前,先羅列一下通用的命令標(biāo)記锣咒,以下這些命令都可適用的:

名稱說明

-a用于強(qiáng)制重新編譯所有涉及的 Go 語言代碼包(包括 Go 語言標(biāo)準(zhǔn)庫中的代碼包)侵状,即使它們已經(jīng)是最新的了。該標(biāo)記可以讓我們有機(jī)會通過改動底層的代碼包做一些實(shí)驗(yàn)毅整。

-n使命令僅打印其執(zhí)行過程中用到的所有命令趣兄,而不去真正執(zhí)行它們。如果不只想查看或者驗(yàn)證命令的執(zhí)行過程悼嫉,而不想改變?nèi)魏螙|西艇潭,使用它正好合適。

-race用于檢測并報(bào)告指定 Go 語言程序中存在的數(shù)據(jù)競爭問題戏蔑。當(dāng)用 Go 語言編寫并發(fā)程序的時(shí)候蹋凝,這是很重要的檢測手段之一。

-v用于打印命令執(zhí)行過程中涉及的代碼包总棵。這一定包括我們指定的目標(biāo)代碼包鳍寂,并且有時(shí)還會包括該代碼包直接或間接依賴的那些代碼包。這會讓你知道哪些代碼包被執(zhí)行過了情龄。

-work用于打印命令執(zhí)行時(shí)生成和使用的臨時(shí)工作目錄的名字迄汛,且命令執(zhí)行完成后不刪除它。這個(gè)目錄下的文件可能會對你有用骤视,也可以從側(cè)面了解命令的執(zhí)行過程鞍爱。如果不添加此標(biāo)記,那么臨時(shí)工作目錄會在命令執(zhí)行完畢前刪除专酗。

-x使命令打印其執(zhí)行過程中用到的所有命令睹逃,并同時(shí)執(zhí)行它們。

1. go run

專門用來運(yùn)行命令源碼文件的命令笼裳,注意唯卖,這個(gè)命令不是用來運(yùn)行所有 Go 的源碼文件的!

go run 命令只能接受一個(gè)命令源碼文件以及若干個(gè)庫源碼文件(必須同屬于 main 包)作為文件參數(shù)躬柬,且不能接受測試源碼文件拜轨。它在執(zhí)行時(shí)會檢查源碼文件的類型。如果參數(shù)中有多個(gè)或者沒有命令源碼文件允青,那么 go run 命令就只會打印錯(cuò)誤提示信息并退出橄碾,而不會繼續(xù)執(zhí)行。

這個(gè)命令具體干了些什么事情呢?來分析分析法牲,我們先重新創(chuàng)建一個(gè)新文件:mytest.go史汗,并加入以下代碼:

packagemain

import"fmt"

funcmain(){

? ? fmt.Println("HelloWorld")

? ? fmt.Println("你好,Go!!!")

}

執(zhí)行g(shù)o run 配合-n:

localhost:hello ruby$ gorun-nmytest.go

?

#

# command-line-arguments

#

?

mkdir-p$WORK/b001/

cat>$WORK/b001/importcfg <<'EOF'# internal

# import config

packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a

packagefileruntime=/usr/local/go/pkg/darwin_amd64/runtime.a

EOF

cd/Users/ruby/go/src/hello

/usr/local/go/pkg/tool/darwin_amd64/compile-o$WORK/b001/_pkg_.a-trimpath$WORK/b001-pmain-complete-buildidieg41NOobNF0eqq3xgnP/ieg41NOobNF0eqq3xgnP-dwarf=false-goversiongo1.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# internal

cat>$WORK/b001/importcfg.link <<'EOF'# internal

...# 此處省略

EOF

mkdir-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/mytest

localhost:hello ruby$

?

運(yùn)行效果圖:

這里可以看到創(chuàng)建了兩個(gè)臨時(shí)文件夾 b001 和 exe拒垃,先執(zhí)行了 compile 命令停撞,然后 link,生成了歸檔文件.a 和 最終可執(zhí)行文件悼瓮,最終的可執(zhí)行文件放在 exe 文件夾里面戈毒。命令的最后一步就是執(zhí)行了可執(zhí)行文件。

總結(jié)一下如下圖:

舉個(gè)例子横堡,生成的臨時(shí)文件可以用go run -work看到埋市,比如當(dāng)前生成的臨時(shí)文件夾是如下的路徑:

localhost:hello ruby$ gorun-workmytest.go

WORK=/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build593750496

HelloWorld

你好,Go!!!

localhost:hello ruby$

我們進(jìn)入:/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build593750496目錄命贴,可以看到如下目錄結(jié)構(gòu):

可以看到道宅,最終go run命令是生成了2個(gè)文件,一個(gè)是歸檔文件胸蛛,一個(gè)是可執(zhí)行文件污茵。

go run 命令在第二次執(zhí)行的時(shí)候,如果發(fā)現(xiàn)導(dǎo)入的代碼包沒有發(fā)生變化葬项,那么 go run 不會再次編譯這個(gè)導(dǎo)入的代碼包省咨。直接靜態(tài)鏈接進(jìn)來。

localhost:hello ruby$ gorun-nmytest.go

mkdir-p$WORK/b001/

cat>$WORK/b001/importcfg.link <<'EOF'# internal

packagefilecommand-line-arguments=/Users/ruby/Library/Caches/go-build/6b/6b9577027c8da20b0ae6da790267f558b3b71eea1feb44039fb933b35eaef6f9-d

packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a

...

EOF

mkdir-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/mytest

localhost:hello ruby$

?

2. go build

go build 命令主要是用于測試編譯玷室。在包的編譯過程中,若有必要笤受,會同時(shí)編譯與之相關(guān)聯(lián)的包穷缤。

如果是普通包,當(dāng)你執(zhí)行g(shù)o build命令后箩兽,不會產(chǎn)生任何文件津肛。

如果是main包,當(dāng)只執(zhí)行g(shù)o build命令后汗贫,會在當(dāng)前目錄下生成一個(gè)可執(zhí)行文件身坐。如果需要在$GOPATH/bin目錄下生成相應(yīng)的exe文件,需要執(zhí)行g(shù)o install 或者使用 go build -o 路徑/可執(zhí)行文件落包。

如果某個(gè)文件夾下有多個(gè)文件部蛇,而你只想編譯其中某一個(gè)文件,可以在 go build 之后加上文件名咐蝇,例如 go build a.go涯鲁;go build 命令默認(rèn)會編譯當(dāng)前目錄下的所有g(shù)o文件。

你也可以指定編譯輸出的文件名。比如抹腿,我們可以指定go build -o 可執(zhí)行文件名岛请,默認(rèn)情況是你的package名(非main包),或者是第一個(gè)源文件的文件名(main包)警绩。

go build 會忽略目錄下以”_”或者”.”開頭的go文件崇败。

如果你的源代碼針對不同的操作系統(tǒng)需要不同的處理,那么你可以根據(jù)不同的操作系統(tǒng)后綴來命名文件肩祥。

當(dāng)代碼包中有且僅有一個(gè)命令源碼文件的時(shí)候后室,在文件夾所在目錄中執(zhí)行 go build 命令,會在該目錄下生成一個(gè)與目錄同名的可執(zhí)行文件搭幻。

// 假設(shè)當(dāng)前文件夾名叫 hello

localhost:hello ruby$ pwd

/Users/ruby/go/src/hello

localhost:hello ruby$ ls

helloworld.go

localhost:hello ruby$ gobuild

localhost:hello ruby$ ls

hello? ? ? helloworld.go

localhost:hello ruby$

于是在當(dāng)前目錄直接生成了以當(dāng)前文件夾為名的可執(zhí)行文件( 在 Mac 平臺下是 Unix executable 文件咧擂,在 Windows 平臺下是 exe 文件)

但是這種情況下,如果使用 go install 命令檀蹋,如果 GOPATH 里面只有一個(gè)工作區(qū)松申,就會在當(dāng)前工作區(qū)的 bin 目錄下生成相應(yīng)的可執(zhí)行文件。如果 GOPATH 下有多個(gè)工作區(qū)俯逾,則是在 GOBIN 下生成對應(yīng)的可執(zhí)行文件贸桶。

localhost:hello ruby$ goinstall

go install hello: open /usr/local/go/bin/hello: permission denied

localhost:hello ruby$

這個(gè)問題是因?yàn)樗枰獎?chuàng)建bin目錄,然后把可剛才的可執(zhí)行文件放進(jìn)去桌肴,而目前我們在gopath下還沒有bin目錄皇筛,那么就需要先創(chuàng)建這個(gè)文件,而普通用戶沒有直接創(chuàng)建文件夾的權(quán)限坠七,這個(gè)和Go語言的命令是沒有關(guān)系的水醋。我們可以加上sodu 來執(zhí)行這個(gè)命令,表示使用管理員的身份執(zhí)行彪置,然后輸入密碼拄踪,那么就可以創(chuàng)建bin這個(gè)文件夾了。

再次執(zhí)行:

localhost:hello ruby$ sudogo install

Password:

localhost:hello ruby$

?

執(zhí)行完 go install 會發(fā)現(xiàn)可執(zhí)行文件不見了拳魁!去哪里了呢惶桐?其實(shí)是被移動到了 bin 目錄下了(如果 GOPATH 下有多個(gè)工作區(qū),就會放在GOBIN 目錄下)潘懊。

查看目錄:

那 go build 和 go install 究竟干了些什么呢姚糊?

先來說說 go build。go build 用于編譯我們指定的源碼文件或代碼包以及它們的依賴包授舟。但是注意如果用來編譯非命令源碼文件救恨,即庫源碼文件,go build 執(zhí)行完是不會產(chǎn)生任何結(jié)果的岂却。這種情況下忿薇,go build 命令只是檢查庫源碼文件的有效性裙椭,只會做檢查性的編譯,而不會輸出任何結(jié)果文件署浩。

go build 編譯命令源碼文件揉燃,則會在該命令的執(zhí)行目錄中生成一個(gè)可執(zhí)行文件,上面的例子也印證了這個(gè)過程筋栋。

go build 后面不追加目錄路徑的話炊汤,它就把當(dāng)前目錄作為代碼包并進(jìn)行編譯评甜。go build 命令后面如果跟了代碼包導(dǎo)入路徑作為參數(shù)豫柬,那么該代碼包及其依賴都會被編譯。

go build 命令究竟做了些什么呢奴饮?我們可以執(zhí)行-n這個(gè)命令來查看:

localhost:hello ruby$ gobuild-n

?

#

# hello

#

?

mkdir-p$WORK/b001/

cat>$WORK/b001/importcfg <<'EOF'# internal

# import config

packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a

packagefileruntime=/usr/local/go/pkg/darwin_amd64/runtime.a

EOF

cd/Users/ruby/go/src/hello

/usr/local/go/pkg/tool/darwin_amd64/compile-o$WORK/b001/_pkg_.a-trimpath$WORK/b001-pmain-complete-buildidPXDetO1R1NhLFMK5QGUc/PXDetO1R1NhLFMK5QGUc-goversiongo1.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# internal

cat>$WORK/b001/importcfg.link <<'EOF'# internal

packagefilehello=$WORK/b001/_pkg_.a

...

EOF

mkdir-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# internal

mv$WORK/b001/exe/a.out hello

localhost:hello ruby$

?

可以看到襟交,執(zhí)行過程和 go run 大體相同迈倍,唯一不同的就是在最后一步,go run 是執(zhí)行了可執(zhí)行文件捣域,但是 go build 命令啼染,只是把庫源碼文件編譯了一遍,然后把可執(zhí)行文件移動到了當(dāng)前目錄的文件夾中焕梅。

總結(jié)一下如下圖:

3. go install

go install 命令是用來編譯并安裝代碼包或者源碼文件的迹鹅。

go install 命令在內(nèi)部實(shí)際上分成了兩步操作:第一步是生成結(jié)果文件(可執(zhí)行文件或者.a包),第二步會把編譯好的結(jié)果移到$GOPATH/pkg或者?$GOPATH/bin贞言。

可執(zhí)行文件: 一般是 go install 帶main函數(shù)的go文件產(chǎn)生的斜棚,有函數(shù)入口,所有可以直接運(yùn)行该窗。

.a應(yīng)用包: 一般是 go install 不包含main函數(shù)的go文件產(chǎn)生的弟蚀,沒有函數(shù)入口,只能被調(diào)用酗失。

go install 用于編譯并安裝指定的代碼包及它們的依賴包粗梭。當(dāng)指定的代碼包的依賴包還沒有被編譯和安裝時(shí),該命令會先去處理依賴包级零。與 go build 命令一樣,傳給 go install 命令的代碼包參數(shù)應(yīng)該以導(dǎo)入路徑的形式提供滞乙。并且奏纪,go build 命令的絕大多數(shù)標(biāo)記也都可以用于實(shí)際上,go install 命令只比 go build 命令多做了一件事斩启,即:安裝編譯后的結(jié)果文件到指定目錄序调。

安裝代碼包會在當(dāng)前工作區(qū)的 pkg 的平臺相關(guān)目錄下生成歸檔文件(即 .a 文件)。安裝命令源碼文件會在當(dāng)前工作區(qū)的 bin 目錄(如果 GOPATH 下有多個(gè)工作區(qū)兔簇,就會放在 GOBIN 目錄下)生成可執(zhí)行文件发绢。

同樣硬耍,go install 命令如果后面不追加任何參數(shù),它會把當(dāng)前目錄作為代碼包并安裝边酒。這和 go build 命令是完全一樣的经柴。

go install 命令后面如果跟了代碼包導(dǎo)入路徑作為參數(shù),那么該代碼包及其依賴都會被安裝墩朦。

go install 命令后面如果跟了命令源碼文件以及相關(guān)庫源碼文件作為參數(shù)的話坯认,只有這些文件會被編譯并安裝。

go install 命令究竟做了些什么呢氓涣?

localhost:hello ruby$ goinstall-n

?

#

# hello

#

?

mkdir-p$WORK/b001/

cat>$WORK/b001/importcfg <<'EOF'# internal

# import config

packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a

packagefileruntime=/usr/local/go/pkg/darwin_amd64/runtime.a

EOF

cd/Users/ruby/go/src/hello

/usr/local/go/pkg/tool/darwin_amd64/compile-o$WORK/b001/_pkg_.a-trimpath$WORK/b001-pmain-complete-buildidE1CTs4eXkD5M28s_FQXT/E1CTs4eXkD5M28s_FQXT-goversiongo1.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# internal

cat>$WORK/b001/importcfg.link <<'EOF'# internal

packagefilehello=$WORK/b001/_pkg_.a

packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a

...

EOF

mkdir-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# internal

mkdir-p/usr/local/go/bin/

mv$WORK/b001/exe/a.out /usr/local/go/bin/hello

localhost:hello ruby$

?

前面幾步依舊和 go run 牛哺、go build 完全一致,只是最后一步的差別劳吠,go install 會把命令源碼文件安裝到當(dāng)前工作區(qū)的 bin 目錄(如果 GOPATH 下有多個(gè)工作區(qū)引润,就會放在 GOBIN 目錄下)。如果是庫源碼文件痒玩,就會被安裝到當(dāng)前工作區(qū)的 pkg 的平臺相關(guān)目錄下淳附。

總結(jié)一下如下圖:

在安裝多個(gè)庫源碼文件時(shí)有可能遇到如下的問題:

localhost:hello ruby$ go install envir.go fpath.go ipath.go pnode.go util.go

go install: no install locationfor.go files listed on command line (GOBIN notset)

而且,在我們?yōu)榄h(huán)境變量 GOBIN 設(shè)置了正確的值之后凰荚,這個(gè)錯(cuò)誤提示信息仍然會出現(xiàn)燃观。這是因?yàn)椋挥性诎惭b命令源碼文件的時(shí)候便瑟,命令程序才會將環(huán)境變量 GOBIN 的值作為結(jié)果文件的存放目錄缆毁。而在安裝庫源碼文件時(shí),在命令程序內(nèi)部的代表結(jié)果文件存放目錄路徑的那個(gè)變量不會被賦值到涂。最后脊框,命令程序會發(fā)現(xiàn)它依然是個(gè)無效的空值。所以践啄,命令程序會同樣返回一個(gè)關(guān)于“無安裝位置”的錯(cuò)誤浇雹。這就引出一個(gè)結(jié)論,我們只能使用安裝代碼包的方式來安裝庫源碼文件屿讽,而不能在 go install 命令羅列并安裝它們昭灵。另外,go install 命令目前無法接受標(biāo)記-o以自定義結(jié)果文件的存放位置伐谈。這也從側(cè)面說明了 go install 命令不支持針對庫源碼文件的安裝操作烂完。

4. go get

go get 命令用于從遠(yuǎn)程代碼倉庫(比如 Github )上下載并安裝代碼包。注意诵棵,go get 命令會把當(dāng)前的代碼包下載到 $GOPATH 中的第一個(gè)工作區(qū)的 src 目錄中抠蚣,并安裝。

使用 go get 下載第三方包的時(shí)候履澳,依舊會下載到 $GOPATH 的第一個(gè)工作空間嘶窄,而非 vendor 目錄怀跛。當(dāng)前工作鏈中并沒有真正意義上的包依賴管理,不過好在有不少第三方工具可選柄冲。

如果在 go get 下載過程中加入-d 標(biāo)記吻谋,那么下載操作只會執(zhí)行下載動作,而不執(zhí)行安裝動作羊初。比如有些非常特殊的代碼包在安裝過程中需要有特殊的處理滨溉,所以我們需要先下載下來,所以就會用到-d 標(biāo)記长赞。

還有一個(gè)很有用的標(biāo)記是-u標(biāo)記晦攒,加上它可以利用網(wǎng)絡(luò)來更新已有的代碼包及其依賴包。如果已經(jīng)下載過一個(gè)代碼包得哆,但是這個(gè)代碼包又有更新了脯颜,那么這時(shí)候可以直接用-u標(biāo)記來更新本地的對應(yīng)的代碼包。如果不加這個(gè)-u標(biāo)記贩据,執(zhí)行 go get 一個(gè)已有的代碼包栋操,會發(fā)現(xiàn)命令什么都不執(zhí)行。只有加了-u標(biāo)記饱亮,命令會去執(zhí)行 git pull 命令拉取最新的代碼包的最新版本矾芙,下載并安裝。

命令 go get 還有一個(gè)很值得稱道的功能——智能下載近上。在使用它檢出或更新代碼包之后剔宪,它會尋找與本地已安裝 Go 語言的版本號相對應(yīng)的標(biāo)簽(tag)或分支(branch)。比如壹无,本機(jī)安裝 Go 語言的版本是1.x葱绒,那么 go get 命令會在該代碼包的遠(yuǎn)程倉庫中尋找名為 “go1” 的標(biāo)簽或者分支。如果找到指定的標(biāo)簽或者分支斗锭,則將本地代碼包的版本切換到此標(biāo)簽或者分支地淀。如果沒有找到指定的標(biāo)簽或者分支,則將本地代碼包的版本切換到主干的最新版本岖是。

go get 常用的一些標(biāo)記如下:

標(biāo)記名稱標(biāo)記描述

-d讓命令程序只執(zhí)行下載動作帮毁,而不執(zhí)行安裝動作。

-f僅在使用-u標(biāo)記時(shí)才有效豺撑。該標(biāo)記會讓命令程序忽略掉對已下載代碼包的導(dǎo)入路徑的檢查作箍。如果下載并安裝的代碼包所屬的項(xiàng)目是你從別人那里 Fork 過來的,那么這樣做就尤為重要了前硫。

-fix讓命令程序在下載代碼包后先執(zhí)行修正動作,而后再進(jìn)行編譯和安裝荧止。

-insecure允許命令程序使用非安全的 scheme(如 HTTP )去下載指定的代碼包屹电。如果你用的代碼倉庫(如公司內(nèi)部的 Gitlab )沒有HTTPS 支持阶剑,可以添加此標(biāo)記。請?jiān)诖_定安全的情況下使用它危号。

-t讓命令程序同時(shí)下載并安裝指定的代碼包中的測試源碼文件中依賴的代碼包牧愁。

-u讓命令利用網(wǎng)絡(luò)來更新已有代碼包及其依賴包。默認(rèn)情況下外莲,該命令只會從網(wǎng)絡(luò)上下載本地不存在的代碼包猪半,而不會更新已有的代碼包。

go get 命令究竟做了些什么呢偷线?我們還是來打印一下每一步的執(zhí)行過程磨确。

localhost:hello ruby$ goget-xgithub.com/go-errors/errors

cd.

gitclone https://github.com/go-errors/errors /Users/ruby/go/src/github.com/go-errors/errors

cd/Users/ruby/go/src/github.com/go-errors/errors

gitsubmodule update--init--recursive

cd/Users/ruby/go/src/github.com/go-errors/errors

gitshow-ref

cd/Users/ruby/go/src/github.com/go-errors/errors

gitsubmodule update--init--recursive

WORK=/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build188558329

localhost:hello ruby$

效果圖:

這里可以很明顯的看到,執(zhí)行完 go get 命令以后声邦,會調(diào)用 git clone 方法下載源碼乏奥,并編譯,最終會把庫源碼文件編譯成歸檔文件安裝到 pkg 對應(yīng)的相關(guān)平臺目錄下亥曹。

總結(jié)一下如下圖:

5. 其他命令

go clean

go clean 命令是用來移除當(dāng)前源碼包里面編譯生成的文件邓了,這些文件包括

_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 產(chǎn)生

DIR.test(.exe) 由 go test -c 產(chǎn)生

MAINFILE(.exe) 由 go build MAINFILE.go產(chǎn)生

go fmt

go fmt 命令主要是用來幫你格式化所寫好的代碼文件。

比如我們寫了一個(gè)格式很糟糕的 test.go 文件龙巨,我們只需要使用 fmt go test.go 命令笼呆,就可以讓go幫我們格式化我們的代碼文件。但是我們一般很少使用這個(gè)命令旨别,因?yàn)槲覀兊拈_發(fā)工具一般都帶有保存時(shí)自動格式化功能诗赌,這個(gè)功能底層其實(shí)就是調(diào)用了 go fmt 命令而已。

使用go fmt命令秸弛,更多時(shí)候是用gofmt铭若,而且需要參數(shù)-w,否則格式化結(jié)果不會寫入文件递览。gofmt -w src叼屠,可以格式化整個(gè)項(xiàng)目。

go test

go test 命令绞铃,會自動讀取源碼目錄下面名為*_test.go的文件镜雨,生成并運(yùn)行測試用的可執(zhí)行文件。默認(rèn)的情況下儿捧,不需要任何的參數(shù)荚坞,它會自動把你源碼包下面所有test文件測試完畢挑宠,當(dāng)然你也可以帶上參數(shù),詳情請參考go help testflag

go doc

go doc 命令其實(shí)就是一個(gè)很強(qiáng)大的文檔工具颓影。

如何查看相應(yīng)package的文檔呢各淀? 例如builtin包,那么執(zhí)行g(shù)o doc builtin诡挂;如果是http包碎浇,那么執(zhí)行g(shù)o doc net/http;查看某一個(gè)包里面的函數(shù)璃俗,那么執(zhí)行g(shù)o doc fmt Printf奴璃;也可以查看相應(yīng)的代碼,執(zhí)行g(shù)o doc -src fmt Printf旧找;

# 查看net/http包

localhost:hello ruby$ godoc net/http

# 查看time包

localhost:hello ruby$ godoc time

# 查看某個(gè)包里的指定函數(shù)

localhost:hello ruby$ godoc fmt Printf

通過命令在命令行執(zhí)行 go doc -http=:端口號溺健,比如godoc -http=:8080。然后在瀏覽器中打開127.0.0.1:8080钮蛛,你將會看到一個(gè)golang.org的本地copy版本鞭缭,通過它你可以查詢pkg文檔等其它內(nèi)容。如果你設(shè)置了GOPATH魏颓,在pkg分類下岭辣,不但會列出標(biāo)準(zhǔn)包的文檔,還會列出你本地GOPATH中所有項(xiàng)目的相關(guān)文檔甸饱,這對于經(jīng)常被限制訪問的用戶來說是一個(gè)不錯(cuò)的選擇沦童。

localhost:hello ruby$ godoc-http=:9527

go fix 用來修復(fù)以前老版本的代碼到新版本,例如go1之前老版本的代碼轉(zhuǎn)化到go1

go version 查看go當(dāng)前的版本

go env 查看當(dāng)前go的環(huán)境變量

go list 列出當(dāng)前全部安裝的package

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末叹话,一起剝皮案震驚了整個(gè)濱河市偷遗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驼壶,老刑警劉巖氏豌,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異热凹,居然都是意外死亡泵喘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門般妙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纪铺,“玉大人,你說我怎么就攤上這事碟渺∠拭” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芜繁。 經(jīng)常有香客問我攒霹,道長,這世上最難降的妖魔是什么浆洗? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮集峦,結(jié)果婚禮上伏社,老公的妹妹穿的比我還像新娘。我一直安慰自己塔淤,他們只是感情好摘昌,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著高蜂,像睡著了一般聪黎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上备恤,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天稿饰,我揣著相機(jī)與錄音,去河邊找鬼露泊。 笑死喉镰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的惭笑。 我是一名探鬼主播侣姆,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼沉噩!你這毒婦竟也來了捺宗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤川蒙,失蹤者是張志新(化名)和其女友劉穎蚜厉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體派歌,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弯囊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了胶果。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匾嘱。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖早抠,靈堂內(nèi)的尸體忽然破棺而出霎烙,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布悬垃,位于F島的核電站游昼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏尝蠕。R本人自食惡果不足惜烘豌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望看彼。 院中可真熱鬧廊佩,春花似錦、人聲如沸靖榕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茁计。三九已至料皇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間星压,已是汗流浹背践剂。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留租幕,地道東北人舷手。 一個(gè)月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像劲绪,于是被迫代替她去往敵國和親男窟。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容