一成畦、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