【问题标题】:How can I use SBT to help my library get around transitive dependency conflicts如何使用 SBT 帮助我的库解决传递依赖冲突
【发布时间】:2015-10-12 17:16:14
【问题描述】:

假设我正在编写一个 Scala 库 L,它依赖于某些依赖项 D,并由程序 P 和另一个程序 Q 使用。P 直接依赖于 D 的 3.2 版,而 Q 直接依赖于 3.3 版。

在这两个版本之间,D 的 API 被改组,以便获得我在 L 中使用的相同函数,我必须在 L 中编写不同的导入语句。同样,P 依赖于 3.2 特定的行为,而 Q 依赖于 3.3 特定的行为。

现在,通常会发生的情况是在编译 P 和 Q 时会选择 D 的最新版本,但是如果 L 依赖于库的 3.3 版本,这将导致 P 中断,或者在编译 Q 时 L 中断如果 L 依赖于 D 的 3.2 版本。

我希望 P 和 Q 都使用相同版本的 L,因为 L 的公共 API 不会改变。这可能吗?

想到的一般方法是基于依赖解析的L的条件编译。尽管在 JVM 世界中这似乎无法实现,因为我们不会传递编译项目的依赖项,而是依赖预编译的工件。

如果 D 是 Scala 本身,我现在可以使用 SBT 执行此操作(即与不同的 Scala 版本交叉编译,并将特定于版本的代码存在于其自己的目录中),但从依赖关系解析的角度来看,这是一种 hack因为 SBT 更改了工件的名称以允许这种交叉编译工作。

【问题讨论】:

    标签: scala sbt dependency-management conditional-compilation transitive-dependency


    【解决方案1】:

    你可以告诉 sbt 处理依赖为intransitive:

    libraryDependencies ++= Seq(
      "org.some.id" % "some-lib" % "1.0.foobar" intransitive()
    )
    

    会将 some-lib 添加到依赖项中,但不会遵循该库的依赖项。因此,如果 some-lib 依赖于 some-other-lib,则不会下载其他库。

    也许更具体一点。比如说,你需要几个库都使用 SLF4J 作为日志接口。也许,一些库需要稍微不同的版本,但没有任何 API 差异。所以他们都可以使用相同的 SLF4J 版本。然后,您会将所有这些 libraryDependencies 标记为不及物,并将 SLF4J 本身添加一次作为顶级库依赖项。

    libraryDependencies ++= Seq(
     "org.slf4j" % "slf4j-api" % 1.7.6,
     "com.typesage.slick" %% "slick" % "2.0.0" intransitive(),
     "com.typesafe.akka" %% "akka-slf4j" % "2.2.0" intransitive()
    )
    

    我说得有道理吗?

    【讨论】:

    • 这不是我面临的问题。以您的 SLF4J 为例,我遇到的问题类似于 Slick 使用 1.7 版的 SLF4J,但也可以使用 1.6 版,对其代码进行一些小的修改。使用 Slick 的应用程序必须使用 1.6 版并在 1.7 上中断。如果 1.6 存在,Slick 作者是否可以通过允许编译适应 1.6 所需的一段适配器代码来适应这种用例,如果存在 1.7,则编译另一段代码?
    • 作为参考,在其他语言生态系统中,这通常是通过预处理器指令完成的,如果检测到某些依赖项,则生成一个代码路径,如果检测到其他依赖项,则生成另一个代码路径。
    猜你喜欢
    • 2017-09-10
    • 2016-02-26
    • 2018-11-01
    • 2016-07-18
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 2015-08-26
    • 1970-01-01
    相关资源
    最近更新 更多