首页 > 技术文章 > go mod 探索

zxq89 2020-12-01 21:53 原文

go mod有时候会报cannot find module providing package xxxx的错,找资料也没有解决。所以自己探索了下,记录一下。

首先,先尝试整一个正常的。

1 // tooljob.go
2 
3 package tools
4 
5 import "fmt"
6 
7 func Print() {
8         fmt.Println("hello,there")
9 }
1 // utiljob.go
2 
3 package util
4 
5 import "tools"
6 
7 func Get() {
8         tools.Print()
9 }
1 // main.go
2 
3 package main
4 
5 import "util"
6 
7 func main() {
8         util.Get()
9 }

目的是在work/中编译出程序。只有这几个文件肯定不行:

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
2 main.go:5:8: cannot find package "util" in any of:
3         /usr/local/go/src/util (from $GOROOT)
4         /home/zxq/go/src/util (from $GOPATH) 

因为,main中包含util包,但是util包没有找到。因为go version go1.14.12 linux/amd64。GO111MODULE="auto"。没有go.mod文件,所以到GOROOT和GOPATH去找。结果自然没有找到。

添加go.mod:

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ go mod init aimport
2 go: creating new go.mod: module aimport
 1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ tree
 2 .
 3 ├── go.mod
 4 ├── tools
 5 │   └── tooljob.go
 6 ├── util
 7 │   └── utiljob.go
 8 └── work
 9     ├── main.go
10     └── work
11 
12 3 directories, 5 files

这里没有让mod名和目录名一致,也是故意不按套路出牌,好探索下。

再次到work下编译,发现已经不到GOPATH去找了:

备注:以上是go1.14.12的提示。在1.13.3中,本地mod没有util包,会在ROOT中查找util包,还找不到的话,会到互联网查找,但是此时会判断包名是否符合域名的命名规则,不符合就报下面的错误。:

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
2 build aimport/work: cannot load util: malformed module path "util": missing dot in first path element

也就是说,尽管go.mod位于它的上一级,也被识别到了,但是没有找到util包。

把main.go中的import修改,补全路径:"aimport/util":

1 // main.go
2 
3 package main
4 
5 import "aimport/util"
6 
7 func main() {
8         util.Get()
9 }

发现引用util不报错,只报tools的错了(毕竟引用tools包还没修改)。

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
2 build aimport/work: cannot load tools: malformed module path "tools": missing dot in first path element

修改完utiljob.go 中的tools引用,可以编译成功了:

 1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ cat ../util/utiljob.go
 2 // utiljob.go
 3 
 4 package utilabc
 5 
 6 import "aimport/tools"
 7 
 8 func Get() {
 9         tools.Print()
10 }
11 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
12 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ ls
13 main.go  work

至此,一个正常的go mod模式的框架完成。

 

探索1,包名和路径:

util包名修改为utilabc:

1 // utiljob.go
2 
3 package utilabc
4 
5 import "aimport/tools"
6 
7 func Get() {
8         tools.Print()
9 }

 

编译结果:  

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
2 # aimport/work
3 ./main.go:5:8: imported and not used: "aimport/util" as utilabc
4 ./main.go:8:2: undefined: util

 没报引用不对,只是引用后没有使用。修改之后:

 1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ cat main.go
 2 // main.go
 3 
 4 package main
 5 
 6 import "aimport/util"
 7 
 8 func main() {
 9         utilabc.Get()
10 }
11 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
12 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ ls
13 main.go  work

 可以编译。反过来试下,引用包名,而不是路径:

zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ cat main.go
// main.go

package main

import "aimport/utilabc"

func main() {
        utilabc.Get()
}
zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
build aimport/work: cannot load aimport/utilabc: malformed module path "aimport/utilabc": missing dot in first path element 

 说明import后面是路径,而不是包名。

但是 import "aimport/util" 不能写成 import "myimport/util" 否则报错:

 同样,上面是1.14.12的报错。在1.13.3:

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
2 build aimport/work: cannot load myimport/util: malformed module path "myimport/util": missing dot in first path element

 所以,import中的mod名,要和go.mod一致,不是路径名;后面的package名,是路径,不是包名。

 

探索2, 编译:

1.14.12的情况:

 1.13.3的情况:

 1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ go build work/main.go
 2 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ tree
 3 .
 4 ├── go.mod
 5 ├── main
 6 ├── tools
 7 │   └── tooljob.go
 8 ├── util
 9 │   └── utiljob.go
10 └── work
11     ├── main.go
12     └── work
13 
14 3 directories, 6 files
15 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ go build
16 build .: cannot find module for path .
17 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ go build aimport
18 can't load package: package aimport: package aimport is not in the main module (aimport)

 

修改下名字,看看二进制文件的命名:

 1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ mv work/main.go work/maina.go
 2 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ go build work/maina.go
 3 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ tree
 4 .
 5 ├── go.mod
 6 ├── maina
 7 ├── tools
 8 │   └── tooljob.go
 9 ├── util
10 │   └── utiljob.go
11 └── work
12     ├── maina.go
13     └── work
14 
15 3 directories, 6 files

 在外部编译,输出的二进制文件名字用main函数所在文件名命名。原地编译,使用目录名来命名。

 

探索3,work模块加上go mod 

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go mod init work
2 go: creating new go.mod: module work
3 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
4 build work: cannot load aimport/util: malformed module path "aimport/util": missing dot in first path element

 找不到aimport/util,在go.mod中添加require和replace:

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ cat go.mod
2 module work
3 
4 go 1.13
5 
6 replace  aimport/util => ../util
7 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
8 go: work imports
9         aimport/util: parsing ../util/go.mod: open /mnt/d/test_work/myimport/util/go.mod: no such file or directory

 报错,需要util中有go.mod文件。既然如此,那就不引用到具体下层, 只添加:

replace aimport => ../

没问题,且go.mod自动加入了require aimport:

zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ cat go.mod
module work

go 1.13

replace aimport => ../

require aimport v0.0.0-00010101000000-000000000000
zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ ls
go.mod  main.go  work

 

探索4:给util加上go.mod

1.14.12:

 1.13.3:

1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/util$ go mod init util
2 go: creating new go.mod: module util
3 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/util$ cd ../work/
4 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
5 build work: cannot load aimport/util: malformed module path "aimport/util": missing dot in first path element

 找不到util了。

到这里其实比较清楚了。go.mod会隔离开各个编译的区间。各个区间如果有上下层目录关系,那么就会透明不可见,不可直接引用。如果需要引用,可以使用replace去指定查找路径。

把work/中的go.mod移除后,保留util中的go.mod,那么work即归属于mod aimport,但是与util隔离。

此时,在mod aimport添加replace 信息,才能引用到util:

 1 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ go build
 2 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport/work$ cd ../
 3 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ tree
 4 .
 5 ├── go.mod
 6 ├── maina
 7 ├── tools
 8 │   └── tooljob.go
 9 ├── util
10 │   ├── go.mod
11 │   └── utiljob.go
12 └── work
13     ├── main.go
14     └── work
15 
16 3 directories, 7 files
17 zxq@DESKTOP-0BAPSTC:/mnt/d/test_work/myimport$ cat go.mod
18 module aimport
19 
20 go 1.13
21 
22 replace aimport/util => ./util
23 
24 require aimport/util v0.0.0-00010101000000-000000000000

 

 

探索5,知道了上面的规则后,看下mod命名,包名,路径名相关:

 

 在main中引用的是utilabc的Get()方法。但是import是引入的aimport/tools,经过其归属的mod文件指向到./util(其实是../util)。

在./util中,mod命名为utilmod,包名为utilabc。

 

至此,还未发现开头提到的错误:cannot find module providing package xxxx。未完待续。。。

 

推荐阅读