diff --git a/CMakeLists.txt b/CMakeLists.txt index 41627ab5..b65bbacc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,8 @@ set(LIBCXX_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING option(LIBCXX_INSTALL_HEADERS "Install the libc++ headers." ON) option(LIBCXX_INSTALL_LIBRARY "Install the libc++ library." ON) option(LIBCXX_INSTALL_SUPPORT_HEADERS "Install libc++ support headers." ON) +set(LIBCXX_ABI_VERSION 1 CACHE STRING "ABI version of libc++.") +option(LIBCXX_ABI_UNSTABLE "Unstable ABI of libc++." OFF) # ABI Library options --------------------------------------------------------- set(LIBCXX_CXX_ABI "${LIBCXX_CXX_ABI}" CACHE STRING @@ -298,6 +300,11 @@ if (LIBCXX_BUILT_STANDALONE) endif() # Configuration file flags ===================================================== +if (NOT LIBCXX_ABI_VERSION EQUAL "1") + config_define(${LIBCXX_ABI_VERSION} _LIBCPP_ABI_VERSION) +endif() +config_define_if(LIBCXX_ABI_UNSTABLE _LIBCPP_ABI_UNSTABLE) + config_define_if_not(LIBCXX_ENABLE_GLOBAL_FILESYSTEM_NAMESPACE _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE) config_define_if_not(LIBCXX_ENABLE_STDIN _LIBCPP_HAS_NO_STDIN) config_define_if_not(LIBCXX_ENABLE_STDOUT _LIBCPP_HAS_NO_STDOUT) diff --git a/cmake/Modules/HandleLibcxxFlags.cmake b/cmake/Modules/HandleLibcxxFlags.cmake index a9e43eae..32065051 100644 --- a/cmake/Modules/HandleLibcxxFlags.cmake +++ b/cmake/Modules/HandleLibcxxFlags.cmake @@ -65,6 +65,12 @@ macro(config_define_if_not condition def) endif() endmacro() +macro(config_define value def) + set(${def} ${value}) + add_definitions(-D${def}=${value}) + set(LIBCXX_NEEDS_SITE_CONFIG ON) +endmacro() + # Add a specified list of flags to both 'LIBCXX_COMPILE_FLAGS' and # 'LIBCXX_LINK_FLAGS'. macro(add_flags) diff --git a/docs/Abi.rst b/docs/Abi.rst new file mode 100644 index 00000000..5960dd18 --- /dev/null +++ b/docs/Abi.rst @@ -0,0 +1,17 @@ + +==================== +Libc++ ABI stability +==================== + +Libc++ aims to preserve stable ABI to avoid subtle bugs when code built to the old ABI +is linked with the code build to the new ABI. At the same time, libc++ allows ABI-breaking +improvements and bugfixes for the scenarios when ABI change is not a issue. + +To support both cases, libc++ allows specifying the ABI version at the +build time. The version is defined with a cmake option +LIBCXX_ABI_VERSION. Another option LIBCXX_ABI_UNSTABLE can be used to +include all present ABI breaking features. These options translate +into C++ macro definitions _LIBCPP_ABI_VERSION, _LIBCPP_ABI_UNSTABLE. + +Any ABI-changing feature is placed under it's own macro, _LIBCPP_ABI_XXX, which is enabled +based on the value of _LIBCPP_ABI_VERSION. _LIBCPP_ABI_UNSTABLE, if set, enables all features at once. diff --git a/docs/BuildingLibcxx.rst b/docs/BuildingLibcxx.rst index e343dfdd..6e45578d 100644 --- a/docs/BuildingLibcxx.rst +++ b/docs/BuildingLibcxx.rst @@ -193,6 +193,25 @@ libc++ Feature options Build libc++ with run time type information. + +libc++ Feature options +---------------------- + +The following options allow building libc++ for a different ABI version. + +.. option:: LIBCXX_ABI_VERSION:STRING + + **Default**: ``1`` + + Defines the target ABI version of libc++. + +.. option:: LIBCXX_ABI_UNSTABLE:BOOL + + **Default**: ``OFF`` + + Build the "unstable" ABI version of libc++. Includes all ABI changing features + on top of the current stable version. + .. _LLVM-specific variables: LLVM-specific options diff --git a/include/__config b/include/__config index a11dbc96..bc01805f 100644 --- a/include/__config +++ b/include/__config @@ -23,7 +23,13 @@ #define _LIBCPP_VERSION 3800 +#ifndef _LIBCPP_ABI_VERSION #define _LIBCPP_ABI_VERSION 1 +#endif + +#if defined(_LIBCPP_ABI_UNSTABLE) || _LIBCPP_ABI_VERSION >= 2 +#define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT +#endif #define _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_X##_LIBCPP_Y #define _LIBCPP_CONCAT(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) @@ -240,9 +246,12 @@ #if defined(__clang__) -#if defined(__APPLE__) && !defined(__i386__) && !defined(__x86_64__) && \ - !defined(__arm__) -#define _LIBCPP_ALTERNATE_STRING_LAYOUT +// _LIBCPP_ALTERNATE_STRING_LAYOUT is an old name for +// _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT left here for backward compatibility. +#if (defined(__APPLE__) && !defined(__i386__) && !defined(__x86_64__) && \ + !defined(__arm__)) || \ + defined(_LIBCPP_ALTERNATE_STRING_LAYOUT) +#define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT #endif #if __has_feature(cxx_alignas) diff --git a/include/__config_site.in b/include/__config_site.in index a248787f..7a1d739f 100644 --- a/include/__config_site.in +++ b/include/__config_site.in @@ -10,6 +10,8 @@ #ifndef _LIBCPP_CONFIG_SITE #define _LIBCPP_CONFIG_SITE +#cmakedefine _LIBCPP_ABI_VERSION @_LIBCPP_ABI_VERSION@ +#cmakedefine _LIBCPP_ABI_UNSTABLE #cmakedefine _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE #cmakedefine _LIBCPP_HAS_NO_STDIN #cmakedefine _LIBCPP_HAS_NO_STDOUT diff --git a/include/string b/include/string index 46c749b6..7650b62b 100644 --- a/include/string +++ b/include/string @@ -1185,7 +1185,7 @@ _LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_TYPE_VIS __basic_string_common) #pragma warning( pop ) #endif // _LIBCPP_MSVC -#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT +#ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT template struct __padding @@ -1198,7 +1198,7 @@ struct __padding<_CharT, 1> { }; -#endif // _LIBCPP_ALTERNATE_STRING_LAYOUT +#endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT template class _LIBCPP_TYPE_VIS_ONLY basic_string @@ -1234,7 +1234,7 @@ public: private: -#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT +#ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT struct __long { @@ -1294,7 +1294,7 @@ private: value_type __data_[__min_cap]; }; -#endif // _LIBCPP_ALTERNATE_STRING_LAYOUT +#endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT union __ulx{__long __lx; __short __lxx;}; @@ -1698,7 +1698,7 @@ private: const allocator_type& __alloc() const _NOEXCEPT {return __r_.second();} -#ifdef _LIBCPP_ALTERNATE_STRING_LAYOUT +#ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT _LIBCPP_INLINE_VISIBILITY void __set_short_size(size_type __s) _NOEXCEPT @@ -1716,7 +1716,7 @@ private: {return __r_.first().__s.__size_;} # endif -#else // _LIBCPP_ALTERNATE_STRING_LAYOUT +#else // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT _LIBCPP_INLINE_VISIBILITY void __set_short_size(size_type __s) _NOEXCEPT @@ -1734,7 +1734,7 @@ private: {return __r_.first().__s.__size_ >> 1;} # endif -#endif // _LIBCPP_ALTERNATE_STRING_LAYOUT +#endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT _LIBCPP_INLINE_VISIBILITY void __set_long_size(size_type __s) _NOEXCEPT diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 28049b5b..1a1c55b1 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -129,8 +129,8 @@ set_target_properties(cxx COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}" LINK_FLAGS "${LIBCXX_LINK_FLAGS}" OUTPUT_NAME "c++" - VERSION "1.0" - SOVERSION "1" + VERSION "${LIBCXX_ABI_VERSION}.0" + SOVERSION "${LIBCXX_ABI_VERSION}" ) if (LIBCXX_INSTALL_LIBRARY) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 60dd7c27..3f0ff9a0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,6 +13,7 @@ pythonize_bool(LIBCXX_ENABLE_EXCEPTIONS) pythonize_bool(LIBCXX_ENABLE_RTTI) pythonize_bool(LIBCXX_ENABLE_SHARED) pythonize_bool(LIBCXX_BUILD_32_BITS) +pythonize_bool(LIBCXX_ABI_UNSTABLE) pythonize_bool(LIBCXX_ENABLE_GLOBAL_FILESYSTEM_NAMESPACE) pythonize_bool(LIBCXX_ENABLE_STDIN) pythonize_bool(LIBCXX_ENABLE_STDOUT) diff --git a/test/libcxx/test/config.py b/test/libcxx/test/config.py index e0f2f5b4..3cc1d3b8 100644 --- a/test/libcxx/test/config.py +++ b/test/libcxx/test/config.py @@ -387,6 +387,7 @@ class Configuration(object): # Configure feature flags. self.configure_compile_flags_exceptions() self.configure_compile_flags_rtti() + self.configure_compile_flags_abi_version() self.configure_compile_flags_no_global_filesystem_namespace() self.configure_compile_flags_no_stdin() self.configure_compile_flags_no_stdout() @@ -440,6 +441,15 @@ class Configuration(object): self.config.available_features.add('libcpp-no-rtti') self.cxx.compile_flags += ['-fno-rtti', '-D_LIBCPP_NO_RTTI'] + def configure_compile_flags_abi_version(self): + abi_version = self.get_lit_conf('abi_version', '').strip() + abi_unstable = self.get_lit_bool('abi_unstable') + if abi_version: + self.cxx.compile_flags += ['-D_LIBCPP_ABI_VERSION=' + abi_version] + if abi_unstable: + self.config.available_features.add('libcpp-abi-unstable') + self.cxx.compile_flags += ['-D_LIBCPP_ABI_UNSTABLE'] + def configure_compile_flags_no_global_filesystem_namespace(self): enable_global_filesystem_namespace = self.get_lit_bool( 'enable_global_filesystem_namespace', True) diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 765ee7c5..997f9dc0 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -7,6 +7,8 @@ config.enable_exceptions = "@LIBCXX_ENABLE_EXCEPTIONS@" config.enable_rtti = "@LIBCXX_ENABLE_RTTI@" config.enable_shared = "@LIBCXX_ENABLE_SHARED@" config.enable_32bit = "@LIBCXX_BUILD_32_BITS@" +config.abi_version = "@LIBCXX_ABI_VERSION@" +config.abi_unstable = "@LIBCXX_ABI_UNSTABLE@" config.enable_global_filesystem_namespace = "@LIBCXX_ENABLE_GLOBAL_FILESYSTEM_NAMESPACE@" config.enable_stdin = "@LIBCXX_ENABLE_STDIN@" config.enable_stdout = "@LIBCXX_ENABLE_STDOUT@"