Splitting implementation and interface in C++
Splitting implementation and interface in C++
Posted Feb 25, 2025 10:43 UTC (Tue) by farnz (subscriber, #17727)In reply to: Splitting implementation and interface in C++ by Wol
Parent article: Rewriting essential Linux packages in Rust
When you provide T, it's monomorphized for you. The hard case is when I want to provide Foo<T>, and allow you to provide an arbitrary T that I haven't thought about up-front.
There are, currently, two reasons for Rust to not have a stable ABI, both being worked on by experts in the field (often overlapping with people solving this problem for Swift and for C++ modules:
- Rust explicitly allows the memory layout of most data structures to vary between compilations, which lets it do things like completely elide fields that never change at runtime, along with all the code to modify them. This is obviously not compatible with a stable ABI for that structure.
- The generics problem. This is a generally hard problem, and no-one has a great solution; there are tricks that reduce the scale of the problem (which are also needed for static linking, because of the compile time and binary size issues), and Rust has had a working group looking into how many of the tricks can be machine-applied to naïve code, as opposed to requiring a human to split the code into generic and monomorphic parts.
There is, however, serious work going into a #[export] style of ABI marker that allows you to mark the bits (or an entire crate) as intended to have a stable ABI, and errors if the compiler can't support that. This will, inevitably, be a restricted subset of the full capabilities of Rust (since macros, generics, and other forms of compile-time code creation can't be supported in an exported ABI), but it's being actively thought about as a research project with a goal of allowing as much code as possible to be dynamically linked while not sacrificing any of the safety promises that Rust makes today using static linking.
