
Go 1.7 引入的 vendor 机制要求依赖必须位于当前模块根目录的 vendor 子目录下,而非任意上级或兄弟项目中;若 import 路径为 zombiezen.com/go/capnproto2,则其 vendor 副本必须置于该包被导入时所在项目的 vendor 目录内,否则 Go 工具链将完全忽略。
go 1.7 引入的 vendor 机制要求依赖必须位于**当前模块根目录的 vendor 子目录下**,而非任意上级或兄弟项目中;若 import 路径为 `zombiezen.com/go/capnproto2`,则其 vendor 副本必须置于该包被导入时所在项目的 vendor 目录内,否则 go 工具链将完全忽略。
在 Go 1.7 中,vendor 机制遵循严格的作用域就近原则:Go 编译器仅在当前构建的主包(即 go build 所在目录)向上逐级查找 vendor/ 目录,直到找到 src/ 根或文件系统根为止。它不会跨 GOPATH 项目边界、不识别兄弟目录下的 vendor、也不继承父级 vendor 内容。
你遇到的报错:
cannot find package "zombiezen.com/go/capnproto2" in any of:
/home/mjohn/software/go/src/zombiezen.com/go/capnproto2 (from $GOROOT)
/home/mjohn/workspace/gopath/src/zombiezen.com/go/capnproto2 (from $GOPATH)明确说明 Go 仍在按传统 GOPATH 模式搜索——它只检查 $GOROOT/src 和 $GOPATH/src,完全跳过了 vendor/ 目录。根本原因在于:go build 当前执行位置是 /home/mjohn/workspace/gopath/src/mjohn/msg,而真正需要 capnproto2 的代码位于 /home/mjohn/workspace/gopath/src/mjohn/fram/rim/(如 fsd.go 和 schema.capnp.go)。由于 mjohn/fram/rim 并未自身携带 vendor/zombiezen.com/go/capnproto2,Go 就无法解析该 import。
✅ 正确做法有两种(任选其一):
方案一:在实际使用方目录下 vendor(推荐)
进入 mjohn/fram/rim 目录,初始化 vendor:
cd /home/mjohn/workspace/gopath/src/mjohn/fram/rim # 确保已安装 dep 或 govendor(Go 1.7 原生 vendor 需手动维护) cp -r /home/mjohn/workspace/gopath/src/zombiezen.com/go/capnproto2 vendor/zombiezen.com/go/
目录结构应变为:
/home/mjohn/workspace/gopath/src/mjohn/fram/rim/
├── fsd.go
├── schema.capnp.go
└── vendor/
└── zombiezen.com/
└── go/
└── capnproto2/ # ✅ 此处路径必须与 import 完全一致方案二:统一提升到顶层项目并启用 vendor 感知构建
将 mjohn/msg 视为顶层应用项目,并确保所有子包(包括 mjohn/fram/rim)均被其 go build ./... 覆盖:
cd /home/mjohn/workspace/gopath/src/mjohn/msg # 复制依赖至本项目 vendor(路径需严格匹配 import) mkdir -p vendor/zombiezen.com/go/ cp -r ../fram/rim/vendor/zombiezen.com/go/capnproto2 vendor/zombiezen.com/go/ # 或直接从 GOPATH 复制 cp -r $GOPATH/src/zombiezen.com/go/capnproto2 vendor/zombiezen.com/go/
然后在 msg/ 目录下运行:
go build ./...
Go 会递归扫描所有子目录,并在 msg/vendor/ 中解析 zombiezen.com/go/capnproto2。
⚠️ 关键注意事项:
-
路径一致性是核心:
vendor/内的目录结构必须与import语句中的完整路径完全一致(区分大小写、斜杠方向、无多余前缀); -
Go 1.7 不支持嵌套 vendor 自动继承:
msg/vendor对fram/rim无效,除非rim是msg的子包且通过相对 import(如import "mjohn/msg/fram/rim")引用; -
避免混用 GOPATH 与 vendor:一旦启用 vendor,应确保
GO111MODULE=off(Go 1.11 前默认),且不要同时依赖$GOPATH/src中的同名包,否则可能引发冲突; -
现代替代建议:Go 1.11+ 默认启用 Modules,
vendor已由go mod vendor统一管理,强烈建议升级 Go 版本并迁移至 Go Modules(go mod init+go mod vendor),彻底规避此类路径歧义。
总结:Go 1.7 的 vendor 不是“全局缓存”,而是“局部快照”。它的生效前提是——被导入的包,其 vendor 副本必须物理存在于发起 import 的那个包的直接 vendor 目录下。定位错误根源、校准 vendor 路径层级,是解决此类问题的唯一正解。

















