因此,我正在阅读COM和DLL,好像,如果我要更新DLL的实现(如果所需的内存超过了旧的需求),则需要使用DLL重新编译程序。与更新的DLL。所以我只是想知道,什么时候使用DLL代替COM是正确的?重新编译所有程序似乎几乎是不可能的,仅仅是因为它们已经更新了依赖性。
另外,还有一个简短的问题:为什么.NET中二进制封装不成问题?我怎么能更改在.NET中找到的DLL,而不必重新编译我的旧项目,而无需使用pimpl / opaque指针和诸如此类的东西呢?
二进制兼容性要求调用者和被调用者就通用ABI(应用程序二进制接口)达成协议。
在Windows和Linux上,操作系统都指定了用于C调用的标准ABI,该标准允许从任何其他语言到C库的调用。只要C ++仅在DLL内部使用extern "C"
并且外表面使用与C兼容的类型(例如,指针和基元以及与C兼容的类型的原始数据组合),这也使C ++对DLL的开发有用。
在Linux和Windows上,C ++ ABI与C ++运行时库关联。在Linux上,人们习惯于自欺欺人地认为C ++共享对象也具有操作系统提供的ABI,因为只有一个广泛使用的C ++库-g ++ libstdc++
,并且该库竭尽全力来保存相同的ABI。因此,C ++ 11之前的libstdc++
ABI是事实上的标准,没有人遇到混合ABI的麻烦。现在,C ++ 11被迫libstdc++
破坏二进制兼容性,而clanglibc++
越来越流行,因此Linux开发人员面临着Windows开发人员长期以来所熟悉的问题。
在Windows上,从来没有C ++标准库以完全相同的方式占据主导地位,部分原因是操作系统供应商工具(Microsoft Visual C ++)的每个版本都引入了不兼容性。是的,有些事情基本上保持不变(名称修改),但其他事情发生了根本性的变化(分配器获得了低碎片堆支持,容器得到了调试迭代器,等等)。
具有讽刺意味的是,Windows上的ABI标准化现在比Linux 1上更好,因为Windows ABI指定了一种C ++功能-vtable布局-支持COM。
本机C ++的底线是您可以在DLL中自由使用它,但是为了进行解耦,DLL的公共表面只需要使用OS ABI中指定的功能-extern "C"
名称,C兼容类型和(仅Windows) )仅由虚函数组成的抽象基类(无静态成员,无非静态数据,所有非静态函数都是虚函数,并且构造函数受到保护)。
但是,如果您可以进行耦合,那么您将获得更多功能。如果应用程序中的每个组件都同意.NET ABI,则其所有功能都将可用。.NET的ABI的开发考虑到了向后和向前的兼容性,它从C ++的不兼容性以及以前的尝试(例如Java)中吸取了教训。
由于.NET ABI非常稳定,因此与之耦合是一个可行的决定,就像许多与C ++ 11之前的Linux开发人员耦合一样 stdlibc++
ABI。但是,如果您破坏了兼容性,则可能会丢失所有可重用的库,这就是为什么将耦合到任何特定的Windows C ++库视为一个坏主意的原因-升级编译器要求您拥有每个库的新版本。当即使只有一个组件卡在旧版本上也无法采用新的编译器时,您将失去对其他已切换组件的新开发的机会。这就是为什么Windows上的C ++ ABI耦合被广泛认为是一个非常糟糕的主意的原因。以及为什么库作者很少以二进制形式分发Linux代码-他们将其留给每个发行版来选择ABI,使用它进行一致地编译,并提供与其兼容的二进制软件包。
当然,这只能解决源代码外部的更改(对库类型的布局更改,参数传递顺序等)。如果您的源代码发生更改(例如,通过添加新的函数参数或更改类类型中的数据成员),则无论ABI有多好(明确规定/稳定),您都将不兼容。.NET通过两阶段编译系统避免了其中一些影响-依赖项更改时,确实会重新编译整个世界,因为JIT编译是在运行时完成的。但是即使在.NET中,某些更改(例如添加新的函数重载)也需要重新编译源代码才能生效。
实际上我不确定,是否也可以在Linux的操作系统级别上指定vtable-layout。重要的是Linux C ++二进制兼容性不再是通用的,这使许多实际上依赖于事实上的标准编译器提供的ABI的开发人员感到惊讶,同时还假设OS ABI永远保证了通用兼容性。因此,Windows开发人员已经学会了管理二进制兼容性的不足,处于更好的位置。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句