1. 4
  1. 2

    This is a great summary of things to be aware of with C++ ABIs. It’s unfortunate enough that some libraries go for the other extreme of header only. For some prior art here, you might also be interested in COM, which achieved API stability with vtables very well. I really wish there was some more expressive calling convention so we didn’t have to shove C++2x/Rust binaries through the very thin C straw.

    1. 2

      I’m honestly really surprised they’re not just doing COM, straight-up. Nano-COM/XPCOM are lightweight, well-understood, have solid existing tooling, run on all relevant OSes, and map cleanly to JS as-is. Hell, the interface model used heavily in TypeScript even maps very well to COM interface usage (by convergent evolution, not intentionally). That’d be a lot easier than going through the whole stabilize-the-ABI hell C++ always dies on.

      1. 3

        Hey, Mozilla got pretty good mileage out of COM and JS!

        1. 2

          I wonder if the background of the Facebook developers that have been working on the C++ React Native core is a factor. I imagine there are many C++ developers these days that just aren’t familiar with COM. My guess is that many Googlers and ex-Googlers fall into that category, since Google tends to use monolithic statically linked binaries (even Chromium is mostly one giant binary), with no COM or other ABI boundary internally.

          Is Nano-COM an actual thing, e.g. an open-source project, or just an informal name for a minimal subset of COM? And is it practical to use XPCOM outside of the huge Gecko codebase and build environment? If Nano-COM isn’t an actual package and XPCOM is too tied to Gecko, then maybe another factor is that people don’t have a straightforward way of introducing a COM-ish thing into a cross-platform project. I, for one, would be afraid to just copy from the Windows SDK headers, for legal reasons. But then, with everything that Microsoft has open-sourced, I suppose there’s a COM variant under the MIT license somewhere now.

        2. 1

          That’s basically Objective-C, which is essentially “COM with language support”. And incidentally, the COM/Objective-C interim in d’OLE was stellar.

        3. 2

          Useful document. I’ve been using these principles for years. The only thing I’d take exception to is:

          All wrapper code must be inlined to the caller.

          That isn’t necessary; the C++ wrapper code is being compiled by the app anyway, so its object code will be part of the app even if it isn’t inlined. But usually it does get inlined in optimized builds, because by its nature it’s a bunch of tiny methods that just call the C API.

          One topic not mentioned is exceptions: if the library uses C++ exceptions they have to be caught at the API boundary and (usually) converted to error codes. This results in some “try…catch…convert exception to int” boilerplate that I usually make into a macro.

          I also declare all API functions as noexcept — this ensures that if any exception isn’t caught, the process will cleanly terminate with a diagnostic message in the offending API function. Otherwise throwing an exception out of a library boundary can create horrible hard-to-diagnose bugs if it gets caught in unsuspecting app code.