在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ GO/ go build
go install
go clean
go list
go test
go doc與godoc
go build
go fix與go tool fix
go tool pprof
go run
go env
go tool cgo
標準命令詳解
go get
go vet與go tool vet

go build

go build命令用于編譯我們指定的源碼文件或代碼包以及它們的依賴包。

例如,如果我們在執(zhí)行go build命令時不后跟任何代碼包,那么命令將試圖編譯當前目錄所對應的代碼包。例如,我們想編譯goc2p項目的代碼包logging。其中一個方法是進入logging目錄并直接執(zhí)行該命令:

hc@ubt:~/golang/goc2p/src/logging$ go build

因為在代碼包logging中只有庫源碼文件和測試源碼文件,所以在執(zhí)行go build命令之后不會在當前目錄和goc2p項目的pkg目錄中產(chǎn)生任何文件。

插播:Go語言的源碼文件有三大類,即:命令源碼文件、庫源碼文件和測試源碼文件。他們的功用各不相同,而寫法也各有各的特點。命令源碼文件總是作為可執(zhí)行的程序的入口。庫源碼文件一般用于集中放置各種待被使用的程序實體(全局常量、全局變量、接口、結構體、函數(shù)等等)。而測試源碼文件主要用于對前兩種源碼文件中的程序實體的功能和性能進行測試。另外,后者也可以用于展現(xiàn)前兩者中程序的使用方法。

另外一種編譯logging包的方法是:

hc@ubt:~/golang/goc2p/src$ go build logging

在這里,我們把代碼包logging的導入路徑作為參數(shù)傳遞給go build命令。另一個例子:如果我們要編譯代碼包cnet/ctcp,只需要在任意目錄下執(zhí)行命令go build cnet/ctcp即可。

插播:之所以這樣的編譯方法可以正常執(zhí)行,是因為我們已經(jīng)在環(huán)境變量GOPATH中加入了goc2p項目的根目錄(即~/golang/goc2p/)。這時,goc2p項目的根目錄就成為了一個工作區(qū)目錄。只有這樣,Go語言才能正確識別我們提供的goc2p項目中某個代碼包的導入路徑。而代碼包的導入路徑是指,相對于Go語言自身的源碼目錄(即$GOROOT/src)或我們在環(huán)境變量GOPATH中指定的某個目錄的src子目錄下的子路徑。例如,這里的代碼包logging的絕對路徑是~/golang/goc2p/src/logging。而不論goc2p項目的根文件夾被放在哪兒,logging包的導入路徑都是logging。顯而易見,我們在稱呼一個代碼包的時候總是以其導入路徑作為其稱謂。

言歸正傳,除了上面的簡單用法,我們還可以同時編譯多個Go源碼文件:

hc@ubt:~/golang/goc2p/src$ go build logging/base.go logging/console_logger.go logging/log_manager.go logging/tag.go

但是,使用這種方法會有一個限制。作為參數(shù)的多個Go源碼文件必須在同一個目錄中。也就是說,如果我們想用這種方法既編譯logging包又編譯basic包是不可能的。不過別擔心,在需要的時候,那些被編譯目標依賴的代碼包會被go build命令自動的編譯。例如,如果有一個導入路徑為app的代碼包,同時依賴了logging包和basic包。那么在執(zhí)行go build app的時候,該命令就會自動的在編譯app包之前去檢查logging包和basic包的編譯狀態(tài)。如果發(fā)現(xiàn)它們的編譯結果文件不是最新的,那么該命令就會先去的編譯這兩個代碼包,然后再編譯app包。

注意,go build命令在編譯只包含庫源碼文件的代碼包(或者同時編譯多個代碼包)時,只會做檢查性的編譯,而不會輸出任何結果文件。

另外,go build命令既不能編譯包含多個命令源碼文件的代碼包,也不能同時編譯多個命令源碼文件。因為,如果把多個命令源碼文件作為一個整體看待,那么每個文件中的main函數(shù)就屬于重名函數(shù),在編譯時會拋出重復定義錯誤。假如,在goc2p項目的代碼包cmd(此代碼包僅用于示例目的,并不會永久存在于該項目中)中包含有兩個命令源碼文件showds.go和initpkg_demo.go,那么我們在使用go build命令同時編譯它們時就會失敗。示例如下:

hc@ubt:~/golang/goc2p/src/cmd$ go build showds.go initpkg_demo.go
# command-line-arguments
./initpkg_demo.go:19: main redeclared in this block
        previous declaration at ./showds.go:56

請注意上面示例中的command-line-arguments。在這個位置上應該顯示的是作為編譯目標的源碼文件所屬的代碼包的導入路徑。但是,這里顯示的并不是它們所屬的代碼包的導入路徑cmd。這是因為,命令程序在分析參數(shù)的時候如果發(fā)現(xiàn)第一個參數(shù)是Go源碼文件而不是代碼包,則會在內部生成一個虛擬代碼包。這個虛擬代碼包的導入路徑和名稱都會是command-line-arguments。在其他基于編譯流程的命令程序中也有與之一致的操作,比如go install命令和go run命令。

另一方面,如果我們編譯的多個屬于main包的源碼文件中沒有main函數(shù)的聲明,那么就會使編譯器立即報出“未定義main函數(shù)聲明”的錯誤并中止編譯。換句話說,在我們同時編譯多個main包的源碼文件時,要保證其中有且僅有一個main函數(shù)聲明,否則編譯是無法成功的。

現(xiàn)在我們使用go build命令編譯單一命令源碼文件。我們在執(zhí)行命令時加入一個標記-v。這個標記的意義在于可以使命令把執(zhí)行過程中構建的包名打印出來。我們會在稍后對這個標記進行詳細說明?,F(xiàn)在我們先來看一個示例:

hc@ubt:~/golang/goc2p/src/basic/pkginit$ ls
initpkg_demo.go
hc@ubt:~/golang/goc2p/src/basic/pkginit$ go build -v initpkg_demo.go 
command-line-arguments
hc@ubt:~/golang/goc2p/src/basic/pkginit$ ls
initpkg_demo  initpkg_demo.go

我們在執(zhí)行命令go build -v initpkg_demo.go之后被打印出的command-line-arguments”`就是命令程序為命令源碼文件initpkg_demo.go生成的虛擬代碼包的包名。順帶說一句,

命令go build會把編譯命令源碼文件后生成的結果文件存放到執(zhí)行該命令時所在的目錄下。這個所說的結果文件就是與命令源碼文件對應的可執(zhí)行文件。它的名稱會與命令源碼文件的主文件名相同。

順便說一下,如果我們有多個聲明為屬于main包的源碼文件,且其中只有一個文件聲明了main函數(shù)的話,那么是可以使用go build命令同時編譯它們的。在這種情況下,不包含main函數(shù)聲明的那幾個源碼文件會被視為庫源碼文件(理所當然)。如此編譯之后的結果文件的名稱將會與我們指定的編譯目標中最左邊的那個源碼文件的主文件名相同。

其實,除了讓Go語言編譯器自行決定可執(zhí)行文件的名稱,我們還可以自定義它。示例如下:

hc@ubt:~/golang/goc2p/src/basic/pkginit$ go build -o initpkg initpkg_demo.go 
hc@ubt:~/golang/goc2p/src/basic/pkginit$ ls
initpkg    initpkg_demo.go

使用-o標記可以指定輸出文件(在這個示例中指的是可執(zhí)行文件)的名稱。它是最常用的一個go build命令標記。但需要注意的是,當使用標記-o的時候,不能同時對多個代碼包進行編譯。

標記-i會使go build命令安裝那些編譯目標依賴的且還未被安裝的代碼包。這里的安裝意味著產(chǎn)生與代碼包對應的歸檔文件,并將其放置到當前工作區(qū)目錄的pkg子目錄的相應子目錄中。在默認情況下,這些代碼包是不會被安裝的。

除此之外,還有一些標記不但受到go build命令的支持,而且對于后面會提到的go install、go run、go test等命令同樣是有效的。下表列出了其中比較常用的標記。

表0-1 go build命令的常用標記說明

標記名稱 標記描述
-a 強行對所有涉及到的代碼包(包含標準庫中的代碼包)進行重新構建,即使它們已經(jīng)是最新的了。
-n 打印編譯期間所用到的其它命令,但是并不真正執(zhí)行它們。
-p n 指定編譯過程中執(zhí)行各任務的并行數(shù)量(確切地說應該是并發(fā)數(shù)量)。在默認情況下,該數(shù)量等于CPU的邏輯核數(shù)。但是在darwin/arm平臺(即iPhone和iPad所用的平臺)下,該數(shù)量默認是1。
-race 開啟競態(tài)條件的檢測。不過此標記目前僅在linux/amd64、freebsd/amd64、darwin/amd64windows/amd64平臺下受到支持。
-v 打印出那些被編譯的代碼包的名字。
-work 打印出編譯時生成的臨時工作目錄的路徑,并在編譯結束時保留它。在默認情況下,編譯結束時會刪除該目錄。
-x 打印編譯期間所用到的其它命令。注意它與-n標記的區(qū)別。

我們在這里忽略了一些并不常用的或作用于編譯器或連接器的標記。在本小節(jié)的最后將會對這些標記進行簡單的說明。如果讀者有興趣,也可以查看Go語言的官方文檔以獲取相關信息。

下面我們就用其中幾個標記來查看一下在構建代碼包logging時創(chuàng)建的臨時工作目錄的路徑:

hc@ubt:~/golang/goc2p/src$ go build -v -work logging
WORK=/tmp/go-build888760008
logging

上面命令的結果輸出的第一行是為了編譯logging包,Go創(chuàng)建的一個臨時工作目錄,這個目錄被創(chuàng)建到了Linux的臨時目錄下。輸出的第二行是對標記-v的響應。這意味著此次命令執(zhí)行時僅編譯了logging包。關于臨時工作目錄的用途和內容,我們會在講解go run命令和go test命令的時候詳細說明。

現(xiàn)在我們再來看看如果強制重新編譯會涉及到哪些代碼包:

hc@ubt:~/golang/goc2p/src$ go build -a -v -work logging
WORK=/tmp/go-build929017331
runtime
errors
sync/atomic
math
unicode/utf8
unicode
sync
io
syscall
strings
time
strconv
reflect
os
fmt
log
logging

怎么會多編譯了這么多代碼包呢?可以確定的是,代碼包logging中的代碼直接依賴了標準庫中的runtime包、strings包、fmt包和log包。那么其他的代碼包為什么也會被重新編譯呢?

從代碼包編譯的角度來說,如果代碼包A依賴代碼包B,則稱代碼包B是代碼包A的依賴代碼包(以下簡稱依賴包),代碼包A是代碼包B的觸發(fā)代碼包(以下簡稱觸發(fā)包)。

go build命令在執(zhí)行時,編譯程序會先查找目標代碼包的所有依賴包,以及這些依賴包的依賴包,直至找到最深層的依賴包為止。在此過程中,如果發(fā)現(xiàn)有循環(huán)依賴的情況,編譯程序就會輸出錯誤信息并立即退出。此過程完成之后,所有的依賴關系也就形成了一棵含有重復元素的依賴樹。對于依賴樹中的一個節(jié)點(代碼包)來說,它的直接分支節(jié)點(前者的依賴包),是按照代碼包導入路徑的字典序從左到右排列的。最左邊的分支節(jié)點會最先被編譯。編譯程序會依此設定每個代碼包的編譯優(yōu)先級。

執(zhí)行go build命令的計算機如果擁有多個邏輯CPU核心,那么編譯代碼包的順序可能會存在一些不確定性。但是,它一定會滿足這樣的約束條件:依賴代碼包 -> 當前代碼包 -> 觸發(fā)代碼包。

標記-p n可以限制編譯過程中任務執(zhí)行的并發(fā)數(shù)量,n默認為當前計算機的CPU邏輯核數(shù)。如果在執(zhí)行go build命令時加入標記-p 1,那么就可以保證代碼包編譯順序嚴格按照預先設定好的優(yōu)先級進行?,F(xiàn)在我們再來編譯logging包:

hc@ubt:~/golang/goc2p/src$ go build -a -v -work -p 1 logging
WORK=/tmp/go-build114039681
runtime
errors
sync/atomic
sync
io
math
syscall
time
os
unicode/utf8
strconv
reflect
fmt
log
unicode
strings
logging

我們可以認為,以上示例中所顯示的代碼包的順序,就是logging包直接或間接依賴的代碼包按照優(yōu)先級從高到低排列后的排序。

另外,如果在命令中加入標記-n,那么編譯程序只會輸出所用到的命令而不會真正運行。在這種情況下,編譯過程不會使用并發(fā)模式。

在本節(jié)的最后,我們對一些并不太常用的標記進行簡要的說明:

  • -asmflags

此標記可以后跟另外一些標記,如-D、-I、-S等。這些后跟的標記用于控制Go語言編譯器編譯匯編語言文件時的行為。

  • -buildmode

此標記用于指定編譯模式,使用方式如-buildmode=default(這等同于默認情況下的設置)。此標記支持的編譯模式目前有6種。借此,我們可以控制編譯器在編譯完成后生成靜態(tài)鏈接庫(即.a文件,也就是我們之前說的歸檔文件)、動態(tài)鏈接庫(即.so文件)或/和可執(zhí)行文件(在Windows下是.exe文件)。

  • -compiler

此標記用于指定當前使用的編譯器的名稱。其值可以為gcgccgo。其中,gc編譯器即為Go語言自帶的編輯器,而gccgo編譯器則為GCC提供的Go語言編譯器。而GCC則是GNU項目出品的編譯器套件。GNU是一個眾所周知的自由軟件項目。在開源軟件界不應該有人不知道它。好吧,如果你確實不知道它,趕緊去google吧。

  • -gccgoflags

此標記用于指定需要傳遞給gccgo編譯器或鏈接器的標記的列表。

  • -gcflags

此標記用于指定需要傳遞給go tool compile命令的標記的列表。

  • -installsuffix

為了使當前的輸出目錄與默認的編譯輸出目錄分離,可以使用這個標記。此標記的值會作為結果文件的父目錄名稱的后綴。其實,如果使用了-race標記,這個標記會被自動追加且其值會為race。如果我們同時使用了-race標記和-installsuffix,那么在-installsuffix標記的值的后面會再被追加_race,并以此來作為實際使用的后綴。

  • -ldflags

此標記用于指定需要傳遞給go tool link命令的標記的列表。

  • -linkshared

此標記用于與-buildmode=shared一同使用。后者會使作為編譯目標的非main代碼包都被合并到一個動態(tài)鏈接庫文件中,而前者則會在此之上進行鏈接操作。

  • -pkgdir

使用此標記可以指定一個目錄。編譯器會只從該目錄中加載代碼包的歸檔文件,并會把編譯可能會生成的代碼包歸檔文件放置在該目錄下。

  • -tags

此標記用于指定在實際編譯期間需要受理的編譯標簽(也可被稱為編譯約束)的列表。這些編譯標簽一般會作為源碼文件開始處的注釋的一部分,例如,在$GOROOT/src/os/file_posix.go開始處的注釋為:

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows

最后一行注釋即包含了與編譯標簽有關的內容。大家可以查看代碼包go/build的文檔已獲得更多的關于編譯標簽的信息。

  • -toolexec

此標記可以讓我們去自定義在編譯期間使用一些Go語言自帶工具(如vet、asm等)的方式。

上一篇:go tool pprof