Go语言进阶篇:最近看上了 《Go语言设计与实现》 一书,按照此书来进一步学习Golang

编译源代码

在Linux上编译源代码,首先先得获取Golang的程序才行。

获取源代码

首先执行命令来获取Golang的源代码:

root@ecs-266516:~# git clone https://github.com/golang/go.git
Cloning into 'go'...
remote: Enumerating objects: 554223, done.
remote: Total 554223 (delta 0), reused 0 (delta 0), pack-reused 554223
Receiving objects: 100% (554223/554223), 318.31 MiB | 814.00 KiB/s, done.
Resolving deltas: 100% (441750/441750), done.
root@ecs-266516:~/go/src#

获取完以后打开其 src 目录下执行 make.bash 文件:

root@ecs-266516:~/go/src# ./make.bash
ERROR: Cannot find /root/go1.4/bin/go.
Set $GOROOT_BOOTSTRAP to a working Go tree >= Go 1.17.13.
root@ecs-266516:~/go/src#

这里会提示找不到go1.4版本,因为从 Go 1.4 编译一个工具链,这是最后一个使用 C 编写编译器的 Go 版本(来自 https://go.dev/doc/install/source )。所以安装新版的Go之前必须先有一个Go的编译器。

如果有下面提示:

root@ecs-266516:~# cd go/src
root@ecs-266516:~/go/src# ./make.bash
-bash: ./src/make.bash: Permission denied
root@ecs-266516:~/go/src#

则将 make.bash 文件的权限变为777

root@ecs-266516:~/go/src# chmod 777 ./make.bash
root@ecs-266516:~/go/src#

安装Go的编译器

这里我们需要通过切换分支进行编译,故我们将刚才clone下来的复制一份,免得再次clone:

root@ecs-266516:~/go/src# cd
root@ecs-266516:~# cp -r go go1.4
root@ecs-266516:~# ls
go       go1.4
root@ecs-266516:~# 

从我们clone下来的仓库文件中切换到Go1.4的分支,从Github仓库中我们知道,Go1.4的分支名为:release-branch.go1.4

root@ecs-266516:~# cd go1.4
root@ecs-266516:~/go1.4# git branch
* master
root@ecs-266516:~/go1.4# git checkout release-branch.go1.4
Branch 'release-branch.go1.4' set up to track remote branch 'release-branch.go1.4' from 'origin'.
Switched to a new branch 'release-branch.go1.4'
root@ecs-266516:~/go1.4# git branch
  master
* release-branch.go1.4
root@ecs-266516:~/go/src#

image-20221204102540766.png

切换好分支以后,我们进行Go1.4这个编译器的安装:

root@ecs-266516:~/go1.4# cd src
root@ecs-266516:~/go1.4/src# ./all.bash
# Building C bootstrap tool.
cmd/dist

# Building compilers and Go bootstrap tool for host, linux/amd64.
lib9

...

runtime/debug
net/rpc/jsonrpc
runtime/race
testing
testing/iotest
testing/quick
text/scanner

Build complete; skipping tests.
To force tests, set GO14TESTS=1 and re-run, but expect some failures.
root@ecs-266516:~/go1.4/src#

获取当前目录的路径,配置环境变量 GOROOT_BOOTSTRAP

root@ecs-266516:~/go1.4/src# pwd
/root/go1.4/src
root@ecs-266516:~/go1.4/src# export GOROOT_BOOTSTRAP=/root/go1.4/
root@ecs-266516:~/go1.4/src#

接下来就能愉快的开始编译新版的Go语言啦。

正式编译Go语言

我们回到刚才的目录,执行 make.bash 文件:

root@ecs-266516:~/go1.4/src# cd
root@ecs-266516:~# cd go/src
root@ecs-266516:~/go/src# ./make.bash
Building Go cmd/dist using /root/go1.4. (go1.4-bootstrap-20170531 linux/amd64)
can't load package: package ./cmd/dist: found packages build.go (main) and notgo117.go (building_Go_requires_Go_1_17_13_or_later) in /root/golang/goroot/src/cmd/dist
root@ecs-266516:~/go/src#

这里会出现报错 can't load package: package ./cmd/dist: found packages build.go (main) and notgo117.go (building_Go_requires_Go_1_17_13_or_later) in /root/golang/goroot/src/cmd/dist,应该是最新版的Go语言(写文章时最新版为1.19.3)安装是需要先安装版本大于1.17.3的Go语言,如果不需要最新版的Go的话,那么可以直接按照上面的 安装Go的编译器 再次安装一遍Go1.18,Go1.8的分支名为:release-branch.go1.18;如果需要最新版Golang的话,那么在编译完1.18版本之后再次编译新版Go。

我这里以编译完1.18后再安装新版Go为例。

安装好后,再次执行编译命令:

root@ecs-266516:~/go/src# export GOROOT_BOOTSTRAP=/root/go1.18/
root@ecs-266516:~/go/src# ./make.bash
Building Go cmd/dist using /root/go1.8. (go1.18.8 linux/amd64)
Building Go toolchain1 using /root/go1.8.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 using go_bootstrap and Go toolchain2.
Building packages and commands for linux/amd64.
---
Installed Go for linux/amd64 in /root/golang/goroot
Installed commands in /root/golang/goroot/bin
root@ecs-266516:~/go/src# /root/go/bin/go version
go version go1.19.3 linux/amd64
root@ecs-266516:~/go/src# 

可以看到,已经成功啦!

修改源代码

接下来我们修改一下他的 fmt.Println 方法下的源代码:

首先通过vim命令打开实现 fmt.Println 方法的文件 /go/src/fmt/print.go ,在第 293 行处:

// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
func Println(a ...any) (n int, err error) {
        return Fprintln(os.Stdout, a...)
}

其中 println注意 “p” 是小写)是Go语言运行时提供的内置方法,我们加上去一行自己的打印字符串:

func Println(a ...any) (n int, err error) {
        println("Stuarx")
        return Fprintln(os.Stdout, a...)
}

修改并且保存之后,我们再次编译生成Go的二进制文件以及相关工具链:

root@ecs-266516:~/go/src# ./make.bash

效果实现

我们来自己写一段代码:

package main

import "fmt"

func main() {
        fmt.Println("Hello World")
}

我们利用编译后的Go语言来执行一下:

root@ecs-266516:~/gotest# /root/go/bin/go run main.go
Stuarx
Hello World
root@ecs-266516:~/gotest#

我们成功的调用了我们修改后的 Println 函数!

最后修改:2024 年 07 月 19 日
如果觉得我的文章对你有用,请随意赞赏