【问题标题】:How to resolve transitive dependencies of local modules如何解决本地模块的传递依赖
【发布时间】:2019-12-31 13:33:36
【问题描述】:

在某个随机文件夹中,有 3 个文件夹 a、b、c。这些文件夹中的每一个都包含一个 mod 文件。

mod 文件包含以下 .

go.mod 里面的一个

module a

go 1.13

go.mod 里面的 b

module b
go 1.13
require a v0.0.0
replace a v0.0.0 => ./../a

c 中的 go.mod

module c
go 1.13
require b v0.0.0
replace b v0.0.0 => ./../b

模块 b 不会引发错误。但是模块 c 抛出错误

go: b@v0.0.0 requires
a@v0.0.0: unrecognized import path "a" (import path does not begin with hostname)

每个模块的模块名称中都必须有一个点(.)。

“一些随机文件夹”更改为 example.com。现在 example.com 命名文件夹包含所有 a.b.c 文件夹。这是模块现在的样子

模块A看起来像

module example.com/a
go 1.13

模块 B 的样子

module example.com/b
go 1.13
require example.com/a v0.0.0
replace example.com/a v0.0.0 => ../a

模块 C 的样子

module example.com/c
go 1.13
require example.com/b v0.0.0
replace example.com/b v0.0.0 => ../b

太糟糕了!错误!

go: example.com/b@v0.0.0 requires
example.com/a@v0.0.0: unrecognized import path "example.com/a" (https fetch: Get 
https://example.com/a?go-get=1: dial tcp 208.73.210.202:443: connect: connection refused)

本地模块的传递依赖是如何工作的? 为什么 Go 要访问 example.com 来带来模块? 怎么回事?

【问题讨论】:

  • “一些聪明的开发人员认为每个模块的模块名称中都必须有一个点 (.)。”因为一些聪明的开发人员实际上理解 Go 导入的用途——它们应该是go get-able,而不仅仅是磁盘上的任意目录。
  • @Adrian 不要生我的气!它非常个人主义的政策。举个例子,除非你在派对上穿红色睡衣,否则你不会得到食物,而你穿任何你想要的东西......来参加派对......我们会给你红色睡衣,然后你有食物... Go 假设有人要编写模块并将其推送到存储库,我将继续处理它... 它不假设(但它提供了使用它的机制)我可以创建多个随机模块在磁盘上而不是试图将它们推到任何地方!
  • 正确。这就是 Go 模块的工作方式。 (完全合理的)假设是任何软件项目都会有一个存储库。通常,除了一次性的单文件脚本之外,任何软件项目的第一步都是为其创建一个存储库,因此这应该不是问题。如果您正在制作一个复杂的、多模块、相互依赖的软件项目并且您没有存储库,那么问题不在于 Go 模块对任意本地模块的支持,而是您没有使用源代码控制。

标签: go go-modules


【解决方案1】:

Go Wiki: Modules: go.mod

excludereplace 指令仅在当前(“主”)模块上运行。 在构建主模块时忽略主模块以外的模块中的excludereplace 指令。 因此,replaceexclude 语句允许主模块完全控制其自己的构建,也不受依赖项的完全控制。 (有关何时使用replace 指令的讨论,请参阅常见问题解答below

还有Command go: The main module and the build list:

主模块的 go.mod 文件通过 require、replace 和 exclude 语句定义了可供 go 命令使用的精确包集。通过以下 require 语句找到的依赖模块也有助于定义该组包,但仅通过其 go.mod 文件的 require 语句:依赖模块中的任何替换和排除语句都将被忽略。因此,replace 和 exclude 语句允许主模块完全控制自己的构建,而不受依赖项的完全控制。

构建模块c时找不到包a,所以go工具尝试解决它,尝试下载它。这就是为什么它试图将包名解释为应该以主机名开头的东西。

您不需要将包a 重命名为example.com/a,但您必须在cgo.mod 中添加一个replace 指令,以告知包a 所在的位置。

【讨论】:

  • 感谢您的解决方案...但这是否可行?我认为导入的整个想法是,作为开发人员,我将从我正在导入的模块的所有依赖项中抽象出来。假设我有一个大项目,其中有 10-12 个层次结构,我想使用最新的 .我必须包含我导入的每个库的依赖项!
  • @deepg 仅当您使用的模块具有 replace 指令时才需要,否则只能用于测试/本地开发。当您发布一个模块时,它不应该依赖于不属于该模块的本地包。使用这样的模块你什么都不用做:你只需导入它们,go 工具和模块系统会自动解析所有依赖项。
  • 感谢@icza 的详细解释。它真的很有帮助。老实说。 Go 从开发 POV 带来了非常新的视角。然而,文档未能突出它的细微差别。不要误会我的意思,这些线条中隐藏着大量信息,但它就像海洋中的一颗明珠。
  • @deepg 需要涵盖的内容很多,因此一个单一的、几页的文档不可能涵盖任何人需要的所有内容。官方主页始终是一个很好的起点,它也涵盖了这一点(作为第二个引用添加)。 Stackoverflow 也是询问您找不到或无法理解的内容的好地方。
猜你喜欢
  • 1970-01-01
  • 2017-12-30
  • 2014-01-14
  • 2016-02-26
  • 2021-11-14
  • 2014-10-20
  • 2021-10-20
  • 2012-12-17
  • 2013-02-12
相关资源
最近更新 更多