go install 的工作方式

前端之家收集整理的这篇文章主要介绍了go install 的工作方式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

go install 是Go语言提供的非常方便的编译工具。但是最近在项目使用过程中遇到一些问题,在这里记录一下。

问题

通常情况下,修改代码之后使用go install编译,运行,都能得到正确的结果。

但是有时候发现,修改了源代码,却没有被重新编译,于是导致许多诡异的问题。

为了弄清楚这个问题,下面用一个简单的例子来做个实验。也顺带把go install的工作方式简单介绍一遍。

简单的代码

现在有一个名叫hello的项目,目录在/tmp/gomain/src/hello/hello.go

package main

import "github.com/my/human"

func main() {
	human.Say("hello!")
}
hello项目引用了一个 human的第三方包,这个包在另一个目录/tmp/ gopkg/src/github.com/my/human/human.go
package human

func Say(s string) {
	println("human say:",s)
}

编译hello项目

好了,代码就这么简单。那么现在要编译这个hello项目,首先设置GOPATH环境变量

export GOPATH=/tmp/gopkg:/tmp/gomain
export GOBIN=/tmp

编译hello项目

go install hello

go install会依次查找所有GOPATH中的目录寻找hello包和它依赖的github.com/my/human包。然后会将报名为main的包生成二进制文件放到GOBIN目录下。将非main包编译成.a文件放到项目对于的pkg目录下

所以执行以上语句之后会在/tmp目录下生成hello可执行文件。并且在/tmp/gopkg/pkg/linux_amd64/github.com/my/human.a生成一个.a文件

执行/tmp/hello

/tmp/hello

human say: hello!

当hello.go被修改

我们修改一行hello.go

human.Say("hello world!")
再次编译并执行
go install hello
/tmp/hello

human say: hello world!
可以看到, go install 会自动检测代码更新,如果有变化则重新编译

如果要更详细知道这个过程,可以加上-x参数,这个参数会输出go install过程中实际执行的命令

go install -x hello

WORK=/tmp/go-build868125788
mkdir -p $WORK/hello/_obj/
mkdir -p $WORK/hello/_obj/exe/
cd /tmp/gomain/src/hello
/usr/local/go/pkg/tool/linux_amd64/6g -o $WORK/hello.a -trimpath $WORK -p hello -complete -D _/tmp/gomain/src/hello -I $WORK -I /tmp/gopkg/pkg/linux_amd64 -pack ./hello.go
cd .
/usr/local/go/pkg/tool/linux_amd64/6l -o $WORK/hello/_obj/exe/a.out -L $WORK -L /tmp/gopkg/pkg/linux_amd64 -extld=gcc $WORK/hello.a
mkdir -p /tmp/
mv $WORK/hello/_obj/exe/a.out /tmp/hello
如果hello.go文件没有变化,这时候再次执行go install
go install -x hello

WORK=/tmp/go-build100249567
结果非常明显,代码没有变化的时候什么都没做。

当human.go被修改后,出问题了

现在我们修改一行human.go文件

println("god say:",s)
再次编译并执行:
go install -x hello
<pre name="code" class="plain">
WORK=/tmp/go-build179497989
/tmp/hello
human say: hello world!
 什么情况,修改代码竟然没有更新!也就是说, 
对于其他文件夹下的依赖包,如果发现存在.a文件,则不会再重新编译。 
 

这种情况解决方案有几个:

1. 使用 -a 参数。go install -a强制更新所有的依赖包,包括Go内置的包。这个方案最简单可靠,不过编译时间会稍长。

2. 使用...手动更新其他目录的包。在编译hello之前,先重新编译gopkg下的所有包,go install /tmp/gopkg/...。使用三个点号go install会遍历目录下的所有包,检查代码如果有更新则重新编译。

3. 删掉.a文件。这样还不如方案2。

再多做一点实验

1. 如果删掉human.go文件,保留human.a文件,go install会报错找不到pkg。

2. 如果将human包移到goman目录下,也就是跟hello项目在同一个GOPATH内。则无论怎么修改human.go,编译hello项目时human包都会被更新。

结论

所以现在看来情况是这样的,go install只会检查“参数指定的包所在的GOPATH”内的源码是否有更新,如果有则重新编译。对于依赖的其他GOPATH下的包,如果存在已经编译好的.a文件,则不会再检查源码是否有更新,不会重新编译

原文链接:https://www.f2er.com/go/190826.html

猜你在找的Go相关文章