[libcxx-commits] [libcxx] [libc++] Document our ABI guarantees and what ABI flags exist to modify these guarantees (PR #132615)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed May 21 09:05:31 PDT 2025


================
@@ -0,0 +1,206 @@
+=======================
+libc++'s ABI Guarantees
+=======================
+
+libc++ provides multiple types of ABI guarantees. These include stability of the layout of structs, the linking of TUs
+built against different versions and configurations of the library, and more. This document describes what guarantees
+libc++ provides in these different fields as well as what options exist for users and vendors to affect these
+guarantees.
+
+Note that all of the guarantees listed below come with an asterisk that there may be circumstances where we deem it
+worth it to break that guarantee. These breaks are communicated to vendors by CCing #libcxx-vendors on GitHub. If you
+are a vendor, please ask to be added to that group to be notified about changes that potentially affect you.
+
+ABI flags
+=========
+All the ABI flags listed below can be added to the ``__config_site`` header by the vendor to opt in to an ABI breaking
+change. These flags should never be set by the user. When porting libc++ to a new platform it should be considered by
+the vendor which flags should be enabled, assuming ABI stability is relevant to them. Please contact the libc++ team on
+Discord or through other means to be able to make an informed decision on which flags make sense to enable, and to avoid
+enabling flags which may not be stable.
+
+
+Stability of the Layout of Structs
+==================================
+
+The layout of any user-observable struct is kept stable across versions of the library and any options users are allowed
+to change. There are a lot of structs that have internal names, but are none the less observable by users; for example
+through public aliases to these types or because they affect the layout of other types.
+
+There are multiple ABI flags which affect the layout of certain structs:
+
+``_LIBCPP_ABI_ALTERNATE_STRING_LAYOUT``
+---------------------------------------
+This changes the internal layout of ``basic_string`` to move the section that is used for the internal buffer to the
+front, making it eight byte aligned instead of being unaligned, improving the performance of some operations
+significantly.
+
+``_LIBCPP_ABI_NO_ITERATOR_BASES``
+---------------------------------
+This removes the ``iterator`` base class from ``back_insert_iterator``, ``front_insert_iterator``, ``insert_iterator``,
+``istream_iterator``, ``ostream_iterator``, ``ostreambuf_itreator``, ``reverse_iterator``, and ``raw_storage_iterator``.
+This doesn't directly affect the layout of these types in most cases, but may result in more padding being used when
+they are used in combination, for example ``reverse_iterator<reverse_iterator<T>>``.
+
+- ``_LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION``
+-------------------------------------------------
+This changes the index type used inside ``variant`` to the smallest required type to reduce the datasize of variants in
+most cases.
+
+``_LIBCPP_ABI_OPTIMIZED_FUNCTION``
+----------------------------------
+This significantly restructures how ``function`` is written to provide better performance, but is currently not ABI
+stable.
+
+``_LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT``
+-----------------------------------------------------
+This changes the layout of ``random_device`` to only holds state with an implementation that gets entropy from a file
+(see ``_LIBCPP_USING_DEV_RANDOM``). When switching from this implementation to another one on a platform that has
+already shipped ``random_device``, one needs to retain the same object layout to remain ABI compatible. This flag
+removes these workarounds for platforms that don't care about ABI compatibility.
+
+``_LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING``
+------------------------------------------
+This removes artifical padding from ``_LIBCPP_COMPRESSED_PAIR`` and ``_LIBCPP_COMPRESSED_TRIPLE``. These macros are used
+inside the associative and unordered containers, ``deque``, ``forward_list``, ``future``, ``list``, ``basic_string``,
+``function``, ``shared_ptr``, ``unique_ptr``, and ``vector`` to stay ABI compatible with the legacy
+``__compressed_pair`` type. ``__compressed_pair`` has historically been used to reduce storage requirements in the case
+of empty types, but has been replaced by ``[[no_unique_address]]``. ``[[no_unique_address]]`` is significantly lighter
+in terms of compile time and debug information, and also improves the layout of structs further. However, to keep ABI
+stability, the additional improvements in layout had to be reverted by introducing artificial padding.
+
+``_LIBCPP_ABI_IOS_ALLOW_ARBITRARY_FILL_VALUE``
+----------------------------------------------
+``basic_ios`` uses ``WEOF`` to indicate that the fill value is uninitialized. However, on platforms where the size of
+``char_type`` is equal to or greater than the size of ``int_type`` and ``char_type`` is unsigned,
+``char_traits<char_type>::eq_int_type()`` cannot distinguish between ``WEOF`` and ``WCHAR_MAX``. This flag changes
+``basic_ios`` to instead track whether the fill value has been initialized using a separate boolean.
+
+
+Linking TUs which have been compiled against different releases of libc++
+=========================================================================
+libc++ supports linking TUs which have beeen compiled against different releases of libc++ by marking symbols with
+hidden visibility and changing the mangling of header-only functions in every release.
+
+
+Linking TUs which have been compiled with different flags affecting code gen
+============================================================================
+There are a lot of compiler (and library) flags which change the code generated for functions. This includes flags like
+``-O1``, which are guaranteed by the compiler to not change the observable behaviour of a correct program, as well as
+flags like ``-fexceptions``, which **do** change the observable behaviour. libc++ allows linking of TUs which have been
+compiled whith specific flags only and makes no guarantees for any of the flags not listed below.
+
+The flags allowed (in any combination) are:
+- ``-f[no-]exceptions``
+- ``-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE{_FAST,_EXTENSIVE,_DEBUG,_NONE}``
+
+Note that this does not provide any guarantees about user-defined functions, but only that the libc++ functions linked
+behave as the flags say.
+
+
+Availability of symbols in the built library (both static and shared)
+=====================================================================
+In general, libc++ does not make any guarantees about forwards-compability. That is, a TU compiled against new headers
+may not work with an older library. Vendors who require such support can leverage the availability markups. On the other
+hand, backwards compatibility is generally guaranteed.
+
+There are multiple ABI flags that change the symbols exported from the built library:
+
+``_LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON``
+-------------------------------------------------
+This removes ``__basic_string_common<true>::__throw_length_error()`` and
+``__basic_string_common<true>::__throw_out_of_range()``. These symbols have been used by ``basic_string`` in the past,
+but are not referenced from the headers anymore.
+
+``_LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON``
+------------------------------------------------
+This removes ``__vector_base_common<true>::__throw_length_error()`` and
+``__vector_base_common<true>::__throw_out_of_range()``. These symbols have been used by ``vector`` in the past, but are
+not referenced from the headers anymore.
+
+``_LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10``
+----------------------------------------------
+This removes ``__itoa::__u32toa()`` and ``__iota::__u64toa``. These symbols have been used by ``to_chars`` in the past,
+but are not referenced from the headers anymore.
+
+``_LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION``
+-------------------------------------------------------
+This replaces the symbols that are exported for ``basic_string`` to avoid exporting functions which are likely to be
+inlined as well as explicitly moving paths to the built library which are slow, improving fast-path inlining of multiple
+functions. This flag is currently unstable.
+
+
+Stability of the traits of a type
+=================================
+Whether a particular trait of a type is kept stable depends heavily on the type in question and the trait. The most
+important trait of a type to keep stable is the triviality for the purpose of calls, since that directly affects the
+function call ABI. Which types are considered non-trivial for the purpose of calls is defined in the
+`Itanium ABI <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions>`_.
+``is_trivially_copyable`` should also be kept stable usually, since many programs depend on this trait for their own
+layouting. This isn't rigit as the previous requirement though.
----------------
ldionne wrote:

```suggestion
layouting. This isn't as rigid as the previous requirement though.
```

https://github.com/llvm/llvm-project/pull/132615


More information about the libcxx-commits mailing list