C++ Logo

std-proposals

Advanced search

Re: [std-proposals] ABI

From: Tiago Freire <tmiguelf_at_[hidden]>
Date: Thu, 18 Jul 2024 22:54:43 +0000

Hans wrote:
> (compiler) "Warning C9002: using unstable type in DLL interface."
> This, again informs them that there is a problem. Now they can look up C9002 and learn about ABI differences.

But here is the thing, it is only unstable if it’s a closed source.
If someone just gives you the source code and you can compile it yourself, it is not unstable, even though it is not my preferred method, I do not condemn developers using this distribution method to deal with the problem. Sure, the penalty isn't that considerable, if a developer knows that they are in this distribution model they can just turn off the warning.
Don't disagree, but I have a different working model.


Hans wrote:
> That is only relevant if multiple ABIs coexist within a platform. Do such platforms exist? What is the purpose of having a C++ compiler on a platform if you can't even call into any platform libraries?

Yes, they do. In my line of work, I didn't only had to deal with different ABI's coexisting in the same platform, I had to deal with multiple ABI's running simultaneously on the same application, in both Windows and Linux environments.
The individual modules by themselves did not crosstalk in C++, but they indirectly did trough a glueing layer designed to make communication compatible.

To manage this, components were divided into families depending on their compiler (and by extension what version of the std library they used). Try to use things directly between components across different families, that was a lost cause. Components within the same family, remarkably stable, compatible, hassle free.
And it has to be if you think about it, because those libraries are just plonked into your operating system and essentially every application is going to link to them (very efficient as this saves a lot of spaces, and each application doesn't have to ship their own).
Break the ABI and thousands and thousands of applications/libraries will no longer be able to work with, you will need to recompile everything, and as a user of that particular system you can imagine it is not going to be a good experience adopting that new update which effectively converts your computer into an expensive paper weight as you wait for the apps you want to use to catchup.

And as I have just explained as to why you would want to keep ABI compatible pretty much indefinitely (and as Thiago points out and supports this model), you may have notice that I have previously advocated to just breaking the ABI quite recklessly as soon as it is mildly inconvenient, and the fact that I have used completely incompatible ABIs simultaneously on the same system should tell you that this is not the end of the story.
While indeed it is a problem changing the ABI of library, that is effectively linked by the binary by explicitly referring to that specific library by name, there is no problem if you change the ABI and put it in library with a different name and have the newer applications use that instead. A compiler could handle that trick for you.

While applications across different ABI families might have a problem interacting, it is much easier to migrate code to a different ABI if you allow different versions of the library to coexist. You don't have to turn your pc into a paper weight because you want to update, old code uses old lib, new code uses new lib.
And if you can effectively manage the binary version and distribution and the linking process, this problem is very much manageable.



Sebastian wrote:
> I do not understand, why to include more complex types like std::string?
> Why not just string_view instead?
> Why include vector, if you can include span?

I quite agree, this observation is far more profound than what it looks at the surfaces. Whenever I design interfaces, I also do tend to gravitate to these sorts of types, and for a good reason, if you look at what they have in common:
1. They don't own memory, or transfer ownership of memory, user owns that responsibility.
2. Mostly in practice used as read-only. When not, data is flat, and it's easy to validate boundaries.
3. They are quite simple, at most describable by a pointer and a size.

They are so simple in fact that it is quite easy to write them yourself. And this is a method that has worked quite well for me. If I want an ABI that is quite durable for my libraries, I write the interface types myself, and then end up looking like plain C structures being passed trough plain C functions. If I want my interface to be high-level, and usable in a C++ style using C++ utilities, I encapsulate them in an adaptor class and ship them in a static library that users can compile themselves.
It's the 3-layer cake technique, a C++ backend, a C interface layer, both of these get compiled into the dll (making it possible to distribute as binaries with high compatibility), and a user compiled static library that uses the simple C style dll interfaces in the back, but presents a high-level face to the user.
And I don't expect that users always use my "C++ static library", as some libraries are intended to support users who are not even coding in C++. And that is key, as standardizing something in C++ doesn't help these users.


The point of this anecdote is that designing library interfaces is a different type of craftsmanship than general C++ coding. There are techniques to manage this that are quite effective at ensuring stability and compatibility, but they are only tangentially related to C++ because I want to use them in code that I have written in C++.
While I wish the authors good luck with the paper, and I think it is honorable to try and improve the situation in C++, I also think it is the wrong approach to the problem.

Received on 2024-07-18 22:54:48