您的位置:首页 > 编程语言 > C语言/C++

C++动态链接库的兼容性

2015-08-25 14:48 579 查看

一.动态链接库的ABI

    动态链接库的兼容性是由于库的ABI(Application binary interface)引起,ABI与API类似,但是主要包括一些诸如函数调用的堆栈结构、符号命名、参数规则、数据结构的内存分布等方面的规定。

二.引起动态链接库不兼容的行为

删除一个导出类;
改变导出类的继承层次
改变模板的模板参数
删除一个导出函数
改变函数的inline属性
改变函数的签名
在一个非虚基类或者没有含有虚函数的类中添加一个虚函数
改变虚函数的声明次序
......

三.一般不会引起动态链接库不兼容的行为

增加一个非虚函数
删除没有被inline函数调用的非虚函数
改变一个函数的默认参数
增加新的static数据成员
导出一个新的参数
增加或者删除一个友元声明
......

四.详细的内容(英文)

    详细的内容可以参考:https://techbase.kde.org/Policies/Binary_Compatibility_Issues_With_C++


Note about ABI

This text applies to most C++ ABIs used by compilers which KDE can be built with. It is mostly based on the Itanium
C++ ABI Draft, which is used by the GCC C++ compiler since version 3.4 in all platforms it supports. Information about Microsoft Visual C++ mangling scheme mostly comes from this
article on calling conventions (it's the most complete information found so far on MSVC ABI and name mangling).

Some of the constraints specified here may not apply to a given compiler. The goal here is to list the most restrictive set of conditions when writing cross-platform C++ code, meant to be compiled with several different compilers.

This page is updated when new binary incompatibility issues are found.


The Do's and Don'ts

You can...
add new non-virtual functions including signals and slots and constructors.
add a new enum to a class.
append new enumerators to an existing enum.
Exeption: if that leads to the compiler choosing a larger underlying type for the enum, that makes the change binary-incompatible. Unfortunately, compilers have some leeway to choose the underlying
type, so from an API-design perspective it's recommended to add a Max.... enumerator with an explicit large value (=255=1<<15, etc) to create an interval of numeric enumerator values that is guaranteed to
fit into the chosen underlying type, whatever that may be.

reimplement virtual functions defined in the primary base class hierarchy (that is, virtuals defined in the first non-virtual base class, or in that class's first non-virtual base class, and so forth) if it
is safe that programs linked with the prior version of the library call the implementation in the base class rather than the derived one. This is tricky and might be dangerous. Think twice before doing it. Alternatively see below for a workaround.
Exception: if the overriding function has a covariant return
type, it's only a binary-compatible change if the more-derived type has always the same pointer address as the less-derived one. If in doubt, do not override with a covariant return type.

change an inline function or make an inline function non-inline if it is safe that programs linked with the prior version of the library call the old implementation. This is tricky
and might be dangerous. Think twice before doing it.
remove private non-virtual functions if they are not called by any inline functions (and have never been).
remove private static members if they are not called by any inline functions (and have never been).
add new static data members.
change the default arguments of a method. It requires recompilation to use the actual new default argument values, though.
add new classes.
export a class that was not previously exported.
add or remove friend declarations to classes.
rename reserved member types
extend reserved bit fields, provided this doesn't cause the bit field to cross the boundary of its underlying type (8 bits for char & bool, 16 bits for short, 32 bits for int, etc.)
add the Q_OBJECT macro to a class if the class already inherits from QObject
add a Q_PROPERTY, Q_ENUMS or Q_FLAGS macro as that only modifies the meta-object generated by moc and not the class itself

You cannot...
For existing classes:
unexport
or remove an exported class.
change
the class hierachy in any way (add, remove, or reorder base classes).

For template classes:
change
the template arguments in any way (add, remove or reorder).

For existing functions of any type:
unexport it.
remove it.
Remove the implementation of existing declared functions. The symbol comes from the implementation of the function, so this is effectively the function.

inline it
(this includes moving a member function's body to the class definition, even without the inline keyword).
add an overload (BC, but not SC: makes &func ambiguous), adding overloads to already overloaded functions is ok (any use of &func already
needed a cast).
change its signature. This includes:
changing any of the types of the arguments in the parameter
list, including changing the const/volatile qualifiers of the existing parameters (instead, add a new method)
changing the const/volatile qualifiers of the function
changing the access
rights to some functions or data members, for example from private to public. With some compilers, this information may
be part of the signature. If you need to make a private function protected or even public, you have to add a new function that calls the private one.
changing the CV-qualifiers
of a member function: the const and/or volatile that apply to the function itself.
extending a function with another parameter, even if this parameter has a default argument. See below for a suggestion on how to avoid this issue
changing the return
type in any way
Exception: non-member functions declared with extern "C" can change parameter types (be very careful).

For virtual member functions:
add
a virtual function to a class that doesn't have any virtual functions or virtual bases.
add
new virtual functions to non-leaf classes as this will break subclasses. Note that a class designed to be subclassed by applications is always a non-leaf class. See below for some workarounds or ask on mailing lists.
add new virtual functions for any reason, even to leaf classes, if the class is intended to remain binary compatible on Windows. Doing so may reorder
existing virtual functions and break binary compatibility.
change
the order of virtual functions in the class declaration.
override
an existing virtual function if that function is not in the primary base class (first non-virtual base class, or the primary base class's primary base class and upwards).
override
an existing virtual function if the overriding function has a covariant return type for which the more-derived
type has a pointer address different from the less-derived one (usually happens when, between the less-derived and the more-derived ones, there's multiple inheritance or virtual inheritance).
Remove a virtual function, even if it is a reimplementation of a virtual function from the base class

For static non-private members or for non-static non-member public data:
Remove or unexport it
Change its type
Change its CV-qualifiers

For non-static members:
add new, data members to an existing class.
change the order of non-static data members in a class.
change the type of the member, except for signedness
remove existing non-static data members from an existing class.

If you need to add extend/modify the parameter list of an existing function, you need to add a new function instead with the new parameters. In that case, you may want to add a short note that the two functions shall be merged with
a default argument in later versions of the library:

void functionname( int a );void functionname( int a, int b ); //BCI: merge with int b = 0


You should...

In order to make a class to extend in the future you should follow these rules:
add d-pointer. See below.
add non-inline virtual destructor even if the body is empty.
reimplement event in QObject-derived classes, even if the body for the function is just calling the base class' implementation.
make all constructors non-inline.
write non-inline implementations of the copy constructor and assignment operator unless the class cannot be copied by value (e.g. classes inherited from QObject can't be)

版权所有,欢迎转载,转载请注明出处,谢谢

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息