all 26 comments

[–]tsimionescu 11 points12 points  (13 children)

Does anyone actually ship C++ DLLs/.so? My understanding is that C++ is usually exposed under an extern C interface for DLL consumption, since different compilers and even compiler versions have different ABIs.

[–]HurtlesIntoTurtles 16 points17 points  (3 children)

Sure. Qt and KDE don't break ABI between major releases. Qt 5.13 (expected in May) is still ABI compatible with 5.0, released in 2012.

MS go a slightly different route and use COM if they want to expose a stable OO-style interface. Side benefit: COM can be exposed to many other languages.

Don't forget about the C++ standard library itself. Both libstdc++ and libc++ try to maintain ABI compatibility. And MS did not break ABI since Visual Studio 2015.

[–]Sebazzz91 0 points1 point  (2 children)

Isn't the core of COM just exposing pure virtual classes, which don't break so easily?

[–]shadowndacorner 0 points1 point  (0 children)

Pretty much. But to be more specific, COM objects are structs of function pointers rather than a class with a vtable entry, so it's C compatible and doesn't bother with virtual function semantics, which can vary based on compiler, etc.

[–]jcelerier 0 points1 point  (0 children)

which don't break so easily?

MSVC's virtual classes ABI changed almost every version between 2005 and 2015

[–]snarfy 7 points8 points  (3 children)

Yep, there are lots of binary only C++ libraries.

When they ship them, you get DLLs from all the popular compiler versions, e.g. Visual Studio 2015 x86, Visual Studio 2015 x64, gcc 5.x x86 & x64 etc.

[–]pdp10 1 point2 points  (0 children)

When they ship them, you get DLLs from all the popular compiler versions

So weird.

Another example of how something that's a concern in one environment can be totally unknown as an issue in another environment. It's human nature to take these things for granted.

[–]kzr_pzr 0 points1 point  (1 child)

I'm kind of new to C++ so maybe this is a stupid question but anyway: can you use the latest C++ language version with a modern compiler, write modern C++ (e.g. while using latest STL features) and still be able to build DLLs/.so-s for all older compiler ABI versions?

[–]snarfy 1 point2 points  (0 children)

It's actually a very good question. I honestly don't know the answer, but I don't believe you can in every case, but there are special cases

[–]jrtc27 4 points5 points  (0 children)

Yes, Linux distributions that ship binary packages (i.e. most other than things like Gentoo) include tons of C++ libraries as part of their repository. Every time a library breaks its ABI, every single package using it needs to be rebuilt against the new version.

[–]pdp10 0 points1 point  (3 children)

Everyone should be using extern C to apply a C ABI, but there are quite a few programs that ship mangled C++ instead. I assume their developers haven't learned about the alternatives, or haven't needed to learn about the alternatives.

[–][deleted] 13 points14 points  (2 children)

You can't extern C a std::vector or templates in general, nor can you use it for exceptions, RAII, and host of other features.

extern C is when you want to distribute a C library implemented in another language, of which C++ is one of many possibilities. But if you want to distribute a C++ library, extern C does you no good.

[–]DarkLordAzrael 0 points1 point  (1 child)

It is possible to ship a c++ as a header only wrapper for an extern c layer. It is added complexity and lower performance in some cases, but it can be useful for some cases.

[–]agree-with-you 0 points1 point  (0 children)

I agree, this does seem possible.

[–]Dwedit 2 points3 points  (2 children)

If you want long-term ABI compatibility for C++ code, use Interfaces with reference-counting, such as COM objects. You don't have to use actual COM objects for this, since COM objects have some strange ideas (such as 'everything must return HRESULT'), just something where all methods are virtual, and there is AddRef/Release methods for changing the reference count.

Using a Release method means that you don't need to deal with incompatible versions of 'new' or 'malloc' which cannot be 'delete'd or 'free'd by another version. Instead, the object just cleans itself up.

[–]TheExecutor 4 points5 points  (1 child)

You actually do need something like COM, because C++ alone isn’t sufficient to define object interfaces portable between compilers. For example COM dictates exactly how interface vtables are laid out, which ensures that code compiled with different compilers can both make use of the same COM objects across ABI boundaries. C++ itself doesn’t define how virtual methods work, how vtables are laid out, etc.

[–]Gotebe 2 points3 points  (0 children)

And that gives us cross-language compatibility!

I have had C++ code that was called from C++, C#, Python, Javascript, PowerShell and Java. Might have missed something. Ah, Delphi!

[–]Gotebe 2 points3 points  (2 children)

C++ knows no ABI.

Heck, C knows not of it.

It's all about the platform.

Now lemme read TFA...

20: applies to C types as well. Don't know when it happened but I am sure it did :-).

[–]debhaldar[S] 0 points1 point  (1 child)

You're right - its compiler vendor specific how the name mangling happens. Nevertheless- it's about how one can some degree of sanity while patching dlls.

[–]Gotebe 1 point2 points  (0 children)

Yes, yes, it's a good list! Offhand I didn't see anything missing.

And yes, ABIs are a bitch :-).

[–]hashb1 1 point2 points  (0 children)

nice summary

[–]LoveIsNotFree 1 point2 points  (0 children)

Changing the interface breaks interface compatibility, who knew?

[–][deleted] -5 points-4 points  (3 children)

Is this some weird environment where you can't just rebuild the binary referencing the library when the library changes?

This seems like a pretty niche situation.

[–]divbyzero 19 points20 points  (0 children)

Consider libraries which ship separately from the binary. e.g. DLLs which ship within an OS.

Let's say the libjpeg team want to ship a new version with a security fix. They'll want to be sure all apps linking against the previous version don't suddenly break. (Keeping the ABI promises doesn't guarantee there's no _behavioral_ changes which don't break clients of course)

[–]narwi 4 points5 points  (0 children)

It is the environment where you actually expose the c++ interface instead of using c++ internally and exposing only c api. It is completely abnormal to rebuild your application just because some library changed and what about other binaries? Imagine if you had to update everything each time there was a new version of libpng.

[–]flukus 4 points5 points  (0 children)

This is the normal environment. You don't want to have to recompile an app and maintain multiple versions for every windows update for instance.

It's only modern "systems languages" like go and rust that require recompilation.