[libc++] Introduce the notion of a minimum header version (#166074)

Introducing the notion of a minimum header version has multiple
benefits. It allows us to merge a bunch of ABI macros into a single one.
This makes configuring the library significantly easier, since, for a
stable ABI, you only need to know which version you started distributing
the library with, instead of checking which ABI flags have been
introduced at what point. For platforms which have a moving window of
the minimum version a program has been compiled against, this also makes
it simple to remove symbols from the dylib when they can't be used by
any program anymore.
This commit is contained in:
Nikolas Klauser 2026-01-09 11:58:29 +01:00 committed by GitHub
parent ddb706bbb0
commit 484ee42096
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 123 additions and 109 deletions

View File

@ -218,6 +218,9 @@ set(LIBCXX_ABI_NAMESPACE "__${LIBCXX_ABI_VERSION}" CACHE STRING "The inline ABI
if (NOT LIBCXX_ABI_NAMESPACE MATCHES "__.*")
message(FATAL_ERROR "LIBCXX_ABI_NAMESPACE must be a reserved identifier, got '${LIBCXX_ABI_NAMESPACE}'.")
endif()
set(LIBCXX_AVAILABILITY_MINIMUM_HEADER_VERSION "2" CACHE STRING
"Minimum version of the libc++ headers that are allowed to be used by binaries linked against the libc++ library. This
version must correspond to the major version of an LLVM release.")
option(LIBCXX_ABI_FORCE_ITANIUM "Ignore auto-detection and force use of the Itanium ABI.")
option(LIBCXX_ABI_FORCE_MICROSOFT "Ignore auto-detection and force use of the Microsoft ABI.")
@ -536,6 +539,7 @@ function(cxx_add_basic_build_flags target)
# Let the library headers know they are currently being used to build the
# library.
target_compile_definitions(${target} PRIVATE -D_LIBCPP_BUILDING_LIBRARY)
target_compile_definitions(${target} PRIVATE -D_LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION=${LIBCXX_AVAILABILITY_MINIMUM_HEADER_VERSION})
# Make sure the library can be build without transitive includes. This makes
# it easier to upgrade the library to a newer language standard without build

View File

@ -114,28 +114,6 @@ 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_ALIGN``
-------------------------------------------------
This removes ``std::align()`` from the built library. In the past, ``std::align()`` was defined in the built library,
but nowadays it is an inline function defined in the headers for performance reasons.
``_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

View File

@ -341,6 +341,22 @@ The following options allow building libc++ for a different ABI version.
This option generate and installs a linker script as ``libc++.so`` which
links the correct ABI library.
.. option:: LIBCXX_AVAILABILITY_MINIMUM_HEADER_VERSION:STRING
**Default**: ``2``
This option configures the oldest version of the libc++ headers that the built
library has to be compatible with. See the
:ref:`minimum header version documentation<MinimumHeaderVersion>` for details.
.. option:: LIBCXXABI_AVAILABILITY_MINIMUM_HEADER_VERSION:STRING
**Default**: ``2``
This is the same as ``LIBCXX_AVAILABILITY_MINIMUM_HEADER_VERSION`` documented
above, but for libc++abi. The two options should be set to the same value if
libc++abi is used.
.. option:: LIBCXXABI_USE_LLVM_UNWINDER:BOOL
**Default**: ``ON``
@ -643,3 +659,18 @@ if it is unavailable on the deployment target.
Note that this mechanism is disabled by default in the "upstream" libc++. Availability annotations are only meaningful
when shipping libc++ inside a platform (i.e. as a system library), and so vendors that want them should turn those
annotations on at CMake configuration time.
.. _MinimumHeaderVersion:
Minimum Header Version
======================
In libc++ we add new functions and remove the use of other functions in the built library on a regular basis. To avoid
breaking programs, we keep old functions in the built library as documented in our
:ref:`header support policy<HeaderSupportPolicy>`. However, there are platforms where some of these functions could
never be referenced, because that platform never provided headers which referenced these functions. To reduce the size
of the built library on these platforms, libc++ provides the notion of a minimum header version. The minimum header
version describes the earliest version of the libc++ headers that can be used in a program linking against the library
currently being built. Functions which have never been referenced in headers since the minimum header version are
removed from the library. The minimum header version can be set with the CMake variables
``LIBCXX_AVAILABILITY_MINIMUM_HEADER_VERSION`` and ``LIBCXXABI_AVAILABILITY_MINIMUM_HEADER_VERSION``.

View File

@ -165,6 +165,11 @@ we don't make any guarantees. If you would like your compiler and/or platform
to be formally supported and listed here, please work with the libc++ team to set
up testing for your configuration.
.. _HeaderSupportPolicy:
Libc++ maintains backwards compatibility with programs compiled against older
versions of the headers. The library can currently be configured by vendors to
support headers from LLVM 2.8 or any later major release.
C++ Standards Conformance
=========================

View File

@ -372,16 +372,6 @@ typedef __char32_t char32_t;
# endif
# define _LIBCPP_HIDE_FROM_ABI_VIRTUAL _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION
# ifdef _LIBCPP_BUILDING_LIBRARY
# if _LIBCPP_ABI_VERSION > 1
# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI
# else
# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1
# endif
# else
# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI
# endif
// Clang modules take a significant compile time hit when pushing and popping diagnostics.
// Since all the headers are marked as system headers unless _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER is defined, we can
// simply disable this pushing and popping when _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER isn't defined.

View File

@ -64,10 +64,6 @@
// These flags are documented in ABIGuarantees.rst
# define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
# define _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE
# define _LIBCPP_ABI_DO_NOT_EXPORT_ALIGN
# define _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
# define _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON
# define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
# define _LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI
# define _LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI
# define _LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION
@ -88,17 +84,6 @@
# define _LIBCPP_ABI_TRIVIALLY_COPYABLE_BIT_ITERATOR
#elif _LIBCPP_ABI_VERSION == 1
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
// Enable compiling copies of now inline methods into the dylib to support
// applications compiled against older libraries. This is unnecessary with
// COFF dllexport semantics, since dllexport forces a non-inline definition
// of inline functions to be emitted anyway. Our own non-inline copy would
// conflict with the dllexport-emitted copy, so we disable it. For XCOFF,
// the linker will take issue with the symbols in the shared object if the
// weak inline methods get visibility (such as from -fvisibility-inlines-hidden),
// so disable it.
# define _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
# endif
// Feature macros for disabling pre ABI v1 features. All of these options
// are deprecated.
# if defined(__FreeBSD__)

View File

@ -304,4 +304,11 @@
# define _LIBCPP_AVAILABILITY_INIT_PRIMARY_EXCEPTION
#endif
// Only define a bunch of symbols in the dylib if we need to be compatible with LLVM 7 headers or older
# if defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 8
# define _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8
# else
# define _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 _LIBCPP_HIDE_FROM_ABI
# endif
#endif // _LIBCPP___CONFIGURATION_AVAILABILITY_H

View File

@ -53,7 +53,7 @@ public:
typedef typename traits_type::off_type off_type;
// 27.7.2.2 Constructor/destructor:
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_ostream(basic_streambuf<char_type, traits_type>* __sb) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_ostream(basic_streambuf<char_type, traits_type>* __sb) {
this->init(__sb);
}
~basic_ostream() override;
@ -67,7 +67,7 @@ protected:
// 27.7.2.3 Assign/swap
inline _LIBCPP_HIDE_FROM_ABI basic_ostream& operator=(basic_ostream&& __rhs);
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_ostream& __rhs) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_ostream& __rhs) {
basic_ios<char_type, traits_type>::swap(__rhs);
}
@ -76,17 +76,17 @@ public:
class sentry;
// 27.7.2.6 Formatted output:
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& operator<<(basic_ostream& (*__pf)(basic_ostream&)) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& operator<<(basic_ostream& (*__pf)(basic_ostream&)) {
return __pf(*this);
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream&
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream&
operator<<(basic_ios<char_type, traits_type>& (*__pf)(basic_ios<char_type, traits_type>&)) {
__pf(*this);
return *this;
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& operator<<(ios_base& (*__pf)(ios_base&)) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& operator<<(ios_base& (*__pf)(ios_base&)) {
__pf(*this);
return *this;
}
@ -174,9 +174,9 @@ public:
basic_ostream& flush();
// 27.7.2.5 seeks:
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type tellp();
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& seekp(pos_type __pos);
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& seekp(off_type __off, ios_base::seekdir __dir);
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type tellp();
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& seekp(pos_type __pos);
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& seekp(off_type __off, ios_base::seekdir __dir);
protected:
_LIBCPP_HIDE_FROM_ABI basic_ostream() {} // extension, intentially does not initialize

View File

@ -209,7 +209,7 @@ public:
typedef typename traits_type::off_type off_type;
// 27.7.1.1.1 Constructor/destructor:
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_istream(basic_streambuf<char_type, traits_type>* __sb)
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_istream(basic_streambuf<char_type, traits_type>* __sb)
: __gc_(0) {
this->init(__sb);
}
@ -221,7 +221,7 @@ protected:
// 27.7.1.1.2 Assign/swap:
inline _LIBCPP_HIDE_FROM_ABI basic_istream& operator=(basic_istream&& __rhs);
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_istream& __rhs) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_istream& __rhs) {
std::swap(__gc_, __rhs.__gc_);
basic_ios<char_type, traits_type>::swap(__rhs);
}
@ -234,17 +234,17 @@ public:
class sentry;
// 27.7.1.2 Formatted input:
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& operator>>(basic_istream& (*__pf)(basic_istream&)) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& operator>>(basic_istream& (*__pf)(basic_istream&)) {
return __pf(*this);
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream&
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream&
operator>>(basic_ios<char_type, traits_type>& (*__pf)(basic_ios<char_type, traits_type>&)) {
__pf(*this);
return *this;
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& operator>>(ios_base& (*__pf)(ios_base&)) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& operator>>(ios_base& (*__pf)(ios_base&)) {
__pf(*this);
return *this;
}
@ -268,26 +268,26 @@ public:
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI streamsize gcount() const { return __gc_; }
int_type get();
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(char_type& __c) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(char_type& __c) {
int_type __ch = get();
if (__ch != traits_type::eof())
__c = traits_type::to_char_type(__ch);
return *this;
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(char_type* __s, streamsize __n) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(char_type* __s, streamsize __n) {
return get(__s, __n, this->widen('\n'));
}
basic_istream& get(char_type* __s, streamsize __n, char_type __dlm);
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(basic_streambuf<char_type, traits_type>& __sb) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(basic_streambuf<char_type, traits_type>& __sb) {
return get(__sb, this->widen('\n'));
}
basic_istream& get(basic_streambuf<char_type, traits_type>& __sb, char_type __dlm);
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& getline(char_type* __s, streamsize __n) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& getline(char_type* __s, streamsize __n) {
return getline(__s, __n, this->widen('\n'));
}
@ -1184,7 +1184,7 @@ public:
typedef typename traits_type::off_type off_type;
// constructor/destructor
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_iostream(basic_streambuf<char_type, traits_type>* __sb)
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_iostream(basic_streambuf<char_type, traits_type>* __sb)
: basic_istream<_CharT, _Traits>(__sb) {}
~basic_iostream() override;
@ -1195,7 +1195,7 @@ protected:
// assign/swap
inline _LIBCPP_HIDE_FROM_ABI basic_iostream& operator=(basic_iostream&& __rhs);
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_iostream& __rhs) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_iostream& __rhs) {
basic_istream<char_type, traits_type>::swap(__rhs);
}
};

View File

@ -150,35 +150,35 @@ public:
virtual ~basic_streambuf() {}
// 27.6.2.2.1 locales:
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 locale pubimbue(const locale& __loc) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 locale pubimbue(const locale& __loc) {
imbue(__loc);
locale __r = __loc_;
__loc_ = __loc;
return __r;
}
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 locale getloc() const { return __loc_; }
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 locale getloc() const { return __loc_; }
// 27.6.2.2.2 buffer and positioning:
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_streambuf* pubsetbuf(char_type* __s, streamsize __n) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_streambuf* pubsetbuf(char_type* __s, streamsize __n) {
return setbuf(__s, __n);
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type
pubseekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which = ios_base::in | ios_base::out) {
return seekoff(__off, __way, __which);
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type
pubseekpos(pos_type __sp, ios_base::openmode __which = ios_base::in | ios_base::out) {
return seekpos(__sp, __which);
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int pubsync() { return sync(); }
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int pubsync() { return sync(); }
// Get and put areas:
// 27.6.2.2.3 Get area:
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize in_avail() {
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize in_avail() {
__check_invariants();
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
@ -187,7 +187,7 @@ public:
return showmanyc();
}
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type snextc() {
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type snextc() {
__check_invariants();
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
@ -196,7 +196,7 @@ public:
return sgetc();
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sbumpc() {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sbumpc() {
__check_invariants();
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
@ -207,7 +207,7 @@ public:
return __c;
}
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sgetc() {
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sgetc() {
__check_invariants();
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
@ -216,10 +216,10 @@ public:
return traits_type::to_int_type(*gptr());
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sgetn(char_type* __s, streamsize __n) { return xsgetn(__s, __n); }
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize sgetn(char_type* __s, streamsize __n) { return xsgetn(__s, __n); }
// 27.6.2.2.4 Putback:
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputbackc(char_type __c) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sputbackc(char_type __c) {
__check_invariants();
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
@ -229,7 +229,7 @@ public:
return traits_type::to_int_type(*gptr());
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sungetc() {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sungetc() {
__check_invariants();
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
@ -240,7 +240,7 @@ public:
}
// 27.6.2.2.5 Put area:
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputc(char_type __c) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sputc(char_type __c) {
__check_invariants();
auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); });
@ -251,7 +251,7 @@ public:
return traits_type::to_int_type(__c);
}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sputn(const char_type* __s, streamsize __n) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize sputn(const char_type* __s, streamsize __n) {
return xsputn(__s, __n);
}
@ -292,12 +292,12 @@ protected:
_LIBCPP_HIDE_FROM_ABI char_type* gptr() const { return __ninp_; }
_LIBCPP_HIDE_FROM_ABI char_type* egptr() const { return __einp_; }
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void gbump(int __n) { __ninp_ += __n; }
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void gbump(int __n) { __ninp_ += __n; }
// gbump takes an int, so it might not be able to represent the offset we want to add.
_LIBCPP_HIDE_FROM_ABI void __gbump_ptrdiff(ptrdiff_t __n) { __ninp_ += __n; }
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gnext), "[gbeg, gnext) must be a valid range");
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gend), "[gbeg, gend) must be a valid range");
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gnext, __gend), "[gnext, gend) must be a valid range");
@ -311,11 +311,11 @@ protected:
_LIBCPP_HIDE_FROM_ABI char_type* pptr() const { return __nout_; }
_LIBCPP_HIDE_FROM_ABI char_type* epptr() const { return __eout_; }
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void pbump(int __n) { __nout_ += __n; }
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void pbump(int __n) { __nout_ += __n; }
_LIBCPP_HIDE_FROM_ABI void __pbump(streamsize __n) { __nout_ += __n; }
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setp(char_type* __pbeg, char_type* __pend) {
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void setp(char_type* __pbeg, char_type* __pend) {
_LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__pbeg, __pend), "[pbeg, pend) must be a valid range");
__bout_ = __nout_ = __pbeg;
__eout_ = __pend;

View File

@ -793,7 +793,7 @@ private:
public:
// construct/destroy:
_LIBCPP_HIDE_FROM_ABI valarray() : __begin_(nullptr), __end_(nullptr) {}
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit valarray(size_t __n);
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit valarray(size_t __n);
_LIBCPP_HIDE_FROM_ABI valarray(const value_type& __x, size_t __n);
valarray(const value_type* __p, size_t __n);
valarray(const valarray& __v);
@ -805,7 +805,7 @@ public:
valarray(const gslice_array<value_type>& __ga);
valarray(const mask_array<value_type>& __ma);
valarray(const indirect_array<value_type>& __ia);
inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 ~valarray();
inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 ~valarray();
// assignment:
valarray& operator=(const valarray& __v);

View File

@ -14,6 +14,8 @@ const char* bad_any_cast::what() const noexcept { return "bad any cast"; }
#include <__config>
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7
// Preserve std::experimental::any_bad_cast for ABI compatibility
// Even though it no longer exists in a header file
_LIBCPP_BEGIN_NAMESPACE_LFTS
@ -25,4 +27,6 @@ public:
const char* bad_any_cast::what() const noexcept { return "bad any cast"; }
#endif
_LIBCPP_END_NAMESPACE_LFTS

View File

@ -14,7 +14,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15
namespace __itoa {
@ -27,7 +27,7 @@ _LIBCPP_DIAGNOSTIC_POP
} // namespace __itoa
#endif // _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15
// The original version of floating-point to_chars was written by Microsoft and
// contributed with the following license.

View File

@ -14,7 +14,7 @@
#include <__config>
#include <__thread/support.h>
#if _LIBCPP_ABI_VERSION == 1 || !_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9 || !_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION
# define NEEDS_CONDVAR_DESTRUCTOR
#endif

View File

@ -8,7 +8,9 @@
#include <__config>
#ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
// This has technically been removed in LLVM 3.4
#if !defined(_LIBCPP_OBJECT_FORMAT_COFF) && !defined(_LIBCPP_OBJECT_FORMAT_XCOFF) && \
_LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 4
# define _LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS
#endif

View File

@ -7,7 +7,8 @@
//===----------------------------------------------------------------------===//
#include <__config>
#ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
#if !defined(_LIBCPP_OBJECT_FORMAT_COFF) && !defined(_LIBCPP_OBJECT_FORMAT_XCOFF) && \
_LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 5
# define _LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS
#endif
@ -132,13 +133,16 @@ __sp_mut& __get_sp_mut(const void* p) {
#endif // _LIBCPP_HAS_THREADS
#if !defined(_LIBCPP_ABI_DO_NOT_EXPORT_ALIGN)
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21
_LIBCPP_EXPORTED_FROM_ABI void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
_LIBCPP_DIAGNOSTIC_PUSH
_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes")
// This function only exists for ABI compatibility and we therefore don't provide a declaration in the headers
_LIBCPP_EXPORTED_FROM_ABI void* align(size_t alignment, size_t size, void*& ptr, size_t& space) {
return __align_inline::align(alignment, size, ptr, space);
}
_LIBCPP_DIAGNOSTIC_POP
#endif // _LIBCPP_ABI_DO_NOT_EXPORT_ALIGN
#endif
_LIBCPP_END_NAMESPACE_STD

View File

@ -19,7 +19,7 @@
#include <__config>
#include <__thread/support.h>
#if _LIBCPP_ABI_VERSION == 1 || !_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9 || !_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION
# define NEEDS_MUTEX_DESTRUCTOR
#endif

View File

@ -19,6 +19,8 @@ const char* bad_optional_access::what() const noexcept { return "bad_optional_ac
#include <__config>
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7
// Preserve std::experimental::bad_optional_access for ABI compatibility
// Even though it no longer exists in a header file
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
@ -34,3 +36,5 @@ public:
bad_optional_access::~bad_optional_access() noexcept = default;
_LIBCPP_END_NAMESPACE_EXPERIMENTAL
#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7

View File

@ -20,7 +20,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 14
template <bool>
struct __basic_string_common;
@ -35,12 +35,12 @@ struct __basic_string_common<true> {
void __basic_string_common<true>::__throw_length_error() const { std::__throw_length_error("basic_string"); }
void __basic_string_common<true>::__throw_out_of_range() const { std::__throw_out_of_range("basic_string"); }
#endif // _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 14
// Define legacy ABI functions
// ---------------------------
#ifndef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21
// This initializes the string with [__s, __s + __sz), but capacity() == __reserve. Assumes that __reserve >= __sz.
template <class _CharT, class _Traits, class _Allocator>
@ -53,15 +53,12 @@ void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, si
__annotate_new(__sz);
}
# define STRING_LEGACY_API(CharT) \
template _LIBCPP_EXPORTED_FROM_ABI void basic_string<CharT>::__init(const value_type*, size_type, size_type)
STRING_LEGACY_API(char);
template _LIBCPP_EXPORTED_FROM_ABI void basic_string<char>::__init(const value_type*, size_type, size_type);
# if _LIBCPP_HAS_WIDE_CHARACTERS
STRING_LEGACY_API(wchar_t);
template _LIBCPP_EXPORTED_FROM_ABI void basic_string<wchar_t>::__init(const value_type*, size_type, size_type);
# endif
#endif // _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21
#define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template _LIBCPP_EXPORTED_FROM_ABI __VA_ARGS__;
#ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION

View File

@ -10,8 +10,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
// These two symbols are part of the v1 ABI but not part of the >=v2 ABI.
#if _LIBCPP_ABI_VERSION == 1
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9
template _LIBCPP_EXPORTED_FROM_ABI valarray<size_t>::valarray(size_t);
template _LIBCPP_EXPORTED_FROM_ABI valarray<size_t>::~valarray();
#endif

View File

@ -10,7 +10,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON
#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15
template <bool>
struct __vector_base_common;
@ -25,6 +25,6 @@ void __vector_base_common<true>::__throw_length_error() const { std::__throw_len
void __vector_base_common<true>::__throw_out_of_range() const { std::__throw_out_of_range("vector"); }
#endif // _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON
#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15
_LIBCPP_END_NAMESPACE_STD

View File

@ -64,6 +64,9 @@ option(LIBCXXABI_HAS_WIN32_THREAD_API "Ignore auto-detection and force use of wi
option(LIBCXXABI_HAS_EXTERNAL_THREAD_API
"Build libc++abi with an externalized threading API.
This option may only be set to ON when LIBCXXABI_ENABLE_THREADS=ON." OFF)
set(LIBCXXABI_AVAILABILITY_MINIMUM_HEADER_VERSION "2" CACHE STRING
"Minimum version of the libc++ headers that are allowed to be used by binaries linked against the libc++ library. This
version must correspond to the major version of an LLVM release.")
option(LIBCXXABI_ENABLE_FORGIVING_DYNAMIC_CAST
"Make dynamic_cast more forgiving when type_info's mistakenly have hidden \
visibility, and thus multiple type_infos can exist for a single type. \
@ -321,6 +324,7 @@ add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY)
# libcxxabi needs to, for various reasons, include the libcpp headers as if
# it is being built as part of libcxx.
add_definitions(-D_LIBCPP_BUILDING_LIBRARY)
add_definitions(-D_LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION=${LIBCXXABI_AVAILABILITY_MINIMUM_HEADER_VERSION})
# Get feature flags.
add_compile_flags_if_supported(-fstrict-aliasing)