go mod 探索
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。未完待续。。。