
本文详解 Go 1.7 中 vendor 机制失效的典型原因:vendor 目录必须位于直接依赖该包的模块根目录下,而非父项目或任意上级路径;错误放置会导致 cannot find package 报错,即使文件物理存在。
本文详解 go 1.7 中 vendor 机制失效的典型原因:vendor 目录必须位于**直接依赖该包的模块根目录下**,而非父项目或任意上级路径;错误放置会导致 `cannot find package` 报错,即使文件物理存在。
Go 1.7 是首个正式支持 vendor 目录的版本(通过 -i 标志启用,后成为默认行为),但其查找逻辑严格遵循 “就近原则”:Go 工具链仅在当前编译单元所在模块的根目录下搜索 vendor/ 子目录,且该目录必须包含所导入包的完整路径结构。它不会向上遍历父目录寻找 vendor,也不会跨 GOPATH 路径合并依赖。
在您的案例中,关键问题在于路径错位:
- 您的
main项目位于$GOPATH/src/mjohn/msg/,其下有vendor/zombiezen.com/go/capnproto2/; - 但报错发生在
mjohn/fram/rim/包(路径为$GOPATH/src/mjohn/fram/rim/)中,该包尝试导入"zombiezen.com/go/capnproto2"; - 此时 Go 编译器查找
vendor/的起点是mjohn/fram/rim/目录 —— 而此处并无 vendor 目录,因此完全忽略mjohn/msg/vendor/中的内容。
✅ 正确做法只有两种(任选其一):
-
将 vendor 目录移至实际依赖方根目录
即在mjohn/fram/rim/目录下创建 vendor 结构:cd $GOPATH/src/mjohn/fram/rim mkdir -p vendor/zombiezen.com/go/capnproto2 # 复制 capnproto2 源码到该路径(保持完整子目录结构) cp -r $GOPATH/src/zombiezen.com/go/capnproto2/* vendor/zombiezen.com/go/capnproto2/
然后在此目录下执行
go build。 -
统一项目结构,使依赖关系扁平化
将mjohn/fram/rim作为子模块纳入mjohn/msg项目,并确保所有.go文件(包括rim/fsd.go)均位于mjohn/msg/下,例如:mjohn/msg/ ├── cmd/ │ ├── main.go │ └── rpc.go ├── fram/ │ └── rim/ │ ├── fsd.go # 此处 import "zombiezen.com/go/capnproto2" │ └── schema.capnp.go └── vendor/ └── zombiezen.com/go/capnproto2/此时
go build在mjohn/msg/目录下运行,即可正确识别 vendor。
⚠️ 重要注意事项:
- Go 1.7 的 vendor 机制不支持嵌套 vendor 或跨路径继承,每个
go build命令的作用域仅限于当前工作目录及其子目录; -
GO111MODULE=off必须保持(Go 1.7 尚未引入 Modules),否则会禁用 vendor; - 验证 vendor 是否生效:运行
go list -f '{{.Dir}}' zombiezen.com/go/capnproto2,输出应为.../vendor/zombiezen.com/go/capnproto2,而非$GOPATH/src/...; - 现代 Go(1.11+)已全面转向 Go Modules,
vendor由go mod vendor自动生成,且受go.build -mod=vendor控制 —— 若可升级,强烈建议弃用 GOPATH + 手动 vendor 模式。
总结:vendor 不是全局缓存,而是模块级依赖快照。它的存在位置必须与 import 语句的解析上下文严格对齐 —— 谁 import,谁负责 vendoring。

















