为啥scala maven工件对每个scala版本都有一个工件,而不是每个scala版本都有一个分类器?

Posted

技术标签:

【中文标题】为啥scala maven工件对每个scala版本都有一个工件,而不是每个scala版本都有一个分类器?【英文标题】:Why do scala maven artifacts have an artifact for each scala version instead of a classifier per scala version?为什么scala maven工件对每个scala版本都有一个工件,而不是每个scala版本都有一个分类器? 【发布时间】:2013-02-12 09:42:48 【问题描述】:

由于您在 Scala-versions 之间只有源代码兼容性,因此不幸的是,您需要为它们支持的每个 scala 版本编译像 scalatest 或 scalamock 这样的库。让我感到困惑的是,这些库提供了大量的工件(scalatest_2.9.0、scalatest_2.9.1、scalatest_2.10 等等)——每个 scala 版本都有一个,这样 maven 存储库中到处都是从构建的工件相同的来源。我的直觉告诉我宁愿为每个 scala 版本使用一个带有分类器的工件。 (事实上​​,maven pom reference 提到有时使用 jdk14 和 jdk15 分类器来处理工件,这看起来和我很相似。)那么,为什么 Scala 的人选择了许多工件矫枉过正:-) 呢?

【问题讨论】:

也许这与 Scala 二进制文件在主要版本之间不兼容并且不应该混合使用的事实有点相关。 它远远超出了“不应该!”当您尝试加载由不兼容版本的编译器生成的类时,通常会出现异常。这也可能是一个相当令人困惑的错误——没有什么比“Scala 版本不匹配;请从兼容版本的 Scala 编译器中找到该类的版本”更直接的了。 【参考方案1】:

我可能是错的,但如果分类器的目的是“区分从同一个 POM 构建但内容不同的工件”,那么我看到一个很好的理由使用它们对于 scala 版本控制:scala 版本不仅仅是二进制不兼容,它们很可能是源不兼容。 例如,当将 scala 从 2.7 升级到 2.8 时,我必须对代码库进行一些重大更改。如果我想同时保留 scala 2.7 和 2.8 版本,我需要创建一个并行分支,并且两个分支肯定不会有相同的源代码。

当我读到“来自同一个 POM”时,我明白它也意味着来自同一个源代码,这显然不是这两个代码分支的情况。

另一个更重要的原因是分类器本质上是一个字符串,它已经用于许多事情。或多或少的标准分类器包括“sources”、“javadoc”或“resources”。这些分类器的含义在 scala 项目中是相同的,并且与 scala 版本完全正交,我将尝试展示。

Maven 的文档建议使用“jdk15”或“jdk14”等分类器来表示编译二进制工件的 jvm 版本。 鉴于 java 代码是向后兼容的,原则上具有两个分类器(“jdk15”或“jdk14”)的工件是从相同的源代码编译的。这就是您不需要为“sources”工件复制分类器的原因,或者换句话说,您不需要需要一个名为“sources-jdk14”和“sources-jdk15”的分类器。 但是你不能对 scala 版本应用相同的理由:假设你可能需要不同的源代码,无论你是针对 scala 2.7 还是 scala 2.8 编译,你确实需要两个不同的带有分类器的工件,例如“sources-scala2.7”或“源-scala2.8"。所以我们已经有了复合分类器。 至于二进制工件,您不仅需要区分目标 jvm 版本(请记住,您可以编译 scala 代码以针对不同的 jvm 版本),还需要区分编译它的 scala 版本。所以你最终会得到类似“jdk14-scala2.7”或“jdk14-scala2.8”或“jdk15-scala2.7”或“jdk15-scala2.8”的东西。还有一组复合分类器。 所以带回家的信息是,scala 版本确实是一种对工件进行分类的单独方法,它与所有现有的分类器完全正交。 是的,我们真的可以像上面那样使用复合分类器(例如“sources-scala2.7”),但是我们不会使用标准分类器,这本身就很混乱,但还需要修改分类器周围的所有工具:如果我使用不了解 scala(仅 java)但知道如何自动发布“源”工件的构建工具怎么办?我是否需要修改此构建工具,以便他知道要发布“sources-scala2.7”工件?另一方面,如果我在(基本)工件名称中编码 scala 版本并将其提供给构建工具,一切都会照常进行,并且我会得到一个带有“源”分类器的工件。

总而言之,与直接的直觉相反,在名称中编码 scala 版本可以更好地集成到现有的 java 构建生态系统中。

【讨论】:

没错,源不兼容是我没有想到的一个好点。不过,这仍然让我想知道为什么他们甚至为同一版本的多个候选版本创建工件,就像在 scalatest 中一样。 顾名思义,候选版本只是稳定版本的候选版本,换句话说,它们只是预览版。因此,他们完全有权完全破坏与先前候选版本的兼容性,因此需要一个单独的版本(只要发现给定候选版本的主要问题,他们就会继续修复它 - 可能会破坏与早期候选版本的兼容性 -直到质量被认为足以正式发布)。【参考方案2】:

Scala 仅在补丁版本(Major.Minor.Patch 版本规范的第三部分)之间提供其字节码输出(.class 文件)的版本间兼容性。

Maven 没有地方将其正确编码为工件的一等属性,因此必须按照名称中的约定对其进行编码。

可惜……

【讨论】:

有人可能会纠正我,但我认为这就是 Maven 分类器的用途。来自maven.apache.org/pom.html -> “分类器允许区分从同一 POM 构建但内容不同的工件。它是一些可选和任意字符串,如果存在的话,它会附加到工件名称之后,紧跟在版本号之后。 "我为我的 Maven 构建的 scala 项目使用版本分类器,例如 github.com/hohonuuli/scilube

以上是关于为啥scala maven工件对每个scala版本都有一个工件,而不是每个scala版本都有一个分类器?的主要内容,如果未能解决你的问题,请参考以下文章

为啥交叉构建约定将 scala 版本附加到 artifactId?

如何构建运行测试套件的 Maven 工件? “sbt 测试”如何工作?

scala 参考 sbt 项目版本

如何在一个库中支持多个 Scala 版本

利用IntelliJ IDEA与Maven开始你的Scala之旅

利用IntelliJ IDEA与Maven开始你的Scala之旅