go install 的工作方式

tiaotiaoyly · · 13149 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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文件,则不会再检查源码是否有更新,不会重新编译




有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:tiaotiaoyly

查看原文:go install 的工作方式

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

13149 次点击  
加入收藏 微博
上一篇:golang-china
下一篇:go资料汇总
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传