清晨的美好过夜晚的雨 發表於 2020-9-18 13:32:00

go 环境使用 go mod

<h1>最近接触到go mod,网上查了查资料,这里记录一下。</h1>
<p>&nbsp;</p>
<h1>1 介绍</h1>
<h2>1.1、go mod是什么</h2>
<p>&nbsp; &nbsp; &nbsp; go mod 是Golang 1.11 版本引入的官方包(package)依赖管理工具,用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。</p>
<p>&nbsp; &nbsp; &nbsp; 之前Golang 主要依靠vendor和GOPATH来管理依赖库,vendor相对主流,但现在官方更提倡go mod。</p>
<h2>1.2、go mod初始化及使用</h2>
<p>下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)</p>
<p>Golang 提供一个环境变量&nbsp;GO111MODULE 来设置是否使用mod,它有3个可选值,分别是off, on,&nbsp;auto(默认值),具体含义如下:</p>
<ol>
<li>off: GOPATH mode,查找vendor和GOPATH目录</li>
<li>on:module-aware mode,使用 go module,忽略GOPATH目录</li>
<li>auto:如果当前目录不在$GOPATH&nbsp;并且&nbsp;当前目录(或者父目录)下有go.mod文件,则使用&nbsp;GO111MODULE, 否则仍旧使用 GOPATH mode。</li>
</ol>
<p>修改&nbsp;GO111MODULE 的值的语句是:set&nbsp;GO111MODULE=on 。</p>
<p>在使用模块的时候,&nbsp;<code>GOPATH</code>&nbsp;是无意义的,不过它还是会把下载的依赖储存在&nbsp;<code>GOPATH/src/mod</code>&nbsp;中,也会把&nbsp;<code>go install</code>&nbsp;的结果放在&nbsp;<code>GOPATH/bin</code>(如果&nbsp;<code>GOBIN</code>&nbsp;不存在的话)</p>
<ul>
<li><code>go mod download</code>&nbsp;下载模块到本地缓存,缓存路径是&nbsp;<code>$GOPATH/pkg/mod/cache</code></li>
<li><code>go mod edit</code>&nbsp;是提供了命令版编辑&nbsp;<code>go.mod</code>&nbsp;的功能,例如&nbsp;<code>go mod edit -fmt go.mod</code>&nbsp;会格式化&nbsp;<code>go.mod</code></li>
<li><code>go mod graph</code>&nbsp;把模块之间的依赖图显示出来</li>
<li><code>go mod init</code>&nbsp;初始化模块(例如把原本dep管理的依赖关系转换过来)</li>
<li><code>go mod tidy</code>&nbsp;增加缺失的包,移除没用的包</li>
<li><code>go mod vendor</code>&nbsp;把依赖拷贝到&nbsp;<code>vendor/</code>&nbsp;目录下</li>
<li><code>go mod verify</code>&nbsp;确认依赖关系</li>
<li><code>go mod why</code>&nbsp;解释为什么需要包和模块</li>
</ul>
<p>注意有几个坑的地方:</p>
<ul>
<li>
<p><code>go mod</code>&nbsp;命令在&nbsp;<code>$GOPATH</code>&nbsp;里默认是执行不了的,因为&nbsp;<code>GO111MODULE</code>&nbsp;的默认值是&nbsp;<code>auto</code>。默认在<code>$GOPATH</code>&nbsp;里是不会执行, 如果一定要强制执行,就设置环境变量为&nbsp;<code>on</code>。</p>
</li>
<li>
<p><code>go mod init</code>&nbsp;在没有接module名字的时候是执行不了的,会报错&nbsp;<code>go: cannot determine module path for source directory</code>。可以这样执行:</p>
<pre><code class="language-html hljs xml">$ go mod init github.com/jiajunhuang/hello
</code></pre>
<p>否则就要在&nbsp;<code>main.go</code>&nbsp;里加上导入声明,例如:</p>
<ol class="hljs-ln">
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ cat main.go</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">package main</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">&nbsp;</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">func main() {</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">println("Hello world")</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">}</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ go mod init</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">go: cannot determine module path for source directory /Users/jiajun/hello (outside GOPATH, no import comments)</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ vim go.mod</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ cat go.mod</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">module github.com/jiajunhuang/hello</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ go mod init</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">go mod init: go.mod already exists</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ rm go.mod</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ vim main.go</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ cat main.go</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">package main // import "github.com/jiajunhuang/hello"</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">&nbsp;</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">func main() {</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">println("Hello world")</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">}</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ go mod init</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">go: creating new go.mod: module github.com/jiajunhuang/hello</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ ls</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">go.mod main.go</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">$ cat go.mod</div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">module github.com/jiajunhuang/hello</div>
</div>
</li>
</ol>
<p>当然,如果在已有代码的仓库里执行是不存在这个问题的。</p>
</li>
</ul>
<p>&nbsp;</p>
<h2>2 命令</h2>
<h2>2.1 指定module的根目录并生成go.mod文件</h2>
<pre name="code" class="has"><code class="hljs go"><span class="hljs-keyword">go mod init example.com/hello</span></code></pre>
<h2>2.2 下载并添加依赖到go.mod文件中</h2>
<pre name="code" class="has"><code class="hljs go"><span class="hljs-keyword">go build, <span class="hljs-keyword">go test</span></span></code></pre>
<h2>2.3 查看module下的所有依赖</h2>
<pre name="code" class="has"><code class="hljs go"><span class="hljs-keyword">go list -m all</span></code></pre>
<h2>2.4 更新稳定版依赖</h2>
<pre name="code" class="has"><code class="hljs go"><span class="hljs-keyword">go get rsc.io/sampler</span></code></pre>
<h2>2.5 更新为指定版本依赖</h2>
<ol class="hljs-ln">
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line"><span class="hljs-attribute">go list -m -versions rsc.io/sampler</span></div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">&nbsp;</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line"><span class="hljs-attribute">rsc.io/sampler v<span class="hljs-number">1.<span class="hljs-number">0.<span class="hljs-number">0 v<span class="hljs-number">1.<span class="hljs-number">2.<span class="hljs-number">0 v<span class="hljs-number">1.<span class="hljs-number">2.<span class="hljs-number">1 v<span class="hljs-number">1.<span class="hljs-number">3.<span class="hljs-number">0 v<span class="hljs-number">1.<span class="hljs-number">3.<span class="hljs-number">1 v<span class="hljs-number">1.<span class="hljs-number">99.<span class="hljs-number">99</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></div>
</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">&nbsp;</div>
</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line"><span class="hljs-attribute">go get rsc.io/sampler@v<span class="hljs-number">1.<span class="hljs-number">3.<span class="hljs-number">1</span></span></span></span></div>
</div>
</li>
</ol>
<h2>2.6 清理无用的依赖</h2>
<pre name="code" class="has"><code class="hljs go"><span class="hljs-keyword">go mod tidy</span></code></pre>
<h2>2.7 将依赖复制到项目路径的vendor文件夹中</h2>
<pre name="code" class="has"><code class="hljs go"><span class="hljs-keyword">go mod vendor</span></code></pre>
<h2>2.8 忽略cache里的包,只使用vendor目录里的依赖进行编译</h2>
<pre name="code" class="has"><code class="hljs go"><span class="hljs-keyword">go build -mod=vendor</span></code></pre>
<p>2.9 校验依赖并查看是否有修改</p>
<pre name="code" class="has"><code class="hljs go"><span class="hljs-keyword">go mod verify</span></code></pre>
<p>&nbsp;</p>
<h1>3 问题</h1>
<h2>3.1&nbsp;go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'</h2>
<p>go mod init</p>
<p>go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'</p>
<p>开启go module:</p>
<ol>
<li>
<p><code>set GO111MODULE=on //windows</code></p>
</li>
<li>
<p><code>export GO111MODULE=on //linux</code></p>
</li>
</ol>
<h2>3.2&nbsp;$GOPATH/go.mod exists but should not</h2>
<p>GO 1.11或之后模块遇到这个问题:</p>
<pre name="code" class="has"><code class="hljs perl">$GOPATH/go.mod <span class="hljs-keyword">exists but should <span class="hljs-keyword">not
</span></span></code></pre>
<p>&nbsp; &nbsp; 开启模块支持后(set&nbsp;GO111MODULE=on),并不能与$GOPATH共存,所以把$GOPATH从env中移出即可(unset GOPATH),可运行“unset GOPATH &amp;&amp; make”。</p>
<p>&nbsp;</p>
<h1>4 例子</h1>
<h2>4.1 例子1</h2>
<p>go mod初始化:在$GOPATH外建一个文件夹,把个人代码放进去,我的测试代码路径:https://github.com/kevinhao8/go-mod-example。</p>
<p>首先main入口代码所在文件夹创建mod</p>
<p>创建语句&nbsp;&nbsp;go mod init </p>
<p>比如我的测试代码&nbsp;redisTest.go,创建语句就是&nbsp;&nbsp;go mod init&nbsp;redisTest,成功创建时返回&nbsp;&nbsp;go: creating new go.mod: module redisTest</p>
<p>此时文件夹下出现&nbsp;go.mod文件,打开发现只有2行如下,并没有记录依赖库。</p>
<p>module redisTest</p>
<p>go 1.12</p>
<p>此时需要输入go test语句,根据需要的依赖自动生成require,也就是依赖包,此时go.mod多了如下内容(红字是我写的注释,文件里面没有)</p>
<p>require (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect(有indirect注释的代表间接依赖,没有的代表直接依赖)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/gin-gonic/gin v1.3.0&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/golang/protobuf v1.3.1 // indirect<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/mattn/go-isatty v0.0.7 // indirect<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect(这里是版本号+时间戳+hash)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gopkg.in/go-playground/validator.v8 v8.18.2 // indirect<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gopkg.in/yaml.v2 v2.2.2 // indirect<br>)</p>
<p>此时会有如下失败提示,此处为我踩得第一个坑!!!花了挺长时间才解决</p>
<p>build redisTest: cannot load dbredis: cannot find module providing package dbredis</p>
<p>dbredis是我写的私有包,代码是没有问题的,为什么找不到呢?从网上查了一圈,发现私有包如果不想发布到网上,需要手动添加require ,然后replace 进行替换,将私有包指向本地module所在的绝对或相对路径。一般用相对路径更通用。</p>
<p>此时手动将go.mod改为如下,红字为新加</p>
<p>require (<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dbredis v0.0.0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/gin-gonic/gin v1.3.0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/golang/protobuf v1.3.1 // indirect<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/mattn/go-isatty v0.0.7 // indirect<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gopkg.in/go-playground/validator.v8 v8.18.2 // indirect<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gopkg.in/yaml.v2 v2.2.2 // indirect<br>)</p>
<p>replace dbredis v0.0.0 =&gt; ./dbredis</p>
<p>再度运行go test&nbsp;&nbsp;命令,发现仍有失败提示如下,找不到dbredis文件夹下的go.mod文件。</p>
<p>go: parsing dbredis\go.mod: open E:\code\go-mod-example\dbredis\go.mod: The system cannot find the file specified.<br>go: error loading module requirements</p>
<p>从网上查资料发现,这种情况下需要给私有包也生成mod,这样整个工程的依赖才能完整。故运行如下命令:</p>
<p>cd dbredis</p>
<p>go mod init&nbsp;dbredis(此处我写的mod名跟package名一致,不知道不一致行不行)</p>
<p>go test</p>
<p>三条命令依次运行通过,dbredis文件夹下的go.mod文件如下:</p>
<p>module dbredis</p>
<p>go 1.12</p>
<p>require github.com/go-redis/redis v6.15.2+incompatible</p>
<p>此时再运行如下命令:</p>
<p>cd ..(回到上层文件夹)</p>
<p>go test</p>
<p>运行通过,不再有报错。运行命令 go build&nbsp;redisTest.go 也能够正常生成redisTest.exe</p>
<p>至此通过mod来管理依赖包基本实现,我们的程序能基本脱离$GOPATH编译。<br>&nbsp;</p>
<h1>5 go mod 和 dep 比较</h1>
<ul>
<li><code>go mod</code>&nbsp;支持代理,以后就可以使用私有镜像源了~,具体请搜索&nbsp;<code>GOPROXY</code></li>
<li><code>go mod</code>&nbsp;速度比&nbsp;<code>dep</code>&nbsp;快很多</li>
<li><code>go.mod</code>&nbsp;中列出了所有的依赖,这一点其实我不是很喜欢,因为当项目一大,历史一久,只要升级其中一个依赖,很可能整个依赖 就挂了。我还是比较喜欢只要列出顶级依赖,由程序处理子依赖的情况。</li>

</ul>
<h2>一个生成的&nbsp;<code>go.mod</code>&nbsp;的示例</h2>
<ol class="hljs-ln">
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">module github.com/my/module/v3// 这是你的包的声明</div>

</div>

</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">&nbsp;</div>

</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">// require 里是依赖。需要带上路径和版本。</div>

</div>

</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">require (</div>

</div>

</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">    github.com/some/dependency v1.2.3</div>

</div>

</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">    github.com/another/dependency v0.1.0</div>

</div>

</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">    github.com/additional/dependency/v4 v4.0.0</div>

</div>

</li>
<li>
<div class="hljs-ln-numbers">&nbsp;</div>
<div class="hljs-ln-code">
<div class="hljs-ln-line">)</div>

</div>

</li>

</ol><hr>
<ul>
<ul>
<li>https://github.com/golang/go/wiki/Modules</li>

</ul>
</ul><br><br>
来源:https://www.cnblogs.com/gaosai/p/13690784.html
頁: [1]
查看完整版本: go 环境使用 go mod