### 10.7.3. 構建包

`go build`命令編譯命令行參數指定的每個包。如果包是一個庫，則忽略輸出結果；這可以用於檢測包的可以正確編譯的。如果包的名字是main，`go build`將調用連接器在當前目録創建一個可執行程序；以導入路徑的最後一段作爲可執行程序的名字。

因爲每個目録隻包含一個包，因此每個對應可執行程序或者叫Unix術語中的命令的包，會要求放到一個獨立的目録中。這些目録有時候會放在名叫cmd目録的子目録下面，例如用於提供Go文檔服務的golang.org/x/tools/cmd/godoc命令就是放在cmd子目録（§10.7.4）。

每個包可以由它們的導入路徑指定，就像前面看到的那樣，或者用一個相對目録的路徑知指定，相對路徑必鬚以`.`或`..`開頭。如果沒有指定參數，那麽默認指定爲當前目録對應的包。 下面的命令用於構建同一個包, 雖然它們的寫法各不相同:

```
$ cd $GOPATH/src/gopl.io/ch1/helloworld
$ go build
```

或者：

```
$ cd anywhere
$ go build gopl.io/ch1/helloworld
```

或者：

```
$ cd $GOPATH
$ go build ./src/gopl.io/ch1/helloworld
```

但不能這樣：

```
$ cd $GOPATH
$ go build src/gopl.io/ch1/helloworld
Error: cannot find package "src/gopl.io/ch1/helloworld".
```

也可以指定包的源文件列表，這一般這隻用於構建一些小程序或做一些臨時性的實驗。如果是main包，將會以第一個Go源文件的基礎文件名作爲最終的可執行程序的名字。

```
$ cat quoteargs.go
package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Printf("%q\n", os.Args[1:])
}
$ go build quoteargs.go
$ ./quoteargs one "two three" four\ five
["one" "two three" "four five"]
```

特别是對於這類一次性運行的程序，我們希望盡快的構建併運行它。`go run`命令實際上是結合了構建和運行的兩個步驟：

```
$ go run quoteargs.go one "two three" four\ five
["one" "two three" "four five"]
```

第一行的參數列表中，第一個不是以`.go`結尾的將作爲可執行程序的參數運行。

默認情況下，`go build`命令構建指定的包和它依賴的包，然後丟棄除了最後的可執行文件之外所有的中間編譯結果。依賴分析和編譯過程雖然都是很快的，但是隨着項目增加到幾十個包和成韆上萬行代碼，依賴關繫分析和編譯時間的消耗將變的可觀，有時候可能需要幾秒種，卽使這些依賴項沒有改變。

`go install`命令和`go build`命令很相似，但是它會保存每個包的編譯成果，而不是將它們都丟棄。被編譯的包會被保存到$GOPATH/pkg目録下，目録路徑和 src目録路徑對應，可執行程序被保存到$GOPATH/bin目録。（很多用戶會將$GOPATH/bin添加到可執行程序的蒐索列表中。）還有，`go install`命令和`go build`命令都不會重新編譯沒有發生變化的包，這可以使後續構建更快捷。爲了方便編譯依賴的包，`go build -i`命令將安裝每個目標所依賴的包。

因爲編譯對應不同的操作繫統平台和CPU架構，`go install`命令會將編譯結果安裝到GOOS和GOARCH對應的目録。例如，在Mac繫統，golang.org/x/net/html包將被安裝到$GOPATH/pkg/darwin_amd64目録下的golang.org/x/net/html.a文件。

針對不同操作繫統或CPU的交叉構建也是很簡單的。隻需要設置好目標對應的GOOS和GOARCH，然後運行構建命令卽可。下面交叉編譯的程序將輸出它在編譯時操作繫統和CPU類型：

```Go
gopl.io/ch10/cross

func main() {
	fmt.Println(runtime.GOOS, runtime.GOARCH)
}
```

下面以64位和32位環境分别執行程序：

```
$ go build gopl.io/ch10/cross
$ ./cross
darwin amd64
$ GOARCH=386 go build gopl.io/ch10/cross
$ ./cross
darwin 386
```

有些包可能需要針對不同平台和處理器類型使用不同版本的代碼文件，以便於處理底層的可移植性問題或提供爲一些特定代碼提供優化。如果一個文件名包含了一個操作繫統或處理器類型名字，例如net_linux.go或asm_amd64.s，Go語言的構建工具將隻在對應的平台編譯這些文件。還有一個特别的構建註釋註釋可以提供更多的構建過程控製。例如，文件中可能包含下面的註釋：

```Go
// +build linux darwin
```

在包聲明和包註釋的前面，該構建註釋參數告訴`go build`隻在編譯程序對應的目標操作繫統是Linux或Mac OS X時才編譯這個文件。下面的構建註釋則表示不編譯這個文件：

```Go
// +build ignore
```

更多細節，可以參考go/build包的構建約束部分的文檔。

```
$ go doc go/build
```
