我将Java库打包为JAR,java.lang.IncompatibleClassChangeError
当我尝试从中调用方法时,它会抛出很多s.这些错误似乎是随机出现的.什么类型的问题可能导致此错误?
我目前正在开发一个Windows的C++库,它将作为DLL发布.我的目标是最大化二进制互操作性; 更确切地说,我的DLL中的函数必须可以从使用多个版本的MSVC++和MinGW编译的代码中使用,而无需重新编译DLL.但是,我对哪种调用约定是最好的cdecl
或者很困惑stdcall
.
有时我会听到诸如"C调用约定是唯一一个保证编译器相同的语句"的陈述,这与诸如" 解释中存在一些变化cdecl
,特别是如何返回值 "之类的陈述形成对比.这似乎并没有阻止某些库开发人员(如libsndfile)在他们分发的DLL中使用C调用约定,而没有任何明显的问题.
另一方面,stdcall
调用约定似乎是明确定义的.据我所知,所有Windows编译器基本上都需要遵循它,因为它是用于Win32和COM的约定.这是基于这样的假设:没有Win32/COM支持的Windows编译器不会非常有用.在论坛上发布的很多代码片段都声明了函数,stdcall
但我似乎无法找到一个明确解释原因的帖子.
那里有太多相互矛盾的信息,我运行的每一次搜索都给出了不同的答案,这些答案并没有真正帮助我在两者之间作出决定.我正在寻找一个清晰,详细,有争议的解释,为什么我应该选择一个而不是另一个(或者为什么两者是等价的).
请注意,这个问题不仅适用于"经典"函数,还适用于虚拟成员函数调用,因为大多数客户端代码将通过"接口",纯虚拟类(以下描述的模式,例如此处和那里)与我的DLL接口.
向后二进制兼容性(或向下兼容性) - 使用旧版本库API构建的客户端在新版本(wiki)上运行的能力.
向上二进制兼容性(或向前兼容性) - 使用新版本的库API构建的客户端在旧版本(wiki)上运行的能力.
关于自1.4.2以来J2SE 5.0中 JDK 不兼容性的一般Sun文档(以及Java SE 6与J2SE 5.0的兼容性)描述了JDK的兼容性,如下所示:
除了下面列出的不兼容性之外,JDK 5.0 与Java 2 SDK v1.4.2 向上二进制兼容.这意味着,除了指出的不兼容性之外,使用1.4.2版编译器构建的类文件将在JDK 5.0中正确运行.
我认为文档编写者在这句话中混淆了 "向上"和"向后"兼容性术语.它们描述了"向后"兼容性,但将此功能称为"向上"兼容性.
这是一个错字,错误或预期的术语吗?JDK"向上"还是"向后"兼容?
java backwards-compatibility binary-compatibility forward-compatibility
我正在为C++库设计一个API,它将分发在一个dll/shared对象中.该库包含具有虚函数的多态类.我担心如果我在DLL API上公开这些虚函数,我就不会使用更多虚函数扩展相同的类,而不会破坏与为以前版本的库构建的应用程序的二进制兼容性.
一种选择是使用PImpl习惯用法来隐藏所有具有虚函数的类,但这似乎也有它的局限性:这样,应用程序就失去了对类的子类进行子类化并覆盖虚方法的可能性.
您将如何设计一个可以在应用程序中进行子类化的API类,而不会失去在新版本的dll中使用(非抽象)虚拟方法扩展API同时保持向后二进制兼容的可能性?
更新:库的目标平台是windows/msvc和linux/gcc.
特别:
以某种方式确保所有版本的glibc 2.x都是二进制兼容的吗?
如果没有,我如何在我的系统上运行二进制(游戏),该二进制(游戏)已针对不同的版本编译?我可以在其他文件夹中安装glibc吗?
我的具体问题是glibc 2.14(我拥有的)和2.15(游戏想要的)之间的兼容性.
我可能也会得到glibc 2.13的版本,但我不确定它是否会在2.14上运行.
有什么办法在Linux发行版中制作二进制文件并在具有相同架构的另一个发行版上运行它?或者我应该在不同的发行版上编译和构建它?
Redhat,基于Debian的二进制文件发行版之间是否有任何兼容性?(我想在fedora上使用我的Ubuntu二进制文件!)
我有一些写C库的经验,但我从来没有读过任何描述良好实践的正式文档.我的问题主要涉及两个主题:
我可以从我的研究中看到的关于二进制兼容性的主要问题是我可以通过使用pImpl惯用法使库二进制兼容,但是即使在使用pImpl时,更改结构/添加新数据成员等也会影响它的二进制兼容性.另外,有没有办法在不实际破坏二进制兼容性的情况下向库中添加新方法/函数?我假设添加这些东西会改变库的大小,从而破坏兼容性.
有没有工具来检查二进制兼容性?
我已经读过这些文章了.还有其他可以仔细阅读的文档吗?
http://en.wikipedia.org/wiki/Opaque_pointer
http://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++
此外,是否有文章描述了在设计库接口的上下文中的内存所有权问题.一般惯例是什么?谁拥有记忆,多长时间,谁负责释放记忆等?
c linux memory-management shared-libraries binary-compatibility
在Spark 2.1 文档中提到了这一点
Spark运行在Java 7 +,Python 2.6 +/3.4 +和R 3.1+上.对于Scala API,Spark 2.1.0使用Scala 2.11.您需要使用兼容的Scala版本(2.11.x).
在Scala 2.12 发布消息时,它还提到:
尽管Scala 2.11和2.12主要是源兼容的,以便于交叉构建,但它们不是二进制兼容的.这使我们能够不断改进Scala编译器和标准库.
但是当我构建一个超级jar(使用Scala 2.12)并在Spark 2.1上运行它时.一切都很好.
我知道它不是任何官方消息来源,但在47度博客中他们提到Spark 2.1确实支持Scala 2.12.
如何解释那些(冲突?)信息?
添加新的依赖项是否会影响二进制兼容性,只要库的外部API以其他方式向后兼容?
我的CBOR库包含任意精度算术的类(在PeterO命名空间中).(它在C#和Java中; Java版本在一个单独的存储库中,但同样的问题适用于这两个版本.)
我已将这些类移动到一个新的命名空间(在PeterO.Numbers中),并重命名它们(保留原始类以实现向后兼容),因为它们现在的命名空间只包含实用程序类.我计划将新类移动到一个单独的库,并使CBOR库将该库作为依赖项调用,因为任意精度类在CBOR之外显然是有用的.(我计划最终弃用旧类.)
但我担心如果以这种方式创建一个单独的库是一个二进制兼容性问题,这样我不能只更新次要版本,而且还要更新主要版本.在撰写本文时,CBOR库是版本2.3.1.我能够做到这一点并将版本更改为2.4,或仅3.0?
.NET中的事件有一个标准模式 - 它们使用一个delegate
类型,它接受一个名为sender的普通对象,然后是第二个参数中的实际"payload",它应该从中派生出来EventArgs
.
派生的第二个参数的基本原理EventArgs
似乎非常清楚(请参阅.NET Framework标准库带注释的参考).它旨在确保随着软件的发展,事件接收器和源之间的二进制兼容性.对于每个事件,即使它只有一个参数,我们派生一个自定义事件参数类,它具有包含该参数的单个属性,这样我们就可以保留在未来版本中向有效负载添加更多属性而不破坏现有客户端代码的能力. .在独立开发组件的生态系统中非常重要.
但我发现零参数也是如此.这意味着如果我的第一个版本中有一个没有参数的事件,我会写:
public event EventHandler Click;
Run Code Online (Sandbox Code Playgroud)
......然后我做错了.如果我将来的委托类型更改为新的类作为其有效负载:
public class ClickEventArgs : EventArgs { ...
Run Code Online (Sandbox Code Playgroud)
...我将破坏与客户的二进制兼容性.客户端上界到内部方法的具体超载add_Click
是需要EventHandler
的,如果我改变了委托类型,然后他们无法找到超载,所以有一个MissingMethodException
.
好的,那么如果我使用方便的通用版本怎么办?
public EventHandler<EventArgs> Click;
Run Code Online (Sandbox Code Playgroud)
不,仍然是错的,因为一个EventHandler<ClickEventArgs>
不是EventHandler<EventArgs>
.
因此,为了获得好处EventArgs
,您必须从中获取,而不是直接使用它.如果你不这样做,你也可以不使用它(在我看来).
然后是第一个论点,sender
.在我看来,这似乎是一个邪恶的耦合配方.事件触发本质上是一个函数调用.一般来说,这个函数是否应该能够通过堆栈挖掘并找出调用者是谁,并相应地调整其行为?我们应该强制要求接口看起来像这样吗?
public interface IFoo
{
void Bar(object caller, int actualArg1, ...);
}
Run Code Online (Sandbox Code Playgroud)
毕竟,实现者Bar
可能想知道是谁caller
,所以他们可以查询更多信息!我希望你现在正在呕吐.为什么事件会有所不同?
因此,即使我已经准备好为EventArgs
我声明的每个事件都要为一个独立的派生类而烦恼,只是为了让它值得我在使用EventArgs
时,我绝对宁愿删除对象发送者参数.
Visual Studio的自动完成功能似乎并不关心您用于事件的委托 - 您可以键入+=
[命中空间,返回]并为您编写一个匹配任何委托的处理程序方法.
那么偏离标准模式我会失去什么价值? …