如何從源代碼構建 Go 1.5 開發環境
近期,Go Team 連續放出了幾個大招來介紹即將在八月問世的 Go 1.5 這個劃時代的版本。Rob 和 Andrew 分別在《Go in Go》和《The State of Go》中詳細說明了出現在 Go 1.5 中的重要特性和細節變化。在這個版本中最主要的變化是移除了所有 C 代碼,不論是 runtime 還是編譯器都使用 Go 語言和一小部分的匯編來實現——也就是人們常說的自舉。但是這樣做也就意味著,Go 在 1.5 和以后的版本中,使用源代碼構建 Go
開發環境將面臨“雞生蛋,蛋生雞”的麻煩(當然了,如果你直接“買雞蛋”——使用二進制安裝包——是沒有這個問題的)。
在 Go1.4 及更早的版本中,會使用 GCC 先編譯一個使用 C 語言編寫的,僅具有基本功能的小編譯器作為構建 Go 環境的引導工具。也就是說必須要安裝 GCC、make 等 C 語言相關的工具才能從源代碼構建 Go 的開發環境。而據 Rob 的講義和其撰寫的《Go 1.5 Bootstrap Plan》中介紹的,Go 1.5 將不再有 C 語言的參與,反而需要使用 Go 1.4 版本的工具鏈進行編譯。那么也就意味著,從源代碼開始構建 Go 1.5 需要兩個版本并存。幾年前,有許多人折戟在 GOROOT/GOPATH 的坑里。現在還需要兩個版本的 Go 并存,想想似乎都是個挺麻煩的事情。
對于 Go 來說,大道至簡!所以通過這篇文章里我想簡單介紹一下如何使用源代碼構建 Go 1.5 開發環境。由于“雞生蛋,蛋生雞”的緣故,需要從構建 Go 1.4 的開發環境開始講起。
需要說明的是,以下所有內容都是在 Ubuntu 14.04 中演示操作的,但只要是符合 POSIX 標準的系統,以下操作應該都是一致的。Windows 的用戶我強烈建議還是使用二進制包進行安裝。不折騰!
準備工作
一個“干凈”的系統是必須的,這里的“干凈”是指沒有設置過 GOROOT/GOPATH/GOBIN 之類的環境變量。如果之前已經配置過 Go 的環境,那只能酌情調整或刪除重新設置了。
同時,由于需要編譯 Go 1.4,所以必須安裝 C 相關的工具:
$ apt-getinstallgcc libc6-dev |
</tr>
</tbody>
</table>
</div>
</div>
</div>
##目錄結構
2012 年的時候,我曾經翻譯過一篇文章《GO 環境設置》。雖然那個時候 Go 的代碼還在使用 hg 進行版本控制,同時 Go 1 也沒有正式發布,不過那篇文章中介紹的目錄設置方式,我卻一直使用至今,其結構如下:
$HOME/golang/ |
</tr>
</tbody>
</table>
</div>
├── 3rdpkg |
</tr>
</tbody>
</table>
</div>
├── go |
</tr>
</tbody>
</table>
</div>
└── own |
</tr>
</tbody>
</table>
</div>
</div>
</div>
其中$HOME/golang/3rdpkg,$HOME/golang/go和$HOME/golang/own目錄應按照順序加入環境變量GOPATH中。這樣的好處是在使用go get獲取 Go 包的時候會直接導入到GOPATH的第一個路徑,也就是3rdpkg這個子目錄中。這樣可以將第三方包,Go 的代碼和自己的工作目錄區分開來。
不過,由于 Go 1.5 需要兩個版本的 Go 并存,那么這個目錄結構也就需要做相應的調整。最終如下,稍候我會詳細介紹。
環境變量
前面已經提到了 GOPATH 的設置:
GOPATH=$HOME/golang/3rdpkg:$HOME/golang/go:$HOME/golang/own |
</tr>
</tbody>
</table>
</div>
</div>
</div>
由于現在有兩個版本的 Go 代碼并存,所以我們需要建立一個軟鏈接指向所需要的版本的代碼目錄,例如:
$HOME/golang/ |
</tr>
</tbody>
</table>
</div>
├── 3rdpkg |
</tr>
</tbody>
</table>
</div>
├── go -> go1.4/ |
</tr>
</tbody>
</table>
</div>
├── go1.4 |
</tr>
</tbody>
</table>
</div>
└── own |
</tr>
</tbody>
</table>
</div>
</div>
</div>
這樣,就 GOROOT 的值就應該設置為:
GOROOT=$HOME/golang/go |
</tr>
</tbody>
</table>
</div>
</div>
</div>
有了這兩個環境變量就足夠了(交叉編譯和環境微調不在本文討論范圍內)。
為了能夠方便的使用 go 命令,還需要將$GOROOT/bin/加入 PATH 中:
PATH=$PATH:$GOROOT/bin/ |
</tr>
</tbody>
</table>
</div>
</div>
</div>
安裝 Go 1.4
使用 git 命令獲取 Go 1.4 的完整代碼。當前最新的 1.4 版本是 1.4.2,所以:
$cd$HOME/golang/ |
</tr>
</tbody>
</table>
</div>
$ git clone -b go1.4.2 https://github.com/golang/go.git go1.4 |
</tr>
</tbody>
</table>
</div>
</div>
</div>
然后讓 GOROOT 的軟鏈接目錄指向實際保存 Go 1.4 代碼的目錄:
$ln-s go1.4 go |
</tr>
</tbody>
</table>
</div>
</div>
</div>
這時目錄結構為:
$HOME/golang/ |
</tr>
</tbody>
</table>
</div>
├── 3rdpkg |
</tr>
</tbody>
</table>
</div>
├── go -> go1.4/ |
</tr>
</tbody>
</table>
</div>
├── go1.4 |
</tr>
</tbody>
</table>
</div>
└── own |
</tr>
</tbody>
</table>
</div>
</div>
</div>
環境變量的值為:
GOPATH=$HOME/golang/3rdpkg:$HOME/golang/go:$HOME/golang/own |
</tr>
</tbody>
</table>
</div>
GOROOT=$HOME/golang/go |
</tr>
</tbody>
</table>
</div>
PATH=$PATH:$GOROOT/bin |
</tr>
</tbody>
</table>
</div>
</div>
</div>
進入目錄$HOME/golang/go/src,運行 all.bash 腳本。
cd$HOME/golang/go/src |
</tr>
</tbody>
</table>
</div>
./all.bash |
</tr>
</tbody>
</table>
</div>
</div>
</div>
經過一個短暫的編譯和一個漫長的測試之后,Go 1.4 應該就部署完成了。
使用go version命令可以看到當前 Go 版本為 1.4.2:
$ go version go1.4.2 linux/amd64 |
</tr>
</tbody>
</table>
</div>
</div>
</div>
安裝 Go 1.5
由于 Go 1.5 需要基于 Go 1.4 構建,所以 Go 1.5 需要一個獨立的目錄放置(實際上用同一個目錄是可以的,不過需要額外的許多設置,不折騰)。
由于已經克隆了 Go 的代碼庫,可以直接復制 go1.4 這個目錄到目錄 go1.5,然后用命令:
$ go checkout -b master |
</tr>
</tbody>
</table>
</div>
</div>
</div>
切換到 Go 1.5 所在的代碼分支中。
有一點需要特別說明一下:由于 Go 1.5 預計要到八月才正式發布,所以要到那個時候才會有 go1.5 這個標簽出現。因此,當前的 master 分支實際上就是功能凍結的 Go 1.5 的代碼分支。
由于已經將 GOROOT 設置為$HOME/golang/go,因此只需要這個軟鏈接重新指向 Go 1.5 代碼所在目錄即可,而無須修改環境變量。
$cd$HOME/golang |
</tr>
</tbody>
</table>
</div>
$ unlink go |
</tr>
</tbody>
</table>
</div>
$ln-s go1.5 go |
</tr>
</tbody>
</table>
</div>
</div>
</div>
為了能夠編譯 Go 1.5,還需要額外設置一個叫做 GOROOT_BOOTSTRAP 環境變量,指向 Go 1.4 所在的目錄。同時為了能夠向后兼容,這個變量也使用軟鏈接的方式進行指向:
$ln-s go1.4 go-bootstrap |
</tr>
</tbody>
</table>
</div>
</div>
</div>
這時目錄結構為:
$HOME/golang/ |
</tr>
</tbody>
</table>
</div>
├── 3rdpkg |
</tr>
</tbody>
</table>
</div>
├── go -> go1.5/ |
</tr>
</tbody>
</table>
</div>
├── go-bootstrap -> go1.4/ |
</tr>
</tbody>
</table>
</div>
├── go1.4 |
</tr>
</tbody>
</table>
</div>
├── go1.5 |
</tr>
</tbody>
</table>
</div>
└── own |
</tr>
</tbody>
</table>
</div>
</div>
</div>
環境變量的值為:
GOPATH=$HOME/golang/3rdpkg:$HOME/golang/go:$HOME/golang/own |
</tr>
</tbody>
</table>
</div>
GOROOT=$HOME/golang/go |
</tr>
</tbody>
</table>
</div>
PATH=$PATH:$GOROOT/bin |
</tr>
</tbody>
</table>
</div>
GOROOT_BOOTSTRAP=$HOME/golang/go-bootstrap |
</tr>
</tbody>
</table>
</div>
</div>
</div>
進入目錄$HOME/golang/go/src,運行 all.bash 腳本。
$cd$HOME/golang/go/src |
</tr>
</tbody>
</table>
</div>
$ ./all.bash |
</tr>
</tbody>
</table>
</div>
</div>
</div>
又一個短暫的編譯和一個漫長的測試之后,Go 1.5 應該就部署完成了。
使用go version命令可以看到當前 Go 版本為開發編號: