Proposal: Managing ABI changes in libc++

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Proposal: Managing ABI changes in libc++

Marshall Clow
In general, we try to avoid making changes to the ABI for libc++.
ABI changes can lead to subtle, hard to find bugs, when part of a piece of software (a dylib or static library, say) is build to the old ABI, and the rest to the new ABI. People have been burned in the past by inadvertent changes to the libc++  ABI. (not to be confused with the libc++abi project)

Eric Fiselier has been working on a tool to detect ABI changes, so that (hopefully) all future changes will be intentional.

ABI-breaking changes can include things like:
        * Changes to structures (sizes, layout)
        * Addition/removal of virtual functions (vtable layouts)
        * Changes to template parameters (addition, removal)

Also, there are times that a change to the standard will mandate an ABI change. I tend to argue against those in the committee meetings, but I don’t always get my way.

In the LLVM community, there are two differing opinions about changes in lib++ that are ABI-breaking. Broadly speaking:

a) There are the people who ship libc++ in production systems, who say: Whoa! Don’t do that! Ever! (or at least “let us decide when”).

b) There are the people who use libc++ internally, who say: Is it faster? Does it work better? Do it!

=== Proposal ===

Goals:
1) Make the default be “ABI is stable” (modulo changes in the C++ standard)
2) Make it possible for people to propose (and use) ABI-breaking changes for libc++, and have them live in tree.
Note: This would make it possible, not trivial. We still want to avoid gratuitously changing the ABI.

Concrete steps:
1) Give each ABI-breaking change its own "enabling macro”, that starts with “_LIBCPP_ABI_”

We have an example of this today. There are two different std::basic_string layouts defined in <string>, and the
second (ABI changing) one is controlled by the macro _LIBCPP_ALTERNATE_STRING_LAYOUT

Under my proposal, I would change this to _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT, and keep the old name as a synonym.

2) Create a global macro “_LIBCPP_ABI_UNSTABLE” which, when defined, turns on ALL of the _LIBCPP_ABI_* changes.

Adding a new, ABI-incompatible change to the library would consist of:
* Choosing an enabling macro name of the form _LIBCPP_ABI_XXXXXXX
* Wrapping the code in #ifdef _LIBCPP_ABI_XXXXXXX
* Enabling the macro if _LIBCPP_ABI_UNSTABLE is defined.

I think that this convention will make it possible both camps ((a) and (b) above) to coexist in the same code base.

Comments?

— Marshall

P.S. There are currently three bugs/feature request in the bug tracker that would require ABI changes to implement.

* Bug 17980 - Container<Incomplete Type> support
* Bug 19153 - Some iterators non-standard
* Bug 21715 - 128-bit integers printing not supported in stl implementation





_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Renato Golin Linaro
Hi Marshall,

I agree this is a good idea...


On 8 December 2014 at 15:42, Marshall Clow <[hidden email]> wrote:
> a) There are the people who ship libc++ in production systems, who say: Whoa! Don’t do that! Ever! (or at least “let us decide when”).
> b) There are the people who use libc++ internally, who say: Is it faster? Does it work better? Do it!

And there are those that accept each one on different occasions. :)


> Concrete steps:
> 1) Give each ABI-breaking change its own "enabling macro”, that starts with “_LIBCPP_ABI_”

This sounds reasonable.


> 2) Create a global macro “_LIBCPP_ABI_UNSTABLE” which, when defined, turns on ALL of the _LIBCPP_ABI_* changes.

While this can be problematic. What if group A wants ABI-breaking
changes X and Y, while group B want Z? In the beginning, we could all
all of them under the same umbrella, but as requests come in, we could
end up with a set of sets, unions and intersections of macros, which
are never pretty. Brainstorming a bit, to avoid intersections and
separate sets, we could make it into a severity scale (like unstable
-> broken -> napalm). But I'm over-engineering, as usual.

Having said that, I think the simple all or nothing will be perfect
for 99% of the cases, so I think this could work very well in
practice. We just have to make sure we test both variations as often
as possible.

cheers,
--renato

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Nick Kledzik
In reply to this post by Marshall Clow
Marshall,

I'm glad you are thinking about this and working through a design!

Have you considered using mangling to keep ABI changes separate?  That is, mangle the class or namespace differently (perhaps __2 instead of __1) for new ABIs.   That way no one case accidentally link two different ABIs.

-Nick

On 12/08/14, Marshall Clow <[hidden email]> wrote:
In general, we try to avoid making changes to the ABI for libc++.
ABI changes can lead to subtle, hard to find bugs, when part of a piece of software (a dylib or static library, say) is build to the old ABI, and the rest to the new ABI. People have been burned in the past by inadvertent changes to the libc++  ABI. (not to be confused with the libc++abi project)

Eric Fiselier has been working on a tool to detect ABI changes, so that (hopefully) all future changes will be intentional.

ABI-breaking changes can include things like:
* Changes to structures (sizes, layout)
* Addition/removal of virtual functions (vtable layouts)
* Changes to template parameters (addition, removal)

Also, there are times that a change to the standard will mandate an ABI change. I tend to argue against those in the committee meetings, but I don’t always get my way.

In the LLVM community, there are two differing opinions about changes in lib++ that are ABI-breaking. Broadly speaking:

a) There are the people who ship libc++ in production systems, who say: Whoa! Don’t do that! Ever! (or at least “let us decide when”).

b) There are the people who use libc++ internally, who say: Is it faster? Does it work better? Do it!

=== Proposal ===

Goals:
1) Make the default be “ABI is stable” (modulo changes in the C++ standard)
2) Make it possible for people to propose (and use) ABI-breaking changes for libc++, and have them live in tree.
Note: This would make it possible, not trivial. We still want to avoid gratuitously changing the ABI.

Concrete steps:
1) Give each ABI-breaking change its own "enabling macro”, that starts with “_LIBCPP_ABI_”

We have an example of this today. There are two different std::basic_string layouts defined in <string>, and the
second (ABI changing) one is controlled by the macro _LIBCPP_ALTERNATE_STRING_LAYOUT

Under my proposal, I would change this to _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT, and keep the old name as a synonym.

2) Create a global macro “_LIBCPP_ABI_UNSTABLE” which, when defined, turns on ALL of the _LIBCPP_ABI_* changes.

Adding a new, ABI-incompatible change to the library would consist of:
* Choosing an enabling macro name of the form _LIBCPP_ABI_XXXXXXX
* Wrapping the code in #ifdef _LIBCPP_ABI_XXXXXXX
* Enabling the macro if _LIBCPP_ABI_UNSTABLE is defined.

I think that this convention will make it possible both camps ((a) and (b) above) to coexist in the same code base.

Comments?

— Marshall

P.S. There are currently three bugs/feature request in the bug tracker that would require ABI changes to implement.

* Bug 17980 - Container<Incomplete Type> support
* Bug 19153 - Some iterators non-standard
* Bug 21715 - 128-bit integers printing not supported in stl implementation





_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Marshall Clow

> On Dec 8, 2014, at 9:57 AM, Nick Kledzik <[hidden email]> wrote:
>
> Marshall,
>
> I'm glad you are thinking about this and working through a design!
>
> Have you considered using mangling to keep ABI changes separate?  That is, mangle the class or namespace differently (perhaps __2 instead of __1) for new ABIs.   That way no one case accidentally link two different ABIs.

Nick —

I’ve done some thinking along those lines, but that seems like a very bit hammer for these kinds of changes.

I’ll puzzle some more.

— Marshall


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Marshall Clow
In reply to this post by Renato Golin Linaro

> On Dec 8, 2014, at 8:40 AM, Renato Golin <[hidden email]> wrote:
>
> Hi Marshall,
>
> I agree this is a good idea...
>
>
> On 8 December 2014 at 15:42, Marshall Clow <[hidden email]> wrote:
>> a) There are the people who ship libc++ in production systems, who say: Whoa! Don’t do that! Ever! (or at least “let us decide when”).
>> b) There are the people who use libc++ internally, who say: Is it faster? Does it work better? Do it!
>
> And there are those that accept each one on different occasions. :)
>
>
>> Concrete steps:
>> 1) Give each ABI-breaking change its own "enabling macro”, that starts with “_LIBCPP_ABI_”
>
> This sounds reasonable.
>
>
>> 2) Create a global macro “_LIBCPP_ABI_UNSTABLE” which, when defined, turns on ALL of the _LIBCPP_ABI_* changes.
>
> While this can be problematic. What if group A wants ABI-breaking
> changes X and Y, while group B want Z? In the beginning, we could all
> all of them under the same umbrella, but as requests come in, we could
> end up with a set of sets, unions and intersections of macros, which
> are never pretty. Brainstorming a bit, to avoid intersections and
> separate sets, we could make it into a severity scale (like unstable
> -> broken -> napalm). But I'm over-engineering, as usual.
>
> Having said that, I think the simple all or nothing will be perfect
> for 99% of the cases, so I think this could work very well in
> practice. We just have to make sure we test both variations as often
> as possible.

My thought here is that if someone wants a subset of the ABI-breaking changes (but not all of them),
they can define the _LIBCPP_ABI_* flags individually in their build system.

Suppose we have:  in <__config>

#ifdef _LIBCPP_ABI_UNSTABLE
#define _LIBCPP_ABI_FEATURE1
#define _LIBCPP_ABI_FEATURE2
#define _LIBCPP_ABI_FEATURE3
#define _LIBCPP_ABI_FEATURE4
#endif

If someone wanted just FEATURE2 and FEATURE3, they could do:
        cmake <blah, blah> -D_LIBCPP_ABI_FEATURE2 -D_LIBCPP_ABI_FEATURE3

— Marshall


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Renato Golin Linaro
On 8 December 2014 at 18:25, Marshall Clow <[hidden email]> wrote:
> My thought here is that if someone wants a subset of the ABI-breaking changes (but not all of them),
> they can define the _LIBCPP_ABI_* flags individually in their build system.

That makes a lot of sense. Leave the complexity to those that need it
and cover the 0% and 100% cases.

cheers,
--renato
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Marshall Clow
In reply to this post by Marshall Clow
On Dec 8, 2014, at 10:25 AM, Marshall Clow <[hidden email]> wrote:
On Dec 8, 2014, at 8:40 AM, Renato Golin <[hidden email]> wrote:
While this can be problematic. What if group A wants ABI-breaking
changes X and Y, while group B want Z? In the beginning, we could all
all of them under the same umbrella, but as requests come in, we could
end up with a set of sets, unions and intersections of macros, which
are never pretty. Brainstorming a bit, to avoid intersections and
separate sets, we could make it into a severity scale (like unstable
-> broken -> napalm). But I'm over-engineering, as usual.

Having said that, I think the simple all or nothing will be perfect
for 99% of the cases, so I think this could work very well in
practice. We just have to make sure we test both variations as often
as possible.

My thought here is that if someone wants a subset of the ABI-breaking changes (but not all of them), 
they can define the _LIBCPP_ABI_* flags individually in their build system.

Suppose we have:  in <__config>

#ifdef _LIBCPP_ABI_UNSTABLE
#define _LIBCPP_ABI_FEATURE1
#define _LIBCPP_ABI_FEATURE2
#define _LIBCPP_ABI_FEATURE3
#define _LIBCPP_ABI_FEATURE4
#endif

If someone wanted just FEATURE2 and FEATURE3, they could do:
cmake <blah, blah> -D_LIBCPP_ABI_FEATURE2 -D_LIBCPP_ABI_FEATURE3

This of course assumes that all the ABI-breaking changes are independent.

— MArshall



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Eric Fiselier
In reply to this post by Marshall Clow
I don't really like allowing users to pick and choose which ABI
changes to adopt. I personally don't see the use case for picking a
subset of ABI changes to adopt. If you can adopt one ABI change,
then why can't you adopt them all? Furthermore, as time goes on and
more ABI changes are commited this could lead to quite a mess.

I also don't like having a stable version and an unstable version of
the ABI. I'm afraid that by only introducing ABI changes into the
"unstable ABI configuration" they will never be adopted.

Instead I think we should version the ABI and introduce a series of
stable ABI's under different versions. This allows us some sort of
forward momentum and fewer configurations that need maintaining and
testing.
When a consumer can tolerate introducing an ABI break they can move to
the most recent ABI version. After a given amount of time ABI versions
would be deprecated.
The only ABI versions that would be maintained indefinitely would be
the current one.

/Eric


On Mon, Dec 8, 2014 at 11:20 AM, Marshall Clow <[hidden email]> wrote:

>
>> On Dec 8, 2014, at 9:57 AM, Nick Kledzik <[hidden email]> wrote:
>>
>> Marshall,
>>
>> I'm glad you are thinking about this and working through a design!
>>
>> Have you considered using mangling to keep ABI changes separate?  That is, mangle the class or namespace differently (perhaps __2 instead of __1) for new ABIs.   That way no one case accidentally link two different ABIs.
>
> Nick —
>
> I’ve done some thinking along those lines, but that seems like a very bit hammer for these kinds of changes.
>
> I’ll puzzle some more.
>
> — Marshall
>

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

C Bergström

On Sat, Dec 20, 2014 at 4:14 AM, Eric Fiselier <[hidden email]> wrote:
I don't really like allowing users to pick and choose which ABI
changes to adopt. I personally don't see the use case for picking a
subset of ABI changes to adopt. If you can adopt one ABI change,
then why can't you adopt them all? Furthermore, as time goes on and
more ABI changes are commited this could lead to quite a mess.

I also don't like having a stable version and an unstable version of
the ABI. I'm afraid that by only introducing ABI changes into the
"unstable ABI configuration" they will never be adopted.

Instead I think we should version the ABI and introduce a series of
stable ABI's under different versions. This allows us some sort of
forward momentum and fewer configurations that need maintaining and
testing.
When a consumer can tolerate introducing an ABI break they can move to
the most recent ABI version. After a given amount of time ABI versions
would be deprecated.
The only ABI versions that would be maintained indefinitely would be
the current one.

This idea of ABI "version" paradigms well with real world packages. At some point we'll in theory have many libc++ packaged and released. If at the same time of the ABI breakage the libc++.so.${N} is incremented we have some tangible way to relay that information to potential end users.

I'm personally against the #if hell which could result in multiple universes (I'd rather put a "stable" piece of code in a maintenance branch, but that's must my not-so-humble opinion.) It's like saying that the IR should be stable and never change... This is more user facing and gets more hand waiving, but at the end of the day it's the same sort of problem.

Every time a set of ABI breaking changes happen.. bump the lib version, cut a branch before the changes and move on with life... what's so wrong about this? Changes can be ported forward/backward to the branch as the owners want. Keep code complexity down..

Further - how do you QA libc++ when there's basically "2" correct ways to build it? Have the buildbots build it twice and report both results?

For anyone who wants or demands stability.. I'd love to hear why a branch won't work..



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Marshall Clow

On Dec 19, 2014, at 2:24 PM, C Bergström <[hidden email]> wrote:


On Sat, Dec 20, 2014 at 4:14 AM, Eric Fiselier <[hidden email]> wrote:
I don't really like allowing users to pick and choose which ABI
changes to adopt. I personally don't see the use case for picking a
subset of ABI changes to adopt. If you can adopt one ABI change,
then why can't you adopt them all? Furthermore, as time goes on and
more ABI changes are commited this could lead to quite a mess.

It’s not the users that will be picking and choosing.
I’m thinking of the people that ship libc++ as part of their systems.
[ Mac OS, FreeBSD, Android, iOS, etc ]

Each of them have different requirements for ABI stability.

Then there are the people/organizations who build and use their own libc++ libraries internally. They may or may not have any requirements for ABI stability, but they’re probably more flexible than the people who ship OS’es - whose change horizon is measured in years.


I also don't like having a stable version and an unstable version of
the ABI. I'm afraid that by only introducing ABI changes into the
"unstable ABI configuration" they will never be adopted.

Yes. There will be vendors who never adopt anything that is an ABI change, 
and I believe that supporting those people is important for libc++.


Instead I think we should version the ABI and introduce a series of
stable ABI's under different versions. This allows us some sort of
forward momentum and fewer configurations that need maintaining and
testing.
When a consumer can tolerate introducing an ABI break they can move to
the most recent ABI version. After a given amount of time ABI versions
would be deprecated.
The only ABI versions that would be maintained indefinitely would be
the current one.

This idea of ABI "version" paradigms well with real world packages. At some point we'll in theory have many libc++ packaged and released. If at the same time of the ABI breakage the libc++.so.${N} is incremented we have some tangible way to relay that information to potential end users.

I may be wrong, but I don’t see a use case (other than testing and/or libc++ development) for having multiple versions of libc++ on a system.
The goal is for it to be “the C++ standard library” - the one that you get from your system/distro vendor.

Changing the ABI of the libc++.dylib means that you have to rebuild *every piece of code* that links to that dylib. That’s a high bar.

What this proposal is about is providing those people (who distribute libc++) a method for managing the ABI that they ship.

I'm personally against the #if hell which could result in multiple universes (I'd rather put a "stable" piece of code in a maintenance branch, but that's must my not-so-humble opinion.) It's like saying that the IR should be stable and never change... This is more user facing and gets more hand waiving, but at the end of the day it's the same sort of problem.

Every time a set of ABI breaking changes happen.. bump the lib version, cut a branch before the changes and move on with life... what's so wrong about this? Changes can be ported forward/backward to the branch as the owners want. Keep code complexity down..

At the cost of pushing the complexity onto the code owners, making sure that every non-ABI breaking change goes to all branches.

Further - how do you QA libc++ when there's basically "2" correct ways to build it? Have the buildbots build it twice and report both results?

That’s what I would expect. Build once w/o any ABI breaks (because that’s the most common use case), and then once with them all.

If someone wants a library with a subset of the changes, they can build and test that.
For example, Apple would build with _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT but no other changes for AArch64, because that’s what they ship today.


For anyone who wants or demands stability.. I'd love to hear why a branch won't work..

It’s not “a branch”, it’s N branches (2^N if you consider combinations).

— Marshall



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Chandler Carruth
In reply to this post by Marshall Clow
First, sorry for delays. I do owe you feedback here though, and then I'll go look at the patch. =]

On Mon, Dec 8, 2014 at 7:42 AM, Marshall Clow <[hidden email]> wrote:
In general, we try to avoid making changes to the ABI for libc++.
ABI changes can lead to subtle, hard to find bugs, when part of a piece of software (a dylib or static library, say) is build to the old ABI, and the rest to the new ABI. People have been burned in the past by inadvertent changes to the libc++  ABI. (not to be confused with the libc++abi project)

Eric Fiselier has been working on a tool to detect ABI changes, so that (hopefully) all future changes will be intentional.

ABI-breaking changes can include things like:
        * Changes to structures (sizes, layout)
        * Addition/removal of virtual functions (vtable layouts)
        * Changes to template parameters (addition, removal)

Also, there are times that a change to the standard will mandate an ABI change. I tend to argue against those in the committee meetings, but I don’t always get my way.

In the LLVM community, there are two differing opinions about changes in lib++ that are ABI-breaking. Broadly speaking:

a) There are the people who ship libc++ in production systems, who say: Whoa! Don’t do that! Ever! (or at least “let us decide when”).

b) There are the people who use libc++ internally, who say: Is it faster? Does it work better? Do it!

(FWIW, there are also people that support users in both camps (a) and (b). I'm one of those.)
 

=== Proposal ===

Goals:
1) Make the default be “ABI is stable” (modulo changes in the C++ standard)
2) Make it possible for people to propose (and use) ABI-breaking changes for libc++, and have them live in tree.
Note: This would make it possible, not trivial. We still want to avoid gratuitously changing the ABI.

Concrete steps:
1) Give each ABI-breaking change its own "enabling macro”, that starts with “_LIBCPP_ABI_”

We have an example of this today. There are two different std::basic_string layouts defined in <string>, and the
second (ABI changing) one is controlled by the macro _LIBCPP_ALTERNATE_STRING_LAYOUT

Under my proposal, I would change this to _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT, and keep the old name as a synonym.

2) Create a global macro “_LIBCPP_ABI_UNSTABLE” which, when defined, turns on ALL of the _LIBCPP_ABI_* changes.

Adding a new, ABI-incompatible change to the library would consist of:
* Choosing an enabling macro name of the form _LIBCPP_ABI_XXXXXXX
* Wrapping the code in #ifdef _LIBCPP_ABI_XXXXXXX
* Enabling the macro if _LIBCPP_ABI_UNSTABLE is defined.

I think that this convention will make it possible both camps ((a) and (b) above) to coexist in the same code base.

Comments?

As far as this goes, I'm 100% in favor.


I think there are two more ABI concerns that we should really figure out a plan for now in order to ensure they fit cohesively with the whole.

1) I think we need a way to more quickly roll standard-mandated or bug-fix ABI breaks into something much more stable than "unstable".
2) I think we need to figure out how to maintain at least two stable ABIs at the same time.

I'll expand a bit below.

A terminology point, when I say a "minor" or "major" ABI break, I am not classifying the *nature* of the break, but the *scope*. Changing the layout of std::string has a radically different scope in its impact than fixing the return type of a infrequently used function for example.

For (1), let's consider two cases.
1.1) We introduce an ABI-significant bug and need to fix it. What do we do? This is exacerbated when the bug has shipped to customers. Some users of libc++ update *very* rapidly, and so even with a very narrow window of fallout in-tree, it would be advantageous in my opinion to have a non-silent way to fix these issues. Note that this only really applies to minor ABI breaks. A massive breaking change would be sufficiently disruptive to warrant more extreme measures and I certainly hope i
1.2) The standard changes in some *minor* way that necessitates an ABI break. Note that I'm not talking about "C++1z requires a whole new ABI" kind of break, I'm talking about the standard equivalent to 1.1 -- we ship a bug, we fix it, but it requires some small ABI break.

In both of these cases, I think the right thing for the default configuration of libc++ is to make the change and take the ABI break. I think we should be standard conforming and correct above all else out of the box. But I think it is important to provide some mechanism to opt *out* of such changes to the ABI, at least in order to control when they arrive in systems that are very susceptible to ABI fallout.

For (2), my motivation is to chart out a path forward, likely measured in years if not decades. This would include the ability to follow any massive upheaval in the standard's ABI, as well as the ability to pick up improvements which go in under the unstable bucket after a resonable interval and in a way that platform vendors are comfortable with. I picked "two" specifically for a reason. I think we should be able to create a new stable major ABI without changing the default while customers test and evaluate it, etc. Then we should be able to switch the default at some point without ever touching the old ABI. Finally, after some lengthy period (likely also measured in years if not decades) we should be able to remove the old ABI and start the process again. When Howard first discussed the time scale at which this kind of breaking change could possibly be acceptable to customers, he used decades. I'm echoing that, as it matches my experience with customers that have hard ABI requirements.

So, here is my initial proposal for how to handle the above two issues.

First, extend the ABI definitions to include what they already (somewhat) do: versions. Specifically, both minor and major versions to handle the above two use cases respectively. We already sort-of have this for the stable ABI, I just think we should formalize it, document it, and incorporate it into the macro naming convention.

The resulting pattern would be that when a bug-fix or minor standards-motivated change is introduced which breaks the ABI, it too is guarded behind an ABI macro, but that macro is by-default enabled. A new high-level macro (i'm trying to avoid picking names here, I suspect Marshall will pick better ones than I will) would be introduced to restrict libc++ to the prior minor ABI version, and that macro would disable the bug-fix. If at some point a contributor wants to build a new major version stable ABI out of a sub set of the unstable changes in the tree (and everyone agrees that is reasonable to do), then the expected new high-level macros for those versions would be introduced, and the per-feature abi-breaking macros would be flipped based on them.

Does this make sense to folks?


One goal I have throughout this is that we *have* per-feature ABI-break macros, but that users essentially never need to use them. I would like to have something closer to version numbers that they interact with in order to request specific sets of features that can be documented together.


Anyways, my slightly-more-than-2-cents on the overarching proposal. Thanks for working on this Marshall. I know I've been clamoring for it without working on it for quite some time. =]

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

David Chisnall-4
In reply to this post by Marshall Clow
On 20 Dec 2014, at 03:19, Marshall Clow <[hidden email]> wrote:

> It’s not the users that will be picking and choosing.
> I’m thinking of the people that ship libc++ as part of their systems.
> [ Mac OS, FreeBSD, Android, iOS, etc ]
>
> Each of them have different requirements for ABI stability.

To make this concrete, in FreeBSD we ship libc++ as part of the base system.  This means that we *must* be able to preserve the ABI for five years.  We are able to ship a new, ABI-breaking, version with each new major release (i.e. every 2 years), but we must then support that ABI for the next five.  We are likely to end support (which really means security updates) for the 10.x series (which was the first to contain libc++) in early 2019.

Our lives would probably be made easier if we could build a single libc++, with different namespaces for the different ABI versions.  We'd then be able to bump the .so version when we switched the headers to a new ABI, but old binaries would still work (you just wouldn't be able to mix them with new binaries in the same process if they passed standard library types across library boundaries - this would be a linker error though, and easy to diagnose).  Building multiple .so versions would not be significant overhead though and we can just put the older one in a compat package.

For static linking, being able to build with -DLATEST_AND_GREATEST (or whatever) and not have any of the legacy compat code compiled in would probably be nice.

David


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Joerg Sonnenberger
In reply to this post by Marshall Clow
On Mon, Dec 08, 2014 at 07:42:17AM -0800, Marshall Clow wrote:
> Under my proposal, I would change this to
> _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT, and keep the old name as a synonym.

Only change is that I would add a warning for the old name.
Platforms should migrate to the new form, the warning tells them to.

Joerg
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Ted Kremenek
In reply to this post by Chandler Carruth
My apologies as well for the delay.  Chandler's response was quite excellent, so I'm going to piggy back on his comments.

On Dec 19, 2014, at 6:28 PM, Chandler Carruth <[hidden email]> wrote:

First, sorry for delays. I do owe you feedback here though, and then I'll go look at the patch. =]

On Mon, Dec 8, 2014 at 7:42 AM, Marshall Clow <[hidden email]> wrote:
In general, we try to avoid making changes to the ABI for libc++.
ABI changes can lead to subtle, hard to find bugs, when part of a piece of software (a dylib or static library, say) is build to the old ABI, and the rest to the new ABI. People have been burned in the past by inadvertent changes to the libc++  ABI. (not to be confused with the libc++abi project)

Eric Fiselier has been working on a tool to detect ABI changes, so that (hopefully) all future changes will be intentional.

ABI-breaking changes can include things like:
        * Changes to structures (sizes, layout)
        * Addition/removal of virtual functions (vtable layouts)
        * Changes to template parameters (addition, removal)

Also, there are times that a change to the standard will mandate an ABI change. I tend to argue against those in the committee meetings, but I don’t always get my way.

In the LLVM community, there are two differing opinions about changes in lib++ that are ABI-breaking. Broadly speaking:

a) There are the people who ship libc++ in production systems, who say: Whoa! Don’t do that! Ever! (or at least “let us decide when”).

b) There are the people who use libc++ internally, who say: Is it faster? Does it work better? Do it!

(FWIW, there are also people that support users in both camps (a) and (b). I'm one of those.)
 

=== Proposal ===

Goals:
1) Make the default be “ABI is stable” (modulo changes in the C++ standard)
2) Make it possible for people to propose (and use) ABI-breaking changes for libc++, and have them live in tree.
Note: This would make it possible, not trivial. We still want to avoid gratuitously changing the ABI.

Concrete steps:
1) Give each ABI-breaking change its own "enabling macro”, that starts with “_LIBCPP_ABI_”

We have an example of this today. There are two different std::basic_string layouts defined in <string>, and the
second (ABI changing) one is controlled by the macro _LIBCPP_ALTERNATE_STRING_LAYOUT

Under my proposal, I would change this to _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT, and keep the old name as a synonym.

2) Create a global macro “_LIBCPP_ABI_UNSTABLE” which, when defined, turns on ALL of the _LIBCPP_ABI_* changes.

Adding a new, ABI-incompatible change to the library would consist of:
* Choosing an enabling macro name of the form _LIBCPP_ABI_XXXXXXX
* Wrapping the code in #ifdef _LIBCPP_ABI_XXXXXXX
* Enabling the macro if _LIBCPP_ABI_UNSTABLE is defined.

I think that this convention will make it possible both camps ((a) and (b) above) to coexist in the same code base.

Comments?

As far as this goes, I'm 100% in favor.

I'm supportive of this initiative; my main concern is the social aspect that we have a manageable way to discern different ABI configurations and that they are all testable.



I think there are two more ABI concerns that we should really figure out a plan for now in order to ensure they fit cohesively with the whole.

1) I think we need a way to more quickly roll standard-mandated or bug-fix ABI breaks into something much more stable than "unstable".
2) I think we need to figure out how to maintain at least two stable ABIs at the same time.

I'll expand a bit below.

A terminology point, when I say a "minor" or "major" ABI break, I am not classifying the *nature* of the break, but the *scope*. Changing the layout of std::string has a radically different scope in its impact than fixing the return type of a infrequently used function for example.

For (1), let's consider two cases.
1.1) We introduce an ABI-significant bug and need to fix it. What do we do? This is exacerbated when the bug has shipped to customers. Some users of libc++ update *very* rapidly, and so even with a very narrow window of fallout in-tree, it would be advantageous in my opinion to have a non-silent way to fix these issues. Note that this only really applies to minor ABI breaks. A massive breaking change would be sufficiently disruptive to warrant more extreme measures and I certainly hope i
1.2) The standard changes in some *minor* way that necessitates an ABI break. Note that I'm not talking about "C++1z requires a whole new ABI" kind of break, I'm talking about the standard equivalent to 1.1 -- we ship a bug, we fix it, but it requires some small ABI break.

In both of these cases, I think the right thing for the default configuration of libc++ is to make the change and take the ABI break. I think we should be standard conforming and correct above all else out of the box. But I think it is important to provide some mechanism to opt *out* of such changes to the ABI, at least in order to control when they arrive in systems that are very susceptible to ABI fallout.

This seems reasonable to me, and provides an option for vendors to curate the ABI based on their particular needs.


For (2), my motivation is to chart out a path forward, likely measured in years if not decades. This would include the ability to follow any massive upheaval in the standard's ABI, as well as the ability to pick up improvements which go in under the unstable bucket after a resonable interval and in a way that platform vendors are comfortable with. I picked "two" specifically for a reason. I think we should be able to create a new stable major ABI without changing the default while customers test and evaluate it, etc. Then we should be able to switch the default at some point without ever touching the old ABI. Finally, after some lengthy period (likely also measured in years if not decades) we should be able to remove the old ABI and start the process again. When Howard first discussed the time scale at which this kind of breaking change could possibly be acceptable to customers, he used decades. I'm echoing that, as it matches my experience with customers that have hard ABI requirements.

I like this goal as well.  I'm concerned about the practicalities of being able to manage such divergences in the libc++ project in a coherent way, but I think it really comes down to the scale of the changes we are talking about as well as the time scale.


So, here is my initial proposal for how to handle the above two issues.

First, extend the ABI definitions to include what they already (somewhat) do: versions. Specifically, both minor and major versions to handle the above two use cases respectively. We already sort-of have this for the stable ABI, I just think we should formalize it, document it, and incorporate it into the macro naming convention.

The resulting pattern would be that when a bug-fix or minor standards-motivated change is introduced which breaks the ABI, it too is guarded behind an ABI macro, but that macro is by-default enabled. A new high-level macro (i'm trying to avoid picking names here, I suspect Marshall will pick better ones than I will) would be introduced to restrict libc++ to the prior minor ABI version, and that macro would disable the bug-fix. If at some point a contributor wants to build a new major version stable ABI out of a sub set of the unstable changes in the tree (and everyone agrees that is reasonable to do), then the expected new high-level macros for those versions would be introduced, and the per-feature abi-breaking macros would be flipped based on them.

Does this make sense to folks?

This makes sense to me.



One goal I have throughout this is that we *have* per-feature ABI-break macros, but that users essentially never need to use them. I would like to have something closer to version numbers that they interact with in order to request specific sets of features that can be documented together.

I very much like this goal as well.

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: Managing ABI changes in libc++

Evgeniy Stepanov
It seems like there is a general agreement on the general direction
this should go. In the hope of pushing this forward, I've uploaded a
very basic implementation to http://reviews.llvm.org/D11740. It does
not include any build system changes, because it's not clear if we
want, for example, to bump soname each time ABI version is increased.

On Mon, Dec 29, 2014 at 10:51 PM, Ted Kremenek <[hidden email]> wrote:

> My apologies as well for the delay.  Chandler's response was quite
> excellent, so I'm going to piggy back on his comments.
>
> On Dec 19, 2014, at 6:28 PM, Chandler Carruth <[hidden email]> wrote:
>
> First, sorry for delays. I do owe you feedback here though, and then I'll go
> look at the patch. =]
>
> On Mon, Dec 8, 2014 at 7:42 AM, Marshall Clow <[hidden email]> wrote:
>>
>> In general, we try to avoid making changes to the ABI for libc++.
>> ABI changes can lead to subtle, hard to find bugs, when part of a piece of
>> software (a dylib or static library, say) is build to the old ABI, and the
>> rest to the new ABI. People have been burned in the past by inadvertent
>> changes to the libc++  ABI. (not to be confused with the libc++abi project)
>>
>> Eric Fiselier has been working on a tool to detect ABI changes, so that
>> (hopefully) all future changes will be intentional.
>>
>> ABI-breaking changes can include things like:
>>         * Changes to structures (sizes, layout)
>>         * Addition/removal of virtual functions (vtable layouts)
>>         * Changes to template parameters (addition, removal)
>>
>> Also, there are times that a change to the standard will mandate an ABI
>> change. I tend to argue against those in the committee meetings, but I don’t
>> always get my way.
>>
>> In the LLVM community, there are two differing opinions about changes in
>> lib++ that are ABI-breaking. Broadly speaking:
>>
>> a) There are the people who ship libc++ in production systems, who say:
>> Whoa! Don’t do that! Ever! (or at least “let us decide when”).
>>
>> b) There are the people who use libc++ internally, who say: Is it faster?
>> Does it work better? Do it!
>
>
> (FWIW, there are also people that support users in both camps (a) and (b).
> I'm one of those.)
>
>>
>>
>> === Proposal ===
>>
>> Goals:
>> 1) Make the default be “ABI is stable” (modulo changes in the C++
>> standard)
>> 2) Make it possible for people to propose (and use) ABI-breaking changes
>> for libc++, and have them live in tree.
>> Note: This would make it possible, not trivial. We still want to avoid
>> gratuitously changing the ABI.
>>
>> Concrete steps:
>> 1) Give each ABI-breaking change its own "enabling macro”, that starts
>> with “_LIBCPP_ABI_”
>>
>> We have an example of this today. There are two different
>> std::basic_string layouts defined in <string>, and the
>> second (ABI changing) one is controlled by the macro
>> _LIBCPP_ALTERNATE_STRING_LAYOUT
>>
>> Under my proposal, I would change this to
>> _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT, and keep the old name as a synonym.
>>
>> 2) Create a global macro “_LIBCPP_ABI_UNSTABLE” which, when defined, turns
>> on ALL of the _LIBCPP_ABI_* changes.
>>
>> Adding a new, ABI-incompatible change to the library would consist of:
>> * Choosing an enabling macro name of the form _LIBCPP_ABI_XXXXXXX
>> * Wrapping the code in #ifdef _LIBCPP_ABI_XXXXXXX
>> * Enabling the macro if _LIBCPP_ABI_UNSTABLE is defined.
>>
>> I think that this convention will make it possible both camps ((a) and (b)
>> above) to coexist in the same code base.
>>
>> Comments?
>
>
> As far as this goes, I'm 100% in favor.
>
>
> I'm supportive of this initiative; my main concern is the social aspect that
> we have a manageable way to discern different ABI configurations and that
> they are all testable.
>
>
>
> I think there are two more ABI concerns that we should really figure out a
> plan for now in order to ensure they fit cohesively with the whole.
>
> 1) I think we need a way to more quickly roll standard-mandated or bug-fix
> ABI breaks into something much more stable than "unstable".
> 2) I think we need to figure out how to maintain at least two stable ABIs at
> the same time.
>
> I'll expand a bit below.
>
> A terminology point, when I say a "minor" or "major" ABI break, I am not
> classifying the *nature* of the break, but the *scope*. Changing the layout
> of std::string has a radically different scope in its impact than fixing the
> return type of a infrequently used function for example.
>
> For (1), let's consider two cases.
> 1.1) We introduce an ABI-significant bug and need to fix it. What do we do?
> This is exacerbated when the bug has shipped to customers. Some users of
> libc++ update *very* rapidly, and so even with a very narrow window of
> fallout in-tree, it would be advantageous in my opinion to have a non-silent
> way to fix these issues. Note that this only really applies to minor ABI
> breaks. A massive breaking change would be sufficiently disruptive to
> warrant more extreme measures and I certainly hope i
> 1.2) The standard changes in some *minor* way that necessitates an ABI
> break. Note that I'm not talking about "C++1z requires a whole new ABI" kind
> of break, I'm talking about the standard equivalent to 1.1 -- we ship a bug,
> we fix it, but it requires some small ABI break.
>
> In both of these cases, I think the right thing for the default
> configuration of libc++ is to make the change and take the ABI break. I
> think we should be standard conforming and correct above all else out of the
> box. But I think it is important to provide some mechanism to opt *out* of
> such changes to the ABI, at least in order to control when they arrive in
> systems that are very susceptible to ABI fallout.
>
>
> This seems reasonable to me, and provides an option for vendors to curate
> the ABI based on their particular needs.
>
>
> For (2), my motivation is to chart out a path forward, likely measured in
> years if not decades. This would include the ability to follow any massive
> upheaval in the standard's ABI, as well as the ability to pick up
> improvements which go in under the unstable bucket after a resonable
> interval and in a way that platform vendors are comfortable with. I picked
> "two" specifically for a reason. I think we should be able to create a new
> stable major ABI without changing the default while customers test and
> evaluate it, etc. Then we should be able to switch the default at some point
> without ever touching the old ABI. Finally, after some lengthy period
> (likely also measured in years if not decades) we should be able to remove
> the old ABI and start the process again. When Howard first discussed the
> time scale at which this kind of breaking change could possibly be
> acceptable to customers, he used decades. I'm echoing that, as it matches my
> experience with customers that have hard ABI requirements.
>
>
> I like this goal as well.  I'm concerned about the practicalities of being
> able to manage such divergences in the libc++ project in a coherent way, but
> I think it really comes down to the scale of the changes we are talking
> about as well as the time scale.
>
>
> So, here is my initial proposal for how to handle the above two issues.
>
> First, extend the ABI definitions to include what they already (somewhat)
> do: versions. Specifically, both minor and major versions to handle the
> above two use cases respectively. We already sort-of have this for the
> stable ABI, I just think we should formalize it, document it, and
> incorporate it into the macro naming convention.
>
> The resulting pattern would be that when a bug-fix or minor
> standards-motivated change is introduced which breaks the ABI, it too is
> guarded behind an ABI macro, but that macro is by-default enabled. A new
> high-level macro (i'm trying to avoid picking names here, I suspect Marshall
> will pick better ones than I will) would be introduced to restrict libc++ to
> the prior minor ABI version, and that macro would disable the bug-fix. If at
> some point a contributor wants to build a new major version stable ABI out
> of a sub set of the unstable changes in the tree (and everyone agrees that
> is reasonable to do), then the expected new high-level macros for those
> versions would be introduced, and the per-feature abi-breaking macros would
> be flipped based on them.
>
> Does this make sense to folks?
>
>
> This makes sense to me.
>
>
>
> One goal I have throughout this is that we *have* per-feature ABI-break
> macros, but that users essentially never need to use them. I would like to
> have something closer to version numbers that they interact with in order to
> request specific sets of features that can be documented together.
>
>
> I very much like this goal as well.
>
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev