在软件生态系统中,不同的包依赖于其他包的不同版本,有时依赖解决以版本冲突结束。
示例:
也许库C的开发人员讨论了依赖E2.*而不是E1.*是否可以,以及有多少人会因此而生气。
也许库E的开发人员也讨论过是否有人会切换到他们的新分支E2,这可能会破坏与仍然使用E1的旧包的兼容性。
我在PHP社区中看到了针对Composer / Packagist生态系统的这类问题的讨论。但我认为类似的讨论也会发生在其他地方。
我一直在想,为什么不以自己的包名和名称空间发布一个新版本呢?这将允许不同版本在不发生冲突的情况下共存。
例如,将出现E1 1和E2 1.*而不是E1.*和E2.。包名将不是"E“,而是"E1”/ "E2“。类的命名空间将是ACME::E1::*或ACME::E::v1::*,而不仅仅是ACME::E::*。
或者在PHP / Composer / Packagist生态系统中:
而不仅仅是symfony/symfony,还有symfony/symfony 1、symfony/symfony 2等等,名称空间将是Symfony2\Component\Asset等。
或者版本号可能适用于较低的级别,例如Symfony\Component2\Asset。
因此,我的问题是:有什么一揽子生态系统,这是常见的做法吗?有什么理由不这么做吗?
发布于 2017-08-28 08:17:34
这在很大程度上取决于生态系统,特别是:
如果这两个问题的答案都是“是”,那就没有问题了。
当确保了向后兼容性时,E v1.X和Ev2.X的依赖之间没有冲突,因为Ev2.X是向后兼容E v1.X的,所以您可以将依赖性解析为Ev2.X,一切都应该正常工作。这意味着包不应指定确切的依赖版本或允许版本的范围,而只应指定最低要求的版本。这种策略在稳定的、经过良好测试的生态系统中是足够的,比如Debian/APT或CPAN。
当我可以安装和加载同一软件包的多个版本时,两个不同的版本不会发生冲突。优点是所有依赖项都是独立的,并且可以固定精确的版本。缺点是库之间不能共享依赖关系,这会导致复制和膨胀。假定全局包命名空间的语言通常对此策略有困难。这种策略还可以处理不稳定的生态系统,在这些生态系统中,破坏性的变化是常见的(例如Ruby或JavaScript)。这一策略的显著用户是NPM和Java/OSGi。
那么,如果出现破坏性的更改,但我不能为同一个软件包安装两个版本,会发生什么情况?
你所建议的命名方案并不少见。假设每个项目都使用一个与SemVer兼容的版本号,如“foov1.X.0”和“foov2.y.0”,则表示中断更改的主要版本号将成为包名的一部分,从而导致像foo X.0和foo2 Y.0这样的包。(如果主要版本是1,对于包名来说基本上是没有意义的,那么可以省略它。)在每个foo和foo2中,只有向后兼容的更改,所以可以使用最小版本策略。
在Ubuntu存储库中,有多个APT包具有这样的名称,例如python与python3、openjdk-8与openjdk-9、libgtk2.0-0与libgtk-3-0。大多数项目没有看到规模上的更改,从而使版本化的包名称成为必要。
发布于 2017-08-28 15:16:42
一个重要的问题是包B和C是否从E导出类型的对象,那么可能存在真正的冲突。如果他们只在内部使用E,那么问题只是他们在编译时需要不同的名称空间,所以构建系统必须能够处理这个问题。
在Java世界中,OSGi可以处理这一问题。缺点是,仅OSGi核心的规范就有80页长,是LISP定义的两倍多(McCarthy,1960年)。您是否真的想要一个比编程语言更复杂的依赖关系管理器取决于您。
https://softwareengineering.stackexchange.com/questions/356365
复制相似问题