语义版本控制是否适用于源或二进制兼容性?

Does semantic versioning apply to source or binary compatibility?

这个问题适用于用一种语言 ("source") 编写的任何语言,例如C 或 Java,并分布在另一个 ("binary"),例如机器代码或 Java 字节代码,使用动态链接。


假设用户已经在使用我的库的版本 A。我发布了一个较新的版本 B.

如果他可以在不改变 B 的情况下编译他的代码并且正确地 运行 使用 B,那么从 A 到 B 的改变被认为是 源代码兼容

如果他可以针对 A 编译代码并使用 B 正确地 运行,则从 A 到 B 的更改被认为是 二进制兼容。当使用没有隔离模块加载(例如 OSGI)的传递依赖图时,这种情况很常见。 X 是针对特定版本的 Y 和 Z 编译的,Y 是针对不同的特定版本的 Z 编译的。在 运行 时间,Y 对 Z 的调用可能不正确并可能崩溃。

更改可能与源兼容,但二进制不兼容。更改也可能与源不兼容和二进制兼容。

我使用哪种兼容性进行语义版本控制?我是使用源兼容性来区分主要更新和 minor/patch 更新,还是使用二进制兼容性来区分主要更新和 minor/patch 更新?


我目前的动机是 Scala 库。 Scala 二进制兼容性很难分析,需要很好地了解编译器细节。源兼容性和二进制不兼容很常见。

这不是一些奇怪的边缘案例;这个问题可能出现在大多数编译的、动态链接的语言中。

要回答这个问题,请假装您是用户而不是程序员。在他们看来,源代码毫无价值;他们不理解,这对他们来说毫无意义。另一方面,他们有一个包含目标代码的文件并且他们知道它需要去某个地方。只有二​​进制文件的版本对他们很重要。

然而,这还没有结束。您的问题隐含地包含更好答案的核心。兼容性有两种,因此应该有两个版本序列。该问题本身包含一个功能失调的假设,即应该只有一个版本序列。

现在,如果您有两个版本序列,并且另外在用户端创建一种将源兼容版本转换为对象兼容版本的自动方式,那么您的问题就得到了缓解。能够做到这一点需要明确指定您如何进行转换,例如编译器版本、解释器版本、命令行参数等。

简而言之,对上述问题的最佳答案是它适用于他们两个。

几个月过去了,我想我有了一个很好的结论。

语义版本控制应同时考虑两者,并遵循 "most changed" 一个。

  • 中断源代码编译是对库用户不兼容的更改。
  • 中断运行时执行是对库用户的不兼容更改。

如果源兼容性或二进制兼容性发生变化,根据语义版本控制,它应该是一个新的主要版本。

就我而言,对于 Scala,二进制兼容性有时很难确定。有几个 JAR API 差异化工具,例如JDiff.