This presentation by Marc Mutz (Senior Software Engineer at The Qt Company) provides a deep dive into the complexities of maintaining Binary Compatibility (BC) in C++ libraries. Addressing the technical challenges faced by long-standing projects like Qt and KDE, the talk defines the critical distinctions between Application Binary Interface (ABI) and Application Programming Interface (API). Mutz explores common pitfalls—such as adding default arguments, modifying class layouts, and the "bodgery" required to keep symbols compatible—while introducing advanced techniques like "Reserved Fields" and a custom "Removed API" pattern to modernize codebases without breaking dynamic linking. The session concludes by demonstrating how to navigate ODR (One Definition Rule) violations and platform-specific compiler behaviors to achieve a rolling binary compatibility window.
Summary: Managing Binary Compatibility in C++
0:00 - The Core Constraint: Binary compatibility means an application linked against version 1.0 of a library will continue to function with version 1.1 without recompilation. This is a local property of types and functions, not the library itself.
4:52 - The Cost of Change: Adding even a defaulted argument to a function breaks binary compatibility because it changes the function signature, causing linker errors. Overloading can solve this but may introduce source incompatibility if the address of the function is taken.
13:35 - ABI vs. API: The ABI is what the linker sees (mangled names, offsets), while the API is what the compiler sees (overload sets, templates). They must be managed independently; one can be changed without impacting the other using specific patterns.
18:26 - The Danger of Wholesale Exporting: Exporting a polymorphic class "wholesale" is necessary for the vtable but can lead to bloated symbols. Mutz advises defining destructors out-of-line to pin the vtable to a single translation unit.
23:22 - Inline Functions & ODR: Inline functions are generally source-compatible but not necessarily binary-compatible. Because the linker only deduplicates per executable, you can end up with multiple copies of a "singleton" variable if not managed carefully.
31:34 - PIML and Reserved Fields: To ensure future-proofing, use the Pointer-to-Implementation (PIML) idiom or reserve explicit padding/void pointers in class layouts. This allows adding data members later without changing the class size (and thus the ABI).
34:58 - Move Semantics: Move constructors and assignments should be inline for performance. However, they must be implemented carefully (e.g., using std::exchange and swap) to avoid breaking encapsulation or forcing data member destructor calls that the compiler doesn't actually need.
43:37 - The "Magic" Removal Technique: Mutz details a pattern using a dedicated RemovedAPI.cpp file. By using macros to hide old overloads from new users while keeping them visible to the linker, one can modernize APIs while maintaining ABI parity.
56:11 - Static vs. Dynamic: Static linking effectively eliminates the binary compatibility problem because the entire application is linked at once. Dynamic linking, however, requires rigorous symbol versioning and strict control over exported symbols.
58:01 - Managing Inline Transitions: To turn an out-of-line function into an inline one, Mutz suggests using conditional compilation to ensure that external users see the inline version while internal library users see the out-of-line implementation to prevent ODR violations.
Expert Review Panel Recommendation
To effectively review and implement these standards, this material should be evaluated by:
Library Maintainers: Specifically those managing high-performance, long-lived C++ frameworks where ABI stability is a requirement for downstream users.
Toolchain/Compiler Engineers: Individuals focused on Linker/Loader internals (specifically Itanium ABI and MSVC behaviors) who can validate the "corner cases" discussed.
Senior Software Architects: Developers responsible for long-term API lifecycle management and build-system integration (CMake/Build generators).