Go 开发组为以下操作系统, 开发了编译器:
• Linux
• FreeBSD
• OS X(或称 Darwin)
同时 Go 编译器包含了两个版本:gc 和 gccgo, 它们都可工作在类 Unix 的操作系统中, gc 编译器已经移植到Windows 平台且公开发布了, 这两个编译器都采用单阶 (single pass) 编译方式.
在以下软硬件平台上,Go 1 同时发布了源码版本和二进制版本.
• FreeBSD 7+: amd64,386
• Linux 2.6+: amd64,386,arm
• OS X(Snow Leopard + Lion): amd64,386
• Windows 2000 及后续版本: amd64,386
在上述操作系统中,Go 代码可提供良好的移植性 (假定只使用了纯粹的 Go 代码, 未包含 cgo 和其他底层包),所以既可以在操作系统之间复制代码完成编译, 也可采用交叉编译 (参见 2.2 节).
2.1.1 gc 编译器
该编译器基于 Ken Thompson 在 Plan 9 操作系统上, 开发的 C 工具链, 因此 gc 编译器和链接器的开发, 都使用了 C 语言, 所以可生成原生代码 (其中不包含 Go 的自举或自引导代码), 因此不同的操作系统和处理架构 (32bit,64bit) 都需要提供不同的编译器.
gc 的编译速度快于 gccgo, 并能生成更好的原生代码, 同时无须与 gcc 关联, 所以不存在沿袭与合并, 带来的隐藏问题, 而且可实现并行.
下表列出了不同 Intel 和 AMD 处理器适用的编译器:
处理器字节 | 名称 | 编译器 | 链接器 |
---|---|---|---|
64bit | amd64(x86-64) | 6g | 6I |
32bit | 386(x86,x86-32) | 8g | 8I |
32bit RISC | arm(ARM) | 5g | 5I |
从上表可见, 编译器和链接器的命名有些奇怪 (来自于 Plan 9 项目的命名规则),
• g 为编译器, 基于源代码可生成目标代码.
• i 为链接器, 可将目标代码转换成二进制执行代码.
因此对应的 C 编译器为 6c,8c,5c, 汇编器为 6a,8a,5a.
下表列出了 gc 支持的硬件架构和操作系统的版本号,
操作系统 | 硬件架构 | 操作系统的版本号 |
---|---|---|
linux | 386/amd64/arm | >= Linux 2.6 |
darwin | 386/amd64 | OS X(Snow Leopard + Lion) |
freebsd | 386/amd64 | >= FreeBSD 7 |
windows | 386/amd64 | >= Windows 2000 |
windows 版本 (8g 与 6g) 的 95% 都来自于外部贡献 (Google 之外的开发者),Google 开发组提交了 arm 版本, 并最终能运行在 Android 操作系统 (隶属于 Google 智能电话项目) 下, 所以 Go 应用也能运行 Android 中.
gc 编译器在命令行中, 可配置一些选项, 而这些选项可影响编译和连接, 或是生成特定的输出, 编译器选项如下:
C:\Users\ivo>8g
gc: usage: 8g [flags] file.go…
flags:
-I DIR search for packages in DIR
-d print declarations
-e no limit on number of errors printed
-f print stack frame structure
-h panic on an error
-o file specify output file
-S print the generated assembly code
-V print the compiler version
-u disable package unsafe
-w print the parse tree after typing
-x print lex tokens
-I 可提供需要编译 Go 文件的路径 (也可包含环境变量 $GOPATH).
链接器的选项如下:
C:\Users\ivo>8l
usage: 8l [-options] [-Eentry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8
-L 可提供需要编译 Go 文件的路径 (也可包含环境变量 $GOPATH).
编译器和链接器的源代码, 放在 $GOROOT/src/cmd 目录下, 查看其中的文件可知,Go 语言开发使用了 C, 而不是 Go 语言本身, 同时使用了 GNU bison 生成了 lexer/parser(编译所需的文法器/解析器), GOROOT/src/cmd/gc/go.y文件(yacc文件)将控制grammar/parser(语法器/解析器),并在相同目录下,将生成输出文件y.tab.c,h,可查看该目录下的Makefile,以得到构建步骤的更多信息,而构建步骤的主要内容都包含在GOROOT/src/make.bash 文件中.
doc.go 文件中包含了大部分的目录信息.
2.1.2 gccgo 编译器
这是一个使用 gcc 为后端的传统编译器, 使用 GNU 编译器, 可兼容大量的处理器架构, 但编译速度比较慢, 而生成的原生代码的执行速度也比较快, 同时需要提供一些与 C 语言关联的信息.
2011 年 3 月 25 日发布的 GCC 4.6.0 版本中, 已经集成了 Go 编译器, 当然其中也包含了其他语言的支持 (比如 Ada,C,C++,Fortran,Java), 相关信息可查看 http://golang.org/doc/gccgo 页面,gc 和 gccgo 编译器的功能是一致的.
2.1.3 文件扩展名和包
Go 源码文件的扩展名为 go, 源码文件可合并成包 (package), 包含二进制代码的包可进行压缩, 提供的扩展名为 a(AR 压缩格式), 它也是 Go 标准库包的格式, 链接 (目标) 文件的扩展名为 o, 可执行程序的默认扩展名,在 Unix 系统中为 out, 在 Windows 系统中为 exe.
注意, 在自定义目录下, 使用 Go 语言的工具时, 应当保证目录名中, 不存在空格, 可以使用_符号替换空格.
2.2 环境变量在 Go 语言中, 使用了少量的环境变量, 应完成它们的定义后, 再进行 Go 语言的安装, 在Windows 中, 可预先定义一个空的根目录, 比如c:\go, 所需的环境变量如下:
- $GOROOT: 大多数情况下, 该变量为 $HOME/go, 当然也可选择 go 源码目录或是安装文件的存放目录,作为根目录.
- $GOARCH: 目标系统的处理器架构, 通常为 386,amd64,arm.
- $GOOS: 目标系统的操作系统, 通常为 darwin,freebsd,linux,windows.
- $GOBIN: 工具 (比如编译器, 链接器等) 的存放目录, 默认为 $GOROOT/bin.
- $GOPATH: 默认为 GOROOT, 通常可定义一组路径, 用于存放 Go 源码, 二进制包和可执行文件, 一般指定为 GOPATH 的子目录, 比如 src,pkg 和 bin, 这些变量必须设定, 以方便语言工具的使用.
- $GOROOT_FINAL: 默认为 GOROOT, 通常无须清晰定义, 如果 Go 安装后, 需要移动到另一个目录,这时可该路径中, 设定 Go 安装文件的最终路径.
- $GOARM: arm 架构, 可能是 5 或 6, 默认值为 6.
- $GOMAXPROCS: 指定一组 Go 应用所需支持的硬件核心 (处理器), 参见 14.1.3.
Go 编译器支持交叉编译.
在后续小节, 将讨论 Go 语言的安装, 比如 Linux,OS X 和 Windows 的安装, 而 FreeBSD 的安装可使用Linux 的安装方法, 而 Go 语言正在移植到其他的操作系统中, 比如OpenBSD, DragonFlyBSD, NetBSD, Plan 9,Haiku 和 Solaris, 最新的进展可查看http://go-lang.cat-v.org/os-ports 页面.
2.3 Linux 安装该安装方式需要下载 Go 语言源码, 进行重新编译, 并能从 verb|//golang.org/doc/install.html| 页面中, 查找到最新的安装方法, 如以下小节的描述.
2.3.1 设置环境变量
在 Linux 系统中, 可在 shell 配置文件 ($HOME/.bashrc 或 $HOME/.profile, 又或是其他的等价文件, 并可使用 gedit 和 vi 编辑器进行文本编辑) 中, 设定 Go 语言所需的环境变量,
C:\Users\ivo>8l
export GOROOT=$HOME/go
export GOBIN=$GOROOT/bin
export GOARCH=amd64
export GOOS=linux
为了在文件系统中, 可搜索到 Go 语言的二进制执行文件, 需将这些文件的目录, 加入到系统的检索路径中:
C:\Users\ivo>8l
export PATH=$GOBIN:$PATH
Go 语言的附带工具, 将使用 GOPATH 环境变量,
export GOPATH=$HOME/goprograms
或者
export GOPATH=$GOROOT
如果登录的账号名为 user1, 那么$HOME 即为/home/user1, 将当前目录加入到 GOPATH 环境变量,
export GOPATH=$GOPATH:.
. 表示当前目录, 使用: 符号, 可加入多个目录, 以便 Go 源码目录, 包对象目录, 可执行工具目录加入到 GOPATH环境变量.
使用 source .bashrc 命令, 可使控制台复位, 并重新载入.bashrc, 以便新设定的环境变量能够启用 (在控制台窗口中, 可使用 env | grep ^GO 或 echo $GOROOT 等命令, 可测试环境变量的设定是否成功).
2.3.2 安装 C 工具链
Go 语言的工具链是由 C 语言开发的, 因此在工具链的构建中, 需要以下软件包:
• GCC
• C 标准开发库:Libc6-dev
• 解析生成器:Bison
• make
• gawk
• 文本编辑器 ed
在基于 Debian 的 Linux 系统中 (比如 Ubuntu), 可使用以下命令, 安装工具链编译所需的软件包:
sudo apt-get install bison ed gawk gcc libc6-dev make
而在其他类型的 Linux 系统中, 可使用 RPM 工具.
2.3.3 安装 Mercurial
Go 语言源码使用了 Mercurial 版本控制工具, 因此需要安装对应的软件包, 在控制台中输入 hg, 可测试 Mercurial 是否已经安装,
sudo apt-get install mercurial
在安装过程中, 可能会出现缺少其他依赖包的错误, 因此还需要安装以下依赖包:
apt-get install python-setuptools python-dev build-essential
如果依然无法安装 Mercurial, 可在http://mercurial.selenic.com/wiki/Download 页面, 直接下载 Mercurial 源码, 手工编译安装.
在 Mercurial 1.7 和后续版本中, 需要提供 CAs(Certification Authorities, 权威认证) 配置, 如果在 Mercurial运行时, 未查找 CAs 配置, 将出现错误信息, warning: go.googlecode.com certificate with fingerprint b1:af: …bc not verified (check hostfingerprints or web.cacerts config setting), 这时需要确认 Mercurial 的版本 ( hg-version), 并配置 CAs.
2.3.4 从源码仓库获取 Go 源码
Go 语言的安装目录需命名为 go, 并配置给环境变量 $GOROOT, 使用以下命令, 可从源码仓库获取 Go 源码:
hg clone -u release https://go.googlecode.com/hg/ $GOROOT
2.3.5 构建
cd $GOROOT/src
./all.bash
构建和测试需要一些时间 (通常是数分钟), 当构建成功后, 将出现以下文本:
ALL TESTS PASSED
Installed Go for linux/amd64 in /home/you/go.
Installed commands in /home/you/go/bin.
*** You need to add /home/you/go/bin to your $PATH. ***
The compiler is 6g.
这时在系统中, 已经安装好相符的 Go 语言环境.
如果在构建过程中出现错误, 可使用命令 hg pull -u, 从源码仓库中, 获取更新内容, 并重新进行构建. 在构建过程中, 会进行 http 测试 (网络测试), 并需要连接到 google.com(2016 年 7 月 10 日 google.com 依然处于被墙的状态, 可使用 vpn 解决 google.com 的连接问题). 从而引发一个经常出现的问题:
‘make[2]: Leaving directory /localusr/go/src/pkg/net’
这通常是由于系统防火墙所导致的问题, 在构建过程中, 可暂时关闭系统防火墙, 或者使用另一个方法, 取消网络测试, 也就是在.bashrc 添加一行命令:
DISABLE_NET_TESTS=1
如果需要取消网络包的测试, 可在 go/src/pkg 目录下的 Makefile 中, 添加 NOTEST 命令. 如果不需要运行网络测试, 也可运行./make.bash.
2.3.6 验证安装结果
在文本编辑器中, 输入以下文本, 并保存成 test.go 文件,
package main
func main () {
println("Hello", “world”)
}
• 6g test.go, 进行源码编译
• test.6, 生成的编译文件
• 6l test.6, 进行编译文件的链接
• 6.out, 生成的可执行文件
• ./6.out, 执行编译完成的二进制文件
• Hello,world, 执行文件产生的文本输出
以下是 64bit 操作系统的工具, 在 32bit 系统中, 需使用 8g/8l, 在 arm 系统中, 则使用 5g/5l.
2.3.7 验证安装版本
使用 release 命令可验证 Go 语言的版本:
• 验证静态版本号, 比如 release.r60 9481
• 验证日期版本号, 比如 release.2011-01-06 release 7053
验证已安装的版本号:
cd $GOROOT
hg identify
最快的验证方法, 是采用命令 go version, 或是编译器的-V 选项 (6g -V 或是 8g -V), 它们将产生以下的输出文本,8g version 7053 release.2011-01-06 release. 同时 Go 语言的当前版本, 也可通过 runtime 包的 Version 函数进行获取:
package main
import (
“fmt”
“runtime”
)
func main ( ) {
fmt.Printf("%s", runtime.Version())
}
执行上述程序, 可得到输出文本,7053 release.2011-01-06 release.
2.3.8 版本更新
cd $GOROOT
hg pull
hg update release
cd src
sudo ./all.bash
从http://golang.org/doc/devel/release.html 页面中, 可查看版本信息, Go 语言的第一个静态版本为 r56(2011.03.16),从 2011 年 3 月 15 日开始, 每周都有最新的改动被加入, 因此每周都需要使用 hg 进行同步更新, 而目前的最新版本为 Go 1, 也就是说第一个静态版本已经历了一年的维护. 在 Go 语言仓库中, 也给出了以下三个分支源码树:
• Go release: 静态版本, 满足大多数的 Go 语言开发
• Go weekly: 每周的更新版本
• Go tip: 最新的开发版本
如果需要及时跟踪 Go 语言的改进, 可选择后两个版本, 使用 gofix 工具, 也可得到最新版本.
不同版本的文档
http://golang.org/pkg 页面, 将给出最新静态版本的文档, 当最新版本发布时, 该文档也将更新,http://weekly.goneat.org/pkg/页面, 将给出周版本的文档, http://tip.goneat.org/pkg/将给出最新开发版本的文档, 在有些站点中,goneat 将替换成 golang.
安装软件包
在http://go-lang.cat-v.org/packages 页面下, 可找到 Go 语言的安装软件包, 在https://launchpad.net/~cz.niclabs/+archive/golang 页面下, 可下载 Ubuntu 的安装软件包.
2.4 OS X 安装(略)
2.5 Windows 安装(略)
2.6 安装结果当 Go 语言安装完成, 将在根目录 ($GOROOT) 中, 出现以下文件结构:
• README,AUTHORS,CONTRIBUTORS,LICENSE 文件
• \bin 子目录: 包含所有的可执行文件 (比如编译器), 以及所有的附带工具
• \doc 子目录: 包含教程, 代码概述, 本地文档, 问题集和 logo 等
• \include 子目录: C/C++ 头文件
• \lib 子目录: 文档的模板
• \misc 子目录: 支持 Go 的文本编辑器所需的配置文件,cgo 示例等
• \pkg\os_arch 子目录: 包含了操作系统的架构, 比如 linux_amd64,windows_386 等, 以及所有标准库包的目标文件 (.a)
• \src 子目录: bash 脚本文件和 make 文件
• \cmd 子目录: 编译器所需的脚本和源码文件 (Go,C), 以及相关命令文件
• \lib9\libbio和libmach 子目录: C 文件
• \pkg 子目录: 所有标准库包的 Go 源码文件 (这才是开源软件!)
在 Windows 386 r59 版本中, 将包含 3084 个文件,355 个目录, 容量约为 129MB, 在 Linux 64bit r60 版本中,将包含 3958 个文件, 容量约为 176MB.
2.7 Go 的运行时状态尽管编译器可生成原生机器码, 但机器码需在一个运行时状态下运行 (runtime 包可提供对应功能), 该运行时状态有时与 Java 和.Net 的虚拟机很相似, 它将负责内存分配, 垃圾收集 (参见 10.8 节), 堆栈处理, 并发协程,并发通道, 切片,map, 发射等诸多功能.
在 Go 包的链接中,runtime 属于上层包, 大部分使用了 C 语言, 可在$GOROOT/src/pkg/runtime/ 目录下找到它 (可参看 mgc0.c 和其他 m 开头的文件).
垃圾收集器
6g 包含了一个简单高效的 mark-and-sweep(标记与互换) 收集器, 同时收集器的开发仍在继续, 目前使用了IBM 提出的循环垃圾收集器, 以创建一个更高效和低延时的并发收集器, 目前 gccgo 中未包含收集器, 准备使用正在开发的收集器, 而具备垃圾收集功能的语言, 并不意味着用户可以忽略内存分配的问题, 因为内存的分配和释放, 都需要使用 CPU 资源.
Go 可执行文件的尺寸, 将远大于源码文件的尺寸, 这时因为 Go 运行时状态会嵌入到每个可执行文件中, 当机器中运行了大量的类似应用时, 这种嵌入很明显是一个缺陷, 但是这也使 Go 得到了一个静态二进制文件 (在执行中无须其他文件的支持), 因此它的开发比 Java 或 Python 更简单, 同时也不会引入不同版本之间的依赖问题.
2.8 Go 解析器由于 Go 语言实现了与动态语言相似的快速编译, 很自然地联想到,Go 语言是否也实现了, 与动态语言相似的编译方法 (read-eval-print loop),Sebastien Binet 开发了 Go 语言的解析器, 从https://bitbucket.org/binet/igo页面中, 可找到相关信息.