20 ABI (Application Binary Interface) breaking changes every C++ developer should know
What is an Application Binary Interface ?
According to Wikipedia, ” an application binary interface (ABI) is an interface between two binary program modules; often, one of these modules is a library or operating system facility, and the other is a program that is being run by a user.An ABI defines how data structures or computational routines are accessed in machine code, which is a low-level, hardware-dependent format; in contrast, an API defines this access in source code, which is a relatively high-level, hardware-independent, often human-readable format. A common aspect of an ABI is the calling convention, which determines how data is provided as input to or read as output from computational routines; examples are the x86 calling conventions.
”
Why should I care about ABI Compatibility?
If you’re packaging your library as a dll, you should be careful not to break ABI compatibility. If ABI compatibility is broken between the calling binary( exe or another dll) and your dll, it can result in unintended crashes.
- ABI Breaking Changes
- ABI COMPATIBLE CHANGES
1. Un-export or remove a class from the dll
2. Un-export or remove a function or method from a class
3. Change the signature of any method in the class. This includes
- Changing the return type
- Changing the order of parameters
- Change the access rights ( eg. public to protected)
- removing or adding parameters
4. Add, remove, or re-order member variables in a class
5. Change the type of any member variable in a class
6. Change the class hierarchy of the class exposed in your dll – for example,
- make the exposed class inherit from a different base class
- make the exposed class inherit from additional base classes
- remove base class(es) from the exposed class
7. Change the template arguments (add, remove,r, re-order) of a templated class
- this is in line with #3 above since changing the template arguments changes the underlying function signatures generated when the template is instantiated
8. Inline a function in an exported class
- When a function is declared inlined, the compiler inlines it where the function is called and may not generate an out-of-line copy. The client binary, which was thus far depending on the exported out-of-line function signature cannot locate it anymoe and will fail in unexpected ways (crash most likely).
9. Change the const or volatile qualifier of a member function
- Some compilers encode the constness of a function in the mangled name and hence changing the function from const to non-const changes the mangled name.
10. Change the type of global data
11. Changing the const or volatile qualifiers on global data
12. Adding an explicit copy constructor or destructor to a class that would otherwise have implicit versions. ( Ref: https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html)
13. Changing a non-virtual method to be virtual, and vice versa.
14. Adding a virtual method to a class with no existing virtual methods.
15. Changing the order of virtual methods.
16. Adding new virtual methods (some compilers may preserve binary compatibility if you only add new virtual methods after existing ones).
17. Override a virtual that doesn’t come from a primary base
18. Remove a virtual function, even if it is a reimplementation of a virtual function from the base class
19. Change the calling convention of an exported function ( from _stdcall to _cdecl and vice versa)
20. If passing C++ types across dll boundary, make sure that your client exe and dll are compiled with the same version of the compiler. There are often ABI breakages between different versions – like VS2012 and VS 2015.
1. Add new class to the dll
2. Add new free functions
3. Add new non-virtual methods to an existing class
4. Add new static variables to a class
5. Remove private static variables (if they are never referenced from an inline method)
6. Remove non-virtual private methods (if they’re never called from an inline method)
7. Change the implementation of an inline method
8. Change an inline method to non-inline
9. Adding new constructors to the class
10. add a new enum to a class
11. Append new enum values to an existing enum class
12. change the default arguments of a method
13. add or remove friend declarations from a class
14. add new static data memebers
15. 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.)
I primarily made the list above to use in code reviews – for in depth discussion of the topic, please refer to the following articles:
1. https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
2. https://community.kde.org/Policies/Binary_Compatibility_Examples
3.https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B#The_Do.27s_and_Don.27ts