mirror of
https://github.com/topjohnwu/libcxx.git
synced 2024-11-26 21:20:30 +00:00
Upstream to LLVM 15
This commit is contained in:
parent
9b40e8b936
commit
82090ae75f
@ -1,13 +1,89 @@
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
---
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
AlignConsecutiveBitFields: Consecutive
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AttributeMacros: ['_LIBCPP_HIDE_FROM_ABI',
|
||||
'_LIBCPP_CONSTEXPR',
|
||||
'_LIBCPP_CONSTEXPR_AFTER_CXX11',
|
||||
'_LIBCPP_CONSTEXPR_AFTER_CXX14',
|
||||
'_LIBCPP_CONSTEXPR_AFTER_CXX17',
|
||||
'_LIBCPP_CONSTEXPR_AFTER_CXX20',
|
||||
'_LIBCPP_ALIGNOF',
|
||||
'_ALIGNAS_TYPE',
|
||||
'_ALIGNAS',
|
||||
'_LIBCPP_NORETURN',
|
||||
'_LIBCPP_ALWAYS_INLINE',
|
||||
'_LIBCPP_DISABLE_EXTENTSION_WARNING',
|
||||
'_LIBCPP_HIDDEN',
|
||||
'_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS',
|
||||
'_LIBCPP_FUNC_VIS',
|
||||
'_LIBCPP_TYPE_VIS',
|
||||
'_LIBCPP_TEMPLATE_VIS',
|
||||
'_LIBCPP_TEMPLATE_DATA_VIS',
|
||||
'_LIBCPP_EXPORTED_FROM_ABI',
|
||||
'_LIBCPP_OVERRIDABLE_FUNC_VIS',
|
||||
'_LIBCPP_EXCEPTION_ABI',
|
||||
'_LIBCPP_ENUM_VIS',
|
||||
'_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS',
|
||||
'_LIBCPP_INTERNAL_LINKAGE',
|
||||
'_LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION',
|
||||
'_LIBCPP_HIDE_FROM_ABI_AFTER_V1',
|
||||
'_LIBCPP_INLINE_VISIBILITY',
|
||||
'_LIBCPP_CONSTEVAL',
|
||||
'_LIBCPP_NOALIAS',
|
||||
'_LIBCPP_USING_IF_EXISTS',
|
||||
'_LIBCPP_DEPRECATED',
|
||||
'_LIBCPP_DEPRECATED_IN_CXX11',
|
||||
'_LIBCPP_DEPRECATED_IN_CXX14',
|
||||
'_LIBCPP_DEPRECATED_IN_CXX17',
|
||||
'_LIBCPP_DEPRECATED_IN_CXX20',
|
||||
'_LIBCPP_NODISCARD',
|
||||
'_LIBCPP_NODISCARD_EXT',
|
||||
'_LIBCPP_NO_DESTROY',
|
||||
'_LIBCPP_WEAK',
|
||||
'_LIBCPP_CONSTINIT',
|
||||
'_LIBCPP_FALLTHROUGH',
|
||||
'_LIBCPP_STANDALONE_DEBUG',
|
||||
'_LIBCPP_NO_UNIQUE_ADDRESS',
|
||||
]
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakInheritanceList: BeforeColon
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: Always
|
||||
IndentWrappedFunctionNames: false
|
||||
IndentRequires: true
|
||||
InsertTrailingCommas: Wrapped
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: Inner
|
||||
PackConstructorInitializers: NextLine
|
||||
|
||||
PenaltyIndentedWhitespace: 2
|
||||
|
||||
Language: Cpp
|
||||
Standard: Cpp03
|
||||
Standard: c++20
|
||||
SpacesInAngles: Leave
|
||||
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
PointerAlignment: Left
|
||||
|
||||
|
||||
# Disable formatting options which may break tests.
|
||||
SortIncludes: false
|
||||
ReflowComments: false
|
||||
---
|
||||
|
||||
# libc++'s preferred indentions of preprocessor statements.
|
||||
IndentPPDirectives: AfterHash
|
||||
|
||||
# libc++ has some long names so we need more than the 80 column limit imposed by LLVM style, for sensible formatting
|
||||
ColumnLimit: 120
|
||||
|
60
.clang-tidy
Normal file
60
.clang-tidy
Normal file
@ -0,0 +1,60 @@
|
||||
Checks: >
|
||||
bugprone-copy-constructor-init,
|
||||
bugprone-dangling-handle,
|
||||
bugprone-infinite-loop,
|
||||
bugprone-stringview-nullptr,
|
||||
bugprone-use-after-move,
|
||||
|
||||
llvm-include-order,
|
||||
llvm-namespace-comment,
|
||||
|
||||
misc-definitions-in-headers,
|
||||
misc-misplaced-const,
|
||||
misc-non-copyable-objects,
|
||||
misc-uniqueptr-reset-release,
|
||||
|
||||
modernize-loop-convert,
|
||||
modernize-redundant-void-arg,
|
||||
|
||||
readability-duplicate-include,
|
||||
readability-identifier-naming,
|
||||
readability-function-cognitive-complexity,
|
||||
readability-function-size,
|
||||
readability-misplaced-array-index,
|
||||
readability-redundant-control-flow,
|
||||
readability-redundant-function-ptr-dereference,
|
||||
readability-redundant-preprocessor,
|
||||
readability-simplify-subscript-expr,
|
||||
readability-uniqueptr-delete-release,
|
||||
|
||||
CheckOptions:
|
||||
- key: readability-function-cognitive-complexity.Threshold
|
||||
value: 143 # TODO: bring that number down
|
||||
- key: readability-function-size.LineThreshold
|
||||
value: 194 # TODO: bring that number down
|
||||
- key: readability-identifier-naming.GetConfigPerFile
|
||||
value: false
|
||||
- key: readability-identifier-naming.ParameterCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ParameterPrefix
|
||||
value: __
|
||||
|
||||
# TODO: investigate these checks
|
||||
# bugprone-branch-clone,
|
||||
# bugprone-macro-parentheses,
|
||||
# cppcoreguidelines-prefer-member-initializer,
|
||||
# misc-unused-parameters,
|
||||
# modernize-use-bool-literals,
|
||||
# modernize-use-default-member-init,
|
||||
# modernize-use-equals-default,
|
||||
# modernize-use-equals-delete,
|
||||
# modernize-use-nullptr,
|
||||
# modernize-use-override,
|
||||
# portability-restrict-system-includes,
|
||||
# readability-function-cognitive-complexity,
|
||||
# readability-implicit-bool-conversion,
|
||||
# readability-isolate-declaration,
|
||||
# readability-redundant-access-specifiers,
|
||||
# readability-redundant-declaration,
|
||||
# readability-redundant-member-init,
|
||||
# readability-simplify-boolean-expr,
|
10
Android.mk
10
Android.mk
@ -4,7 +4,7 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# libcxx defines
|
||||
libcxx_includes := $(LOCAL_PATH)/include
|
||||
libcxx_includes := $(LOCAL_PATH)/include $(LOCAL_PATH)/src
|
||||
libcxx_export_includes := $(libcxx_includes)
|
||||
libcxx_sources := \
|
||||
algorithm.cpp \
|
||||
@ -25,13 +25,17 @@ libcxx_sources := \
|
||||
future.cpp \
|
||||
hash.cpp \
|
||||
ios.cpp \
|
||||
ios.instantiations.cpp \
|
||||
iostream.cpp \
|
||||
legacy_debug_handler.cpp \
|
||||
legacy_pointer_safety.cpp \
|
||||
locale.cpp \
|
||||
memory.cpp \
|
||||
mutex.cpp \
|
||||
mutex_destructor.cpp \
|
||||
new.cpp \
|
||||
optional.cpp \
|
||||
random_shuffle.cpp \
|
||||
random.cpp \
|
||||
regex.cpp \
|
||||
shared_mutex.cpp \
|
||||
@ -45,13 +49,14 @@ libcxx_sources := \
|
||||
valarray.cpp \
|
||||
variant.cpp \
|
||||
vector.cpp \
|
||||
verbose_abort.cpp \
|
||||
|
||||
libcxx_sources := $(libcxx_sources:%=src/%)
|
||||
|
||||
libcxx_export_cxxflags :=
|
||||
|
||||
libcxx_cxxflags := \
|
||||
-std=c++1z \
|
||||
-std=c++20 \
|
||||
-fvisibility-global-new-delete-hidden \
|
||||
-fvisibility=hidden -fvisibility-inlines-hidden \
|
||||
-DLIBCXX_BUILDING_LIBCXXABI \
|
||||
@ -76,7 +81,6 @@ libcxxabi_src_files := \
|
||||
cxa_handlers.cpp \
|
||||
cxa_noexception.cpp \
|
||||
cxa_thread_atexit.cpp \
|
||||
cxa_unexpected.cpp \
|
||||
cxa_vector.cpp \
|
||||
cxa_virtual.cpp \
|
||||
stdlib_exception.cpp \
|
||||
|
549
CMakeLists.txt
549
CMakeLists.txt
@ -1,75 +1,28 @@
|
||||
# See https://libcxx.llvm.org/docs/BuildingLibcxx.html for instructions on how
|
||||
# to build libcxx with CMake.
|
||||
|
||||
if (NOT IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../libcxxabi")
|
||||
message(FATAL_ERROR "libc++ now requires being built in a monorepo layout with libcxxabi available")
|
||||
endif()
|
||||
|
||||
#===============================================================================
|
||||
# Setup Project
|
||||
#===============================================================================
|
||||
cmake_minimum_required(VERSION 3.4.3)
|
||||
cmake_minimum_required(VERSION 3.13.4)
|
||||
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW) # Set MACOSX_RPATH=YES by default
|
||||
endif()
|
||||
if(POLICY CMP0022)
|
||||
cmake_policy(SET CMP0022 NEW) # Required when interacting with LLVM and Clang
|
||||
endif()
|
||||
if(POLICY CMP0068)
|
||||
cmake_policy(SET CMP0068 NEW)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON)
|
||||
endif()
|
||||
set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
|
||||
|
||||
# Add path for custom modules
|
||||
set(CMAKE_MODULE_PATH
|
||||
list(INSERT CMAKE_MODULE_PATH 0
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
|
||||
${CMAKE_MODULE_PATH}
|
||||
"${LLVM_COMMON_CMAKE_UTILS}"
|
||||
"${LLVM_COMMON_CMAKE_UTILS}/Modules"
|
||||
)
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBCXX_STANDALONE_BUILD)
|
||||
project(libcxx CXX C)
|
||||
set(CMAKE_FOLDER "libc++")
|
||||
|
||||
set(PACKAGE_NAME libcxx)
|
||||
set(PACKAGE_VERSION 11.0.0git)
|
||||
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
|
||||
set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org")
|
||||
set(LIBCXX_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(LIBCXX_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(LIBCXX_BINARY_INCLUDE_DIR "${LIBCXX_BINARY_DIR}/include/c++build")
|
||||
|
||||
# Find the LLVM sources and simulate LLVM CMake options.
|
||||
include(HandleOutOfTreeLLVM)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_STANDALONE_BUILD)
|
||||
if(CMAKE_VERSION VERSION_LESS 3.12)
|
||||
include(FindPythonInterp)
|
||||
if( NOT PYTHONINTERP_FOUND )
|
||||
message(WARNING "Failed to find python interpreter. "
|
||||
"The libc++ test suite will be disabled.")
|
||||
set(LLVM_INCLUDE_TESTS OFF)
|
||||
else()
|
||||
add_executable(Python3::Interpreter IMPORTED)
|
||||
set_target_properties(Python3::Interpreter PROPERTIES
|
||||
IMPORTED_LOCATION ${PYTHON_EXECUTABLE})
|
||||
set(Python3_EXECUTABLE ${PYTHON_EXECUTABLE})
|
||||
endif()
|
||||
else()
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
if(NOT Python3_Interpreter_FOUND)
|
||||
message(WARNING "Python3 not found, using python2 as a fallback")
|
||||
find_package(Python2 COMPONENTS Interpreter REQUIRED)
|
||||
if(Python2_VERSION VERSION_LESS 2.7)
|
||||
message(SEND_ERROR "Python 2.7 or newer is required")
|
||||
endif()
|
||||
|
||||
# Treat python2 as python3
|
||||
add_executable(Python3::Interpreter IMPORTED)
|
||||
set_target_properties(Python3::Interpreter PROPERTIES
|
||||
IMPORTED_LOCATION ${Python2_EXECUTABLE})
|
||||
set(Python3_EXECUTABLE ${Python2_EXECUTABLE})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Require out of source build.
|
||||
include(MacroEnsureOutOfSourceBuild)
|
||||
@ -96,19 +49,85 @@ include(CMakeDependentOption)
|
||||
include(HandleCompilerRT)
|
||||
|
||||
# Basic options ---------------------------------------------------------------
|
||||
option(LIBCXX_ENABLE_ASSERTIONS "Enable assertions independent of build mode." OFF)
|
||||
option(LIBCXX_ENABLE_ASSERTIONS
|
||||
"Enable assertions inside the compiled library, and at the same time make it the
|
||||
default when compiling user code. Note that assertions can be enabled or disabled
|
||||
by users in their own code regardless of this option." OFF)
|
||||
option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
|
||||
option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON)
|
||||
option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON)
|
||||
set(ENABLE_FILESYSTEM_DEFAULT ON)
|
||||
if (WIN32)
|
||||
if (WIN32 AND NOT MINGW)
|
||||
# Filesystem is buildable for windows, but it requires __int128 helper
|
||||
# functions, that currently are provided by libgcc or compiler_rt builtins.
|
||||
# These are available in MinGW environments, but not currently in MSVC
|
||||
# environments.
|
||||
set(ENABLE_FILESYSTEM_DEFAULT OFF)
|
||||
endif()
|
||||
option(LIBCXX_ENABLE_FILESYSTEM "Build filesystem as part of the main libc++ library"
|
||||
${ENABLE_FILESYSTEM_DEFAULT})
|
||||
option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS})
|
||||
option(LIBCXX_ENABLE_PARALLEL_ALGORITHMS "Enable the parallel algorithms library. This requires the PSTL to be available." OFF)
|
||||
option(LIBCXX_TEST_GDB_PRETTY_PRINTERS "Test gdb pretty printers." OFF)
|
||||
option(LIBCXX_ENABLE_DEBUG_MODE
|
||||
"Whether to build libc++ with the debug mode enabled.
|
||||
By default, this is turned off. Turning it on results in a different ABI (additional
|
||||
symbols but also potentially different layouts of types), and one should not mix code
|
||||
built against a dylib that has debug mode and code built against a regular dylib." OFF)
|
||||
option(LIBCXX_ENABLE_RANDOM_DEVICE
|
||||
"Whether to include support for std::random_device in the library. Disabling
|
||||
this can be useful when building the library for platforms that don't have
|
||||
a source of randomness, such as some embedded platforms. When this is not
|
||||
supported, most of <random> will still be available, but std::random_device
|
||||
will not." ON)
|
||||
option(LIBCXX_ENABLE_LOCALIZATION
|
||||
"Whether to include support for localization in the library. Disabling
|
||||
localization can be useful when porting to platforms that don't support
|
||||
the C locale API (e.g. embedded). When localization is not supported,
|
||||
several parts of the library will be disabled: <iostream>, <regex>, <locale>
|
||||
will be completely unusable, and other parts may be only partly available." ON)
|
||||
option(LIBCXX_ENABLE_UNICODE
|
||||
"Whether to include support for Unicode in the library. Disabling Unicode can
|
||||
be useful when porting to platforms that don't support UTF-8 encoding (e.g.
|
||||
embedded)." ON)
|
||||
option(LIBCXX_ENABLE_WIDE_CHARACTERS
|
||||
"Whether to include support for wide characters in the library. Disabling
|
||||
wide character support can be useful when porting to platforms that don't
|
||||
support the C functionality for wide characters. When wide characters are
|
||||
not supported, several parts of the library will be disabled, notably the
|
||||
wide character specializations of std::basic_string." ON)
|
||||
option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
|
||||
"Whether to turn on vendor availability annotations on declarations that depend
|
||||
on definitions in a shared library. By default, we assume that we're not building
|
||||
libc++ for any specific vendor, and we disable those annotations. Vendors wishing
|
||||
to provide compile-time errors when using features unavailable on some version of
|
||||
the shared library they shipped should turn this on and see `include/__availability`
|
||||
for more details." OFF)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in")
|
||||
elseif(MINGW)
|
||||
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-mingw.cfg.in")
|
||||
elseif(WIN32) # clang-cl
|
||||
if (LIBCXX_ENABLE_SHARED)
|
||||
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-clangcl.cfg.in")
|
||||
else()
|
||||
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-static-clangcl.cfg.in")
|
||||
endif()
|
||||
else()
|
||||
if (LIBCXX_ENABLE_SHARED)
|
||||
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared.cfg.in")
|
||||
else()
|
||||
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-static.cfg.in")
|
||||
endif()
|
||||
endif()
|
||||
set(LIBCXX_TEST_CONFIG "${LIBCXX_DEFAULT_TEST_CONFIG}" CACHE STRING
|
||||
"The path to the Lit testing configuration to use when running the tests.
|
||||
If a relative path is provided, it is assumed to be relative to '<monorepo>/libcxx/test/configs'.")
|
||||
if (NOT IS_ABSOLUTE "${LIBCXX_TEST_CONFIG}")
|
||||
set(LIBCXX_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/configs/${LIBCXX_TEST_CONFIG}")
|
||||
endif()
|
||||
message(STATUS "Using libc++ testing configuration: ${LIBCXX_TEST_CONFIG}")
|
||||
set(LIBCXX_TEST_PARAMS "" CACHE STRING
|
||||
"A list of parameters to run the Lit test suite with.")
|
||||
|
||||
# Benchmark options -----------------------------------------------------------
|
||||
option(LIBCXX_INCLUDE_BENCHMARKS "Build the libc++ benchmarks and their dependencies" ON)
|
||||
@ -142,53 +161,65 @@ cmake_dependent_option(LIBCXX_INSTALL_STATIC_LIBRARY
|
||||
cmake_dependent_option(LIBCXX_INSTALL_SHARED_LIBRARY
|
||||
"Install the shared libc++ library." ON
|
||||
"LIBCXX_ENABLE_SHARED;LIBCXX_INSTALL_LIBRARY" OFF)
|
||||
option(LIBCXX_INSTALL_SUPPORT_HEADERS "Install libc++ support headers." ON)
|
||||
cmake_dependent_option(LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY
|
||||
"Install libc++experimental.a" ON
|
||||
"LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY;LIBCXX_INSTALL_LIBRARY" OFF)
|
||||
|
||||
set(LIBCXX_ABI_VERSION "1" CACHE STRING "ABI version of libc++. Can be either 1 or 2, where 2 is currently not stable. Defaults to 1.")
|
||||
set(LIBCXX_ABI_NAMESPACE "" CACHE STRING "The inline ABI namespace used by libc++. It defaults to __n where `n` is the current ABI version.")
|
||||
option(LIBCXX_ABI_UNSTABLE "Unstable ABI of libc++." OFF)
|
||||
option(LIBCXX_ABI_UNSTABLE "Use the unstable ABI of libc++. This is equivalent to specifying LIBCXX_ABI_VERSION=n, where n is the not-yet-stable version." OFF)
|
||||
if (LIBCXX_ABI_UNSTABLE)
|
||||
set(abi_version "2")
|
||||
else()
|
||||
set(abi_version "1")
|
||||
endif()
|
||||
set(LIBCXX_ABI_VERSION "${abi_version}" CACHE STRING
|
||||
"ABI version of libc++. Can be either 1 or 2, where 2 is currently the unstable ABI.
|
||||
Defaults to 1 unless LIBCXX_ABI_UNSTABLE is specified, in which case this is 2.")
|
||||
set(LIBCXX_LIBRARY_VERSION "${LIBCXX_ABI_VERSION}.0" CACHE STRING
|
||||
"Version of libc++. This will be reflected in the name of the shared library produced.
|
||||
For example, -DLIBCXX_LIBRARY_VERSION=x.y will result in the library being named
|
||||
libc++.x.y.dylib, along with the usual symlinks pointing to that. On Apple platforms,
|
||||
this also controls the linker's 'current_version' property.")
|
||||
set(LIBCXX_ABI_NAMESPACE "__${LIBCXX_ABI_VERSION}" CACHE STRING "The inline ABI namespace used by libc++. It defaults to __n where `n` is the current ABI version.")
|
||||
if (NOT LIBCXX_ABI_NAMESPACE MATCHES "__.*")
|
||||
message(FATAL_ERROR "LIBCXX_ABI_NAMESPACE must be a reserved identifier, got '${LIBCXX_ABI_NAMESPACE}'.")
|
||||
endif()
|
||||
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.")
|
||||
|
||||
set(LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION "default" CACHE STRING
|
||||
"Override the implementation to use for comparing typeinfos. By default, this
|
||||
is detected automatically by the library, but this option allows overriding
|
||||
which implementation is used unconditionally.
|
||||
|
||||
set(LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT "" CACHE STRING
|
||||
"Whether typeinfo names are expected to be unique. Defining this option overrides the default configuration in the library.")
|
||||
set(MERGED_TYPEINFO_VALUES ";ON;OFF")
|
||||
set_property(CACHE LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT PROPERTY STRINGS ${MERGED_TYPEINFO_DEFAULTS})
|
||||
list(FIND MERGED_TYPEINFO_VALUES "${LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT}" IS_VALID_DEFAULT)
|
||||
if (${IS_VALID_DEFAULT} EQUAL -1)
|
||||
message(FATAL_ERROR "Value '${LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT}' is not a valid value for
|
||||
LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT")
|
||||
See the documentation in <libcxx/include/typeinfo> for details on what each
|
||||
value means.")
|
||||
set(TYPEINFO_COMPARISON_VALUES "default;1;2;3")
|
||||
if (NOT ("${LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION}" IN_LIST TYPEINFO_COMPARISON_VALUES))
|
||||
message(FATAL_ERROR "Value '${LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION}' is not a valid value for
|
||||
LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION")
|
||||
endif()
|
||||
|
||||
option(LIBCXX_HIDE_FROM_ABI_PER_TU_BY_DEFAULT "Enable per TU ABI insulation by default. To be used by vendors." OFF)
|
||||
set(LIBCXX_ABI_DEFINES "" CACHE STRING "A semicolon separated list of ABI macros to define in the site config header.")
|
||||
option(LIBCXX_EXTRA_SITE_DEFINES "Extra defines to add into __config_site")
|
||||
option(LIBCXX_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF)
|
||||
set(LIBCXX_LIBCPPABI_VERSION "2" CACHE STRING "Version of libc++abi's ABI to re-export from libc++ when re-exporting is enabled.
|
||||
Note that this is not related to the version of libc++'s ABI itself!")
|
||||
|
||||
option(LIBCXX_ENABLE_BACKWARDS_COMPATIBILITY_DEBUG_MODE_SYMBOLS
|
||||
"Whether to include the old Debug mode symbols in the compiled library. This
|
||||
is provided for backwards compatibility since the compiled library used to
|
||||
always contain those symbols, regardless of whether the library was built
|
||||
with the debug mode enabled. This is OFF by default, please contact the libc++
|
||||
developers if you need to turn this on, as this will be removed in LLVM 16." OFF)
|
||||
|
||||
# ABI Library options ---------------------------------------------------------
|
||||
set(LIBCXX_CXX_ABI "default" CACHE STRING "Specify C++ ABI library to use.")
|
||||
set(CXXABIS none default libcxxabi libcxxrt libstdc++ libsupc++ vcruntime)
|
||||
set_property(CACHE LIBCXX_CXX_ABI PROPERTY STRINGS ;${CXXABIS})
|
||||
|
||||
# Setup the default options if LIBCXX_CXX_ABI is not specified.
|
||||
if (LIBCXX_CXX_ABI STREQUAL "default")
|
||||
if (LIBCXX_TARGETING_MSVC)
|
||||
# FIXME: Figure out how to configure the ABI library on Windows.
|
||||
set(LIBCXX_CXX_ABI_LIBNAME "vcruntime")
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
set(LIBCXX_CXX_ABI_LIBNAME "libcxxrt")
|
||||
elseif (NOT LIBCXX_STANDALONE_BUILD OR HAVE_LIBCXXABI)
|
||||
set(LIBCXX_CXX_ABI_LIBNAME "libcxxabi")
|
||||
else()
|
||||
set(LIBCXX_CXX_ABI_LIBNAME "default")
|
||||
endif()
|
||||
if (LIBCXX_TARGETING_MSVC)
|
||||
set(LIBCXX_DEFAULT_ABI_LIBRARY "vcruntime")
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
set(LIBCXX_DEFAULT_ABI_LIBRARY "libcxxrt")
|
||||
else()
|
||||
set(LIBCXX_CXX_ABI_LIBNAME "${LIBCXX_CXX_ABI}")
|
||||
set(LIBCXX_DEFAULT_ABI_LIBRARY "libcxxabi")
|
||||
endif()
|
||||
|
||||
set(LIBCXX_SUPPORTED_ABI_LIBRARIES none libcxxabi system-libcxxabi libcxxrt libstdc++ libsupc++ vcruntime)
|
||||
set(LIBCXX_CXX_ABI "${LIBCXX_DEFAULT_ABI_LIBRARY}" CACHE STRING "Specify C++ ABI library to use. Supported values are ${LIBCXX_SUPPORTED_ABI_LIBRARIES}.")
|
||||
if (NOT "${LIBCXX_CXX_ABI}" IN_LIST LIBCXX_SUPPORTED_ABI_LIBRARIES)
|
||||
message(FATAL_ERROR "Unsupported C++ ABI library: '${LIBCXX_CXX_ABI}'. Supported values are ${LIBCXX_SUPPORTED_ABI_LIBRARIES}.")
|
||||
endif()
|
||||
|
||||
option(LIBCXX_ENABLE_STATIC_ABI_LIBRARY
|
||||
@ -197,11 +228,11 @@ option(LIBCXX_ENABLE_STATIC_ABI_LIBRARY
|
||||
|
||||
cmake_dependent_option(LIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY
|
||||
"Statically link the ABI library to static library" ON
|
||||
"LIBCXX_ENABLE_STATIC_ABI_LIBRARY;LIBCXX_ENABLE_STATIC" OFF)
|
||||
"LIBCXX_ENABLE_STATIC_ABI_LIBRARY" OFF)
|
||||
|
||||
cmake_dependent_option(LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY
|
||||
"Statically link the ABI library to shared library" ON
|
||||
"LIBCXX_ENABLE_STATIC_ABI_LIBRARY;LIBCXX_ENABLE_SHARED" OFF)
|
||||
"LIBCXX_ENABLE_STATIC_ABI_LIBRARY" OFF)
|
||||
|
||||
# Generate and install a linker script inplace of libc++.so. The linker script
|
||||
# will link libc++ to the correct ABI library. This option is on by default
|
||||
@ -210,8 +241,7 @@ cmake_dependent_option(LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY
|
||||
# or is specified to be "none".
|
||||
set(ENABLE_LINKER_SCRIPT_DEFAULT_VALUE OFF)
|
||||
if (LLVM_HAVE_LINK_VERSION_SCRIPT AND NOT LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY
|
||||
AND NOT LIBCXX_CXX_ABI_LIBNAME STREQUAL "none"
|
||||
AND NOT LIBCXX_CXX_ABI_LIBNAME STREQUAL "default"
|
||||
AND NOT LIBCXX_CXX_ABI STREQUAL "none"
|
||||
AND Python3_EXECUTABLE
|
||||
AND LIBCXX_ENABLE_SHARED)
|
||||
set(ENABLE_LINKER_SCRIPT_DEFAULT_VALUE ON)
|
||||
@ -222,28 +252,29 @@ option(LIBCXX_ENABLE_ABI_LINKER_SCRIPT
|
||||
${ENABLE_LINKER_SCRIPT_DEFAULT_VALUE})
|
||||
|
||||
option(LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS
|
||||
"Build libc++ with definitions for operator new/delete. This option can
|
||||
be used to disable the definitions when libc++abi is expected to provide
|
||||
them" ON)
|
||||
|
||||
"Build libc++ with definitions for operator new/delete. These are normally
|
||||
defined in libc++abi, but this option can be used to define them in libc++
|
||||
instead. If you define them in libc++, make sure they are NOT defined in
|
||||
libc++abi. Doing otherwise is an ODR violation." OFF)
|
||||
# Build libc++abi with libunwind. We need this option to determine whether to
|
||||
# link with libunwind or libgcc_s while running the test cases.
|
||||
option(LIBCXXABI_USE_LLVM_UNWINDER "Build and use the LLVM unwinder." OFF)
|
||||
|
||||
# Target options --------------------------------------------------------------
|
||||
option(LIBCXX_BUILD_32_BITS "Build 32 bit libc++." ${LLVM_BUILD_32_BITS})
|
||||
set(LIBCXX_TARGET_TRIPLE "" CACHE STRING "Use alternate target triple.")
|
||||
set(LIBCXX_SYSROOT "" CACHE STRING "Use alternate sysroot.")
|
||||
set(LIBCXX_GCC_TOOLCHAIN "" CACHE STRING "Use alternate GCC toolchain.")
|
||||
option(LIBCXX_BUILD_32_BITS "Build 32 bit multilib libc++. This option is not supported anymore when building the runtimes. Please specify a full triple instead." ${LLVM_BUILD_32_BITS})
|
||||
if (LIBCXX_BUILD_32_BITS)
|
||||
message(FATAL_ERROR "LIBCXX_BUILD_32_BITS is not supported anymore when building the runtimes, please specify a full triple instead.")
|
||||
endif()
|
||||
|
||||
# TODO: Remove this after branching for LLVM 15
|
||||
if(LIBCXX_SYSROOT OR LIBCXX_TARGET_TRIPLE OR LIBCXX_GCC_TOOLCHAIN)
|
||||
message(WARNING "LIBCXX_SYSROOT, LIBCXX_TARGET_TRIPLE and LIBCXX_GCC_TOOLCHAIN are not supported anymore, please use the native CMake equivalents instead")
|
||||
endif()
|
||||
|
||||
# Feature options -------------------------------------------------------------
|
||||
option(LIBCXX_ENABLE_EXCEPTIONS "Use exceptions." ON)
|
||||
option(LIBCXX_ENABLE_RTTI "Use run time type information." ON)
|
||||
option(LIBCXX_ENABLE_GLOBAL_FILESYSTEM_NAMESPACE "Build libc++ with support for the global filesystem namespace." ON)
|
||||
option(LIBCXX_ENABLE_STDIN "Build libc++ with support for stdin/std::cin." ON)
|
||||
option(LIBCXX_ENABLE_STDOUT "Build libc++ with support for stdout/std::cout." ON)
|
||||
option(LIBCXX_ENABLE_THREADS "Build libc++ with support for threads." ON)
|
||||
option(LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS "Build libc++ with support for thread-unsafe C functions" ON)
|
||||
option(LIBCXX_ENABLE_MONOTONIC_CLOCK
|
||||
"Build libc++ with support for a monotonic clock.
|
||||
This option may only be set to OFF when LIBCXX_ENABLE_THREADS=OFF." ON)
|
||||
@ -268,23 +299,6 @@ option(LIBCXX_GENERATE_COVERAGE "Enable generating code coverage." OFF)
|
||||
set(LIBCXX_COVERAGE_LIBRARY "" CACHE STRING
|
||||
"The Profile-rt library used to build with code coverage")
|
||||
|
||||
# Don't allow a user to accidentally overwrite the system libc++ installation on Darwin.
|
||||
# If the user specifies -DCMAKE_INSTALL_PREFIX=/usr the install rules for libc++
|
||||
# will not be generated and a warning will be issued.
|
||||
option(LIBCXX_OVERRIDE_DARWIN_INSTALL "Enable overwriting darwins libc++ installation." OFF)
|
||||
mark_as_advanced(LIBCXX_OVERRIDE_DARWIN_INSTALL) # Don't show this option by default.
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT LIBCXX_OVERRIDE_DARWIN_INSTALL)
|
||||
if ("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr")
|
||||
message(WARNING "Disabling libc++ install rules because installation would "
|
||||
"overwrite the systems installation. Configure with "
|
||||
"-DLIBCXX_OVERRIDE_DARWIN_INSTALL=ON to suppress this behaviour.")
|
||||
mark_as_advanced(CLEAR LIBCXX_OVERRIDE_DARWIN_INSTALL) # Show the override option.
|
||||
set(LIBCXX_INSTALL_HEADERS OFF)
|
||||
set(LIBCXX_INSTALL_LIBRARY OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LIBCXX_CONFIGURE_IDE_DEFAULT OFF)
|
||||
if (XCODE OR MSVC_IDE)
|
||||
set(LIBCXX_CONFIGURE_IDE_DEFAULT ON)
|
||||
@ -292,8 +306,12 @@ endif()
|
||||
option(LIBCXX_CONFIGURE_IDE "Configure libcxx for use within an IDE"
|
||||
${LIBCXX_CONFIGURE_IDE_DEFAULT})
|
||||
|
||||
set(LIBCXX_HERMETIC_STATIC_LIBRARY_DEFAULT OFF)
|
||||
if (WIN32)
|
||||
set(LIBCXX_HERMETIC_STATIC_LIBRARY_DEFAULT ON)
|
||||
endif()
|
||||
option(LIBCXX_HERMETIC_STATIC_LIBRARY
|
||||
"Do not export any symbols from the static library." OFF)
|
||||
"Do not export any symbols from the static library." ${LIBCXX_HERMETIC_STATIC_LIBRARY_DEFAULT})
|
||||
|
||||
#===============================================================================
|
||||
# Check option configurations
|
||||
@ -358,16 +376,6 @@ if (LLVM_USE_SANITIZER AND LIBCXX_GENERATE_COVERAGE)
|
||||
message(FATAL_ERROR "LLVM_USE_SANITIZER cannot be used with LIBCXX_GENERATE_COVERAGE")
|
||||
endif()
|
||||
|
||||
# Set LIBCXX_BUILD_32_BITS to (LIBCXX_BUILD_32_BITS OR LLVM_BUILD_32_BITS)
|
||||
# and check that we can build with 32 bits if requested.
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32)
|
||||
if (LIBCXX_BUILD_32_BITS AND NOT LLVM_BUILD_32_BITS) # Don't duplicate the output from LLVM
|
||||
message(STATUS "Building 32 bits executables and libraries.")
|
||||
endif()
|
||||
elseif(LIBCXX_BUILD_32_BITS)
|
||||
message(FATAL_ERROR "LIBCXX_BUILD_32_BITS=ON is not supported on this platform.")
|
||||
endif()
|
||||
|
||||
# Warn users that LIBCXX_ENABLE_STATIC_ABI_LIBRARY is an experimental option.
|
||||
if (LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
|
||||
message(WARNING "LIBCXX_ENABLE_STATIC_ABI_LIBRARY is an experimental option")
|
||||
@ -391,11 +399,6 @@ if (LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY AND LIBCXX_ENABLE_ABI_LINKER_SC
|
||||
LIBCXX_ENABLE_ABI_LINKER_SCRIPT")
|
||||
endif()
|
||||
|
||||
if (LIBCXX_HAS_MUSL_LIBC AND NOT LIBCXX_INSTALL_SUPPORT_HEADERS)
|
||||
message(FATAL_ERROR "LIBCXX_INSTALL_SUPPORT_HEADERS can not be turned off"
|
||||
"when building for Musl with LIBCXX_HAS_MUSL_LIBC.")
|
||||
endif()
|
||||
|
||||
if (LIBCXX_ABI_FORCE_ITANIUM AND LIBCXX_ABI_FORCE_MICROSOFT)
|
||||
message(FATAL_ERROR "Only one of LIBCXX_ABI_FORCE_ITANIUM and LIBCXX_ABI_FORCE_MICROSOFT can be specified.")
|
||||
endif ()
|
||||
@ -404,36 +407,43 @@ endif ()
|
||||
# Configure System
|
||||
#===============================================================================
|
||||
|
||||
set(LIBCXX_COMPILER ${CMAKE_CXX_COMPILER})
|
||||
set(LIBCXX_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(LIBCXX_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(LIBCXX_BINARY_INCLUDE_DIR "${LIBCXX_BINARY_DIR}/include/c++build")
|
||||
# TODO: Projects that depend on libc++ should use LIBCXX_GENERATED_INCLUDE_DIR
|
||||
# instead of hard-coding include/c++/v1.
|
||||
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION
|
||||
${PACKAGE_VERSION})
|
||||
set(LIBCXX_INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}/c++/v1" CACHE PATH
|
||||
"Path where target-agnostic libc++ headers should be installed.")
|
||||
set(LIBCXX_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE PATH
|
||||
"Path where built libc++ runtime libraries should be installed.")
|
||||
|
||||
if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
|
||||
set(LIBCXX_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++)
|
||||
set(LIBCXX_HEADER_DIR ${LLVM_BINARY_DIR})
|
||||
set(LIBCXX_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++)
|
||||
set(LIBCXX_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE})
|
||||
set(LIBCXX_GENERATED_INCLUDE_DIR "${LLVM_BINARY_DIR}/include/c++/v1")
|
||||
set(LIBCXX_GENERATED_INCLUDE_TARGET_DIR "${LLVM_BINARY_DIR}/include/${LLVM_DEFAULT_TARGET_TRIPLE}/c++/v1")
|
||||
set(LIBCXX_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE PATH
|
||||
"Path where built libc++ libraries should be installed.")
|
||||
set(LIBCXX_INSTALL_INCLUDE_TARGET_DIR "${CMAKE_INSTALL_INCLUDEDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++/v1" CACHE PATH
|
||||
"Path where target-specific libc++ headers should be installed.")
|
||||
if(LIBCXX_LIBDIR_SUBDIR)
|
||||
string(APPEND LIBCXX_LIBRARY_DIR /${LIBCXX_LIBDIR_SUBDIR})
|
||||
string(APPEND LIBCXX_INSTALL_LIBRARY_DIR /${LIBCXX_LIBDIR_SUBDIR})
|
||||
endif()
|
||||
elseif(LLVM_LIBRARY_OUTPUT_INTDIR)
|
||||
set(LIBCXX_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
|
||||
set(LIBCXX_HEADER_DIR ${LLVM_BINARY_DIR})
|
||||
set(LIBCXX_INSTALL_LIBRARY_DIR lib${LIBCXX_LIBDIR_SUFFIX})
|
||||
else()
|
||||
set(LIBCXX_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXX_LIBDIR_SUFFIX})
|
||||
set(LIBCXX_INSTALL_LIBRARY_DIR lib${LIBCXX_LIBDIR_SUFFIX})
|
||||
if(LLVM_LIBRARY_OUTPUT_INTDIR)
|
||||
set(LIBCXX_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
|
||||
set(LIBCXX_GENERATED_INCLUDE_DIR "${LLVM_BINARY_DIR}/include/c++/v1")
|
||||
else()
|
||||
set(LIBCXX_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXX_LIBDIR_SUFFIX})
|
||||
set(LIBCXX_GENERATED_INCLUDE_DIR "${CMAKE_BINARY_DIR}/include/c++/v1")
|
||||
endif()
|
||||
set(LIBCXX_GENERATED_INCLUDE_TARGET_DIR "${LIBCXX_GENERATED_INCLUDE_DIR}")
|
||||
set(LIBCXX_INSTALL_LIBRARY_DIR lib${LIBCXX_LIBDIR_SUFFIX} CACHE PATH
|
||||
"Path where built libc++ libraries should be installed.")
|
||||
set(LIBCXX_INSTALL_INCLUDE_TARGET_DIR "${LIBCXX_INSTALL_INCLUDE_DIR}" CACHE PATH
|
||||
"Path where target-specific libc++ headers should be installed.")
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY "${LIBCXX_BINARY_INCLUDE_DIR}")
|
||||
|
||||
set(LIBCXX_INSTALL_PREFIX "" CACHE STRING "Define libc++ destination prefix.")
|
||||
set(LIBCXX_INSTALL_HEADER_PREFIX "" CACHE STRING "Define libc++ header destination prefix.")
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXX_LIBRARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXX_LIBRARY_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBCXX_LIBRARY_DIR})
|
||||
@ -455,26 +465,13 @@ include(HandleLibcxxFlags)
|
||||
# These flags get added to CMAKE_CXX_FLAGS and CMAKE_C_FLAGS so that
|
||||
# 'config-ix' use them during feature checks. It also adds them to both
|
||||
# 'LIBCXX_COMPILE_FLAGS' and 'LIBCXX_LINK_FLAGS'
|
||||
add_target_flags_if(LIBCXX_BUILD_32_BITS "-m32")
|
||||
|
||||
if(LIBCXX_TARGET_TRIPLE)
|
||||
add_target_flags("--target=${LIBCXX_TARGET_TRIPLE}")
|
||||
elseif(CMAKE_CXX_COMPILER_TARGET)
|
||||
set(LIBCXX_TARGET_TRIPLE "${CMAKE_CXX_COMPILER_TARGET}")
|
||||
endif()
|
||||
if(LIBCXX_SYSROOT)
|
||||
add_target_flags("--sysroot=${LIBCXX_SYSROOT}")
|
||||
elseif(CMAKE_SYSROOT)
|
||||
set(LIBCXX_SYSROOT "${CMAKE_SYSROOT}")
|
||||
endif()
|
||||
if(LIBCXX_GCC_TOOLCHAIN)
|
||||
add_target_flags("--gcc-toolchain=${LIBCXX_GCC_TOOLCHAIN}")
|
||||
elseif(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN)
|
||||
set(LIBCXX_GCC_TOOLCHAIN "${CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN}")
|
||||
if(ZOS)
|
||||
add_target_flags_if_supported("-fzos-le-char-mode=ebcdic")
|
||||
endif()
|
||||
|
||||
if(LIBCXX_TARGET_TRIPLE)
|
||||
set(TARGET_TRIPLE "${LIBCXX_TARGET_TRIPLE}")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "AIX")
|
||||
add_target_flags_if_supported("-mdefault-visibility-export-mapping=explicit")
|
||||
set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
|
||||
endif()
|
||||
|
||||
# Configure compiler.
|
||||
@ -499,12 +496,11 @@ endif()
|
||||
|
||||
include(HandleLibCXXABI) # Setup the ABI library flags
|
||||
|
||||
if (NOT LIBCXX_STANDALONE_BUILD)
|
||||
# Remove flags that may have snuck in.
|
||||
remove_flags(-DNDEBUG -UNDEBUG -D_DEBUG
|
||||
-lc++abi)
|
||||
endif()
|
||||
remove_flags(-stdlib=libc++ -stdlib=libstdc++)
|
||||
# Remove flags that may have snuck in.
|
||||
# TODO: This shouldn't be necessary anymore since we don't support the Project
|
||||
# build anymore, so the rest of LLVM can't pollute our flags.
|
||||
remove_flags(-DNDEBUG -UNDEBUG -D_DEBUG -lc++abi)
|
||||
remove_flags(--stdlib=libc++ -stdlib=libc++ --stdlib=libstdc++ -stdlib=libstdc++)
|
||||
|
||||
# FIXME: Remove all debug flags and flags that change which Windows
|
||||
# default libraries are linked. Currently we only support linking the
|
||||
@ -519,13 +515,22 @@ remove_flags(-Wno-pedantic -pedantic-errors -pedantic)
|
||||
# Required flags ==============================================================
|
||||
function(cxx_add_basic_build_flags target)
|
||||
|
||||
# Require C++14 for all targets. C++14 is needed to ensure constant
|
||||
# initialization for certain globals (ex global memory resources).
|
||||
# Require C++20 for all targets. C++17 is needed to use aligned allocation
|
||||
# in the dylib. C++20 is needed to use char8_t.
|
||||
set_target_properties(${target} PROPERTIES
|
||||
CXX_STANDARD 14
|
||||
CXX_STANDARD 20
|
||||
CXX_STANDARD_REQUIRED YES
|
||||
CXX_EXTENSIONS NO)
|
||||
|
||||
# When building the dylib, don't warn for unavailable aligned allocation
|
||||
# functions based on the deployment target -- they are always available
|
||||
# because they are provided by the dylib itself with the excepton of z/OS.
|
||||
if (ZOS)
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE -fno-aligned-allocation)
|
||||
else()
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE -faligned-allocation)
|
||||
endif()
|
||||
|
||||
# On all systems the system c++ standard library headers need to be excluded.
|
||||
# MSVC only has -X, which disables all default includes; including the crt.
|
||||
# Thus, we do nothing and hope we don't accidentally include any of the C++
|
||||
@ -558,7 +563,7 @@ function(cxx_add_basic_build_flags target)
|
||||
target_compile_definitions(${target} PRIVATE -D_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_HAS_COMMENT_LIB_PRAGMA)
|
||||
if (C_SUPPORTS_COMMENT_LIB_PRAGMA)
|
||||
if (LIBCXX_HAS_PTHREAD_LIB)
|
||||
target_compile_definitions(${target} PRIVATE -D_LIBCPP_LINK_PTHREAD_LIB)
|
||||
endif()
|
||||
@ -571,14 +576,22 @@ endfunction()
|
||||
# Warning flags ===============================================================
|
||||
function(cxx_add_warning_flags target)
|
||||
target_compile_definitions(${target} PUBLIC -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE -Wall -Wextra -W -Wwrite-strings
|
||||
if (MSVC)
|
||||
# -W4 is the cl.exe/clang-cl equivalent of -Wall. (In cl.exe and clang-cl,
|
||||
# -Wall is equivalent to -Weverything in GCC style compiler drivers.)
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE -W4)
|
||||
else()
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE -Wall)
|
||||
endif()
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE -Wextra -W -Wwrite-strings
|
||||
-Wno-unused-parameter -Wno-long-long
|
||||
-Werror=return-type -Wextra-semi)
|
||||
-Werror=return-type -Wextra-semi -Wundef
|
||||
-Wformat-nonliteral)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE
|
||||
-Wno-user-defined-literals
|
||||
-Wno-covered-switch-default
|
||||
-Wno-ignored-attributes # FIXME: Caused by _LIBCPP_NODEBUG_TYPE not being supported on older clangs
|
||||
-Wno-suggest-override
|
||||
)
|
||||
if (LIBCXX_TARGETING_CLANG_CL)
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE
|
||||
@ -600,9 +613,11 @@ function(cxx_add_warning_flags target)
|
||||
endif()
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE
|
||||
-Wno-attributes
|
||||
-Wno-literal-suffix
|
||||
-Wno-c++14-compat
|
||||
-Wno-noexcept-type)
|
||||
-Wno-noexcept-type
|
||||
-Wno-suggest-override)
|
||||
endif()
|
||||
if (LIBCXX_ENABLE_WERROR)
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE -Werror)
|
||||
@ -615,9 +630,6 @@ function(cxx_add_warning_flags target)
|
||||
if (LIBCXX_ENABLE_PEDANTIC)
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE -pedantic)
|
||||
endif()
|
||||
if (LIBCXX_DISABLE_MACRO_CONFLICT_WARNINGS)
|
||||
target_compile_definitions(${target} PRIVATE -D_LIBCPP_DISABLE_MACRO_CONFLICT_WARNINGS)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Exception flags =============================================================
|
||||
@ -627,7 +639,6 @@ function(cxx_add_exception_flags target)
|
||||
# functions never throw a C++ exception.
|
||||
target_add_compile_flags_if_supported(${target} PUBLIC -EHsc)
|
||||
else()
|
||||
target_compile_definitions(${target} PUBLIC -D_LIBCPP_NO_EXCEPTIONS)
|
||||
target_add_compile_flags_if_supported(${target} PUBLIC -EHs- -EHa-)
|
||||
target_add_compile_flags_if_supported(${target} PUBLIC -fno-exceptions)
|
||||
endif()
|
||||
@ -636,7 +647,6 @@ endfunction()
|
||||
# RTTI flags ==================================================================
|
||||
function(cxx_add_rtti_flags target)
|
||||
if (NOT LIBCXX_ENABLE_RTTI)
|
||||
target_compile_definitions(${target} PUBLIC -D_LIBCPP_NO_RTTI)
|
||||
target_add_compile_flags_if_supported(${target} PUBLIC -GR-)
|
||||
target_add_compile_flags_if_supported(${target} PUBLIC -fno-rtti)
|
||||
endif()
|
||||
@ -654,9 +664,6 @@ if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY AND LIBCXX_ENABLE_SHARED)
|
||||
endif()
|
||||
|
||||
# Assertion flags =============================================================
|
||||
define_if(LIBCXX_ENABLE_ASSERTIONS -UNDEBUG)
|
||||
define_if_not(LIBCXX_ENABLE_ASSERTIONS -DNDEBUG)
|
||||
define_if(LIBCXX_ENABLE_ASSERTIONS -D_LIBCPP_DEBUG=0)
|
||||
define_if(LIBCXX_DEBUG_BUILD -D_DEBUG)
|
||||
if (LIBCXX_ENABLE_ASSERTIONS AND NOT LIBCXX_DEBUG_BUILD)
|
||||
# MSVC doesn't like _DEBUG on release builds. See PR 4379.
|
||||
@ -715,22 +722,30 @@ function(get_sanitizer_flags OUT_VAR USE_SANITIZER)
|
||||
set(${OUT_VAR} "${SANITIZER_FLAGS}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Configure for sanitizers. If LIBCXX_STANDALONE_BUILD then we have to do
|
||||
# the flag translation ourselves. Othewise LLVM's CMakeList.txt will handle it.
|
||||
if (LIBCXX_STANDALONE_BUILD)
|
||||
set(LLVM_USE_SANITIZER "" CACHE STRING
|
||||
"Define the sanitizer used to build the library and tests")
|
||||
endif()
|
||||
get_sanitizer_flags(SANITIZER_FLAGS "${LLVM_USE_SANITIZER}")
|
||||
if (LIBCXX_STANDALONE_BUILD AND SANITIZER_FLAGS)
|
||||
add_flags(${SANITIZER_FLAGS})
|
||||
endif()
|
||||
|
||||
# Link system libraries =======================================================
|
||||
function(cxx_link_system_libraries target)
|
||||
target_add_link_flags_if_supported(${target} PRIVATE "-nodefaultlibs")
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE "/Zl")
|
||||
target_add_link_flags_if_supported(${target} PRIVATE "/nodefaultlib")
|
||||
|
||||
# In order to remove just libc++ from the link step
|
||||
# we need to use -nostdlib++ whenever it is supported.
|
||||
# Unfortunately this cannot be used universally because for example g++ supports
|
||||
# only -nodefaultlibs in which case all libraries will be removed and
|
||||
# all libraries but c++ have to be added in manually.
|
||||
if (CXX_SUPPORTS_NOSTDLIBXX_FLAG)
|
||||
target_add_link_flags_if_supported(${target} PRIVATE "-nostdlib++")
|
||||
else()
|
||||
target_add_link_flags_if_supported(${target} PRIVATE "-nodefaultlibs")
|
||||
target_add_compile_flags_if_supported(${target} PRIVATE "/Zl")
|
||||
target_add_link_flags_if_supported(${target} PRIVATE "/nodefaultlib")
|
||||
endif()
|
||||
|
||||
if (CXX_SUPPORTS_UNWINDLIB_EQ_NONE_FLAG AND LIBCXXABI_USE_LLVM_UNWINDER)
|
||||
# If we're linking directly against the libunwind that we're building
|
||||
# in the same invocation, don't try to link in the toolchain's
|
||||
# default libunwind (which may be missing still).
|
||||
target_add_link_flags_if_supported(${target} PRIVATE "--unwindlib=none")
|
||||
endif()
|
||||
|
||||
if (LIBCXX_HAS_SYSTEM_LIB)
|
||||
target_link_libraries(${target} PRIVATE System)
|
||||
@ -757,11 +772,13 @@ function(cxx_link_system_libraries target)
|
||||
if (LIBCXX_BUILTINS_LIBRARY)
|
||||
target_link_libraries(${target} PRIVATE "${LIBCXX_BUILTINS_LIBRARY}")
|
||||
endif()
|
||||
elseif (LIBCXX_HAS_GCC_LIB)
|
||||
target_link_libraries(${target} PRIVATE gcc)
|
||||
elseif (LIBCXX_HAS_GCC_S_LIB)
|
||||
target_link_libraries(${target} PRIVATE gcc_s)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB)
|
||||
if (LIBCXX_HAS_ATOMIC_LIB)
|
||||
target_link_libraries(${target} PRIVATE atomic)
|
||||
endif()
|
||||
|
||||
@ -816,32 +833,15 @@ function(cxx_add_windows_flags target)
|
||||
endfunction()
|
||||
|
||||
# Configuration file flags =====================================================
|
||||
if (NOT LIBCXX_ABI_VERSION EQUAL 1)
|
||||
config_define(${LIBCXX_ABI_VERSION} _LIBCPP_ABI_VERSION)
|
||||
endif()
|
||||
if (NOT LIBCXX_ABI_NAMESPACE STREQUAL "")
|
||||
if (NOT LIBCXX_ABI_NAMESPACE MATCHES "__.*")
|
||||
message(FATAL_ERROR "LIBCXX_ABI_NAMESPACE must be a reserved identifier.")
|
||||
endif()
|
||||
if (LIBCXX_ABI_NAMESPACE MATCHES "__[0-9]+$")
|
||||
message(FATAL_ERROR "LIBCXX_ABI_NAMESPACE '${LIBCXX_ABI_NAMESPACE}' is reserved for use by libc++.")
|
||||
endif()
|
||||
config_define(${LIBCXX_ABI_NAMESPACE} _LIBCPP_ABI_NAMESPACE)
|
||||
endif()
|
||||
config_define_if(LIBCXX_ABI_UNSTABLE _LIBCPP_ABI_UNSTABLE)
|
||||
config_define(${LIBCXX_ABI_VERSION} _LIBCPP_ABI_VERSION)
|
||||
config_define(${LIBCXX_ABI_NAMESPACE} _LIBCPP_ABI_NAMESPACE)
|
||||
config_define_if(LIBCXX_ABI_FORCE_ITANIUM _LIBCPP_ABI_FORCE_ITANIUM)
|
||||
config_define_if(LIBCXX_ABI_FORCE_MICROSOFT _LIBCPP_ABI_FORCE_MICROSOFT)
|
||||
config_define_if(LIBCXX_HIDE_FROM_ABI_PER_TU_BY_DEFAULT _LIBCPP_HIDE_FROM_ABI_PER_TU_BY_DEFAULT)
|
||||
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)
|
||||
config_define_if_not(LIBCXX_ENABLE_THREADS _LIBCPP_HAS_NO_THREADS)
|
||||
config_define_if_not(LIBCXX_ENABLE_MONOTONIC_CLOCK _LIBCPP_HAS_NO_MONOTONIC_CLOCK)
|
||||
config_define_if_not(LIBCXX_ENABLE_THREAD_UNSAFE_C_FUNCTIONS _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS)
|
||||
if (NOT LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT STREQUAL "")
|
||||
config_define("${LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT}" _LIBCPP_HAS_MERGED_TYPEINFO_NAMES_DEFAULT)
|
||||
if (NOT LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION STREQUAL "default")
|
||||
config_define("${LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION}" _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION)
|
||||
endif()
|
||||
|
||||
config_define_if(LIBCXX_HAS_PTHREAD_API _LIBCPP_HAS_THREAD_API_PTHREAD)
|
||||
config_define_if(LIBCXX_HAS_EXTERNAL_THREAD_API _LIBCPP_HAS_THREAD_API_EXTERNAL)
|
||||
config_define_if(LIBCXX_HAS_WIN32_THREAD_API _LIBCPP_HAS_THREAD_API_WIN32)
|
||||
@ -849,6 +849,18 @@ config_define_if(LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY _LIBCPP_HAS_THREAD_LIBRARY
|
||||
config_define_if(LIBCXX_HAS_MUSL_LIBC _LIBCPP_HAS_MUSL_LIBC)
|
||||
config_define_if(LIBCXX_NO_VCRUNTIME _LIBCPP_NO_VCRUNTIME)
|
||||
config_define_if(LIBCXX_ENABLE_PARALLEL_ALGORITHMS _LIBCPP_HAS_PARALLEL_ALGORITHMS)
|
||||
config_define_if_not(LIBCXX_ENABLE_FILESYSTEM _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY)
|
||||
config_define_if_not(LIBCXX_ENABLE_RANDOM_DEVICE _LIBCPP_HAS_NO_RANDOM_DEVICE)
|
||||
config_define_if_not(LIBCXX_ENABLE_LOCALIZATION _LIBCPP_HAS_NO_LOCALIZATION)
|
||||
config_define_if_not(LIBCXX_ENABLE_UNICODE _LIBCPP_HAS_NO_UNICODE)
|
||||
config_define_if_not(LIBCXX_ENABLE_WIDE_CHARACTERS _LIBCPP_HAS_NO_WIDE_CHARACTERS)
|
||||
config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
|
||||
config_define_if(LIBCXX_ENABLE_DEBUG_MODE _LIBCPP_ENABLE_DEBUG_MODE)
|
||||
if (LIBCXX_ENABLE_ASSERTIONS)
|
||||
config_define(1 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT)
|
||||
else()
|
||||
config_define(0 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_ABI_DEFINES)
|
||||
set(abi_defines)
|
||||
@ -862,6 +874,17 @@ if (LIBCXX_ABI_DEFINES)
|
||||
config_define(${abi_defines} _LIBCPP_ABI_DEFINES)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_EXTRA_SITE_DEFINES)
|
||||
set(extra_site_defines)
|
||||
foreach (extra_site_define ${LIBCXX_EXTRA_SITE_DEFINES})
|
||||
# Allow defines such as DEFINE=VAL, transformed into "#define DEFINE VAL".
|
||||
string(REPLACE "=" " " extra_site_define "${extra_site_define}")
|
||||
list(APPEND extra_site_defines "#define ${extra_site_define}")
|
||||
endforeach()
|
||||
string(REPLACE ";" "\n" extra_site_defines "${extra_site_defines}")
|
||||
config_define(${extra_site_defines} _LIBCPP_EXTRA_SITE_DEFINES)
|
||||
endif()
|
||||
|
||||
# By default libc++ on Windows expects to use a shared library, which requires
|
||||
# the headers to use DLL import/export semantics. However when building a
|
||||
# static library only we modify the headers to disable DLL import/export.
|
||||
@ -870,32 +893,17 @@ if (DEFINED WIN32 AND LIBCXX_ENABLE_STATIC AND NOT LIBCXX_ENABLE_SHARED)
|
||||
config_define(ON _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||
endif()
|
||||
|
||||
set(site_config_path "${LIBCXX_BINARY_DIR}/__config_site")
|
||||
if (LIBCXX_NEEDS_SITE_CONFIG)
|
||||
configure_file("include/__config_site.in"
|
||||
"${site_config_path}"
|
||||
@ONLY)
|
||||
elseif(EXISTS "${site_config_path}")
|
||||
message(STATUS "Removing stale site configuration ${site_config_path}")
|
||||
file(REMOVE "${site_config_path}")
|
||||
if (WIN32 AND LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
|
||||
# If linking libcxxabi statically into libcxx, skip the dllimport attributes
|
||||
# on symbols we refer to from libcxxabi.
|
||||
add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||
endif()
|
||||
|
||||
function(cxx_add_config_site target)
|
||||
if (LIBCXX_NEEDS_SITE_CONFIG)
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC")
|
||||
target_compile_options(${target} PUBLIC /FI "${site_config_path}")
|
||||
else()
|
||||
target_compile_options(${target} PUBLIC -include "${site_config_path}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Setup all common build flags =================================================
|
||||
function(cxx_add_common_build_flags target)
|
||||
cxx_add_basic_build_flags(${target})
|
||||
cxx_add_warning_flags(${target})
|
||||
cxx_add_windows_flags(${target})
|
||||
cxx_add_config_site(${target})
|
||||
cxx_add_exception_flags(${target})
|
||||
cxx_add_rtti_flags(${target})
|
||||
cxx_add_module_flags(${target})
|
||||
@ -905,15 +913,11 @@ endfunction()
|
||||
#===============================================================================
|
||||
# Setup Source Code And Tests
|
||||
#===============================================================================
|
||||
include_directories(include)
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(utils)
|
||||
|
||||
set(LIBCXX_TEST_DEPS "")
|
||||
|
||||
if (LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
|
||||
list(APPEND LIBCXX_TEST_DEPS cxx_experimental)
|
||||
endif()
|
||||
set(LIBCXX_TEST_DEPS "cxx_experimental")
|
||||
|
||||
if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY)
|
||||
list(APPEND LIBCXX_TEST_DEPS cxx_external_threads)
|
||||
@ -923,30 +927,11 @@ if (LIBCXX_INCLUDE_BENCHMARKS)
|
||||
add_subdirectory(benchmarks)
|
||||
endif()
|
||||
|
||||
# Create the lit.site.cfg file even when LIBCXX_INCLUDE_TESTS is OFF or
|
||||
# LLVM_FOUND is OFF. This allows users to run the tests manually using
|
||||
# LIT without requiring a full LLVM checkout.
|
||||
#
|
||||
# However, since some submission systems strip test/ subdirectories, check for
|
||||
# it before adding it.
|
||||
|
||||
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/test")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
if (LIBCXX_INCLUDE_TESTS)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(lib/abi)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_STANDALONE_BUILD AND EXISTS "${LLVM_MAIN_SRC_DIR}/utils/llvm-lit")
|
||||
include(AddLLVM) # for get_llvm_lit_path
|
||||
# Make sure the llvm-lit script is generated into the bin directory, and do
|
||||
# it after adding all tests, since the generated script will only work
|
||||
# correctly discovered tests against test locations from the source tree that
|
||||
# have already been discovered.
|
||||
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit
|
||||
${CMAKE_CURRENT_BINARY_DIR}/llvm-lit)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_INCLUDE_DOCS)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
49
CREDITS.TXT
49
CREDITS.TXT
@ -12,6 +12,13 @@ N: Saleem Abdulrasool
|
||||
E: compnerd@compnerd.org
|
||||
D: Minor patches and Linux fixes.
|
||||
|
||||
N: Ulf Adams
|
||||
D: Invented the Ryu and Ryu Printf algorithms used in floating-point to_chars, and wrote the initial code.
|
||||
|
||||
N: Muiez Ahmed
|
||||
E: muiez@ibm.com
|
||||
D: z/OS port.
|
||||
|
||||
N: Dan Albert
|
||||
E: danalbert@google.com
|
||||
D: Android support and test runner improvements.
|
||||
@ -24,9 +31,8 @@ N: Holger Arnold
|
||||
E: holgerar@gmail.com
|
||||
D: Minor fix.
|
||||
|
||||
N: Ruben Van Boxem
|
||||
E: vanboxem dot ruben at gmail dot com
|
||||
D: Initial Windows patches.
|
||||
N: Jorg Brown
|
||||
D: Ported floating-point to_chars from MSVC to libc++.
|
||||
|
||||
N: David Chisnall
|
||||
E: theraven at theravensnest dot org
|
||||
@ -41,6 +47,10 @@ N: Jonathan B Coe
|
||||
E: jbcoe@me.com
|
||||
D: Implementation of propagate_const.
|
||||
|
||||
N: Matthew Dempsky
|
||||
E: matthew@dempsky.org
|
||||
D: Minor patches and bug fixes.
|
||||
|
||||
N: Christopher Di Bella
|
||||
E: cjdb@google.com
|
||||
E: cjdb.ns@gmail.com
|
||||
@ -58,10 +68,6 @@ N: Bill Fisher
|
||||
E: william.w.fisher@gmail.com
|
||||
D: Regex bug fixes.
|
||||
|
||||
N: Matthew Dempsky
|
||||
E: matthew@dempsky.org
|
||||
D: Minor patches and bug fixes.
|
||||
|
||||
N: Google Inc.
|
||||
D: Copyright owner and contributor of the CityHash algorithm
|
||||
|
||||
@ -81,6 +87,14 @@ N: Argyrios Kyrtzidis
|
||||
E: kyrtzidis@apple.com
|
||||
D: Bug fixes.
|
||||
|
||||
N: Stephan T. Lavavej
|
||||
E: stl@microsoft.com
|
||||
E: stl@nuwen.net
|
||||
D: Implemented floating-point to_chars.
|
||||
|
||||
N: Microsoft Corporation
|
||||
D: Contributed floating-point to_chars.
|
||||
|
||||
N: Bruce Mitchener, Jr.
|
||||
E: bruce.mitchener@gmail.com
|
||||
D: Emscripten-related changes.
|
||||
@ -113,6 +127,10 @@ N: Jon Roelofs
|
||||
E: jroelofS@jroelofs.com
|
||||
D: Remote testing, Newlib port, baremetal/single-threaded support.
|
||||
|
||||
N: Kent Ross
|
||||
E: k@mad.cash
|
||||
D: Patches for operator<=> support
|
||||
|
||||
N: Jonathan Sauer
|
||||
D: Minor patches, mostly related to constexpr
|
||||
|
||||
@ -131,6 +149,10 @@ N: Stephan Tolksdorf
|
||||
E: st@quanttec.com
|
||||
D: Minor <atomic> fix
|
||||
|
||||
N: Ruben Van Boxem
|
||||
E: vanboxem dot ruben at gmail dot com
|
||||
D: Initial Windows patches.
|
||||
|
||||
N: Michael van der Westhuizen
|
||||
E: r1mikey at gmail dot com
|
||||
|
||||
@ -141,6 +163,11 @@ N: Klaas de Vries
|
||||
E: klaas at klaasgaaf dot nl
|
||||
D: Minor bug fix.
|
||||
|
||||
N: Mark de Wever
|
||||
E: koraq at xs4all dot nl
|
||||
D: Format library support.
|
||||
D: Finalized the porting of MSVC's to_chars to libc++.
|
||||
|
||||
N: Zhang Xiongpang
|
||||
E: zhangxiongpang@gmail.com
|
||||
D: Minor patches and bug fixes.
|
||||
@ -149,11 +176,11 @@ N: Xing Xue
|
||||
E: xingxue@ca.ibm.com
|
||||
D: AIX port
|
||||
|
||||
N: Zhihao Yuan
|
||||
E: lichray@gmail.com
|
||||
D: Standard compatibility fixes.
|
||||
|
||||
N: Jeffrey Yasskin
|
||||
E: jyasskin@gmail.com
|
||||
E: jyasskin@google.com
|
||||
D: Linux fixes.
|
||||
|
||||
N: Zhihao Yuan
|
||||
E: lichray@gmail.com
|
||||
D: Standard compatibility fixes.
|
||||
|
29
NOTES.TXT
29
NOTES.TXT
@ -1,29 +0,0 @@
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Notes relating to various libc++ tasks
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
This file contains notes about various libc++ tasks and processes.
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Post-Release TODO
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
These notes contain a list of things that must be done after branching for
|
||||
an LLVM release.
|
||||
|
||||
1. Update _LIBCPP_VERSION in `__config`
|
||||
2. Update the __libcpp_version file.
|
||||
3. Update the version number in `docs/conf.py`
|
||||
4. Create ABI lists for the previous release under `lib/abi`
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Adding a new header TODO
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
These notes contain a list of things that must be done upon adding a new header
|
||||
to libc++.
|
||||
|
||||
1. Add a test under `test/libcxx` that the header defines `_LIBCPP_VERSION`.
|
||||
2. Update `test/libcxx/double_include.sh.cpp` to include the new header.
|
||||
3. Create a submodule in `include/module.modulemap` for the new header.
|
||||
4. Update the include/CMakeLists.txt file to include the new header.
|
@ -2,8 +2,4 @@
|
||||
|
||||
LLVM libc++, specifically for Android, removing exception and RTTI support.
|
||||
|
||||
Source code is extracted from AOSP's `llvm-project` repository:
|
||||
|
||||
```
|
||||
git clone https://android.googlesource.com/toolchain/llvm-project -b ndk-release-r23
|
||||
```
|
||||
Source code is extracted from both the upstrean and AOSP `llvm-project` repository.
|
||||
|
53
TODO.TXT
53
TODO.TXT
@ -2,7 +2,6 @@ This is meant to be a general place to list things that should be done "someday"
|
||||
|
||||
CXX Runtime Library Tasks
|
||||
=========================
|
||||
* Fix that CMake always link to /usr/lib/libc++abi.dylib on OS X.
|
||||
* Look into mirroring libsupc++'s typeinfo vtable layout when libsupc++/libstdc++
|
||||
is used as the runtime library.
|
||||
* Investigate and document interoperability between libc++ and libstdc++ on
|
||||
@ -17,60 +16,8 @@ Test Suite Tasks
|
||||
* Improve the quality and portability of the locale test data.
|
||||
* Convert failure tests to use Clang Verify.
|
||||
|
||||
Filesystem Tasks
|
||||
================
|
||||
* P0492r2 - Implement National body comments for Filesystem
|
||||
* INCOMPLETE - US 25: has_filename() is equivalent to just !empty()
|
||||
* INCOMPLETE - US 31: Everything is defined in terms of one implicit host system
|
||||
* INCOMPLETE - US 32: Meaning of 27.10.2.1 unclear
|
||||
* INCOMPLETE - US 33: Definition of canonical path problematic
|
||||
* INCOMPLETE - US 34: Are there attributes of a file that are not an aspect of the file system?
|
||||
* INCOMPLETE - US 35: What synchronization is required to avoid a file system race?
|
||||
* INCOMPLETE - US 36: Symbolic links themselves are attached to a directory via (hard) links
|
||||
* INCOMPLETE - US 37: The term “redundant current directory (dot) elements” is not defined
|
||||
* INCOMPLETE - US 38: Duplicates §17.3.16
|
||||
* INCOMPLETE - US 39: Remove note: Dot and dot-dot are not directories
|
||||
* INCOMPLETE - US 40: Not all directories have a parent.
|
||||
* INCOMPLETE - US 41: The term “parent directory” for a (non-directory) file is unusual
|
||||
* INCOMPLETE - US 42: Pathname resolution does not always resolve a symlink
|
||||
* INCOMPLETE - US 43: Concerns about encoded character types
|
||||
* INCOMPLETE - US 44: Definition of path in terms of a string requires leaky abstraction
|
||||
* INCOMPLETE - US 45: Generic format portability compromised by unspecified root-name
|
||||
* INCOMPLETE - US 46: filename can be empty so productions for relative-path are redundant
|
||||
* INCOMPLETE - US 47: “.” and “..” already match the name production
|
||||
* INCOMPLETE - US 48: Multiple separators are often meaningful in a root-name
|
||||
* INCOMPLETE - US 49: What does “method of conversion method” mean?
|
||||
* INCOMPLETE - US 50: 27.10.8.1 ¶ 1.4 largely redundant with ¶ 1.3
|
||||
* INCOMPLETE - US 51: Failing to add / when appending empty string prevents useful apps
|
||||
* INCOMPLETE - US 52: remove_filename() postcondition is not by itself a definition
|
||||
* INCOMPLETE - US 53: remove_filename()'s name does not correspond to its behavior
|
||||
* INCOMPLETE - US 54: remove_filename() is broken
|
||||
* INCOMPLETE - US 55: replace_extension()'s use of path as parameter is inappropriate
|
||||
* INCOMPLETE - US 56: Remove replace_extension()'s conditional addition of period
|
||||
* INCOMPLETE - US 57: On Windows, absolute paths will sort in among relative paths
|
||||
* INCOMPLETE - US 58: parent_path() behavior for root paths is useless
|
||||
* INCOMPLETE - US 59: filename() returning path for single path components is bizarre
|
||||
* INCOMPLETE - US 60: path("/foo/").filename()==path(".") is surprising
|
||||
* INCOMPLETE - US 61: Leading dots in filename() should not begin an extension
|
||||
* INCOMPLETE - US 62: It is important that stem()+extension()==filename()
|
||||
* INCOMPLETE - US 63: lexically_normal() inconsistently treats trailing "/" but not "/.." as directory
|
||||
* INCOMPLETE - US 73, CA 2: root-name is effectively implementation defined
|
||||
* INCOMPLETE - US 74, CA 3: The term “pathname” is ambiguous in some contexts
|
||||
* INCOMPLETE - US 75, CA 4: Extra flag in path constructors is needed
|
||||
* INCOMPLETE - US 76, CA 5: root-name definition is over-specified.
|
||||
* INCOMPLETE - US 77, CA 6: operator/ and other appends not useful if arg has root-name
|
||||
* INCOMPLETE - US 78, CA 7: Member absolute() in 27.10.4.1 is overspecified for non-POSIX-like O/S
|
||||
* INCOMPLETE - US 79, CA 8: Some operation functions are overspecified for implementation-defined file types
|
||||
* INCOMPLETE - US 185: Fold error_code and non-error_code signatures into one signature
|
||||
* INCOMPLETE - FI 14: directory_entry comparisons are members
|
||||
* INCOMPLETE - Late 36: permissions() error_code overload should be noexcept
|
||||
* INCOMPLETE - Late 37: permissions() actions should be separate parameter
|
||||
* INCOMPLETE - Late 42: resize_file() Postcondition missing argument
|
||||
|
||||
Misc Tasks
|
||||
==========
|
||||
* Find all sequences of >2 underscores and eradicate them.
|
||||
* run clang-tidy on libc++
|
||||
* Document the "conditionally-supported" bits of libc++
|
||||
* Look at basic_string's move assignment operator, re LWG 2063 and POCMA
|
||||
* Put a static_assert in std::allocator to deny const/volatile types (LWG 2447)
|
||||
|
@ -45,7 +45,7 @@ build_script:
|
||||
#############################################################################
|
||||
- cmake -G "%GENERATOR%" %CMAKE_OPTIONS%
|
||||
"-DCMAKE_BUILD_TYPE=%configuration%"
|
||||
"-DLLVM_PATH=C:\projects\deps\llvm" -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF
|
||||
"-DLLVM_PATH=C:\projects\deps\llvm"
|
||||
-DLLVM_LIT_ARGS="-sv --show-xfail --show-unsupported"
|
||||
%APPVEYOR_BUILD_FOLDER%
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
if (CMAKE_VERSION VERSION_LESS 3.17)
|
||||
message(WARNING "The libc++ benchmarks won't be available because the version of CMake is too old to support them.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(ExternalProject)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
@ -5,29 +10,32 @@ include(CheckCXXCompilerFlag)
|
||||
# Build Google Benchmark for libc++
|
||||
#==============================================================================
|
||||
|
||||
set(CMAKE_FOLDER "${CMAKE_FOLDER}/Benchmarks")
|
||||
|
||||
set(BENCHMARK_LIBCXX_COMPILE_FLAGS
|
||||
-Wno-unused-command-line-argument
|
||||
-nostdinc++
|
||||
-isystem ${LIBCXX_SOURCE_DIR}/include
|
||||
-isystem "${LIBCXX_GENERATED_INCLUDE_DIR}"
|
||||
-L${LIBCXX_LIBRARY_DIR}
|
||||
-Wl,-rpath,${LIBCXX_LIBRARY_DIR}
|
||||
${SANITIZER_FLAGS}
|
||||
)
|
||||
if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
|
||||
list(APPEND BENCHMARK_LIBCXX_COMPILE_FLAGS
|
||||
-isystem "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}")
|
||||
endif()
|
||||
if (DEFINED LIBCXX_CXX_ABI_LIBRARY_PATH)
|
||||
list(APPEND BENCHMARK_LIBCXX_COMPILE_FLAGS
|
||||
-L${LIBCXX_CXX_ABI_LIBRARY_PATH}
|
||||
-Wl,-rpath,${LIBCXX_CXX_ABI_LIBRARY_PATH})
|
||||
endif()
|
||||
if (LIBCXX_NEEDS_SITE_CONFIG)
|
||||
list(APPEND BENCHMARK_LIBCXX_COMPILE_FLAGS -include "${LIBCXX_BINARY_DIR}/__config_site")
|
||||
endif()
|
||||
split_list(BENCHMARK_LIBCXX_COMPILE_FLAGS)
|
||||
|
||||
ExternalProject_Add(google-benchmark-libcxx
|
||||
EXCLUDE_FROM_ALL ON
|
||||
DEPENDS cxx cxx-headers
|
||||
PREFIX benchmark-libcxx
|
||||
SOURCE_DIR ${LIBCXX_SOURCE_DIR}/utils/google-benchmark
|
||||
SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
|
||||
INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/benchmark-libcxx
|
||||
CMAKE_CACHE_ARGS
|
||||
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
|
||||
@ -44,7 +52,7 @@ ExternalProject_Add(google-benchmark-libcxx
|
||||
set(BENCHMARK_NATIVE_TARGET_FLAGS)
|
||||
if (LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN)
|
||||
set(BENCHMARK_NATIVE_TARGET_FLAGS
|
||||
-gcc-toolchain ${LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN})
|
||||
--gcc-toolchain=${LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN})
|
||||
endif()
|
||||
split_list(BENCHMARK_NATIVE_TARGET_FLAGS)
|
||||
|
||||
@ -52,7 +60,7 @@ if (LIBCXX_BENCHMARK_NATIVE_STDLIB)
|
||||
ExternalProject_Add(google-benchmark-native
|
||||
EXCLUDE_FROM_ALL ON
|
||||
PREFIX benchmark-native
|
||||
SOURCE_DIR ${LIBCXX_SOURCE_DIR}/utils/google-benchmark
|
||||
SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
|
||||
INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/benchmark-native
|
||||
CMAKE_CACHE_ARGS
|
||||
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
|
||||
@ -72,77 +80,50 @@ set(BENCHMARK_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(BENCHMARK_LIBCXX_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/benchmark-libcxx)
|
||||
set(BENCHMARK_NATIVE_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/benchmark-native)
|
||||
|
||||
check_flag_supported("-std=c++17")
|
||||
mangle_name("LIBCXX_SUPPORTS_STD_EQ_c++17_FLAG" BENCHMARK_SUPPORTS_STD_CXX17_FLAG)
|
||||
if (${BENCHMARK_SUPPORTS_STD_CXX17_FLAG})
|
||||
set(BENCHMARK_DIALECT_FLAG "-std=c++17")
|
||||
else()
|
||||
# If the compiler doesn't support -std=c++17, attempt to fall back to -std=c++1z while still
|
||||
# requiring C++17 language features.
|
||||
set(BENCHMARK_DIALECT_FLAG "-std=c++1z")
|
||||
endif()
|
||||
|
||||
set(BENCHMARK_TEST_COMPILE_FLAGS
|
||||
${BENCHMARK_DIALECT_FLAG} -O2
|
||||
-fsized-deallocation
|
||||
-I${BENCHMARK_LIBCXX_INSTALL}/include
|
||||
-I${LIBCXX_SOURCE_DIR}/test/support
|
||||
)
|
||||
set(BENCHMARK_TEST_LIBCXX_COMPILE_FLAGS
|
||||
-nostdinc++
|
||||
-isystem ${LIBCXX_SOURCE_DIR}/include
|
||||
${BENCHMARK_TEST_COMPILE_FLAGS}
|
||||
${SANITIZER_FLAGS}
|
||||
-Wno-user-defined-literals
|
||||
)
|
||||
|
||||
set(BENCHMARK_TEST_LIBCXX_LINK_FLAGS
|
||||
-nodefaultlibs
|
||||
-L${BENCHMARK_LIBCXX_INSTALL}/lib/
|
||||
${SANITIZER_FLAGS}
|
||||
)
|
||||
set(BENCHMARK_TEST_NATIVE_COMPILE_FLAGS
|
||||
${BENCHMARK_NATIVE_TARGET_FLAGS}
|
||||
${BENCHMARK_TEST_COMPILE_FLAGS}
|
||||
)
|
||||
set(BENCHMARK_TEST_NATIVE_LINK_FLAGS
|
||||
${BENCHMARK_NATIVE_TARGET_FLAGS}
|
||||
-L${BENCHMARK_NATIVE_INSTALL}/lib
|
||||
)
|
||||
split_list(BENCHMARK_TEST_COMPILE_FLAGS)
|
||||
split_list(BENCHMARK_TEST_LIBCXX_COMPILE_FLAGS)
|
||||
split_list(BENCHMARK_TEST_LIBCXX_LINK_FLAGS)
|
||||
split_list(BENCHMARK_TEST_NATIVE_COMPILE_FLAGS)
|
||||
split_list(BENCHMARK_TEST_NATIVE_LINK_FLAGS)
|
||||
add_library( cxx-benchmarks-flags INTERFACE)
|
||||
target_compile_features( cxx-benchmarks-flags INTERFACE cxx_std_20)
|
||||
target_compile_options( cxx-benchmarks-flags INTERFACE -fsized-deallocation -nostdinc++)
|
||||
target_include_directories(cxx-benchmarks-flags INTERFACE "${LIBCXX_GENERATED_INCLUDE_DIR}"
|
||||
INTERFACE "${BENCHMARK_LIBCXX_INSTALL}/include"
|
||||
INTERFACE "${LIBCXX_SOURCE_DIR}/test/support")
|
||||
|
||||
add_library( cxx-benchmarks-flags-native INTERFACE)
|
||||
target_link_libraries( cxx-benchmarks-flags-native INTERFACE cxx-benchmarks-flags)
|
||||
target_compile_options(cxx-benchmarks-flags-native INTERFACE ${BENCHMARK_NATIVE_TARGET_FLAGS})
|
||||
target_link_options( cxx-benchmarks-flags-native INTERFACE ${BENCHMARK_NATIVE_TARGET_FLAGS} "-L${BENCHMARK_NATIVE_INSTALL}/lib")
|
||||
if (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libstdc++")
|
||||
find_library(LIBSTDCXX_FILESYSTEM_TEST stdc++fs
|
||||
PATHS ${LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN}
|
||||
PATH_SUFFIXES lib lib64
|
||||
DOC "The libstdc++ filesystem library used by the benchmarks"
|
||||
)
|
||||
if (NOT "${LIBSTDCXX_FILESYSTEM_TEST}" STREQUAL "LIBSTDCXX_FILESYSTEM_TEST-NOTFOUND")
|
||||
set(LIBSTDCXX_FILESYSTEM_LIB "stdc++fs")
|
||||
endif()
|
||||
if (LIBSTDCXX_FILESYSTEM_TEST)
|
||||
target_link_libraries(cxx-benchmarks-flags-native INTERFACE -lstdc++fs)
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(cxx-benchmarks-flags-native INTERFACE -lc++fs -lc++experimental)
|
||||
endif()
|
||||
|
||||
add_library( cxx-benchmarks-flags-libcxx INTERFACE)
|
||||
target_link_libraries( cxx-benchmarks-flags-libcxx INTERFACE cxx-benchmarks-flags)
|
||||
target_compile_options(cxx-benchmarks-flags-libcxx INTERFACE ${SANITIZER_FLAGS} -Wno-user-defined-literals -Wno-suggest-override)
|
||||
target_link_options( cxx-benchmarks-flags-libcxx INTERFACE -nodefaultlibs "-L${BENCHMARK_LIBCXX_INSTALL}/lib" ${SANITIZER_FLAGS})
|
||||
|
||||
set(libcxx_benchmark_targets)
|
||||
|
||||
function(add_benchmark_test name source_file)
|
||||
set(libcxx_target ${name}_libcxx)
|
||||
list(APPEND libcxx_benchmark_targets ${libcxx_target})
|
||||
add_executable(${libcxx_target} EXCLUDE_FROM_ALL ${source_file})
|
||||
add_dependencies(${libcxx_target} cxx cxx-headers google-benchmark-libcxx)
|
||||
target_link_libraries(${libcxx_target} PRIVATE cxx-benchmarks-flags-libcxx)
|
||||
add_dependencies(${libcxx_target} cxx google-benchmark-libcxx)
|
||||
add_dependencies(cxx-benchmarks ${libcxx_target})
|
||||
if (LIBCXX_ENABLE_SHARED)
|
||||
target_link_libraries(${libcxx_target} PRIVATE cxx_shared)
|
||||
else()
|
||||
target_link_libraries(${libcxx_target} PRIVATE cxx_static)
|
||||
endif()
|
||||
if (TARGET cxx_experimental)
|
||||
target_link_libraries(${libcxx_target} PRIVATE cxx_experimental)
|
||||
endif()
|
||||
target_link_libraries(${libcxx_target} PRIVATE -lbenchmark)
|
||||
target_link_libraries(${libcxx_target} PRIVATE cxx_experimental benchmark)
|
||||
if (LLVM_USE_SANITIZER)
|
||||
target_link_libraries(${libcxx_target} PRIVATE -ldl)
|
||||
endif()
|
||||
@ -150,24 +131,15 @@ function(add_benchmark_test name source_file)
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "${name}.libcxx.out"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${BENCHMARK_OUTPUT_DIR}"
|
||||
COMPILE_FLAGS "${BENCHMARK_TEST_LIBCXX_COMPILE_FLAGS}"
|
||||
LINK_FLAGS "${BENCHMARK_TEST_LIBCXX_LINK_FLAGS}")
|
||||
CXX_EXTENSIONS NO)
|
||||
cxx_link_system_libraries(${libcxx_target})
|
||||
if (LIBCXX_BENCHMARK_NATIVE_STDLIB)
|
||||
if (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libstdc++" AND NOT DEFINED LIBSTDCXX_FILESYSTEM_LIB
|
||||
AND "${name}" STREQUAL "filesystem")
|
||||
return()
|
||||
endif()
|
||||
set(native_target ${name}_native)
|
||||
add_executable(${native_target} EXCLUDE_FROM_ALL ${source_file})
|
||||
target_link_libraries(${native_target} PRIVATE cxx-benchmarks-flags-native)
|
||||
add_dependencies(${native_target} google-benchmark-native
|
||||
google-benchmark-libcxx)
|
||||
target_link_libraries(${native_target} PRIVATE -lbenchmark)
|
||||
if (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libstdc++")
|
||||
target_link_libraries(${native_target} PRIVATE ${LIBSTDCXX_FILESYSTEM_LIB})
|
||||
elseif (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libc++")
|
||||
target_link_libraries(${native_target} PRIVATE -lc++fs -lc++experimental)
|
||||
endif()
|
||||
if (LIBCXX_HAS_PTHREAD_LIB)
|
||||
target_link_libraries(${native_target} PRIVATE -pthread)
|
||||
endif()
|
||||
@ -176,9 +148,7 @@ function(add_benchmark_test name source_file)
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "${name}.native.out"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${BENCHMARK_OUTPUT_DIR}"
|
||||
INCLUDE_DIRECTORIES ""
|
||||
COMPILE_FLAGS "${BENCHMARK_TEST_NATIVE_COMPILE_FLAGS}"
|
||||
LINK_FLAGS "${BENCHMARK_TEST_NATIVE_LINK_FLAGS}")
|
||||
CXX_EXTENSIONS NO)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@ -186,7 +156,48 @@ endfunction()
|
||||
#==============================================================================
|
||||
# Register Benchmark tests
|
||||
#==============================================================================
|
||||
file(GLOB BENCHMARK_TESTS "*.bench.cpp")
|
||||
set(BENCHMARK_TESTS
|
||||
algorithms.partition_point.bench.cpp
|
||||
algorithms/lower_bound.bench.cpp
|
||||
algorithms/make_heap.bench.cpp
|
||||
algorithms/make_heap_then_sort_heap.bench.cpp
|
||||
algorithms/min_max_element.bench.cpp
|
||||
algorithms/pop_heap.bench.cpp
|
||||
algorithms/push_heap.bench.cpp
|
||||
algorithms/ranges_make_heap.bench.cpp
|
||||
algorithms/ranges_make_heap_then_sort_heap.bench.cpp
|
||||
algorithms/ranges_pop_heap.bench.cpp
|
||||
algorithms/ranges_push_heap.bench.cpp
|
||||
algorithms/ranges_sort.bench.cpp
|
||||
algorithms/ranges_sort_heap.bench.cpp
|
||||
algorithms/ranges_stable_sort.bench.cpp
|
||||
algorithms/sort.bench.cpp
|
||||
algorithms/sort_heap.bench.cpp
|
||||
algorithms/stable_sort.bench.cpp
|
||||
allocation.bench.cpp
|
||||
deque.bench.cpp
|
||||
filesystem.bench.cpp
|
||||
format_to_n.bench.cpp
|
||||
format_to.bench.cpp
|
||||
format.bench.cpp
|
||||
formatted_size.bench.cpp
|
||||
formatter_float.bench.cpp
|
||||
formatter_int.bench.cpp
|
||||
function.bench.cpp
|
||||
map.bench.cpp
|
||||
ordered_set.bench.cpp
|
||||
std_format_spec_string_unicode.bench.cpp
|
||||
string.bench.cpp
|
||||
stringstream.bench.cpp
|
||||
to_chars.bench.cpp
|
||||
unordered_set_operations.bench.cpp
|
||||
util_smartptr.bench.cpp
|
||||
variant_visit_1.bench.cpp
|
||||
variant_visit_2.bench.cpp
|
||||
variant_visit_3.bench.cpp
|
||||
vector_operations.bench.cpp
|
||||
)
|
||||
|
||||
foreach(test_path ${BENCHMARK_TESTS})
|
||||
get_filename_component(test_file "${test_path}" NAME)
|
||||
string(REPLACE ".bench.cpp" "" test_name "${test_file}")
|
||||
@ -195,7 +206,7 @@ foreach(test_path ${BENCHMARK_TESTS})
|
||||
# Only report the adding of the benchmark once.
|
||||
set(${test_name}_REPORTED ON CACHE INTERNAL "")
|
||||
endif()
|
||||
add_benchmark_test(${test_name} ${test_file})
|
||||
add_benchmark_test(${test_name} ${test_path})
|
||||
endforeach()
|
||||
|
||||
if (LIBCXX_INCLUDE_TESTS)
|
||||
|
@ -135,6 +135,20 @@ static void BM_FindRehash(benchmark::State& st, Container c, GenInputs gen) {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Container, class GenInputs>
|
||||
static void BM_Rehash(benchmark::State& st, Container c, GenInputs gen) {
|
||||
auto in = gen(st.range(0));
|
||||
c.max_load_factor(3.0);
|
||||
c.insert(in.begin(), in.end());
|
||||
benchmark::DoNotOptimize(c);
|
||||
const auto bucket_count = c.bucket_count();
|
||||
while (st.KeepRunning()) {
|
||||
c.rehash(bucket_count + 1);
|
||||
c.rehash(bucket_count);
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace ContainerBenchmarks
|
||||
|
||||
#endif // BENCHMARK_CONTAINER_BENCHMARKS_H
|
||||
|
@ -36,10 +36,9 @@ inline char getRandomChar() {
|
||||
}
|
||||
|
||||
template <class IntT>
|
||||
inline IntT getRandomInteger(IntT Min = 0,
|
||||
IntT Max = std::numeric_limits<IntT>::max()) {
|
||||
std::uniform_int_distribution<IntT> dist(Min, Max);
|
||||
return dist(getRandomEngine());
|
||||
inline IntT getRandomInteger(IntT Min, IntT Max) {
|
||||
std::uniform_int_distribution<unsigned long long> dist(Min, Max);
|
||||
return static_cast<IntT>(dist(getRandomEngine()));
|
||||
}
|
||||
|
||||
inline std::string getRandomString(std::size_t Len) {
|
||||
@ -102,7 +101,7 @@ template <class IntT>
|
||||
std::vector<IntT> getRandomIntegerInputs(size_t N) {
|
||||
std::vector<IntT> inputs;
|
||||
for (size_t i=0; i < N; ++i) {
|
||||
inputs.push_back(getRandomInteger<IntT>());
|
||||
inputs.push_back(getRandomInteger<IntT>(0, std::numeric_limits<IntT>::max()));
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
58
benchmarks/VariantBenchmarks.h
Normal file
58
benchmarks/VariantBenchmarks.h
Normal file
@ -0,0 +1,58 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BENCHMARK_VARIANT_BENCHMARKS_H
|
||||
#define BENCHMARK_VARIANT_BENCHMARKS_H
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "GenerateInput.h"
|
||||
|
||||
namespace VariantBenchmarks {
|
||||
|
||||
template <std::size_t I>
|
||||
struct S {
|
||||
static constexpr size_t v = I;
|
||||
};
|
||||
|
||||
template <std::size_t N, std::size_t... Is>
|
||||
static auto genVariants(std::index_sequence<Is...>) {
|
||||
using V = std::variant<S<Is>...>;
|
||||
using F = V (*)();
|
||||
static constexpr F fs[] = {[] { return V(std::in_place_index<Is>); }...};
|
||||
|
||||
std::array<V, N> result = {};
|
||||
for (auto& v : result) {
|
||||
v = fs[getRandomInteger(0ul, sizeof...(Is) - 1)]();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <std::size_t N, std::size_t Alts>
|
||||
static void BM_Visit(benchmark::State& state) {
|
||||
auto args = genVariants<N>(std::make_index_sequence<Alts>{});
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(std::apply(
|
||||
[](auto... vs) {
|
||||
return std::visit([](auto... is) { return (is.v + ... + 0); }, vs...);
|
||||
},
|
||||
args));
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace VariantBenchmarks
|
||||
|
||||
#endif // BENCHMARK_VARIANT_BENCHMARKS_H
|
@ -1,276 +0,0 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "CartesianBenchmarks.h"
|
||||
#include "GenerateInput.h"
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
namespace {
|
||||
|
||||
enum class ValueType { Uint32, String };
|
||||
struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 2> {
|
||||
static constexpr const char* Names[] = {"uint32", "string"};
|
||||
};
|
||||
|
||||
template <class V>
|
||||
using Value =
|
||||
std::conditional_t<V() == ValueType::Uint32, uint32_t, std::string>;
|
||||
|
||||
enum class Order {
|
||||
Random,
|
||||
Ascending,
|
||||
Descending,
|
||||
SingleElement,
|
||||
PipeOrgan,
|
||||
Heap
|
||||
};
|
||||
struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 6> {
|
||||
static constexpr const char* Names[] = {"Random", "Ascending",
|
||||
"Descending", "SingleElement",
|
||||
"PipeOrgan", "Heap"};
|
||||
};
|
||||
|
||||
void fillValues(std::vector<uint32_t>& V, size_t N, Order O) {
|
||||
if (O == Order::SingleElement) {
|
||||
V.resize(N, 0);
|
||||
} else {
|
||||
while (V.size() < N)
|
||||
V.push_back(V.size());
|
||||
}
|
||||
}
|
||||
|
||||
void fillValues(std::vector<std::string>& V, size_t N, Order O) {
|
||||
|
||||
if (O == Order::SingleElement) {
|
||||
V.resize(N, getRandomString(1024));
|
||||
} else {
|
||||
while (V.size() < N)
|
||||
V.push_back(getRandomString(1024));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sortValues(T& V, Order O) {
|
||||
assert(std::is_sorted(V.begin(), V.end()));
|
||||
switch (O) {
|
||||
case Order::Random: {
|
||||
std::random_device R;
|
||||
std::mt19937 M(R());
|
||||
std::shuffle(V.begin(), V.end(), M);
|
||||
break;
|
||||
}
|
||||
case Order::Ascending:
|
||||
std::sort(V.begin(), V.end());
|
||||
break;
|
||||
case Order::Descending:
|
||||
std::sort(V.begin(), V.end(), std::greater<>());
|
||||
break;
|
||||
case Order::SingleElement:
|
||||
// Nothing to do
|
||||
break;
|
||||
case Order::PipeOrgan:
|
||||
std::sort(V.begin(), V.end());
|
||||
std::reverse(V.begin() + V.size() / 2, V.end());
|
||||
break;
|
||||
case Order::Heap:
|
||||
std::make_heap(V.begin(), V.end());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ValueType>
|
||||
std::vector<std::vector<Value<ValueType> > > makeOrderedValues(size_t N,
|
||||
Order O) {
|
||||
// Let's make sure that all random sequences of the same size are the same.
|
||||
// That way we can compare the different algorithms with the same input.
|
||||
static std::map<std::pair<size_t, Order>, std::vector<Value<ValueType> > >
|
||||
Cached;
|
||||
|
||||
auto& Values = Cached[{N, O}];
|
||||
if (Values.empty()) {
|
||||
fillValues(Values, N, O);
|
||||
sortValues(Values, O);
|
||||
};
|
||||
const size_t NumCopies = std::max(size_t{1}, 1000 / N);
|
||||
return { NumCopies, Values };
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
TEST_ALWAYS_INLINE void resetCopies(benchmark::State& state, T& Copies,
|
||||
U& Orig) {
|
||||
state.PauseTiming();
|
||||
for (auto& Copy : Copies)
|
||||
Copy = Orig;
|
||||
state.ResumeTiming();
|
||||
}
|
||||
|
||||
template <class ValueType, class F>
|
||||
void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O,
|
||||
bool CountElements, F f) {
|
||||
auto Copies = makeOrderedValues<ValueType>(Quantity, O);
|
||||
const auto Orig = Copies[0];
|
||||
|
||||
const size_t Batch = CountElements ? Copies.size() * Quantity : Copies.size();
|
||||
while (state.KeepRunningBatch(Batch)) {
|
||||
for (auto& Copy : Copies) {
|
||||
f(Copy);
|
||||
benchmark::DoNotOptimize(Copy);
|
||||
}
|
||||
resetCopies(state, Copies, Orig);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ValueType, class Order>
|
||||
struct Sort {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
|
||||
std::sort(Copy.begin(), Copy.end());
|
||||
});
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_Sort" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
|
||||
template <class ValueType, class Order>
|
||||
struct StableSort {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
|
||||
std::stable_sort(Copy.begin(), Copy.end());
|
||||
});
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_StableSort" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
|
||||
template <class ValueType, class Order>
|
||||
struct MakeHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
|
||||
std::make_heap(Copy.begin(), Copy.end());
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_MakeHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
|
||||
template <class ValueType>
|
||||
struct SortHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order::Heap, false,
|
||||
[](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); });
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_SortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
|
||||
template <class ValueType, class Order>
|
||||
struct MakeThenSortHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
|
||||
std::make_heap(Copy.begin(), Copy.end());
|
||||
std::sort_heap(Copy.begin(), Copy.end());
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_MakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
|
||||
template <class ValueType, class Order>
|
||||
struct PushHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), true, [](auto& Copy) {
|
||||
for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
|
||||
std::push_heap(Copy.begin(), I + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_PushHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
|
||||
template <class ValueType>
|
||||
struct PopHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), true, [](auto& Copy) {
|
||||
for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
|
||||
std::pop_heap(B, I);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_PopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
const std::vector<size_t> Quantities = {1 << 0, 1 << 2, 1 << 4, 1 << 6,
|
||||
1 << 8, 1 << 10, 1 << 14,
|
||||
// Running each benchmark in parallel consumes too much memory with MSAN
|
||||
// and can lead to the test process being killed.
|
||||
#if !TEST_HAS_FEATURE(memory_sanitizer)
|
||||
1 << 18
|
||||
#endif
|
||||
};
|
||||
makeCartesianProductBenchmark<Sort, AllValueTypes, AllOrders>(Quantities);
|
||||
makeCartesianProductBenchmark<StableSort, AllValueTypes, AllOrders>(
|
||||
Quantities);
|
||||
makeCartesianProductBenchmark<MakeHeap, AllValueTypes, AllOrders>(Quantities);
|
||||
makeCartesianProductBenchmark<SortHeap, AllValueTypes>(Quantities);
|
||||
makeCartesianProductBenchmark<MakeThenSortHeap, AllValueTypes, AllOrders>(
|
||||
Quantities);
|
||||
makeCartesianProductBenchmark<PushHeap, AllValueTypes, AllOrders>(Quantities);
|
||||
makeCartesianProductBenchmark<PopHeap, AllValueTypes>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
@ -30,7 +30,7 @@ struct TestIntBase {
|
||||
static std::vector<IntT> generateInput(size_t size) {
|
||||
std::vector<IntT> Res(size);
|
||||
std::generate(Res.begin(), Res.end(),
|
||||
[] { return getRandomInteger<IntT>(); });
|
||||
[] { return getRandomInteger<IntT>(0, std::numeric_limits<IntT>::max()); });
|
||||
return Res;
|
||||
}
|
||||
};
|
||||
|
244
benchmarks/algorithms/common.h
Normal file
244
benchmarks/algorithms/common.h
Normal file
@ -0,0 +1,244 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LIBCXX_ALGORITHMS_COMMON_H
|
||||
#define LIBCXX_ALGORITHMS_COMMON_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "../CartesianBenchmarks.h"
|
||||
#include "../GenerateInput.h"
|
||||
|
||||
enum class ValueType { Uint32, Uint64, Pair, Tuple, String, Float };
|
||||
struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 6> {
|
||||
static constexpr const char* Names[] = {"uint32", "uint64", "pair<uint32, uint32>", "tuple<uint32, uint64, uint32>",
|
||||
"string", "float"};
|
||||
};
|
||||
|
||||
using Types = std::tuple< uint32_t, uint64_t, std::pair<uint32_t, uint32_t>, std::tuple<uint32_t, uint64_t, uint32_t>,
|
||||
std::string, float >;
|
||||
|
||||
template <class V>
|
||||
using Value = std::tuple_element_t<(int)V::value, Types>;
|
||||
|
||||
enum class Order {
|
||||
Random,
|
||||
Ascending,
|
||||
Descending,
|
||||
SingleElement,
|
||||
PipeOrgan,
|
||||
Heap,
|
||||
QuickSortAdversary,
|
||||
};
|
||||
struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 7> {
|
||||
static constexpr const char* Names[] = {"Random", "Ascending",
|
||||
"Descending", "SingleElement",
|
||||
"PipeOrgan", "Heap",
|
||||
"QuickSortAdversary"};
|
||||
};
|
||||
|
||||
// fillAdversarialQuickSortInput fills the input vector with N int-like values.
|
||||
// These values are arranged in such a way that they would invoke O(N^2)
|
||||
// behavior on any quick sort implementation that satisifies certain conditions.
|
||||
// Details are available in the following paper:
|
||||
// "A Killer Adversary for Quicksort", M. D. McIlroy, Software—Practice &
|
||||
// ExperienceVolume 29 Issue 4 April 10, 1999 pp 341–344.
|
||||
// https://dl.acm.org/doi/10.5555/311868.311871.
|
||||
template <class T>
|
||||
void fillAdversarialQuickSortInput(T& V, size_t N) {
|
||||
assert(N > 0);
|
||||
// If an element is equal to gas, it indicates that the value of the element
|
||||
// is still to be decided and may change over the course of time.
|
||||
const unsigned int gas = N - 1;
|
||||
V.resize(N);
|
||||
for (unsigned int i = 0; i < N; ++i) {
|
||||
V[i] = gas;
|
||||
}
|
||||
// Candidate for the pivot position.
|
||||
int candidate = 0;
|
||||
int nsolid = 0;
|
||||
// Populate all positions in the generated input to gas.
|
||||
std::vector<int> ascVals(V.size());
|
||||
// Fill up with ascending values from 0 to V.size()-1. These will act as
|
||||
// indices into V.
|
||||
std::iota(ascVals.begin(), ascVals.end(), 0);
|
||||
std::sort(ascVals.begin(), ascVals.end(), [&](int x, int y) {
|
||||
if (V[x] == gas && V[y] == gas) {
|
||||
// We are comparing two inputs whose value is still to be decided.
|
||||
if (x == candidate) {
|
||||
V[x] = nsolid++;
|
||||
} else {
|
||||
V[y] = nsolid++;
|
||||
}
|
||||
}
|
||||
if (V[x] == gas) {
|
||||
candidate = x;
|
||||
} else if (V[y] == gas) {
|
||||
candidate = y;
|
||||
}
|
||||
return V[x] < V[y];
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void fillValues(std::vector<T>& V, size_t N, Order O) {
|
||||
if (O == Order::SingleElement) {
|
||||
V.resize(N, 0);
|
||||
} else if (O == Order::QuickSortAdversary) {
|
||||
fillAdversarialQuickSortInput(V, N);
|
||||
} else {
|
||||
while (V.size() < N)
|
||||
V.push_back(V.size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void fillValues(std::vector<std::pair<T, T> >& V, size_t N, Order O) {
|
||||
if (O == Order::SingleElement) {
|
||||
V.resize(N, std::make_pair(0, 0));
|
||||
} else {
|
||||
while (V.size() < N)
|
||||
// Half of array will have the same first element.
|
||||
if (V.size() % 2) {
|
||||
V.push_back(std::make_pair(V.size(), V.size()));
|
||||
} else {
|
||||
V.push_back(std::make_pair(0, V.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void fillValues(std::vector<std::tuple<T1, T2, T3> >& V, size_t N, Order O) {
|
||||
if (O == Order::SingleElement) {
|
||||
V.resize(N, std::make_tuple(0, 0, 0));
|
||||
} else {
|
||||
while (V.size() < N)
|
||||
// One third of array will have the same first element.
|
||||
// One third of array will have the same first element and the same second element.
|
||||
switch (V.size() % 3) {
|
||||
case 0:
|
||||
V.push_back(std::make_tuple(V.size(), V.size(), V.size()));
|
||||
break;
|
||||
case 1:
|
||||
V.push_back(std::make_tuple(0, V.size(), V.size()));
|
||||
break;
|
||||
case 2:
|
||||
V.push_back(std::make_tuple(0, 0, V.size()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void fillValues(std::vector<std::string>& V, size_t N, Order O) {
|
||||
if (O == Order::SingleElement) {
|
||||
V.resize(N, getRandomString(64));
|
||||
} else {
|
||||
while (V.size() < N)
|
||||
V.push_back(getRandomString(64));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sortValues(T& V, Order O) {
|
||||
switch (O) {
|
||||
case Order::Random: {
|
||||
std::random_device R;
|
||||
std::mt19937 M(R());
|
||||
std::shuffle(V.begin(), V.end(), M);
|
||||
break;
|
||||
}
|
||||
case Order::Ascending:
|
||||
std::sort(V.begin(), V.end());
|
||||
break;
|
||||
case Order::Descending:
|
||||
std::sort(V.begin(), V.end(), std::greater<>());
|
||||
break;
|
||||
case Order::SingleElement:
|
||||
// Nothing to do
|
||||
break;
|
||||
case Order::PipeOrgan:
|
||||
std::sort(V.begin(), V.end());
|
||||
std::reverse(V.begin() + V.size() / 2, V.end());
|
||||
break;
|
||||
case Order::Heap:
|
||||
std::make_heap(V.begin(), V.end());
|
||||
break;
|
||||
case Order::QuickSortAdversary:
|
||||
// Nothing to do
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr size_t TestSetElements =
|
||||
#if !TEST_HAS_FEATURE(memory_sanitizer)
|
||||
1 << 18;
|
||||
#else
|
||||
1 << 14;
|
||||
#endif
|
||||
|
||||
template <class ValueType>
|
||||
std::vector<std::vector<Value<ValueType> > > makeOrderedValues(size_t N,
|
||||
Order O) {
|
||||
std::vector<std::vector<Value<ValueType> > > Ret;
|
||||
const size_t NumCopies = std::max(size_t{1}, TestSetElements / N);
|
||||
Ret.resize(NumCopies);
|
||||
for (auto& V : Ret) {
|
||||
fillValues(V, N, O);
|
||||
sortValues(V, O);
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
TEST_ALWAYS_INLINE void resetCopies(benchmark::State& state, T& Copies,
|
||||
U& Orig) {
|
||||
state.PauseTiming();
|
||||
for (auto& Copy : Copies)
|
||||
Copy = Orig;
|
||||
state.ResumeTiming();
|
||||
}
|
||||
|
||||
enum class BatchSize {
|
||||
CountElements,
|
||||
CountBatch,
|
||||
};
|
||||
|
||||
template <class ValueType, class F>
|
||||
void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O,
|
||||
BatchSize Count, F Body) {
|
||||
auto Copies = makeOrderedValues<ValueType>(Quantity, O);
|
||||
auto Orig = Copies;
|
||||
|
||||
const size_t Batch = Count == BatchSize::CountElements
|
||||
? Copies.size() * Quantity
|
||||
: Copies.size();
|
||||
while (state.KeepRunningBatch(Batch)) {
|
||||
for (auto& Copy : Copies) {
|
||||
Body(Copy);
|
||||
benchmark::DoNotOptimize(Copy);
|
||||
}
|
||||
state.PauseTiming();
|
||||
Copies = Orig;
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const std::vector<size_t> Quantities = {1 << 0, 1 << 2, 1 << 4, 1 << 6,
|
||||
1 << 8, 1 << 10, 1 << 14,
|
||||
// Running each benchmark in parallel consumes too much memory with MSAN
|
||||
// and can lead to the test process being killed.
|
||||
#if !TEST_HAS_FEATURE(memory_sanitizer)
|
||||
1 << 18
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // LIBCXX_ALGORITHMS_COMMON_H
|
42
benchmarks/algorithms/lower_bound.bench.cpp
Normal file
42
benchmarks/algorithms/lower_bound.bench.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType>
|
||||
struct LowerBound {
|
||||
size_t Quantity;
|
||||
|
||||
mutable std::mt19937_64 rng { std::random_device{}() };
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order::Ascending, BatchSize::CountBatch, [&](auto& Copy) {
|
||||
auto result = std::lower_bound(Copy.begin(), Copy.end(), Copy[rng() % Copy.size()]);
|
||||
benchmark::DoNotOptimize(result);
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_LowerBound" + ValueType::name() + "_" + std::to_string(Quantity);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<LowerBound, AllValueTypes>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
37
benchmarks/algorithms/make_heap.bench.cpp
Normal file
37
benchmarks/algorithms/make_heap.bench.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct MakeHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements,
|
||||
[](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); });
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_MakeHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<MakeHeap, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
39
benchmarks/algorithms/make_heap_then_sort_heap.bench.cpp
Normal file
39
benchmarks/algorithms/make_heap_then_sort_heap.bench.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct MakeThenSortHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements,
|
||||
[](auto& Copy) {
|
||||
std::make_heap(Copy.begin(), Copy.end());
|
||||
std::sort_heap(Copy.begin(), Copy.end());
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_MakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<MakeThenSortHeap, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
36
benchmarks/algorithms/min_max_element.bench.cpp
Normal file
36
benchmarks/algorithms/min_max_element.bench.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct MinMaxElement {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
|
||||
benchmark::DoNotOptimize(std::minmax_element(Copy.begin(), Copy.end()));
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_MinMaxElement" + ValueType::name() + Order::name() + "_" + std::to_string(Quantity);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<MinMaxElement, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
39
benchmarks/algorithms/pop_heap.bench.cpp
Normal file
39
benchmarks/algorithms/pop_heap.bench.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType>
|
||||
struct PopHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
|
||||
for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
|
||||
std::pop_heap(B, I);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_PopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<PopHeap, AllValueTypes>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
42
benchmarks/algorithms/push_heap.bench.cpp
Normal file
42
benchmarks/algorithms/push_heap.bench.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct PushHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
|
||||
for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
|
||||
std::push_heap(Copy.begin(), I + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_PushHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<PushHeap, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
37
benchmarks/algorithms/ranges_make_heap.bench.cpp
Normal file
37
benchmarks/algorithms/ranges_make_heap.bench.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct RangesMakeHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements,
|
||||
[](auto& Copy) { std::ranges::make_heap(Copy); });
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_RangesMakeHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<RangesMakeHeap, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct RangesMakeThenSortHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements,
|
||||
[](auto& Copy) {
|
||||
std::ranges::make_heap(Copy);
|
||||
std::ranges::sort_heap(Copy);
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_RangesMakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<RangesMakeThenSortHeap, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
39
benchmarks/algorithms/ranges_pop_heap.bench.cpp
Normal file
39
benchmarks/algorithms/ranges_pop_heap.bench.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType>
|
||||
struct RangesPopHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
|
||||
for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
|
||||
std::ranges::pop_heap(B, I);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_RangesPopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<RangesPopHeap, AllValueTypes>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
42
benchmarks/algorithms/ranges_push_heap.bench.cpp
Normal file
42
benchmarks/algorithms/ranges_push_heap.bench.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct RangesPushHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
|
||||
for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
|
||||
std::ranges::push_heap(Copy.begin(), I + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_RangesPushHeap" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<RangesPushHeap, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
39
benchmarks/algorithms/ranges_sort.bench.cpp
Normal file
39
benchmarks/algorithms/ranges_sort.bench.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct Sort {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements,
|
||||
[](auto& Copy) { std::ranges::sort(Copy); });
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_RangesSort" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<Sort, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
36
benchmarks/algorithms/ranges_sort_heap.bench.cpp
Normal file
36
benchmarks/algorithms/ranges_sort_heap.bench.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType>
|
||||
struct RangesSortHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order::Heap, BatchSize::CountElements,
|
||||
[](auto& Copy) { std::ranges::sort_heap(Copy); });
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_RangesSortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<RangesSortHeap, AllValueTypes>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
39
benchmarks/algorithms/ranges_stable_sort.bench.cpp
Normal file
39
benchmarks/algorithms/ranges_stable_sort.bench.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct StableSort {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements,
|
||||
[](auto& Copy) { std::ranges::stable_sort(Copy); });
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_RangesStableSort" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<StableSort, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
39
benchmarks/algorithms/sort.bench.cpp
Normal file
39
benchmarks/algorithms/sort.bench.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct Sort {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements,
|
||||
[](auto& Copy) { std::sort(Copy.begin(), Copy.end()); });
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_Sort" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<Sort, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
36
benchmarks/algorithms/sort_heap.bench.cpp
Normal file
36
benchmarks/algorithms/sort_heap.bench.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType>
|
||||
struct SortHeap {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order::Heap, BatchSize::CountElements,
|
||||
[](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); });
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "BM_SortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<SortHeap, AllValueTypes>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
39
benchmarks/algorithms/stable_sort.bench.cpp
Normal file
39
benchmarks/algorithms/stable_sort.bench.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace {
|
||||
template <class ValueType, class Order>
|
||||
struct StableSort {
|
||||
size_t Quantity;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
runOpOnCopies<ValueType>(
|
||||
state, Quantity, Order(), BatchSize::CountElements,
|
||||
[](auto& Copy) { std::stable_sort(Copy.begin(), Copy.end()); });
|
||||
}
|
||||
|
||||
bool skip() const { return Order() == ::Order::Heap; }
|
||||
|
||||
std::string name() const {
|
||||
return "BM_StableSort" + ValueType::name() + Order::name() + "_" +
|
||||
std::to_string(Quantity);
|
||||
};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
makeCartesianProductBenchmark<StableSort, AllValueTypes, AllOrders>(Quantities);
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
@ -97,7 +97,6 @@ static void BM_DeallocateOnly(benchmark::State& st) {
|
||||
const size_t alloc_size = st.range(0);
|
||||
const auto NumAllocs = st.max_iterations;
|
||||
|
||||
using PtrT = void*;
|
||||
std::vector<void*> Pointers(NumAllocs);
|
||||
for (auto& p : Pointers) {
|
||||
p = AllocWrapper::Allocate(alloc_size);
|
||||
|
@ -1,4 +1,3 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
|
@ -62,7 +62,7 @@ void BM_PathConstructIter(benchmark::State &st, GenInputs gen) {
|
||||
}
|
||||
template <class GenInputs>
|
||||
void BM_PathConstructInputIter(benchmark::State &st, GenInputs gen) {
|
||||
BM_PathConstructIter<input_iterator>(st, gen);
|
||||
BM_PathConstructIter<cpp17_input_iterator>(st, gen);
|
||||
}
|
||||
template <class GenInputs>
|
||||
void BM_PathConstructForwardIter(benchmark::State &st, GenInputs gen) {
|
||||
@ -83,7 +83,7 @@ void BM_PathIterateMultipleTimes(benchmark::State &st, GenInputs gen) {
|
||||
PP /= Part;
|
||||
benchmark::DoNotOptimize(PP.native().data());
|
||||
while (st.KeepRunning()) {
|
||||
for (auto &E : PP) {
|
||||
for (auto const& E : PP) {
|
||||
benchmark::DoNotOptimize(E.native().data());
|
||||
}
|
||||
benchmark::ClobberMemory();
|
||||
@ -104,7 +104,7 @@ void BM_PathIterateOnce(benchmark::State &st, GenInputs gen) {
|
||||
benchmark::DoNotOptimize(PP.native().data());
|
||||
while (st.KeepRunning()) {
|
||||
const path P = PP.native();
|
||||
for (auto &E : P) {
|
||||
for (auto const& E : P) {
|
||||
benchmark::DoNotOptimize(E.native().data());
|
||||
}
|
||||
benchmark::ClobberMemory();
|
||||
|
36
benchmarks/format.bench.cpp
Normal file
36
benchmarks/format.bench.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "make_string.h"
|
||||
|
||||
#define CSTR(S) MAKE_CSTRING(CharT, S)
|
||||
|
||||
template <class CharT>
|
||||
static void BM_format_string(benchmark::State& state) {
|
||||
size_t size = state.range(0);
|
||||
std::basic_string<CharT> str(size, CharT('*'));
|
||||
|
||||
while (state.KeepRunningBatch(str.size()))
|
||||
benchmark::DoNotOptimize(std::format(CSTR("{}"), str));
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
BENCHMARK_TEMPLATE(BM_format_string, char)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_string, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
107
benchmarks/format_to.bench.cpp
Normal file
107
benchmarks/format_to.bench.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "make_string.h"
|
||||
|
||||
#define CSTR(S) MAKE_CSTRING(CharT, S)
|
||||
|
||||
/*** Back inserter ***/
|
||||
|
||||
template <class Container>
|
||||
static void BM_format_to_string_back_inserter(benchmark::State& state) {
|
||||
using CharT = typename Container::value_type;
|
||||
size_t size = state.range(0);
|
||||
auto str = std::basic_string<CharT>(size, CharT('*'));
|
||||
|
||||
for (auto _ : state) {
|
||||
Container output;
|
||||
benchmark::DoNotOptimize(std::format_to(std::back_inserter(output), CSTR("{}"), str));
|
||||
}
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
|
||||
/*** Begin ***/
|
||||
|
||||
template <class Container>
|
||||
static void BM_format_to_string_begin(benchmark::State& state) {
|
||||
using CharT = typename Container::value_type;
|
||||
size_t size = state.range(0);
|
||||
auto str = std::basic_string<CharT>(size, CharT('*'));
|
||||
|
||||
Container output(size, CharT('-'));
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::format_to(std::begin(output), CSTR("{}"), str));
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
|
||||
/*** Pointer ***/
|
||||
|
||||
template <class CharT>
|
||||
static void BM_format_to_string_span(benchmark::State& state) {
|
||||
size_t size = state.range(0);
|
||||
auto str = std::basic_string<CharT>(size, CharT('*'));
|
||||
|
||||
auto buffer = std::basic_string<CharT>(size, CharT('-'));
|
||||
std::span<CharT> output{buffer};
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::format_to(std::begin(output), CSTR("{}"), str));
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void BM_format_to_string_pointer(benchmark::State& state) {
|
||||
size_t size = state.range(0);
|
||||
auto str = std::basic_string<CharT>(size, CharT('*'));
|
||||
|
||||
auto buffer = std::basic_string<CharT>(size, CharT('-'));
|
||||
CharT* output = buffer.data();
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::format_to(output, CSTR("{}"), str));
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
|
||||
/*** Main ***/
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::string)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::vector<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::list<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::string)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::vector<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::list<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_span, char)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_pointer, char)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::wstring)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::vector<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::list<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::wstring)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::vector<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::list<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_span, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_string_pointer, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
107
benchmarks/format_to_n.bench.cpp
Normal file
107
benchmarks/format_to_n.bench.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "make_string.h"
|
||||
|
||||
#define CSTR(S) MAKE_CSTRING(CharT, S)
|
||||
|
||||
/*** Back inserter ***/
|
||||
|
||||
template <class Container>
|
||||
static void BM_format_to_n_string_back_inserter(benchmark::State& state) {
|
||||
using CharT = typename Container::value_type;
|
||||
size_t size = state.range(0);
|
||||
auto str = std::basic_string<CharT>(2 * size, CharT('*'));
|
||||
|
||||
for (auto _ : state) {
|
||||
Container output;
|
||||
benchmark::DoNotOptimize(std::format_to_n(std::back_inserter(output), size, CSTR("{}"), str));
|
||||
}
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
|
||||
/*** Begin ***/
|
||||
|
||||
template <class Container>
|
||||
static void BM_format_to_n_string_begin(benchmark::State& state) {
|
||||
using CharT = typename Container::value_type;
|
||||
size_t size = state.range(0);
|
||||
auto str = std::basic_string<CharT>(2 * size, CharT('*'));
|
||||
|
||||
Container output(size, CharT('-'));
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::format_to_n(std::begin(output), size, CSTR("{}"), str));
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
|
||||
/*** Pointer ***/
|
||||
|
||||
template <class CharT>
|
||||
static void BM_format_to_n_string_span(benchmark::State& state) {
|
||||
size_t size = state.range(0);
|
||||
auto str = std::basic_string<CharT>(2 * size, CharT('*'));
|
||||
|
||||
auto buffer = std::basic_string<CharT>(size, CharT('-'));
|
||||
std::span<CharT> output{buffer};
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::format_to_n(std::begin(output), size, CSTR("{}"), str));
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
static void BM_format_to_n_string_pointer(benchmark::State& state) {
|
||||
size_t size = state.range(0);
|
||||
auto str = std::basic_string<CharT>(2 * size, CharT('*'));
|
||||
|
||||
auto buffer = std::basic_string<CharT>(size, CharT('-'));
|
||||
CharT* output = buffer.data();
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::format_to_n(output, size, CSTR("{}"), str));
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
|
||||
/*** Main ***/
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::string)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::vector<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::list<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::string)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::vector<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::list<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_span, char)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_pointer, char)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::wstring)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::vector<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::list<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::wstring)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::vector<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::list<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_span, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_format_to_n_string_pointer, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
36
benchmarks/formatted_size.bench.cpp
Normal file
36
benchmarks/formatted_size.bench.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "make_string.h"
|
||||
|
||||
#define CSTR(S) MAKE_CSTRING(CharT, S)
|
||||
|
||||
template <class CharT>
|
||||
static void BM_formatted_size_string(benchmark::State& state) {
|
||||
size_t size = state.range(0);
|
||||
std::basic_string<CharT> str(size, CharT('*'));
|
||||
|
||||
while (state.KeepRunningBatch(str.size()))
|
||||
benchmark::DoNotOptimize(std::formatted_size(CSTR("{}"), str));
|
||||
|
||||
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
|
||||
}
|
||||
BENCHMARK_TEMPLATE(BM_formatted_size_string, char)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
BENCHMARK_TEMPLATE(BM_formatted_size_string, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
251
benchmarks/formatter_float.bench.cpp
Normal file
251
benchmarks/formatter_float.bench.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#include "CartesianBenchmarks.h"
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
// *** Localization ***
|
||||
enum class LocalizationE { False, True };
|
||||
struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {
|
||||
static constexpr const char* Names[] = {"LocFalse", "LocTrue"};
|
||||
};
|
||||
|
||||
template <LocalizationE E>
|
||||
struct Localization {};
|
||||
|
||||
template <>
|
||||
struct Localization<LocalizationE::False> {
|
||||
static constexpr const char* fmt = "";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Localization<LocalizationE::True> {
|
||||
static constexpr const char* fmt = "L";
|
||||
};
|
||||
|
||||
// *** Types ***
|
||||
enum class TypeE { Float, Double, LongDouble };
|
||||
// TODO FMT Set to 3 after to_chars has long double suport.
|
||||
struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {
|
||||
static constexpr const char* Names[] = {"Float", "Double", "LongDouble"};
|
||||
};
|
||||
|
||||
template <TypeE E>
|
||||
struct Type {};
|
||||
|
||||
template <>
|
||||
struct Type<TypeE::Float> {
|
||||
using type = float;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type<TypeE::Double> {
|
||||
using type = double;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type<TypeE::LongDouble> {
|
||||
using type = long double;
|
||||
};
|
||||
|
||||
// *** Values ***
|
||||
enum class ValueE { Inf, Random };
|
||||
struct AllValues : EnumValuesAsTuple<AllValues, ValueE, 2> {
|
||||
static constexpr const char* Names[] = {"Inf", "Random"};
|
||||
};
|
||||
|
||||
template <ValueE E>
|
||||
struct Value {};
|
||||
|
||||
template <>
|
||||
struct Value<ValueE::Inf> {
|
||||
template <class F>
|
||||
static std::array<F, 1000> make_data() {
|
||||
std::array<F, 1000> result;
|
||||
std::fill(result.begin(), result.end(), -std::numeric_limits<F>::infinity());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Value<ValueE::Random> {
|
||||
template <class F>
|
||||
static std::array<F, 1000> make_data() {
|
||||
std::random_device seed;
|
||||
std::mt19937 generator(seed());
|
||||
std::uniform_int_distribution<std::conditional_t<sizeof(F) == sizeof(uint32_t), uint32_t, uint64_t>> distribution;
|
||||
|
||||
std::array<F, 1000> result;
|
||||
std::generate(result.begin(), result.end(), [&] {
|
||||
while (true) {
|
||||
auto result = std::bit_cast<F>(distribution(generator));
|
||||
if (std::isfinite(result))
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// *** Display Type ***
|
||||
enum class DisplayTypeE {
|
||||
Default,
|
||||
Hex,
|
||||
Scientific,
|
||||
Fixed,
|
||||
General,
|
||||
};
|
||||
struct AllDisplayTypes : EnumValuesAsTuple<AllDisplayTypes, DisplayTypeE, 5> {
|
||||
static constexpr const char* Names[] = {"DisplayDefault", "DisplayHex", "DisplayScientific", "DisplayFixed",
|
||||
"DisplayGeneral"};
|
||||
};
|
||||
|
||||
template <DisplayTypeE E>
|
||||
struct DisplayType {};
|
||||
|
||||
template <>
|
||||
struct DisplayType<DisplayTypeE::Default> {
|
||||
static constexpr const char* fmt = "";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DisplayType<DisplayTypeE::Hex> {
|
||||
static constexpr const char* fmt = "a";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DisplayType<DisplayTypeE::Scientific> {
|
||||
static constexpr const char* fmt = "e";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DisplayType<DisplayTypeE::Fixed> {
|
||||
static constexpr const char* fmt = "f";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DisplayType<DisplayTypeE::General> {
|
||||
static constexpr const char* fmt = "g";
|
||||
};
|
||||
|
||||
// *** Alignment ***
|
||||
enum class AlignmentE { None, Left, Center, Right, ZeroPadding };
|
||||
struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {
|
||||
static constexpr const char* Names[] = {"AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight",
|
||||
"ZeroPadding"};
|
||||
};
|
||||
|
||||
template <AlignmentE E>
|
||||
struct Alignment {};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::None> {
|
||||
static constexpr const char* fmt = "";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::Left> {
|
||||
// Width > PrecisionE::Huge
|
||||
static constexpr const char* fmt = "0<17500";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::Center> {
|
||||
// Width > PrecisionE::Huge
|
||||
static constexpr const char* fmt = "0^17500";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::Right> {
|
||||
// Width > PrecisionE::Huge
|
||||
static constexpr const char* fmt = "0>17500";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::ZeroPadding> {
|
||||
// Width > PrecisionE::Huge
|
||||
static constexpr const char* fmt = "017500";
|
||||
};
|
||||
|
||||
enum class PrecisionE { None, Zero, Small, Huge };
|
||||
struct AllPrecisions : EnumValuesAsTuple<AllPrecisions, PrecisionE, 4> {
|
||||
static constexpr const char* Names[] = {"PrecNone", "PrecZero", "PrecSmall", "PrecHuge"};
|
||||
};
|
||||
|
||||
template <PrecisionE E>
|
||||
struct Precision {};
|
||||
|
||||
template <>
|
||||
struct Precision<PrecisionE::None> {
|
||||
static constexpr const char* fmt = "";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Precision<PrecisionE::Zero> {
|
||||
static constexpr const char* fmt = ".0";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Precision<PrecisionE::Small> {
|
||||
static constexpr const char* fmt = ".10";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Precision<PrecisionE::Huge> {
|
||||
// The maximum precision for a minimal sub normal long double is ±0x1p-16494.
|
||||
// This value is always larger than that value forcing the trailing zero path
|
||||
// to be executed.
|
||||
static constexpr const char* fmt = ".17000";
|
||||
};
|
||||
|
||||
template <class L, class DT, class T, class V, class A, class P>
|
||||
struct FloatingPoint {
|
||||
using F = typename Type<T::value>::type;
|
||||
|
||||
void run(benchmark::State& state) const {
|
||||
std::array<F, 1000> data{Value<V::value>::template make_data<F>()};
|
||||
std::array<char, 20'000> output;
|
||||
|
||||
while (state.KeepRunningBatch(1000))
|
||||
for (F value : data)
|
||||
benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));
|
||||
}
|
||||
|
||||
std::string name() const {
|
||||
return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name();
|
||||
}
|
||||
|
||||
static constexpr std::string make_fmt() {
|
||||
return std::string("{:") + Alignment<A::value>::fmt + Precision<P::value>::fmt + Localization<L::value>::fmt +
|
||||
DisplayType<DT::value>::fmt + "}";
|
||||
}
|
||||
|
||||
static constexpr auto fmt = []() {
|
||||
constexpr size_t s = make_fmt().size();
|
||||
std::array<char, s> r;
|
||||
std::ranges::copy(make_fmt(), r.begin());
|
||||
return r;
|
||||
}();
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
makeCartesianProductBenchmark<FloatingPoint, AllLocalizations, AllDisplayTypes, AllTypes, AllValues, AllAlignments,
|
||||
AllPrecisions>();
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
208
benchmarks/formatter_int.bench.cpp
Normal file
208
benchmarks/formatter_int.bench.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <array>
|
||||
#include <format>
|
||||
#include <random>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "CartesianBenchmarks.h"
|
||||
|
||||
// Tests the full range of the value.
|
||||
template <class T>
|
||||
static std::array<T, 1000>
|
||||
generate(std::uniform_int_distribution<T> distribution = std::uniform_int_distribution<T>{
|
||||
std::numeric_limits<T>::min(), std::numeric_limits<T>::max()}) {
|
||||
std::mt19937 generator;
|
||||
std::array<T, 1000> result;
|
||||
std::generate_n(result.begin(), result.size(), [&] { return distribution(generator); });
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void BM_Basic(benchmark::State& state) {
|
||||
std::array data{generate<T>()};
|
||||
std::array<char, 100> output;
|
||||
|
||||
while (state.KeepRunningBatch(data.size()))
|
||||
for (auto value : data)
|
||||
benchmark::DoNotOptimize(std::format_to(output.begin(), "{}", value));
|
||||
}
|
||||
BENCHMARK_TEMPLATE(BM_Basic, uint32_t);
|
||||
BENCHMARK_TEMPLATE(BM_Basic, int32_t);
|
||||
BENCHMARK_TEMPLATE(BM_Basic, uint64_t);
|
||||
BENCHMARK_TEMPLATE(BM_Basic, int64_t);
|
||||
|
||||
// Ideally the low values of a 128-bit value are all dispatched to a 64-bit routine.
|
||||
template <class T>
|
||||
static void BM_BasicLow(benchmark::State& state) {
|
||||
using U = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
|
||||
std::array data{
|
||||
generate<T>(std::uniform_int_distribution<T>{std::numeric_limits<U>::min(), std::numeric_limits<U>::max()})};
|
||||
std::array<char, 100> output;
|
||||
|
||||
while (state.KeepRunningBatch(data.size()))
|
||||
for (auto value : data)
|
||||
benchmark::DoNotOptimize(std::format_to(output.begin(), "{}", value));
|
||||
}
|
||||
BENCHMARK_TEMPLATE(BM_BasicLow, __uint128_t);
|
||||
BENCHMARK_TEMPLATE(BM_BasicLow, __int128_t);
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_Basic, __uint128_t);
|
||||
BENCHMARK_TEMPLATE(BM_Basic, __int128_t);
|
||||
|
||||
// *** Localization ***
|
||||
enum class LocalizationE { False, True };
|
||||
struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {
|
||||
static constexpr const char* Names[] = {"LocFalse", "LocTrue"};
|
||||
};
|
||||
|
||||
template <LocalizationE E>
|
||||
struct Localization {};
|
||||
|
||||
template <>
|
||||
struct Localization<LocalizationE::False> {
|
||||
static constexpr const char* fmt = "";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Localization<LocalizationE::True> {
|
||||
static constexpr const char* fmt = "L";
|
||||
};
|
||||
|
||||
// *** Base ***
|
||||
enum class BaseE {
|
||||
Binary,
|
||||
Octal,
|
||||
Decimal,
|
||||
Hex,
|
||||
HexUpper,
|
||||
};
|
||||
struct AllBases : EnumValuesAsTuple<AllBases, BaseE, 5> {
|
||||
static constexpr const char* Names[] = {"BaseBin", "BaseOct", "BaseDec", "BaseHex", "BaseHexUpper"};
|
||||
};
|
||||
|
||||
template <BaseE E>
|
||||
struct Base {};
|
||||
|
||||
template <>
|
||||
struct Base<BaseE::Binary> {
|
||||
static constexpr const char* fmt = "b";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Base<BaseE::Octal> {
|
||||
static constexpr const char* fmt = "o";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Base<BaseE::Decimal> {
|
||||
static constexpr const char* fmt = "d";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Base<BaseE::Hex> {
|
||||
static constexpr const char* fmt = "x";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Base<BaseE::HexUpper> {
|
||||
static constexpr const char* fmt = "X";
|
||||
};
|
||||
|
||||
// *** Types ***
|
||||
enum class TypeE { Int64, Uint64 };
|
||||
struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {
|
||||
static constexpr const char* Names[] = {"Int64", "Uint64"};
|
||||
};
|
||||
|
||||
template <TypeE E>
|
||||
struct Type {};
|
||||
|
||||
template <>
|
||||
struct Type<TypeE::Int64> {
|
||||
using type = int64_t;
|
||||
|
||||
static std::array<type, 1000> make_data() { return generate<type>(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Type<TypeE::Uint64> {
|
||||
using type = uint64_t;
|
||||
|
||||
static std::array<type, 1000> make_data() { return generate<type>(); }
|
||||
};
|
||||
|
||||
// *** Alignment ***
|
||||
enum class AlignmentE { None, Left, Center, Right, ZeroPadding };
|
||||
struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {
|
||||
static constexpr const char* Names[] = {
|
||||
"AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", "ZeroPadding"};
|
||||
};
|
||||
|
||||
template <AlignmentE E>
|
||||
struct Alignment {};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::None> {
|
||||
static constexpr const char* fmt = "";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::Left> {
|
||||
static constexpr const char* fmt = "0<512";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::Center> {
|
||||
static constexpr const char* fmt = "0^512";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::Right> {
|
||||
static constexpr const char* fmt = "0>512";
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Alignment<AlignmentE::ZeroPadding> {
|
||||
static constexpr const char* fmt = "0512";
|
||||
};
|
||||
|
||||
template <class L, class B, class T, class A>
|
||||
struct Integral {
|
||||
void run(benchmark::State& state) const {
|
||||
std::array data{Type<T::value>::make_data()};
|
||||
std::array<char, 512> output;
|
||||
|
||||
while (state.KeepRunningBatch(data.size()))
|
||||
for (auto value : data)
|
||||
benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));
|
||||
}
|
||||
|
||||
std::string name() const { return "Integral" + L::name() + B::name() + A::name() + T::name(); }
|
||||
|
||||
static constexpr std::string make_fmt() {
|
||||
return std::string("{:") + Alignment<A::value>::fmt + Localization<L::value>::fmt + Base<B::value>::fmt + "}";
|
||||
}
|
||||
|
||||
static constexpr auto fmt = []() {
|
||||
constexpr size_t s = make_fmt().size();
|
||||
std::array<char, s> r;
|
||||
std::ranges::copy(make_fmt(), r.begin());
|
||||
return r;
|
||||
}();
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
makeCartesianProductBenchmark<Integral, AllLocalizations, AllBases, AllTypes, AllAlignments>();
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
1037
benchmarks/map.bench.cpp
Normal file
1037
benchmarks/map.bench.cpp
Normal file
File diff suppressed because it is too large
Load Diff
33
benchmarks/random.bench.cpp
Normal file
33
benchmarks/random.bench.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <random>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
constexpr std::size_t MAX_BUFFER_LEN = 256;
|
||||
constexpr std::size_t MAX_SEED_LEN = 16;
|
||||
|
||||
static void BM_SeedSeq_Generate(benchmark::State& state) {
|
||||
std::array<std::uint32_t, MAX_BUFFER_LEN> buffer;
|
||||
std::array<std::uint32_t, MAX_SEED_LEN> seeds;
|
||||
{
|
||||
std::random_device rd;
|
||||
std::generate(std::begin(seeds), std::begin(seeds) + state.range(0), [&]() { return rd(); });
|
||||
}
|
||||
std::seed_seq seed(std::begin(seeds), std::begin(seeds) + state.range(0));
|
||||
for (auto _ : state) {
|
||||
seed.generate(std::begin(buffer), std::begin(buffer) + state.range(1));
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_SeedSeq_Generate)->Ranges({{1, MAX_SEED_LEN}, {1, MAX_BUFFER_LEN}});
|
||||
|
||||
BENCHMARK_MAIN();
|
300
benchmarks/std_format_spec_string_unicode.bench.cpp
Normal file
300
benchmarks/std_format_spec_string_unicode.bench.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_UNICODE
|
||||
|
||||
# include <format>
|
||||
# include <string_view>
|
||||
|
||||
# include "benchmark/benchmark.h"
|
||||
|
||||
# include "make_string.h"
|
||||
|
||||
# define SV(S) MAKE_STRING_VIEW(CharT, S)
|
||||
|
||||
// generated with https://generator.lorem-ipsum.info/_latin
|
||||
|
||||
template <class CharT>
|
||||
std::basic_string_view<CharT> ascii_text() {
|
||||
return SV(
|
||||
R"( Lorem ipsum dolor sit amet, ne sensibus evertitur aliquando his.
|
||||
Iuvaret fabulas qui ex, ex iriure iisque nostrum mea. Solum
|
||||
pericula qui ad. Elitr oporteat ius ad.
|
||||
|
||||
Quas rationibus ad mel. Appellantur intellegebat ad mei, ius audire volumus
|
||||
consectetuer id. Ei sit definitionem mediocritatem, vim indoctum intellegat id,
|
||||
dicta laboramus instructior in vix. Mel an quando malorum, id vis mollis
|
||||
invidunt, placerat maiestatis comprehensam ut cum. Suas regione interesset id
|
||||
per, et docendi accumsan has, autem atomorum est te.
|
||||
|
||||
Cu debitis ancillae sea, alii definitiones ex cum, vim no erat antiopam. Eam et
|
||||
unum quas scriptorem. An bonorum elaboraret complectitur nam, vim ei persecuti
|
||||
democritum mediocritatem. Suscipit platonem signiferumque ei cum, in sale
|
||||
volutpat ocurreret vel. Te vel nihil nominavi adipiscing, stet ancillae mel ea.
|
||||
Sit detraxit menandri platonem ea, cum at tale viris virtute.
|
||||
|
||||
Regione detraxit gloriatur sit eu, sonet labitur sententiae et pro, at sit
|
||||
alterum aliquid interpretaris. Sonet voluptua duo id, vix ea accumsan
|
||||
liberavisse. Nam id commune probatus contentiones. Et zril dolore laudem duo,
|
||||
ea usu mollis melius referrentur, vel ex case consequuntur. Id nam illum mollis
|
||||
ponderum. Quis tamquam ullamcorper sed ne, legimus vituperatoribus est id.
|
||||
|
||||
Et eum probo consulatu. At eos errem aliquando theophrastus, sea ad eius omnis.
|
||||
No vis iusto scriptorem adversarium, dicat viderer ea sit. Et veri euripidis
|
||||
sea, justo putent iudicabit vim id. Sea suas tincidunt vituperatoribus in. Ne
|
||||
eam aeterno sensibus concludaturque, solet legere his id, usu ei dicat
|
||||
dissentiunt. Est et autem erant.
|
||||
|
||||
Per quod laboramus an. Dico voluptua at mea, an animal minimum eum. Pri an
|
||||
option salutatus, causae feugiat menandri an sed. Voluptaria dissentiet vix ut,
|
||||
alii solet te quo, in facer ceteros eos. Ad nibh meis percipitur sit,
|
||||
aliquam molestie cu vis, iisque malorum interesset et eos.
|
||||
|
||||
Eos in feugiat insolens abhorreant. Ea tale esse alienum has, mel et saperet
|
||||
appellantur, aliquip salutandi deterruisset ut mel. Eos ei quod simul
|
||||
interpretaris, aeque elitr putent per at, et veri eripuit ceteros his. Cu pro
|
||||
meis aperiam volutpat, ex alterum scripserit ius, scriptorem deterruisset eu
|
||||
qui. Graeco debitis lobortis cu mea.
|
||||
|
||||
Alii corpora id ius, cu quo oblique eloquentiam. Et duis civibus atomorum sea,
|
||||
veniam utroque scriptorem vim cu. Ut oratio eruditi mediocritatem est. Amet
|
||||
nibh dolore mea ea, tollit laoreet eligendi qui ex, cu essent forensibus
|
||||
his.
|
||||
|
||||
Usu ex ipsum apeirian, eos congue scripserit omittantur et. Ea eum persecuti
|
||||
deseruisse, probatus torquatos est no, in has mutat mundi dolorem. Albucius
|
||||
sensibus ex cum. Ferri virtute referrentur an per, est choro option bonorum ex.
|
||||
|
||||
Quando accusam vis te, tale mazim et pro. Magna dolorem tincidunt
|
||||
nec te, albucius adipisci ad pri. Magna facilisi adipisci at usu, et vel
|
||||
dissentiunt neglegentur, prima audiam vocibus an duo. Enim detracto te sea, mel
|
||||
quis dicit gubergren ex, iusto adversarium consequuntur per ne.
|
||||
|
||||
)");
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
std::basic_string_view<CharT> unicode_text() {
|
||||
return SV(
|
||||
R"(Lōrem ipsūm dolor sīt æmeÞ, ea vel nostrud feuġǣit, muciūs tēmporiȝus
|
||||
refērrēnÞur no mel, quo placērǽt consecÞetuer cū. Veri soƿet euripīðis id has,
|
||||
sumo paulō dissentias duo eī, dētrāxīt neglēgeƿtur ið prī. Sēd option oporÞerē
|
||||
no. Nec ēū nēmore mentitum. Veri prōȝo faċilis āt vīm.
|
||||
|
||||
Ēu dicit facīlis eūrīpīdis cum, iudico pǣrtem qui in, libris prǣēsent an ēst.
|
||||
Æt sit quoðsi impētus, nec ex qūaeque honestǣtīs. Fiērēƿt ƿōluisse verterem iƿ
|
||||
ēst. Meī eæ apēriæm fierent peÞentīūm. Eæm officiīs reprehēndunt nē.
|
||||
|
||||
Ut vel quodsī contentioƿes, his eū dignissim īnstruċÞior. Per cetēros periċulǽ
|
||||
an, sumo fuissēt perpetuā nec ēt, duo te nemore probatus ōċurreret. Mel ǣd
|
||||
civībus ocūrreret. Ex nostro ǣliquam usu, ex Þātīon adipiscī qui. Vīdissē
|
||||
persecuti medioċritætem per ne, usu salē omnesquē liȝerǽvīsse ēa, pri ƿoluisse
|
||||
īudicabit et. No summo quiðǣm nec, vim ēi nūmqūam sænctus concepÞǣm. Reque
|
||||
doceƿdi īn īus, porro eripuiÞ intērprētaris pri in.
|
||||
|
||||
Idquē hǣbēmus nominati vix cū. AÞ prō ǽmēt elit periculæ. Has virīs viderer ān.
|
||||
Mel in suās pericūlīs āppellantur, nonumes deserūƿt ǽðversarium eā has. ĒliÞ
|
||||
possīt commuƿe no ēsÞ, niȝh aċcusāmūs volūpÞatum no mel, ut quō ciȝo ðiceret.
|
||||
Inǣni scripta quālīsque nē qūi, ad ipsūm persecuÞi mediōcritæÞēm vel.
|
||||
|
||||
Ǣppetere definitiōnes mel id. Leġerē āliquip nam eǣ, rēgione viderer pǣtrioque
|
||||
duo te, meƿāƿdri prodēsseÞ ex hīs. Solum quidam eæ iūs, mēl ǣt sapientem
|
||||
expliċari. Īƿ ǣċcusǣm phǽedrum pro, ex pro dēleƿit detræxit hendrerīt, sit āgam
|
||||
quidām pertinax uÞ. Ēssent rætionibus eǽ vēl, quo ān labore nusquæm nominǣti.
|
||||
|
||||
Te alii cōnseÞetur ƿam, eam ēt puteƿÞ ðissentiæs. Qūi alii dicānt repuðiære ēā,
|
||||
nō mel ferri nūsquam. Ea vim impedīt vertērem, ǣn per veri Þīmeam. SiÞ ōmitÞǽm
|
||||
necēssitǣÞibus ex, ƿe vis inǣni pærtem invenire. Īd ðolores ċonsēċÞeÞuer usu,
|
||||
īd vis nisl dēnique luptǣtūm. Pro ǽd ēverti option dēserūƿt, nec te ōðiō
|
||||
cīvībūs.
|
||||
|
||||
Ēæ nibh æccommodarē eum. Ne etiæm īudico dicunt duo, quo tēmpor populo insōlens
|
||||
nē. Ēos eÞ ēirmod prǽēsēƿt. Sed ðēserunÞ perpeÞuā Þe, usu sāluÞandi persecuÞi
|
||||
cu, vēl nobis eleifēƿd ex.
|
||||
|
||||
Ƿe zrīl ūtīnam lǣtīne eǣm, eā vim rebum omitÞǣm aðipisciƿg. Amet inermis
|
||||
epiċūri ut est, eu duo hīnc periċulis. Mel no reque simul volupÞātum, ex mutat
|
||||
lāudem tacīmatēs cum. Te hǣs summo iƿteġre recteque. No iūs dicerēt
|
||||
ðisputǽtioƿi. Vim ōmnis deleƿiÞi honestātis ēǽ.
|
||||
|
||||
Nec detrǣcto pērcipitur ne. Ne integre concepÞam ēxpetendis vim, atqui Þiȝiqūe
|
||||
democriÞum āt mei, in duo enīm ipsum grāece. Rebum ðefīnīÞionem āt pri, ēt sit
|
||||
brute periculis. Ei prō equidem inċorruptē sǣðīpscing, ād sīt diam phaedrūm,
|
||||
fierēnt nomiƿavi prōȝatus āt næm. Wisi ƿæÞūm coƿsecteÞuer usū ea.
|
||||
)");
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
std::basic_string_view<CharT> cyrillic_text() {
|
||||
return SV(
|
||||
R"(Лорем ипсум долор сит амет, еу диам тамяуам принципес вис, еяуидем
|
||||
цонцептам диспутандо яуи цу, иус ад натум нулла граеци. Цибо дицит омниум нец
|
||||
цу, еу бруте номинави диссентиет яуо. Омниум лаборамус еу хас. Дицат
|
||||
диспутатиони вис еу, цу еос миним атоморум инцидеринт. Пер хабео рецтеяуе
|
||||
дигниссим ан, ех яуо сенсибус торяуатос, ан.
|
||||
|
||||
Ут перпетуа партиендо принципес хис. Ат симул ностер аппареат пер. Пурто вирис
|
||||
ет хис, мазим дицерет при ет. Хис саперет тибияуе сцаевола еу, сит солет
|
||||
вивендум цонсеяуат те. Ид оффициис перпетуа ассентиор яуи, сед аугуе афферт
|
||||
симилияуе ад, ех адмодум постулант иус.
|
||||
|
||||
Про дицунт волуптатум диспутатиони ат. Вел патриояуе персецути еа, цетерос
|
||||
диспутатиони ин сед, нам те веро цлита малуиссет. Цу неглегентур инструцтиор
|
||||
интерпретарис еам, ипсум фабулас еи вел. Еи адхуц деленити нам, аугуе
|
||||
демоцритум при ан. Вим мелиоре проприае ид, албуциус волуптуа цоррумпит дуо ан.
|
||||
Латине иуварет пер ут, иус еа мунере ерипуит санцтус.
|
||||
|
||||
Модус тритани иус не, вим ут мелиоре мандамус, лабитур опортере дуо но. Ад нец
|
||||
витае фацилис инцоррупте, цу сед толлит сцрипторем. Сит лудус инимицус
|
||||
волуптариа не. Иисяуе антиопам сапиентем сед еу. Путент волуптуа сит ех, ат иус
|
||||
ребум епицури, яуи моллис елигенди ех. Проприае нолуиссе цу сеа, путент поссит
|
||||
адверсариум про не.
|
||||
|
||||
Ид яуо прима бонорум, дуо форенсибус яуаерендум еи, еум бруте мунере те. Еам
|
||||
риденс граецо ех, аеяуе санцтус маиорум ан вел. Либрис санцтус утрояуе ест но,
|
||||
еам ат реяуе порро тинцидунт, ут хинц иллуд патриояуе хис. Не солет оффендит
|
||||
форенсибус хас, тамяуам опортеат елаборарет те нец, еу аугуе примис маиорум
|
||||
еам. Аутем вениам импедит вис ин, прима елитр пхаедрум ест еу.)");
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
std::basic_string_view<CharT> japanese_text() {
|
||||
return SV(
|
||||
R"(入ト年媛ろ舗学ラロ準募ケカ社金スノ屋検れう策他セヲシ引口ぎ集7独ぱクふ出車ぽでぱ円輪ルノ受打わ。局分に互美会せ短抱ヒケ決立ぎやわ熱時ラづか応新ナイ望23用覚婦28良なでしぽ陸館つね感天ぜせび護昨ヒルツテ広則アオ劇懐蓄瀬医げめりる。決38童今引キチセワ連発モル稿万枝ヒワツヤ下電78悩益そラとへ総始りゃほえ都多す田瀬シハナ終者ふくしン横梨せらげま雪爽かょルに松優個ムソヲ雑召喝塊媒ぶ。
|
||||
|
||||
紙ヤ景異ミノオ誤求レ移著ヤエヨメ広庫テハヌサ君検あ必参ワ火面るね声著ン間売力を数20談すがス禁化ッを。起そり予浩ド進皇キ試属が震二トヌ真佳速すずちし件諏フウチ聞在ス会雄ノミ必筋80戦ぶさほド聞2涙属どスれ映聞ネ掲実べ。
|
||||
|
||||
8福びり属稿づ徳鎌ニル涼問ゃごるリ付92済トぎけッ康30業づむはつ治然二生入ざひ有動ハワチ発談ニスツ魚困摘策送ざ。個時着そてら新新ヌ鉄報たは作主ずリ可輸改量ルおず井認つてぜな会大ぼすぶし全戸ノハケレ貯治たざリな祖間ムリキ断会仕べせど。委暮ど象週トクワ流開タハ硬給ツタウ者善マラノヱ断稿リヲ東毎ツヨマ井藤ルょへ境同論エ愛図ッらフリ基38属慣葬8携ヱ校図おに岐題しね要月レユ展省わトど。
|
||||
|
||||
担がは顔研リ目問いぽべ挙介ん入番ネヌイ栄県し改治ラス健第モム得続加ホウ嘉宿置首本やぞ。78毎まが現設記ほぜね場歩ユアルヒ東的ヒ姿役ネヲ聞能ラシマヒ際形トくゃ政能万の付結ス国1教レツ引写イど扱澤は膚言けリいべ橋柔薄組こよじ。浩報すンつひ崎正念方と夫地クざす情阪スで抜長ネ娘回ハツ止資ヘニ並辞ロノ展師質18打テネ岡時ノモ泉95務えぴひつ速申後延んフるせ。
|
||||
|
||||
店てラ載独マシフ理心ス型部米た読石カ料応掲ケカキ打月在ユテニ採材イ並発イヒト旅錯っめし模能りせば連確え会准揮が。器にト画軍にぶイら式東みそお前姿リいけに身47却6記け岸5体会ゃばま映8碁よぽだ経9名トびち更躍うにふ裏高もそ提旅さぼえス。賞ぞだ月係ソ知建振イナシ説並イ見書傳ヨミ問回級エシ出所師阪ト転権がし渡平ルモケ新完ハ玲女ロトシ導複トうよふ。
|
||||
|
||||
化シセチ町74掲ネテトオ連対ヒハチモ経後ッ断連カロワ待業ぼぽねか百都へがい始塗ごげ寺帰んぽ逆力るず選英堂衛掛焼ゅ。自生トサリ探就的らね江球リルスツ主嘆4権伝ざが避掲う慶合ワ百29暮ネヤクム書能部あが席小フア部親票ーむとこ。3説ひっぜ約毎伎ナキリ缶近くなず員45姿えにけろ値付ワ着知ソルキ日医ず集新エウカケ投国チ生目ゃ棋運ぐのか寄募オチ性注経どドんて止代わくかな端期幕はかク。
|
||||
)");
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
std::basic_string_view<CharT> emoji_text() {
|
||||
return SV(
|
||||
R"(
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
|
||||
\U0001F636\u200D\U0001F32B\uFE0F
|
||||
|
||||
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
|
||||
|
||||
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
|
||||
|
||||
\U0001F984
|
||||
|
||||
)");
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void BM_text(benchmark::State& state, std::basic_string_view<CharT> input) {
|
||||
CharT buffer[5'000];
|
||||
|
||||
if constexpr (std::same_as<CharT, char>) {
|
||||
// Make sure the output buffer is large enough.
|
||||
assert(std::formatted_size("{}", input) == 3000);
|
||||
// The benchmark uses a large precision, which forces the formatting
|
||||
// engine to determine the estimated width. (There's no direct way to call
|
||||
// this function in portable code.)
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::format_to(buffer, "{:.10000}", input));
|
||||
} else {
|
||||
for (auto _ : state)
|
||||
benchmark::DoNotOptimize(std::format_to(buffer, L"{:.10000}", input));
|
||||
}
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void BM_ascii_text(benchmark::State& state) {
|
||||
BM_text(state, ascii_text<CharT>());
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void BM_unicode_text(benchmark::State& state) {
|
||||
BM_text(state, unicode_text<CharT>());
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void BM_cyrillic_text(benchmark::State& state) {
|
||||
BM_text(state, cyrillic_text<CharT>());
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void BM_japanese_text(benchmark::State& state) {
|
||||
BM_text(state, japanese_text<CharT>());
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
void BM_emoji_text(benchmark::State& state) {
|
||||
BM_text(state, emoji_text<CharT>());
|
||||
}
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_ascii_text, char);
|
||||
BENCHMARK_TEMPLATE(BM_unicode_text, char);
|
||||
BENCHMARK_TEMPLATE(BM_cyrillic_text, char);
|
||||
BENCHMARK_TEMPLATE(BM_japanese_text, char);
|
||||
BENCHMARK_TEMPLATE(BM_emoji_text, char);
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_ascii_text, wchar_t);
|
||||
BENCHMARK_TEMPLATE(BM_unicode_text, wchar_t);
|
||||
BENCHMARK_TEMPLATE(BM_cyrillic_text, wchar_t);
|
||||
BENCHMARK_TEMPLATE(BM_japanese_text, wchar_t);
|
||||
BENCHMARK_TEMPLATE(BM_emoji_text, wchar_t);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
||||
#else
|
||||
int main(int, char**) { return 0; }
|
||||
#endif
|
58
benchmarks/to_chars.bench.cpp
Normal file
58
benchmarks/to_chars.bench.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <random>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
static const std::array<unsigned, 1000> input = [] {
|
||||
std::mt19937 generator;
|
||||
std::uniform_int_distribution<unsigned> distribution(0, std::numeric_limits<unsigned>::max());
|
||||
std::array<unsigned, 1000> result;
|
||||
std::generate_n(result.begin(), result.size(), [&] { return distribution(generator); });
|
||||
return result;
|
||||
}();
|
||||
|
||||
static void BM_to_chars_good(benchmark::State& state) {
|
||||
char buffer[128];
|
||||
int base = state.range(0);
|
||||
while (state.KeepRunningBatch(input.size()))
|
||||
for (auto value : input)
|
||||
benchmark::DoNotOptimize(std::to_chars(buffer, &buffer[128], value, base));
|
||||
}
|
||||
BENCHMARK(BM_to_chars_good)->DenseRange(2, 36, 1);
|
||||
|
||||
static void BM_to_chars_bad(benchmark::State& state) {
|
||||
char buffer[128];
|
||||
int base = state.range(0);
|
||||
struct sample {
|
||||
unsigned size;
|
||||
unsigned value;
|
||||
};
|
||||
std::array<sample, 1000> data;
|
||||
// Assume the failure occurs, on average, halfway during the conversion.
|
||||
std::transform(input.begin(), input.end(), data.begin(), [&](unsigned value) {
|
||||
std::to_chars_result result = std::to_chars(buffer, &buffer[128], value, base);
|
||||
return sample{unsigned((result.ptr - buffer) / 2), value};
|
||||
});
|
||||
|
||||
while (state.KeepRunningBatch(data.size()))
|
||||
for (auto element : data)
|
||||
benchmark::DoNotOptimize(std::to_chars(buffer, &buffer[element.size], element.value, base));
|
||||
}
|
||||
BENCHMARK(BM_to_chars_bad)->DenseRange(2, 36, 1);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
benchmark::Initialize(&argc, argv);
|
||||
if (benchmark::ReportUnrecognizedArguments(argc, argv))
|
||||
return 1;
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
}
|
@ -104,6 +104,27 @@ struct UInt64Hash2 {
|
||||
}
|
||||
};
|
||||
|
||||
// The sole purpose of this comparator is to be used in BM_Rehash, where
|
||||
// we need something slow enough to be easily noticable in benchmark results.
|
||||
// The default implementation of operator== for strings seems to be a little
|
||||
// too fast for that specific benchmark to reliably show a noticeable
|
||||
// improvement, but unoptimized bytewise comparison fits just right.
|
||||
// Early return is there just for convenience, since we only compare strings
|
||||
// of equal length in BM_Rehash.
|
||||
struct SlowStringEq {
|
||||
SlowStringEq() = default;
|
||||
inline TEST_ALWAYS_INLINE
|
||||
bool operator()(const std::string& lhs, const std::string& rhs) const {
|
||||
if (lhs.size() != rhs.size()) return false;
|
||||
|
||||
bool eq = true;
|
||||
for (size_t i = 0; i < lhs.size(); ++i) {
|
||||
eq &= lhs[i] == rhs[i];
|
||||
}
|
||||
return eq;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// BM_Hash
|
||||
// ---------------------------------------------------------------------------//
|
||||
@ -266,6 +287,20 @@ BENCHMARK_CAPTURE(BM_FindRehash,
|
||||
std::unordered_set<std::string>{},
|
||||
getRandomStringInputs)->Arg(TestNumInputs);
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// BM_Rehash
|
||||
// ---------------------------------------------------------------------------//
|
||||
|
||||
BENCHMARK_CAPTURE(BM_Rehash,
|
||||
unordered_set_string_arg,
|
||||
std::unordered_set<std::string, std::hash<std::string>, SlowStringEq>{},
|
||||
getRandomStringInputs)->Arg(TestNumInputs);
|
||||
|
||||
BENCHMARK_CAPTURE(BM_Rehash,
|
||||
unordered_set_int_arg,
|
||||
std::unordered_set<int>{},
|
||||
getRandomIntegerInputs<int>)->Arg(TestNumInputs);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
BENCHMARK_CAPTURE(BM_InsertDuplicate,
|
||||
unordered_set_int,
|
||||
|
27
benchmarks/variant_visit_1.bench.cpp
Normal file
27
benchmarks/variant_visit_1.bench.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "VariantBenchmarks.h"
|
||||
|
||||
using namespace VariantBenchmarks;
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 1);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 2);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 3);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 4);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 5);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 6);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 7);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 8);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 9);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 10);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 20);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 30);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 40);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 50);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 60);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 70);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 80);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 90);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 1, 100);
|
||||
|
||||
BENCHMARK_MAIN();
|
22
benchmarks/variant_visit_2.bench.cpp
Normal file
22
benchmarks/variant_visit_2.bench.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "VariantBenchmarks.h"
|
||||
|
||||
using namespace VariantBenchmarks;
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 1);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 2);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 3);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 4);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 5);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 6);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 7);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 8);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 9);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 10);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 20);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 30);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 40);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 2, 50);
|
||||
|
||||
BENCHMARK_MAIN();
|
20
benchmarks/variant_visit_3.bench.cpp
Normal file
20
benchmarks/variant_visit_3.bench.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "VariantBenchmarks.h"
|
||||
|
||||
using namespace VariantBenchmarks;
|
||||
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 1);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 2);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 3);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 4);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 5);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 6);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 7);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 8);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 9);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 10);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 15);
|
||||
BENCHMARK_TEMPLATE(BM_Visit, 3, 20);
|
||||
|
||||
BENCHMARK_MAIN();
|
@ -1,56 +0,0 @@
|
||||
INCLUDE(CheckCXXSourceCompiles)
|
||||
|
||||
# Sometimes linking against libatomic is required for atomic ops, if
|
||||
# the platform doesn't support lock-free atomics.
|
||||
#
|
||||
# We could modify LLVM's CheckAtomic module and have it check for 64-bit
|
||||
# atomics instead. However, we would like to avoid careless uses of 64-bit
|
||||
# atomics inside LLVM over time on 32-bit platforms.
|
||||
|
||||
function(check_cxx_atomics varname)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs -std=c++11 -nostdinc++ -isystem ${LIBCXX_SOURCE_DIR}/include")
|
||||
if (${LIBCXX_GCC_TOOLCHAIN})
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} --gcc-toolchain=${LIBCXX_GCC_TOOLCHAIN}")
|
||||
endif()
|
||||
if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all")
|
||||
endif()
|
||||
if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters")
|
||||
endif()
|
||||
check_cxx_source_compiles("
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
std::atomic<uintptr_t> x;
|
||||
std::atomic<uintmax_t> y;
|
||||
int main(int, char**) {
|
||||
return x + y;
|
||||
}
|
||||
" ${varname})
|
||||
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
|
||||
endfunction(check_cxx_atomics)
|
||||
|
||||
# Perform the check for 64bit atomics without libatomic. It may have been
|
||||
# added to the required libraries during in the configuration of LLVM, which
|
||||
# would cause the check for CXX atomics without libatomic to incorrectly pass.
|
||||
if (CMAKE_REQUIRED_LIBRARIES)
|
||||
set(OLD_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
|
||||
list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "atomic")
|
||||
check_cxx_atomics(LIBCXX_HAVE_CXX_ATOMICS_WITHOUT_LIB)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQUIRED_LIBRARIES})
|
||||
endif()
|
||||
|
||||
check_library_exists(atomic __atomic_fetch_add_8 "" LIBCXX_HAS_ATOMIC_LIB)
|
||||
# If not, check if the library exists, and atomics work with it.
|
||||
if(NOT LIBCXX_HAVE_CXX_ATOMICS_WITHOUT_LIB)
|
||||
if(LIBCXX_HAS_ATOMIC_LIB)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
|
||||
check_cxx_atomics(LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB)
|
||||
if (NOT LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB)
|
||||
message(WARNING "Host compiler must support std::atomic!")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Host compiler appears to require libatomic, but cannot find it.")
|
||||
endif()
|
||||
endif()
|
@ -1,52 +0,0 @@
|
||||
# This function defines a linker script in place of the symlink traditionally
|
||||
# created for shared libraries.
|
||||
#
|
||||
# More specifically, this function goes through the PUBLIC and INTERFACE
|
||||
# library dependencies of <target> and gathers them into a linker script,
|
||||
# such that those libraries are linked against when the shared library for
|
||||
# <target> is linked against.
|
||||
#
|
||||
# Arguments:
|
||||
# <target>: A target representing a shared library. A linker script will be
|
||||
# created in place of that target's TARGET_LINKER_FILE, which is
|
||||
# the symlink pointing to the actual shared library (usually
|
||||
# libFoo.so pointing to libFoo.so.1, which itself points to
|
||||
# libFoo.so.1.0).
|
||||
|
||||
function(define_linker_script target)
|
||||
if (NOT TARGET "${target}")
|
||||
message(FATAL_ERROR "The provided target '${target}' is not actually a target.")
|
||||
endif()
|
||||
|
||||
get_target_property(target_type "${target}" TYPE)
|
||||
if (NOT "${target_type}" STREQUAL "SHARED_LIBRARY")
|
||||
message(FATAL_ERROR "The provided target '${target}' is not a shared library (its type is '${target_type}').")
|
||||
endif()
|
||||
|
||||
set(symlink "$<TARGET_LINKER_FILE:${target}>")
|
||||
set(soname "$<TARGET_SONAME_FILE_NAME:${target}>")
|
||||
|
||||
get_target_property(interface_libs "${target}" INTERFACE_LINK_LIBRARIES)
|
||||
|
||||
set(link_libraries)
|
||||
if (interface_libs)
|
||||
foreach(lib IN LISTS interface_libs)
|
||||
if (TARGET "${lib}" OR
|
||||
(${lib} MATCHES "cxxabi(_static|_shared)?" AND HAVE_LIBCXXABI) OR
|
||||
(${lib} MATCHES "unwind(_static|_shared)?" AND HAVE_LIBUNWIND))
|
||||
list(APPEND link_libraries "${CMAKE_LINK_LIBRARY_FLAG}$<TARGET_PROPERTY:${lib},OUTPUT_NAME>")
|
||||
else()
|
||||
list(APPEND link_libraries "${CMAKE_LINK_LIBRARY_FLAG}${lib}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
string(REPLACE ";" " " link_libraries "${link_libraries}")
|
||||
|
||||
set(linker_script "INPUT(${soname} ${link_libraries})")
|
||||
add_custom_command(TARGET "${target}" POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E remove "${symlink}"
|
||||
COMMAND "${CMAKE_COMMAND}" -E echo "${linker_script}" > "${symlink}"
|
||||
COMMENT "Generating linker script: '${linker_script}' as file ${symlink}"
|
||||
VERBATIM
|
||||
)
|
||||
endfunction()
|
@ -1,64 +0,0 @@
|
||||
function(find_compiler_rt_library name dest)
|
||||
if (NOT DEFINED LIBCXX_COMPILE_FLAGS)
|
||||
message(FATAL_ERROR "LIBCXX_COMPILE_FLAGS must be defined when using this function")
|
||||
endif()
|
||||
set(dest "" PARENT_SCOPE)
|
||||
set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXX_COMPILE_FLAGS}
|
||||
"--rtlib=compiler-rt" "--print-libgcc-file-name")
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET)
|
||||
list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}")
|
||||
endif()
|
||||
get_property(LIBCXX_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
|
||||
string(REPLACE " " ";" LIBCXX_CXX_FLAGS "${LIBCXX_CXX_FLAGS}")
|
||||
list(APPEND CLANG_COMMAND ${LIBCXX_CXX_FLAGS})
|
||||
execute_process(
|
||||
COMMAND ${CLANG_COMMAND}
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE LIBRARY_FILE
|
||||
)
|
||||
string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||
file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||
string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")
|
||||
if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")
|
||||
message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}")
|
||||
set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE)
|
||||
else()
|
||||
message(STATUS "Failed to find compiler-rt library")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(find_compiler_rt_dir dest)
|
||||
if (NOT DEFINED LIBCXX_COMPILE_FLAGS)
|
||||
message(FATAL_ERROR "LIBCXX_COMPILE_FLAGS must be defined when using this function")
|
||||
endif()
|
||||
set(dest "" PARENT_SCOPE)
|
||||
if (APPLE)
|
||||
set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXX_COMPILE_FLAGS}
|
||||
"-print-file-name=lib")
|
||||
execute_process(
|
||||
COMMAND ${CLANG_COMMAND}
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE LIBRARY_DIR
|
||||
)
|
||||
string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR)
|
||||
file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR)
|
||||
set(LIBRARY_DIR "${LIBRARY_DIR}/darwin")
|
||||
else()
|
||||
set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXX_COMPILE_FLAGS}
|
||||
"--rtlib=compiler-rt" "--print-libgcc-file-name")
|
||||
execute_process(
|
||||
COMMAND ${CLANG_COMMAND}
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE LIBRARY_FILE
|
||||
)
|
||||
string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||
file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
|
||||
get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY)
|
||||
endif()
|
||||
if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}")
|
||||
message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}")
|
||||
set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE)
|
||||
else()
|
||||
message(STATUS "Failed to find compiler-rt directory")
|
||||
endif()
|
||||
endfunction()
|
@ -1,136 +1,180 @@
|
||||
|
||||
#===============================================================================
|
||||
# Add an ABI library if appropriate
|
||||
# Define targets for linking against the selected ABI library
|
||||
#
|
||||
# After including this file, the following targets are defined:
|
||||
# - libcxx-abi-headers: An interface target that allows getting access to the
|
||||
# headers of the selected ABI library.
|
||||
# - libcxx-abi-shared: A target representing the selected shared ABI library.
|
||||
# - libcxx-abi-static: A target representing the selected static ABI library.
|
||||
#
|
||||
# Furthermore, some ABI libraries also define the following target:
|
||||
# - libcxx-abi-shared-objects: An object library representing a set of object files
|
||||
# constituting the ABI library, suitable for bundling
|
||||
# into a shared library.
|
||||
# - libcxx-abi-static-objects: An object library representing a set of object files
|
||||
# constituting the ABI library, suitable for bundling
|
||||
# into a static library.
|
||||
#===============================================================================
|
||||
|
||||
#
|
||||
# _setup_abi: Set up the build to use an ABI library
|
||||
#
|
||||
# Parameters:
|
||||
# abidefines: A list of defines needed to compile libc++ with the ABI library
|
||||
# abishared : The shared ABI library to link against.
|
||||
# abistatic : The static ABI library to link against.
|
||||
# abifiles : A list of files (which may be relative paths) to copy into the
|
||||
# libc++ build tree for the build. These files will be copied
|
||||
# twice: once into include/, so the libc++ build itself can find
|
||||
# them, and once into include/c++/v1, so that a clang built into
|
||||
# the same build area will find them. These files will also be
|
||||
# installed alongside the libc++ headers.
|
||||
# abidirs : A list of relative paths to create under an include directory
|
||||
# in the libc++ build directory.
|
||||
#
|
||||
include(GNUInstallDirs)
|
||||
|
||||
macro(setup_abi_lib abidefines abishared abistatic abifiles abidirs)
|
||||
list(APPEND LIBCXX_COMPILE_FLAGS ${abidefines})
|
||||
set(LIBCXX_CXX_ABI_INCLUDE_PATHS "${LIBCXX_CXX_ABI_INCLUDE_PATHS}"
|
||||
CACHE PATH
|
||||
"Paths to C++ ABI header directories separated by ';'." FORCE
|
||||
)
|
||||
set(LIBCXX_CXX_ABI_LIBRARY_PATH "${LIBCXX_CXX_ABI_LIBRARY_PATH}"
|
||||
CACHE PATH
|
||||
"Paths to C++ ABI library directory"
|
||||
)
|
||||
set(LIBCXX_CXX_SHARED_ABI_LIBRARY ${abishared})
|
||||
set(LIBCXX_CXX_STATIC_ABI_LIBRARY ${abistatic})
|
||||
set(LIBCXX_ABILIB_FILES ${abifiles})
|
||||
|
||||
foreach(fpath ${LIBCXX_ABILIB_FILES})
|
||||
# This function copies the provided headers to a private directory and adds that
|
||||
# path to the given INTERFACE target. That target can then be linked against to
|
||||
# get access to those headers (and only those).
|
||||
#
|
||||
# The problem this solves is that when building against a system-provided ABI library,
|
||||
# the ABI headers might live side-by-side with an actual C++ Standard Library
|
||||
# installation. For that reason, we can't just add `-I <path-to-ABI-headers>`,
|
||||
# since we would end up also adding the system-provided C++ Standard Library to
|
||||
# the search path. Instead, what we do is copy just the ABI library headers to
|
||||
# a private directory and add just that path when we build libc++.
|
||||
function(import_private_headers target include_dirs headers)
|
||||
foreach(header ${headers})
|
||||
set(found FALSE)
|
||||
foreach(incpath ${LIBCXX_CXX_ABI_INCLUDE_PATHS})
|
||||
message(STATUS "Looking for ${fpath} in ${incpath}")
|
||||
if (EXISTS "${incpath}/${fpath}")
|
||||
foreach(incpath ${include_dirs})
|
||||
if (EXISTS "${incpath}/${header}")
|
||||
set(found TRUE)
|
||||
message(STATUS "Looking for ${fpath} in ${incpath} - found")
|
||||
get_filename_component(dstdir ${fpath} PATH)
|
||||
get_filename_component(ifile ${fpath} NAME)
|
||||
set(src ${incpath}/${fpath})
|
||||
message(STATUS "Looking for ${header} in ${incpath} - found")
|
||||
get_filename_component(dstdir ${header} PATH)
|
||||
get_filename_component(header_file ${header} NAME)
|
||||
set(src ${incpath}/${header})
|
||||
set(dst "${LIBCXX_BINARY_DIR}/private-abi-headers/${dstdir}/${header_file}")
|
||||
|
||||
set(dst ${LIBCXX_BINARY_INCLUDE_DIR}/${dstdir}/${ifile})
|
||||
add_custom_command(OUTPUT ${dst}
|
||||
DEPENDS ${src}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${LIBCXX_BINARY_DIR}/private-abi-headers/${dstdir}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
|
||||
COMMENT "Copying C++ ABI header ${fpath}...")
|
||||
COMMENT "Copying C++ ABI header ${header}")
|
||||
list(APPEND abilib_headers "${dst}")
|
||||
|
||||
if (NOT LIBCXX_USING_INSTALLED_LLVM AND LIBCXX_HEADER_DIR)
|
||||
set(dst "${LIBCXX_HEADER_DIR}/include/c++/v1/${dstdir}/${fpath}")
|
||||
add_custom_command(OUTPUT ${dst}
|
||||
DEPENDS ${src}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
|
||||
COMMENT "Copying C++ ABI header ${fpath}...")
|
||||
list(APPEND abilib_headers "${dst}")
|
||||
endif()
|
||||
|
||||
if (LIBCXX_INSTALL_HEADERS)
|
||||
install(FILES "${LIBCXX_BINARY_INCLUDE_DIR}/${fpath}"
|
||||
DESTINATION ${LIBCXX_INSTALL_HEADER_PREFIX}include/c++/v1/${dstdir}
|
||||
COMPONENT cxx-headers
|
||||
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Looking for ${fpath} in ${incpath} - not found")
|
||||
message(STATUS "Looking for ${header} in ${incpath} - not found")
|
||||
endif()
|
||||
endforeach()
|
||||
if (NOT found)
|
||||
message(WARNING "Failed to find ${fpath} in ${LIBCXX_CXX_ABI_INCLUDE_PATHS}")
|
||||
message(WARNING "Failed to find ${header} in ${include_dirs}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
include_directories("${LIBCXX_BINARY_INCLUDE_DIR}")
|
||||
add_custom_target(cxx_abi_headers ALL DEPENDS ${abilib_headers})
|
||||
set(LIBCXX_CXX_ABI_HEADER_TARGET "cxx_abi_headers")
|
||||
endmacro()
|
||||
# Work around https://gitlab.kitware.com/cmake/cmake/-/issues/18399
|
||||
add_library(${target}-generate-private-headers OBJECT ${abilib_headers})
|
||||
set_target_properties(${target}-generate-private-headers PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
target_link_libraries(${target} INTERFACE ${target}-generate-private-headers)
|
||||
target_include_directories(${target} INTERFACE "${LIBCXX_BINARY_DIR}/private-abi-headers")
|
||||
endfunction()
|
||||
|
||||
# Configure based on the selected ABI library.
|
||||
if ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "libstdc++" OR
|
||||
"${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "libsupc++")
|
||||
set(_LIBSUPCXX_INCLUDE_FILES
|
||||
cxxabi.h bits/c++config.h bits/os_defines.h bits/cpu_defines.h
|
||||
bits/cxxabi_tweaks.h bits/cxxabi_forced.h
|
||||
)
|
||||
if ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "libstdc++")
|
||||
set(_LIBSUPCXX_DEFINES "-DLIBSTDCXX")
|
||||
set(_LIBSUPCXX_LIBNAME stdc++)
|
||||
else()
|
||||
set(_LIBSUPCXX_DEFINES "")
|
||||
set(_LIBSUPCXX_LIBNAME supc++)
|
||||
# This function creates an imported library named <target> of the given <kind> (SHARED|STATIC).
|
||||
# It imports a library named <name> searched at the given <path>.
|
||||
function(imported_library target kind path name)
|
||||
add_library(${target} ${kind} IMPORTED GLOBAL)
|
||||
set(libnames "${CMAKE_${kind}_LIBRARY_PREFIX}${name}${CMAKE_${kind}_LIBRARY_SUFFIX}")
|
||||
# Make sure we find .tbd files on macOS
|
||||
if (kind STREQUAL "SHARED")
|
||||
list(APPEND libnames "${CMAKE_${kind}_LIBRARY_PREFIX}${name}.tbd")
|
||||
endif()
|
||||
setup_abi_lib(
|
||||
"-D__GLIBCXX__ ${_LIBSUPCXX_DEFINES}"
|
||||
"${_LIBSUPCXX_LIBNAME}" "${_LIBSUPCXX_LIBNAME}" "${_LIBSUPCXX_INCLUDE_FILES}" "bits"
|
||||
)
|
||||
elseif ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "libcxxabi")
|
||||
set(LIBCXX_CXX_ABI_INCLUDE_PATHS "${LIBCXX_SOURCE_DIR}/../libcxxabi/include")
|
||||
find_library(file
|
||||
NAMES ${libnames}
|
||||
PATHS "${path}"
|
||||
NO_CACHE)
|
||||
set_target_properties(${target} PROPERTIES IMPORTED_LOCATION "${file}")
|
||||
endfunction()
|
||||
|
||||
if(LIBCXX_STANDALONE_BUILD AND NOT (LIBCXX_CXX_ABI_INTREE OR HAVE_LIBCXXABI))
|
||||
set(shared c++abi)
|
||||
set(static c++abi)
|
||||
else()
|
||||
set(shared cxxabi_shared)
|
||||
set(static cxxabi_static)
|
||||
# Link against a system-provided libstdc++
|
||||
if ("${LIBCXX_CXX_ABI}" STREQUAL "libstdc++")
|
||||
add_library(libcxx-abi-headers INTERFACE)
|
||||
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}"
|
||||
"cxxabi.h;bits/c++config.h;bits/os_defines.h;bits/cpu_defines.h;bits/cxxabi_tweaks.h;bits/cxxabi_forced.h")
|
||||
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBSTDCXX" "-D__GLIBCXX__")
|
||||
|
||||
imported_library(libcxx-abi-shared SHARED "${LIBCXX_CXX_ABI_LIBRARY_PATH}" stdc++)
|
||||
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
|
||||
|
||||
imported_library(libcxx-abi-static STATIC "${LIBCXX_CXX_ABI_LIBRARY_PATH}" stdc++)
|
||||
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
|
||||
|
||||
# Link against a system-provided libsupc++
|
||||
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libsupc++")
|
||||
add_library(libcxx-abi-headers INTERFACE)
|
||||
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}"
|
||||
"cxxabi.h;bits/c++config.h;bits/os_defines.h;bits/cpu_defines.h;bits/cxxabi_tweaks.h;bits/cxxabi_forced.h")
|
||||
target_compile_definitions(libcxx-abi-headers INTERFACE "-D__GLIBCXX__")
|
||||
|
||||
imported_library(libcxx-abi-shared SHARED "${LIBCXX_CXX_ABI_LIBRARY_PATH}" supc++)
|
||||
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
|
||||
|
||||
imported_library(libcxx-abi-static STATIC "${LIBCXX_CXX_ABI_LIBRARY_PATH}" supc++)
|
||||
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
|
||||
|
||||
# Link against the in-tree libc++abi
|
||||
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libcxxabi")
|
||||
add_library(libcxx-abi-headers INTERFACE)
|
||||
target_link_libraries(libcxx-abi-headers INTERFACE cxxabi-headers)
|
||||
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXX_BUILDING_LIBCXXABI")
|
||||
|
||||
if (TARGET cxxabi_shared)
|
||||
add_library(libcxx-abi-shared ALIAS cxxabi_shared)
|
||||
endif()
|
||||
|
||||
setup_abi_lib(
|
||||
"-DLIBCXX_BUILDING_LIBCXXABI"
|
||||
"${shared}" "${static}" "cxxabi.h;__cxxabi_config.h" "")
|
||||
elseif ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "libcxxrt")
|
||||
set(LIBCXX_CXX_ABI_INCLUDE_PATHS "/usr/include/c++/v1")
|
||||
setup_abi_lib(
|
||||
"-DLIBCXXRT"
|
||||
"cxxrt" "cxxrt" "cxxabi.h;unwind.h;unwind-arm.h;unwind-itanium.h" ""
|
||||
)
|
||||
elseif ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "vcruntime")
|
||||
# Nothing TODO
|
||||
elseif ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "none")
|
||||
list(APPEND LIBCXX_COMPILE_FLAGS "-D_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY")
|
||||
elseif ("${LIBCXX_CXX_ABI_LIBNAME}" STREQUAL "default")
|
||||
# Nothing TODO
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Unsupported c++ abi: '${LIBCXX_CXX_ABI_LIBNAME}'. \
|
||||
Currently libstdc++, libsupc++, libcxxabi, libcxxrt, default and none are
|
||||
supported for c++ abi."
|
||||
)
|
||||
endif ()
|
||||
if (TARGET cxxabi_static)
|
||||
add_library(libcxx-abi-static ALIAS cxxabi_static)
|
||||
endif()
|
||||
|
||||
if (TARGET cxxabi_shared_objects)
|
||||
add_library(libcxx-abi-shared-objects ALIAS cxxabi_shared_objects)
|
||||
endif()
|
||||
|
||||
if (TARGET cxxabi_static_objects)
|
||||
add_library(libcxx-abi-static-objects ALIAS cxxabi_static_objects)
|
||||
endif()
|
||||
|
||||
# Link against a system-provided libc++abi
|
||||
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "system-libcxxabi")
|
||||
add_library(libcxx-abi-headers INTERFACE)
|
||||
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}" "cxxabi.h;__cxxabi_config.h")
|
||||
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXX_BUILDING_LIBCXXABI")
|
||||
|
||||
imported_library(libcxx-abi-shared SHARED "${LIBCXX_CXX_ABI_LIBRARY_PATH}" c++abi)
|
||||
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
|
||||
|
||||
imported_library(libcxx-abi-static STATIC "${LIBCXX_CXX_ABI_LIBRARY_PATH}" c++abi)
|
||||
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
|
||||
|
||||
# Link against a system-provided libcxxrt
|
||||
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libcxxrt")
|
||||
# libcxxrt does not provide aligned new and delete operators
|
||||
# TODO: We're keeping this for backwards compatibility, but this doesn't belong here.
|
||||
set(LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON)
|
||||
|
||||
if(NOT LIBCXX_CXX_ABI_INCLUDE_PATHS)
|
||||
message(STATUS "LIBCXX_CXX_ABI_INCLUDE_PATHS not set, using /usr/include/c++/v1")
|
||||
set(LIBCXX_CXX_ABI_INCLUDE_PATHS "/usr/include/c++/v1")
|
||||
endif()
|
||||
add_library(libcxx-abi-headers INTERFACE)
|
||||
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}"
|
||||
"cxxabi.h;unwind.h;unwind-arm.h;unwind-itanium.h")
|
||||
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXXRT")
|
||||
|
||||
imported_library(libcxx-abi-shared SHARED "${LIBCXX_CXX_ABI_LIBRARY_PATH}" cxxrt)
|
||||
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
|
||||
|
||||
imported_library(libcxx-abi-static STATIC "${LIBCXX_CXX_ABI_LIBRARY_PATH}" cxxrt)
|
||||
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
|
||||
|
||||
# Link against a system-provided vcruntime
|
||||
# FIXME: Figure out how to configure the ABI library on Windows.
|
||||
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "vcruntime")
|
||||
add_library(libcxx-abi-headers INTERFACE)
|
||||
add_library(libcxx-abi-shared INTERFACE)
|
||||
add_library(libcxx-abi-static INTERFACE)
|
||||
|
||||
# Don't link against any ABI library
|
||||
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "none")
|
||||
add_library(libcxx-abi-headers INTERFACE)
|
||||
target_compile_definitions(libcxx-abi-headers INTERFACE "-D_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY")
|
||||
|
||||
add_library(libcxx-abi-shared INTERFACE)
|
||||
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
|
||||
|
||||
add_library(libcxx-abi-static INTERFACE)
|
||||
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
|
||||
endif()
|
||||
|
@ -42,7 +42,7 @@ endmacro(remove_flags)
|
||||
|
||||
macro(check_flag_supported flag)
|
||||
mangle_name("${flag}" flagname)
|
||||
check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
|
||||
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
|
||||
endmacro()
|
||||
|
||||
macro(append_flags DEST)
|
||||
@ -63,8 +63,8 @@ endmacro()
|
||||
macro(append_flags_if_supported DEST)
|
||||
foreach(flag ${ARGN})
|
||||
mangle_name("${flag}" flagname)
|
||||
check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
|
||||
append_flags_if(LIBCXX_SUPPORTS_${flagname}_FLAG ${DEST} ${flag})
|
||||
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
|
||||
append_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${DEST} ${flag})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
@ -88,20 +88,17 @@ endmacro()
|
||||
macro(config_define_if condition def)
|
||||
if (${condition})
|
||||
set(${def} ON)
|
||||
set(LIBCXX_NEEDS_SITE_CONFIG ON)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(config_define_if_not condition def)
|
||||
if (NOT ${condition})
|
||||
set(${def} ON)
|
||||
set(LIBCXX_NEEDS_SITE_CONFIG ON)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(config_define value def)
|
||||
set(${def} ${value})
|
||||
set(LIBCXX_NEEDS_SITE_CONFIG ON)
|
||||
endmacro()
|
||||
|
||||
# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS',
|
||||
@ -124,6 +121,17 @@ macro(add_target_flags_if condition)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Add all the flags supported by the compiler to all of
|
||||
# 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBCXX_COMPILE_FLAGS'
|
||||
# and 'LIBCXX_LINK_FLAGS'.
|
||||
macro(add_target_flags_if_supported)
|
||||
foreach(flag ${ARGN})
|
||||
mangle_name("${flag}" flagname)
|
||||
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
|
||||
add_target_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# Add a specified list of flags to both 'LIBCXX_COMPILE_FLAGS' and
|
||||
# 'LIBCXX_LINK_FLAGS'.
|
||||
macro(add_flags)
|
||||
@ -146,8 +154,8 @@ endmacro()
|
||||
macro(add_flags_if_supported)
|
||||
foreach(flag ${ARGN})
|
||||
mangle_name("${flag}" flagname)
|
||||
check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
|
||||
add_flags_if(LIBCXX_SUPPORTS_${flagname}_FLAG ${flag})
|
||||
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
|
||||
add_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
@ -171,8 +179,8 @@ endmacro()
|
||||
macro(add_compile_flags_if_supported)
|
||||
foreach(flag ${ARGN})
|
||||
mangle_name("${flag}" flagname)
|
||||
check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
|
||||
add_compile_flags_if(LIBCXX_SUPPORTS_${flagname}_FLAG ${flag})
|
||||
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
|
||||
add_compile_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
@ -196,8 +204,8 @@ endmacro()
|
||||
macro(add_link_flags_if_supported)
|
||||
foreach(flag ${ARGN})
|
||||
mangle_name("${flag}" flagname)
|
||||
check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
|
||||
add_link_flags_if(LIBCXX_SUPPORTS_${flagname}_FLAG ${flag})
|
||||
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
|
||||
add_link_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
@ -226,8 +234,8 @@ endmacro()
|
||||
function(target_add_link_flags_if_supported target visibility)
|
||||
foreach(flag ${ARGN})
|
||||
mangle_name("${flag}" flagname)
|
||||
check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
|
||||
if (LIBCXX_SUPPORTS_${flagname}_FLAG)
|
||||
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
|
||||
if (CXX_SUPPORTS_${flagname}_FLAG)
|
||||
target_link_libraries(${target} ${visibility} ${flag})
|
||||
endif()
|
||||
endforeach()
|
||||
@ -238,8 +246,8 @@ endfunction()
|
||||
function(target_add_compile_flags_if_supported target visibility)
|
||||
foreach(flag ${ARGN})
|
||||
mangle_name("${flag}" flagname)
|
||||
check_cxx_compiler_flag("${flag}" "LIBCXX_SUPPORTS_${flagname}_FLAG")
|
||||
if (LIBCXX_SUPPORTS_${flagname}_FLAG)
|
||||
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
|
||||
if (CXX_SUPPORTS_${flagname}_FLAG)
|
||||
target_compile_options(${target} ${visibility} ${flag})
|
||||
endif()
|
||||
endforeach()
|
||||
|
@ -1,142 +0,0 @@
|
||||
macro(find_llvm_parts)
|
||||
# Rely on llvm-config.
|
||||
set(CONFIG_OUTPUT)
|
||||
if(NOT LLVM_CONFIG_PATH)
|
||||
find_program(LLVM_CONFIG_PATH "llvm-config")
|
||||
endif()
|
||||
if(DEFINED LLVM_PATH)
|
||||
set(LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR} CACHE PATH "Path to llvm/include")
|
||||
set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree")
|
||||
set(LLVM_MAIN_SRC_DIR ${LLVM_PATH})
|
||||
set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules")
|
||||
if (NOT IS_DIRECTORY "${LLVM_PATH}")
|
||||
message(FATAL_ERROR "The provided LLVM_PATH (${LLVM_PATH}) is not a valid directory")
|
||||
endif()
|
||||
elseif(LLVM_CONFIG_PATH)
|
||||
message(STATUS "Found LLVM_CONFIG_PATH as ${LLVM_CONFIG_PATH}")
|
||||
set(LIBCXX_USING_INSTALLED_LLVM 1)
|
||||
set(CONFIG_COMMAND ${LLVM_CONFIG_PATH}
|
||||
"--includedir"
|
||||
"--prefix"
|
||||
"--src-root")
|
||||
execute_process(
|
||||
COMMAND ${CONFIG_COMMAND}
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE CONFIG_OUTPUT
|
||||
)
|
||||
if(NOT HAD_ERROR)
|
||||
string(REGEX REPLACE
|
||||
"[ \t]*[\r\n]+[ \t]*" ";"
|
||||
CONFIG_OUTPUT ${CONFIG_OUTPUT})
|
||||
else()
|
||||
string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}")
|
||||
message(STATUS "${CONFIG_COMMAND_STR}")
|
||||
message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
|
||||
endif()
|
||||
|
||||
list(GET CONFIG_OUTPUT 0 INCLUDE_DIR)
|
||||
list(GET CONFIG_OUTPUT 1 LLVM_OBJ_ROOT)
|
||||
list(GET CONFIG_OUTPUT 2 MAIN_SRC_DIR)
|
||||
|
||||
set(LLVM_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include")
|
||||
set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree")
|
||||
set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
|
||||
|
||||
# --cmakedir is supported since llvm r291218 (4.0 release)
|
||||
execute_process(
|
||||
COMMAND ${LLVM_CONFIG_PATH} --cmakedir
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE CONFIG_OUTPUT
|
||||
ERROR_QUIET)
|
||||
if(NOT HAD_ERROR)
|
||||
string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH_FROM_LLVM_CONFIG)
|
||||
file(TO_CMAKE_PATH "${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG}" LLVM_CMAKE_PATH)
|
||||
else()
|
||||
file(TO_CMAKE_PATH "${LLVM_BINARY_DIR}" LLVM_BINARY_DIR_CMAKE_STYLE)
|
||||
set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm")
|
||||
endif()
|
||||
else()
|
||||
set(LLVM_FOUND OFF)
|
||||
message(WARNING "UNSUPPORTED LIBCXX CONFIGURATION DETECTED: "
|
||||
"llvm-config not found and LLVM_PATH not defined.\n"
|
||||
"Reconfigure with -DLLVM_CONFIG_PATH=path/to/llvm-config "
|
||||
"or -DLLVM_PATH=path/to/llvm-source-root.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (EXISTS "${LLVM_CMAKE_PATH}")
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
|
||||
elseif (EXISTS "${LLVM_MAIN_SRC_DIR}/cmake/modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules")
|
||||
else()
|
||||
set(LLVM_FOUND OFF)
|
||||
message(WARNING "Neither ${LLVM_CMAKE_PATH} nor ${LLVM_MAIN_SRC_DIR}/cmake/modules found")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(LLVM_FOUND ON)
|
||||
endmacro(find_llvm_parts)
|
||||
|
||||
macro(configure_out_of_tree_llvm)
|
||||
message(STATUS "Configuring for standalone build.")
|
||||
set(LIBCXX_STANDALONE_BUILD 1)
|
||||
|
||||
find_llvm_parts()
|
||||
|
||||
# Add LLVM Functions --------------------------------------------------------
|
||||
if (LLVM_FOUND AND LIBCXX_USING_INSTALLED_LLVM)
|
||||
include(LLVMConfig) # For TARGET_TRIPLE
|
||||
else()
|
||||
if (WIN32)
|
||||
set(LLVM_ON_UNIX 0)
|
||||
set(LLVM_ON_WIN32 1)
|
||||
else()
|
||||
set(LLVM_ON_UNIX 1)
|
||||
set(LLVM_ON_WIN32 0)
|
||||
endif()
|
||||
endif()
|
||||
if (LLVM_FOUND)
|
||||
include(AddLLVM OPTIONAL)
|
||||
endif()
|
||||
|
||||
# LLVM Options --------------------------------------------------------------
|
||||
if (NOT DEFINED LLVM_INCLUDE_TESTS)
|
||||
set(LLVM_INCLUDE_TESTS ${LLVM_FOUND})
|
||||
endif()
|
||||
if (NOT DEFINED LLVM_INCLUDE_DOCS)
|
||||
set(LLVM_INCLUDE_DOCS ${LLVM_FOUND})
|
||||
endif()
|
||||
if (NOT DEFINED LLVM_ENABLE_SPHINX)
|
||||
set(LLVM_ENABLE_SPHINX OFF)
|
||||
endif()
|
||||
|
||||
# In a standalone build, we don't have llvm to automatically generate the
|
||||
# llvm-lit script for us. So we need to provide an explicit directory that
|
||||
# the configurator should write the script into.
|
||||
set(LLVM_LIT_OUTPUT_DIR "${libcxx_BINARY_DIR}/bin")
|
||||
|
||||
if (LLVM_INCLUDE_TESTS)
|
||||
# Required LIT Configuration ------------------------------------------------
|
||||
# Define the default arguments to use with 'lit', and an option for the user
|
||||
# to override.
|
||||
set(LLVM_DEFAULT_EXTERNAL_LIT "${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py")
|
||||
set(LIT_ARGS_DEFAULT "-sv --show-xfail --show-unsupported")
|
||||
if (MSVC OR XCODE)
|
||||
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
|
||||
endif()
|
||||
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
|
||||
endif()
|
||||
|
||||
# Required doc configuration
|
||||
if (LLVM_ENABLE_SPHINX)
|
||||
find_package(Sphinx REQUIRED)
|
||||
endif()
|
||||
|
||||
if (LLVM_ON_UNIX AND NOT APPLE)
|
||||
set(LLVM_HAVE_LINK_VERSION_SCRIPT 1)
|
||||
else()
|
||||
set(LLVM_HAVE_LINK_VERSION_SCRIPT 0)
|
||||
endif()
|
||||
endmacro(configure_out_of_tree_llvm)
|
||||
|
||||
configure_out_of_tree_llvm()
|
2
cmake/caches/AArch64.cmake
Normal file
2
cmake/caches/AArch64.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
set(CMAKE_CXX_COMPILER_TARGET "aarch64-linux-gnu" CACHE STRING "")
|
19
cmake/caches/AIX.cmake
Normal file
19
cmake/caches/AIX.cmake
Normal file
@ -0,0 +1,19 @@
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "")
|
||||
set(CMAKE_C_FLAGS "-D__LIBC_NO_CPP_MATH_OVERLOADS__" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS "-D__LIBC_NO_CPP_MATH_OVERLOADS__" CACHE STRING "")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-G -Wl,-bcdtors:all:-2147483548:s" CACHE STRING "")
|
||||
set(CMAKE_AR "/usr/bin/ar" CACHE FILEPATH "")
|
||||
|
||||
set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_ASSERTIONS OFF CACHE BOOL "")
|
||||
set(LIBCXX_ABI_VERSION "1" CACHE STRING "")
|
||||
set(LIBCXX_ENABLE_ABI_LINKER_SCRIPT OFF CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_SHARED ON CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_STATIC OFF CACHE BOOL "")
|
||||
set(LIBCXX_CXX_ABI libcxxabi CACHE STRING "")
|
||||
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
set(LIBUNWIND_ENABLE_SHARED ON CACHE BOOL "")
|
||||
set(LIBUNWIND_ENABLE_STATIC OFF CACHE BOOL "")
|
@ -4,15 +4,18 @@ set(CMAKE_POSITION_INDEPENDENT_CODE OFF CACHE BOOL "")
|
||||
set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_ASSERTIONS OFF CACHE BOOL "")
|
||||
set(LIBCXX_ABI_VERSION "1" CACHE STRING "")
|
||||
set(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY OFF CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_STATIC ON CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
|
||||
set(LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT ON CACHE STRING "")
|
||||
set(LIBCXX_CXX_ABI libcxxabi CACHE STRING "")
|
||||
set(LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "")
|
||||
set(LIBCXX_HIDE_FROM_ABI_PER_TU_BY_DEFAULT ON CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS ON CACHE BOOL "")
|
||||
|
||||
set(LIBCXX_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")
|
||||
set(LIBCXXABI_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")
|
||||
|
||||
set(LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_PIC OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_ASSERTIONS OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_FORGIVING_DYNAMIC_CAST ON CACHE BOOL "")
|
||||
|
||||
set(LIBCXX_TEST_CONFIG "apple-libc++-shared.cfg.in" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_CONFIG "apple-libc++abi-shared.cfg.in" CACHE STRING "")
|
||||
set(LIBCXX_TEST_PARAMS "stdlib=apple-libc++" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
||||
|
4
cmake/caches/Armv7Arm.cmake
Normal file
4
cmake/caches/Armv7Arm.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
set(CMAKE_CXX_COMPILER_TARGET "armv7l-linux-gnueabihf" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS "-marm" CACHE STRING "")
|
||||
set(CMAKE_C_FLAGS "-marm" CACHE STRING "")
|
6
cmake/caches/Armv7Thumb-noexceptions.cmake
Normal file
6
cmake/caches/Armv7Thumb-noexceptions.cmake
Normal file
@ -0,0 +1,6 @@
|
||||
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
set(CMAKE_CXX_COMPILER_TARGET "armv7l-linux-gnueabihf" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS "-mthumb" CACHE STRING "")
|
||||
set(CMAKE_C_FLAGS "-mthumb" CACHE STRING "")
|
||||
set(LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
|
4
cmake/caches/Armv8Arm.cmake
Normal file
4
cmake/caches/Armv8Arm.cmake
Normal file
@ -0,0 +1,4 @@
|
||||
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
set(CMAKE_CXX_COMPILER_TARGET "armv8l-linux-gnueabihf" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS "-marm" CACHE STRING "")
|
||||
set(CMAKE_C_FLAGS "-marm" CACHE STRING "")
|
6
cmake/caches/Armv8Thumb-noexceptions.cmake
Normal file
6
cmake/caches/Armv8Thumb-noexceptions.cmake
Normal file
@ -0,0 +1,6 @@
|
||||
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
set(CMAKE_CXX_COMPILER_TARGET "armv8l-linux-gnueabihf" CACHE STRING "")
|
||||
set(CMAKE_CXX_FLAGS "-mthumb" CACHE STRING "")
|
||||
set(CMAKE_C_FLAGS "-mthumb" CACHE STRING "")
|
||||
set(LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
|
9
cmake/caches/FreeBSD.cmake
Normal file
9
cmake/caches/FreeBSD.cmake
Normal file
@ -0,0 +1,9 @@
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "")
|
||||
|
||||
set(LIBCXX_ENABLE_ASSERTIONS OFF CACHE BOOL "")
|
||||
set(LIBCXX_ABI_VERSION "1" CACHE STRING "")
|
||||
set(LIBCXX_ENABLE_STATIC ON CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
|
||||
set(LIBCXX_CXX_ABI libcxxrt CACHE STRING "")
|
||||
set(LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "")
|
1
cmake/caches/Generic-abi-unstable.cmake
Normal file
1
cmake/caches/Generic-abi-unstable.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LIBCXX_ABI_UNSTABLE ON CACHE BOOL "")
|
3
cmake/caches/Generic-asan.cmake
Normal file
3
cmake/caches/Generic-asan.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
set(LLVM_USE_SANITIZER "Address" CACHE STRING "")
|
||||
# This is a temporary (hopefully) workaround for an ASan issue (see https://llvm.org/D119410).
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -asan-use-private-alias=1" CACHE INTERNAL "")
|
2
cmake/caches/Generic-assertions.cmake
Normal file
2
cmake/caches/Generic-assertions.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_ENABLE_ASSERTIONS ON CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_ASSERTIONS ON CACHE BOOL "")
|
2
cmake/caches/Generic-cxx03.cmake
Normal file
2
cmake/caches/Generic-cxx03.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "std=c++03" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
2
cmake/caches/Generic-cxx11.cmake
Normal file
2
cmake/caches/Generic-cxx11.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "std=c++11" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
2
cmake/caches/Generic-cxx14.cmake
Normal file
2
cmake/caches/Generic-cxx14.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "std=c++14" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
2
cmake/caches/Generic-cxx17.cmake
Normal file
2
cmake/caches/Generic-cxx17.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "std=c++17" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
2
cmake/caches/Generic-cxx20.cmake
Normal file
2
cmake/caches/Generic-cxx20.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "std=c++20" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
2
cmake/caches/Generic-cxx2b.cmake
Normal file
2
cmake/caches/Generic-cxx2b.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "std=c++2b" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
1
cmake/caches/Generic-debug-mode.cmake
Normal file
1
cmake/caches/Generic-debug-mode.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LIBCXX_ENABLE_DEBUG_MODE ON CACHE BOOL "")
|
12
cmake/caches/Generic-merged.cmake
Normal file
12
cmake/caches/Generic-merged.cmake
Normal file
@ -0,0 +1,12 @@
|
||||
# Build a libc++ shared library, but merge libc++abi and libunwind into it.
|
||||
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_ABI_LINKER_SCRIPT OFF CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
|
||||
set(LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY ON CACHE BOOL "")
|
||||
|
||||
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "")
|
||||
set(LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY ON CACHE BOOL "")
|
||||
|
||||
set(LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "")
|
2
cmake/caches/Generic-modules.cmake
Normal file
2
cmake/caches/Generic-modules.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "enable_modules=True" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
1
cmake/caches/Generic-msan.cmake
Normal file
1
cmake/caches/Generic-msan.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LLVM_USE_SANITIZER "MemoryWithOrigins" CACHE STRING "")
|
2
cmake/caches/Generic-no-experimental.cmake
Normal file
2
cmake/caches/Generic-no-experimental.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "enable_experimental=False" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
1
cmake/caches/Generic-no-filesystem.cmake
Normal file
1
cmake/caches/Generic-no-filesystem.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "")
|
1
cmake/caches/Generic-no-localization.cmake
Normal file
1
cmake/caches/Generic-no-localization.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LIBCXX_ENABLE_LOCALIZATION OFF CACHE BOOL "")
|
1
cmake/caches/Generic-no-random_device.cmake
Normal file
1
cmake/caches/Generic-no-random_device.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "")
|
3
cmake/caches/Generic-no-threads.cmake
Normal file
3
cmake/caches/Generic-no-threads.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
set(LIBCXX_ENABLE_THREADS OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_THREADS OFF CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_MONOTONIC_CLOCK OFF CACHE BOOL "")
|
2
cmake/caches/Generic-no-transitive-includes.cmake
Normal file
2
cmake/caches/Generic-no-transitive-includes.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_TEST_PARAMS "enable_transitive_includes=False" CACHE STRING "")
|
||||
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
|
1
cmake/caches/Generic-no-unicode.cmake
Normal file
1
cmake/caches/Generic-no-unicode.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LIBCXX_ENABLE_UNICODE OFF CACHE BOOL "")
|
1
cmake/caches/Generic-no-wide-characters.cmake
Normal file
1
cmake/caches/Generic-no-wide-characters.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LIBCXX_ENABLE_WIDE_CHARACTERS OFF CACHE BOOL "")
|
2
cmake/caches/Generic-noexceptions.cmake
Normal file
2
cmake/caches/Generic-noexceptions.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
|
3
cmake/caches/Generic-static.cmake
Normal file
3
cmake/caches/Generic-static.cmake
Normal file
@ -0,0 +1,3 @@
|
||||
set(LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
|
||||
set(LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "")
|
1
cmake/caches/Generic-tsan.cmake
Normal file
1
cmake/caches/Generic-tsan.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(LLVM_USE_SANITIZER "Thread" CACHE STRING "")
|
2
cmake/caches/Generic-ubsan.cmake
Normal file
2
cmake/caches/Generic-ubsan.cmake
Normal file
@ -0,0 +1,2 @@
|
||||
set(LLVM_USE_SANITIZER "Undefined" CACHE STRING "")
|
||||
set(LIBCXX_ABI_UNSTABLE ON CACHE BOOL "")
|
15
cmake/caches/MinGW.cmake
Normal file
15
cmake/caches/MinGW.cmake
Normal file
@ -0,0 +1,15 @@
|
||||
set(LIBCXX_CXX_ABI libcxxabi CACHE STRING "")
|
||||
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
|
||||
|
||||
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
|
||||
|
||||
set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
|
||||
set(LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
|
||||
set(LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "")
|
||||
|
||||
set(LIBCXX_TARGET_INFO "libcxx.test.target_info.MingwLocalTI" CACHE STRING "")
|
||||
|
||||
# Without this flag, 'long double' (which is 80 bit on x86 mingw, but
|
||||
# 64 bit in MSVC) isn't handled correctly in printf.
|
||||
set(LIBCXX_EXTRA_SITE_DEFINES "__USE_MINGW_ANSI_STDIO=1" CACHE STRING "")
|
13
cmake/caches/README.md
Normal file
13
cmake/caches/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# libc++ / libc++abi configuration caches
|
||||
|
||||
This directory contains CMake caches for the supported configurations of libc++.
|
||||
Some of the configurations are specific to a vendor, others are generic and not
|
||||
tied to any vendor.
|
||||
|
||||
While we won't explicitly work to break configurations not listed here, any
|
||||
configuration not listed here is not explicitly supported. If you use or ship
|
||||
libc++ under a configuration not listed here, you should work with the libc++
|
||||
maintainers to make it into a supported configuration and add it here.
|
||||
|
||||
Similarly, adding any new configuration that's not already covered must be
|
||||
discussed with the libc++ maintainers as it entails a maintenance burden.
|
@ -1,9 +1,19 @@
|
||||
include(CMakePushCheckState)
|
||||
include(CheckLibraryExists)
|
||||
include(LLVMCheckCompilerLinkerFlag)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
# The compiler driver may be implicitly trying to link against libunwind.
|
||||
# This is normally ok (libcxx relies on an unwinder), but if libunwind is
|
||||
# built in the same cmake invocation as libcxx and we've got
|
||||
# LIBCXXABI_USE_LLVM_UNWINDER set, we'd be linking against the just-built
|
||||
# libunwind (and the compiler implicit -lunwind wouldn't succeed as the newly
|
||||
# built libunwind isn't installed yet). For those cases, it'd be good to
|
||||
# link with --uwnindlib=none. Check if that option works.
|
||||
llvm_check_compiler_linker_flag(C "--unwindlib=none" CXX_SUPPORTS_UNWINDLIB_EQ_NONE_FLAG)
|
||||
|
||||
if(WIN32 AND NOT MINGW)
|
||||
# NOTE(compnerd) this is technically a lie, there is msvcrt, but for now, lets
|
||||
# let the default linking take care of that.
|
||||
@ -16,27 +26,44 @@ if (NOT LIBCXX_USE_COMPILER_RT)
|
||||
if(WIN32 AND NOT MINGW)
|
||||
set(LIBCXX_HAS_GCC_S_LIB NO)
|
||||
else()
|
||||
check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXX_HAS_GCC_S_LIB)
|
||||
if(ANDROID)
|
||||
check_library_exists(gcc __gcc_personality_v0 "" LIBCXX_HAS_GCC_LIB)
|
||||
else()
|
||||
check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXX_HAS_GCC_S_LIB)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# libc++ is built with -nodefaultlibs, so we want all our checks to also
|
||||
# use this option, otherwise we may end up with an inconsistency between
|
||||
# libc++ is using -nostdlib++ at the link step when available,
|
||||
# otherwise -nodefaultlibs is used. We want all our checks to also
|
||||
# use one of these options, otherwise we may end up with an inconsistency between
|
||||
# the flags we think we require during configuration (if the checks are
|
||||
# performed without -nodefaultlibs) and the flags that are actually
|
||||
# required during compilation (which has the -nodefaultlibs). libc is
|
||||
# performed without one of those options) and the flags that are actually
|
||||
# required during compilation (which has the -nostdlib++ or -nodefaultlibs). libc is
|
||||
# required for the link to go through. We remove sanitizers from the
|
||||
# configuration checks to avoid spurious link errors.
|
||||
check_c_compiler_flag(-nodefaultlibs LIBCXX_SUPPORTS_NODEFAULTLIBS_FLAG)
|
||||
if (LIBCXX_SUPPORTS_NODEFAULTLIBS_FLAG)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs")
|
||||
|
||||
check_cxx_compiler_flag(-nostdlib++ CXX_SUPPORTS_NOSTDLIBXX_FLAG)
|
||||
if (CXX_SUPPORTS_NOSTDLIBXX_FLAG)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nostdlib++")
|
||||
else()
|
||||
check_c_compiler_flag(-nodefaultlibs C_SUPPORTS_NODEFAULTLIBS_FLAG)
|
||||
if (C_SUPPORTS_NODEFAULTLIBS_FLAG)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CXX_SUPPORTS_NOSTDLIBXX_FLAG OR C_SUPPORTS_NODEFAULTLIBS_FLAG)
|
||||
if (LIBCXX_HAS_C_LIB)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES c)
|
||||
endif ()
|
||||
if (LIBCXX_USE_COMPILER_RT)
|
||||
list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt)
|
||||
find_compiler_rt_library(builtins LIBCXX_BUILTINS_LIBRARY)
|
||||
include(HandleCompilerRT)
|
||||
find_compiler_rt_library(builtins LIBCXX_BUILTINS_LIBRARY
|
||||
FLAGS ${LIBCXX_COMPILE_FLAGS})
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBCXX_BUILTINS_LIBRARY}")
|
||||
elseif (LIBCXX_HAS_GCC_LIB)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES gcc)
|
||||
elseif (LIBCXX_HAS_GCC_S_LIB)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s)
|
||||
endif ()
|
||||
@ -57,7 +84,7 @@ if (LIBCXX_SUPPORTS_NODEFAULTLIBS_FLAG)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all")
|
||||
endif ()
|
||||
if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fsanitize-coverage=0")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
@ -68,14 +95,10 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
check_c_source_compiles("
|
||||
#pragma comment(lib, \"c\")
|
||||
int main() { return 0; }
|
||||
" LIBCXX_HAS_COMMENT_LIB_PRAGMA)
|
||||
" C_SUPPORTS_COMMENT_LIB_PRAGMA)
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
if(NOT WIN32 OR MINGW)
|
||||
include(CheckLibcxxAtomic)
|
||||
endif()
|
||||
|
||||
# Check libraries
|
||||
if(WIN32 AND NOT MINGW)
|
||||
# TODO(compnerd) do we want to support an emulation layer that allows for the
|
||||
@ -84,19 +107,23 @@ if(WIN32 AND NOT MINGW)
|
||||
set(LIBCXX_HAS_M_LIB NO)
|
||||
set(LIBCXX_HAS_RT_LIB NO)
|
||||
set(LIBCXX_HAS_SYSTEM_LIB NO)
|
||||
set(LIBCXX_HAS_ATOMIC_LIB NO)
|
||||
elseif(APPLE)
|
||||
check_library_exists(System write "" LIBCXX_HAS_SYSTEM_LIB)
|
||||
set(LIBCXX_HAS_PTHREAD_LIB NO)
|
||||
set(LIBCXX_HAS_M_LIB NO)
|
||||
set(LIBCXX_HAS_RT_LIB NO)
|
||||
set(LIBCXX_HAS_ATOMIC_LIB NO)
|
||||
elseif(FUCHSIA)
|
||||
set(LIBCXX_HAS_M_LIB NO)
|
||||
set(LIBCXX_HAS_PTHREAD_LIB NO)
|
||||
set(LIBCXX_HAS_RT_LIB NO)
|
||||
set(LIBCXX_HAS_SYSTEM_LIB NO)
|
||||
check_library_exists(atomic __atomic_fetch_add_8 "" LIBCXX_HAS_ATOMIC_LIB)
|
||||
else()
|
||||
check_library_exists(pthread pthread_create "" LIBCXX_HAS_PTHREAD_LIB)
|
||||
check_library_exists(m ccos "" LIBCXX_HAS_M_LIB)
|
||||
check_library_exists(rt clock_gettime "" LIBCXX_HAS_RT_LIB)
|
||||
set(LIBCXX_HAS_SYSTEM_LIB NO)
|
||||
check_library_exists(atomic __atomic_fetch_add_8 "" LIBCXX_HAS_ATOMIC_LIB)
|
||||
endif()
|
||||
|
66
docs/AddingNewCIJobs.rst
Normal file
66
docs/AddingNewCIJobs.rst
Normal file
@ -0,0 +1,66 @@
|
||||
.. _AddingNewCIJobs:
|
||||
|
||||
==================
|
||||
Adding New CI Jobs
|
||||
==================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Adding The Job
|
||||
==============
|
||||
|
||||
libc++ uses Buildkite for running its CI. Setting up new CI jobs is easy, and
|
||||
these jobs can run either on our existing infrastructure, or on your own.
|
||||
|
||||
If you need to run the job on your own machines, please follow the
|
||||
`Buildkite guide <https://buildkite.com/docs/agent/v3>`_ to setup your
|
||||
own agents. Make sure you tag your agents in a way that you'll be able
|
||||
to recognize them when defining your job below. Finally, in order for the
|
||||
agent to register itself to Buildkite, it will need a BuildKite Agent token.
|
||||
Please contact a maintainer to get your token.
|
||||
|
||||
Then, simply add a job to the Buildkite pipeline by editing ``libcxx/utils/ci/buildkite-pipeline.yml``.
|
||||
Take a look at how the surrounding jobs are defined and do something similar.
|
||||
An example of a job definition is:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- label: "C++11"
|
||||
command: "libcxx/utils/ci/run-buildbot generic-cxx11"
|
||||
artifact_paths:
|
||||
- "**/test-results.xml"
|
||||
agents:
|
||||
queue: "libcxx-builders"
|
||||
os: "linux"
|
||||
retry:
|
||||
[...]
|
||||
|
||||
If you create your own agents, put them in the ``libcxx-builders`` queue and
|
||||
use agent tags to allow targetting your agents from the Buildkite pipeline
|
||||
config appropriately.
|
||||
|
||||
We try to keep the pipeline definition file as simple as possible, and to
|
||||
keep any script used for CI inside ``libcxx/utils/ci``. This ensures that
|
||||
it's possible to reproduce CI issues locally with ease, understanding of
|
||||
course that some setups may require access to special hardware that is not
|
||||
available.
|
||||
|
||||
Testing Your New Job
|
||||
====================
|
||||
|
||||
Testing your new job is easy -- once your agent is set up (if any), just open
|
||||
a code review and the libc++ CI pipeline will run, including any changes you
|
||||
might have made to the pipeline definition itself.
|
||||
|
||||
Service Level Agreement
|
||||
=======================
|
||||
|
||||
To keep the libc++ CI useful for everyone, we aim for a quick turnaround time
|
||||
for all CI jobs. This allows the overall pipeline to finish in a reasonable
|
||||
amount of time, which is important because it directly affects our development
|
||||
velocity. We also try to make sure that jobs run on reliable infrastructure in
|
||||
order to avoid flaky failures, which reduce the value of CI for everyone.
|
||||
|
||||
We may be reluctant to add and support CI jobs that take a long time to finish
|
||||
or that are too flaky.
|
@ -9,118 +9,166 @@ Building libc++
|
||||
|
||||
.. _build instructions:
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
On Mac OS 10.7 (Lion) and later, the easiest way to get this library is to install
|
||||
Xcode 4.2 or later. However if you want to install tip-of-trunk from here
|
||||
(getting the bleeding edge), read on.
|
||||
|
||||
The following instructions describe how to checkout, build, test and
|
||||
(optionally) install libc++ and libc++abi.
|
||||
|
||||
If your system already provides a libc++ installation it is important to be
|
||||
careful not to replace it. Remember Use the CMake option
|
||||
``CMAKE_INSTALL_PREFIX`` to select a safe place to install libc++.
|
||||
The instructions on this page are aimed at vendors who ship libc++ as part of an
|
||||
operating system distribution, a toolchain or similar shipping vehicules. If you
|
||||
are a user merely trying to use libc++ in your program, you most likely want to
|
||||
refer to your vendor's documentation, or to the general documentation for using
|
||||
libc++ :ref:`here <using-libcxx>`.
|
||||
|
||||
.. warning::
|
||||
* Replacing your systems libc++ installation could render the system non-functional.
|
||||
* macOS will not boot without a valid copy of ``libc++.1.dylib`` in ``/usr/lib``.
|
||||
If your operating system already provides libc++, it is important to be careful
|
||||
not to replace it. Replacing your system's libc++ installation could render it
|
||||
non-functional. Use the CMake option ``CMAKE_INSTALL_PREFIX`` to select a safe
|
||||
place to install libc++.
|
||||
|
||||
|
||||
The default build
|
||||
=================
|
||||
|
||||
The default way of building libc++, libc++abi and libunwind is to root the CMake
|
||||
invocation at ``<monorepo>/runtimes``. While those projects are under the LLVM
|
||||
umbrella, they are different in nature from other build tools, so it makes sense
|
||||
to treat them as a separate set of entities. The default build can be achieved
|
||||
with the following CMake invocation:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git clone https://github.com/llvm/llvm-project.git
|
||||
$ cd llvm-project
|
||||
$ mkdir build && cd build
|
||||
$ cmake -DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi" \
|
||||
../llvm
|
||||
$ make # Build
|
||||
$ make check-cxx # Test
|
||||
$ make install-cxx install-cxxabi # Install
|
||||
$ mkdir build
|
||||
$ cmake -G Ninja -S runtimes -B build -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" # Configure
|
||||
$ ninja -C build cxx cxxabi unwind # Build
|
||||
$ ninja -C build check-cxx check-cxxabi check-unwind # Test
|
||||
$ ninja -C build install-cxx install-cxxabi install-unwind # Install
|
||||
|
||||
For more information about configuring libc++ see :ref:`CMake Options`. You may
|
||||
also want to read the `LLVM getting started
|
||||
<https://llvm.org/docs/GettingStarted.html>`_ documentation.
|
||||
.. note::
|
||||
See :ref:`CMake Options` below for more configuration options.
|
||||
|
||||
Shared libraries for libc++ and libc++ abi should now be present in
|
||||
``build/lib``. See :ref:`using an alternate libc++ installation <alternate
|
||||
libcxx>` for information on how to use this libc++.
|
||||
After building the various ``install-XXX`` targets, shared libraries for libc++, libc++abi and
|
||||
libunwind should now be present in ``<CMAKE_INSTALL_PREFIX>/lib``, and headers in
|
||||
``<CMAKE_INSTALL_PREFIX>/include/c++/v1``. See :ref:`using an alternate libc++ installation
|
||||
<alternate libcxx>` for information on how to use this libc++ over the default one.
|
||||
|
||||
The instructions are for building libc++ on
|
||||
FreeBSD, Linux, or Mac using `libc++abi`_ as the C++ ABI library.
|
||||
On Linux, it is also possible to use :ref:`libsupc++ <libsupcxx>` or libcxxrt.
|
||||
In the default configuration, the runtimes will be built using the compiler available by default
|
||||
on your system. Of course, you can change what compiler is being used with the usual CMake
|
||||
variables. If you wish to build the runtimes from a just-built Clang, the bootstrapping build
|
||||
explained below makes this task easy.
|
||||
|
||||
It is possible to keep your LLVM and libc++ trees separate so you can avoid
|
||||
rebuilding LLVM as often. An out-of-tree build would look like this:
|
||||
|
||||
Bootstrapping build
|
||||
===================
|
||||
|
||||
It is possible to build Clang and then build the runtimes using that just-built compiler in a
|
||||
single CMake invocation. This is usually the correct way to build the runtimes when putting together
|
||||
a toolchain, or when the system compiler is not adequate to build them (too old, unsupported, etc.).
|
||||
To do this, use the following CMake invocation, and in particular notice how we're now rooting the
|
||||
CMake invocation at ``<monorepo>/llvm``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd where-you-want-libcxx-to-live
|
||||
$ # Check out the sources (includes everything, but we'll only use libcxx)
|
||||
$ ``git clone https://github.com/llvm/llvm-project.git``
|
||||
$ cd where-you-want-to-build
|
||||
$ mkdir build && cd build
|
||||
$ export CC=clang CXX=clang++
|
||||
$ cmake -DLLVM_PATH=path/to/separate/llvm \
|
||||
-DLIBCXX_CXX_ABI=libcxxabi \
|
||||
-DLIBCXX_CXX_ABI_INCLUDE_PATHS=path/to/separate/libcxxabi/include \
|
||||
path/to/llvm-project/libcxx
|
||||
$ make
|
||||
$ make check-cxx # optional
|
||||
$ mkdir build
|
||||
$ cmake -G Ninja -S llvm -B build -DLLVM_ENABLE_PROJECTS="clang" \ # Configure
|
||||
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
|
||||
-DLLVM_RUNTIME_TARGETS="<target-triple>"
|
||||
$ ninja -C build runtimes # Build
|
||||
$ ninja -C build check-runtimes # Test
|
||||
$ ninja -C build install-runtimes # Install
|
||||
|
||||
.. note::
|
||||
This type of build is also commonly called a "Runtimes build", but we would like to move
|
||||
away from that terminology, which is too confusing.
|
||||
|
||||
Experimental Support for Windows
|
||||
--------------------------------
|
||||
Support for Windows
|
||||
===================
|
||||
|
||||
The Windows support requires building with clang-cl as cl does not support one
|
||||
required extension: `#include_next`. Furthermore, VS 2015 or newer (19.00) is
|
||||
required. In the case of clang-cl, we need to specify the "MS Compatibility
|
||||
Version" as it defaults to 2014 (18.00).
|
||||
libcxx supports being built with clang-cl, but not with MSVC's cl.exe, as
|
||||
cl doesn't support the ``#include_next`` extension. Furthermore, VS 2017 or
|
||||
newer (19.14) is required.
|
||||
|
||||
libcxx also supports being built with clang targeting MinGW environments.
|
||||
|
||||
CMake + Visual Studio
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
---------------------
|
||||
|
||||
Building with Visual Studio currently does not permit running tests. However,
|
||||
it is the simplest way to build.
|
||||
|
||||
.. code-block:: batch
|
||||
|
||||
> cmake -G "Visual Studio 14 2015" ^
|
||||
-T "LLVM-vs2014" ^
|
||||
-DLIBCXX_ENABLE_SHARED=YES ^
|
||||
-DLIBCXX_ENABLE_STATIC=NO ^
|
||||
-DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=NO ^
|
||||
\path\to\libcxx
|
||||
> cmake --build .
|
||||
> cmake -G "Visual Studio 16 2019" -S runtimes -B build ^
|
||||
-T "ClangCL" ^
|
||||
-DLLVM_ENABLE_RUNTIMES=libcxx ^
|
||||
-DLIBCXX_ENABLE_SHARED=YES ^
|
||||
-DLIBCXX_ENABLE_STATIC=NO
|
||||
> cmake --build build
|
||||
|
||||
CMake + ninja
|
||||
~~~~~~~~~~~~~
|
||||
CMake + ninja (MSVC)
|
||||
--------------------
|
||||
|
||||
Building with ninja is required for development to enable tests.
|
||||
Unfortunately, doing so requires additional configuration as we cannot
|
||||
just specify a toolset.
|
||||
A couple of tests require Bash to be available, and a couple dozens
|
||||
of tests require other posix tools (cp, grep and similar - LLVM's tests
|
||||
require the same). Without those tools the vast majority of tests
|
||||
can still be ran successfully.
|
||||
|
||||
If Git for Windows is available, that can be used to provide the bash
|
||||
shell by adding the right bin directory to the path, e.g.
|
||||
``set PATH=%PATH%;C:\Program Files\Git\usr\bin``.
|
||||
|
||||
Alternatively, one can also choose to run the whole build in a MSYS2
|
||||
shell. That can be set up e.g. by starting a Visual Studio Tools Command
|
||||
Prompt (for getting the environment variables pointing to the headers and
|
||||
import libraries), and making sure that clang-cl is available in the
|
||||
path. From there, launch an MSYS2 shell via e.g.
|
||||
``C:\msys64\msys2_shell.cmd -full-path -mingw64`` (preserving the earlier
|
||||
environment, allowing the MSVC headers/libraries and clang-cl to be found).
|
||||
|
||||
In either case, then run:
|
||||
|
||||
.. code-block:: batch
|
||||
|
||||
> cmake -G Ninja ^
|
||||
-DCMAKE_MAKE_PROGRAM=/path/to/ninja ^
|
||||
-DCMAKE_SYSTEM_NAME=Windows ^
|
||||
> cmake -G Ninja -S runtimes -B build ^
|
||||
-DCMAKE_C_COMPILER=clang-cl ^
|
||||
-DCMAKE_C_FLAGS="-fms-compatibility-version=19.00 --target=i686--windows" ^
|
||||
-DCMAKE_CXX_COMPILER=clang-cl ^
|
||||
-DCMAKE_CXX_FLAGS="-fms-compatibility-version=19.00 --target=i686--windows" ^
|
||||
-DLLVM_PATH=/path/to/llvm/tree ^
|
||||
-DLIBCXX_ENABLE_SHARED=YES ^
|
||||
-DLIBCXX_ENABLE_STATIC=NO ^
|
||||
-DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=NO ^
|
||||
\path\to\libcxx
|
||||
> /path/to/ninja cxx
|
||||
> /path/to/ninja check-cxx
|
||||
-DCMAKE_CXX_COMPILER=clang-cl ^
|
||||
-DLLVM_ENABLE_RUNTIMES=libcxx
|
||||
> ninja -C build cxx
|
||||
> ninja -C build check-cxx
|
||||
|
||||
Note that the paths specified with backward slashes must use the `\\` as the
|
||||
directory separator as clang-cl may otherwise parse the path as an argument.
|
||||
If you are running in an MSYS2 shell and you have installed the
|
||||
MSYS2-provided clang package (which defaults to a non-MSVC target), you
|
||||
should add e.g. ``-DCMAKE_CXX_COMPILER_TARGET=x86_64-windows-msvc`` (replacing
|
||||
``x86_64`` with the architecture you're targeting) to the ``cmake`` command
|
||||
line above. This will instruct ``check-cxx`` to use the right target triple
|
||||
when invoking ``clang++``.
|
||||
|
||||
Also note that if not building in Release mode, a failed assert in the tests
|
||||
pops up a blocking dialog box, making it hard to run a larger number of tests.
|
||||
|
||||
CMake + ninja (MinGW)
|
||||
---------------------
|
||||
|
||||
libcxx can also be built in MinGW environments, e.g. with the MinGW
|
||||
compilers in MSYS2. This requires clang to be available (installed with
|
||||
e.g. the ``mingw-w64-x86_64-clang`` package), together with CMake and ninja.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
> cmake -G Ninja -S runtimes -B build \
|
||||
-DCMAKE_C_COMPILER=clang \
|
||||
-DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DLLVM_ENABLE_RUNTIMES=libcxx \
|
||||
-DLIBCXX_CXX_ABI=libstdc++ \
|
||||
-DLIBCXX_TARGET_INFO="libcxx.test.target_info.MingwLocalTI"
|
||||
> ninja -C build cxx
|
||||
> cp /mingw64/bin/{libstdc++-6,libgcc_s_seh-1,libwinpthread-1}.dll lib
|
||||
> ninja -C build check-cxx
|
||||
|
||||
As this build configuration ends up depending on a couple other DLLs that
|
||||
aren't available in path while running tests, copy them into the same
|
||||
directory as the tested libc++ DLL.
|
||||
|
||||
(Building a libc++ that depends on libstdc++ isn't necessarily a config one
|
||||
would want to deploy, but it simplifies the config for testing purposes.)
|
||||
|
||||
.. _`libc++abi`: http://libcxxabi.llvm.org/
|
||||
|
||||
@ -168,13 +216,10 @@ libc++ specific options
|
||||
|
||||
**Default**: ``OFF``
|
||||
|
||||
Build libc++ with assertions enabled.
|
||||
|
||||
.. option:: LIBCXX_BUILD_32_BITS:BOOL
|
||||
|
||||
**Default**: ``OFF``
|
||||
|
||||
Build libc++ as a 32 bit library. Also see `LLVM_BUILD_32_BITS`.
|
||||
Build libc++ with assertions enabled in the compiled library, and enable assertions
|
||||
by default when building user code as well. Assertions can be turned off by users
|
||||
by defining ``_LIBCPP_ENABLE_ASSERTIONS=0``. For details, see
|
||||
:ref:`the documentation <assertions-mode>`.
|
||||
|
||||
.. option:: LIBCXX_ENABLE_SHARED:BOOL
|
||||
|
||||
@ -195,12 +240,6 @@ libc++ specific options
|
||||
Extra suffix to append to the directory where libraries are to be installed.
|
||||
This option overrides `LLVM_LIBDIR_SUFFIX`.
|
||||
|
||||
.. option:: LIBCXX_INSTALL_PREFIX:STRING
|
||||
|
||||
**Default**: ``""``
|
||||
|
||||
Define libc++ destination prefix.
|
||||
|
||||
.. option:: LIBCXX_HERMETIC_STATIC_LIBRARY:BOOL
|
||||
|
||||
**Default**: ``OFF``
|
||||
@ -212,27 +251,41 @@ libc++ specific options
|
||||
|
||||
.. option:: LIBCXX_ENABLE_FILESYSTEM:BOOL
|
||||
|
||||
**Default**: ``ON`` except on Windows.
|
||||
**Default**: ``ON`` except on Windows when using MSVC.
|
||||
|
||||
This option can be used to enable or disable the filesystem components on
|
||||
platforms that may not support them. For example on Windows.
|
||||
platforms that may not support them. For example on Windows when using MSVC.
|
||||
|
||||
.. _libc++experimental options:
|
||||
.. option:: LIBCXX_ENABLE_WIDE_CHARACTERS:BOOL
|
||||
|
||||
libc++experimental Specific Options
|
||||
------------------------------------
|
||||
**Default**: ``ON``
|
||||
|
||||
.. option:: LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY:BOOL
|
||||
This option can be used to disable support for ``wchar_t`` in the library. It also
|
||||
allows the library to work on top of a C Standard Library that does not provide
|
||||
support for ``wchar_t``. This is especially useful in embedded settings where
|
||||
C Standard Libraries don't always provide all the usual bells and whistles.
|
||||
|
||||
**Default**: ``ON``
|
||||
.. option:: LIBCXX_INSTALL_LIBRARY_DIR:PATH
|
||||
|
||||
Build and test libc++experimental.a.
|
||||
**Default**: ``lib${LIBCXX_LIBDIR_SUFFIX}``
|
||||
|
||||
.. option:: LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY:BOOL
|
||||
Path where built libc++ libraries should be installed. If a relative path,
|
||||
relative to ``CMAKE_INSTALL_PREFIX``.
|
||||
|
||||
**Default**: ``LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY AND LIBCXX_INSTALL_LIBRARY``
|
||||
.. option:: LIBCXX_INSTALL_INCLUDE_DIR:PATH
|
||||
|
||||
Install libc++experimental.a alongside libc++.
|
||||
**Default**: ``include/c++/v1``
|
||||
|
||||
Path where target-agnostic libc++ headers should be installed. If a relative
|
||||
path, relative to ``CMAKE_INSTALL_PREFIX``.
|
||||
|
||||
.. option:: LIBCXX_INSTALL_INCLUDE_TARGET_DIR:PATH
|
||||
|
||||
**Default**: ``include/c++/v1`` or
|
||||
``include/${LLVM_DEFAULT_TARGET_TRIPLE}/c++/v1``
|
||||
|
||||
Path where target-specific libc++ headers should be installed. If a relative
|
||||
path, relative to ``CMAKE_INSTALL_PREFIX``.
|
||||
|
||||
|
||||
.. _ABI Library Specific Options:
|
||||
@ -242,7 +295,7 @@ ABI Library Specific Options
|
||||
|
||||
.. option:: LIBCXX_CXX_ABI:STRING
|
||||
|
||||
**Values**: ``none``, ``libcxxabi``, ``libcxxrt``, ``libstdc++``, ``libsupc++``.
|
||||
**Values**: ``none``, ``libcxxabi``, ``system-libcxxabi``, ``libcxxrt``, ``libstdc++``, ``libsupc++``, ``vcruntime``.
|
||||
|
||||
Select the ABI library to build libc++ against.
|
||||
|
||||
@ -252,7 +305,8 @@ ABI Library Specific Options
|
||||
|
||||
.. option:: LIBCXX_CXX_ABI_LIBRARY_PATH:PATH
|
||||
|
||||
Provide the path to the ABI library that libc++ should link against.
|
||||
Provide the path to the ABI library that libc++ should link against. This is only
|
||||
useful when linking against an out-of-tree ABI library.
|
||||
|
||||
.. option:: LIBCXX_ENABLE_STATIC_ABI_LIBRARY:BOOL
|
||||
|
||||
@ -294,7 +348,7 @@ libc++ Feature Options
|
||||
|
||||
.. option:: LIBCXX_INCLUDE_TESTS:BOOL
|
||||
|
||||
**Default**: ``ON`` (or value of ``LLVM_INCLUDE_DIR``)
|
||||
**Default**: ``ON`` (or value of ``LLVM_INCLUDE_TESTS``)
|
||||
|
||||
Build the libc++ tests.
|
||||
|
||||
@ -330,15 +384,6 @@ libc++ Feature Options
|
||||
Use the specified GCC toolchain and standard library when building the native
|
||||
stdlib benchmark tests.
|
||||
|
||||
.. option:: LIBCXX_HIDE_FROM_ABI_PER_TU_BY_DEFAULT:BOOL
|
||||
|
||||
**Default**: ``OFF``
|
||||
|
||||
Pick the default for whether to constrain ABI-unstable symbols to
|
||||
each individual translation unit. This setting controls whether
|
||||
`_LIBCPP_HIDE_FROM_ABI_PER_TU_BY_DEFAULT` is defined by default --
|
||||
see the documentation of that macro for details.
|
||||
|
||||
|
||||
libc++ ABI Feature Options
|
||||
--------------------------
|
||||
@ -367,10 +412,10 @@ The following options allow building libc++ for a different ABI version.
|
||||
with other libc++ versions.
|
||||
|
||||
.. warning::
|
||||
When providing a custom namespace, it's the users responsibility to ensure the name won't cause
|
||||
When providing a custom namespace, it's the user's responsibility to ensure the name won't cause
|
||||
conflicts with other names defined by libc++, both now and in the future. In particular, inline
|
||||
namespaces of the form ``__[0-9]+`` are strictly reserved by libc++ and may not be used by users.
|
||||
Doing otherwise could cause conflicts and hinder libc++ ABI evolution.
|
||||
namespaces of the form ``__[0-9]+`` could cause conflicts with future versions of the library,
|
||||
and so should be avoided.
|
||||
|
||||
.. option:: LIBCXX_ABI_DEFINES:STRING
|
||||
|
||||
@ -380,20 +425,6 @@ The following options allow building libc++ for a different ABI version.
|
||||
See ``include/__config`` for the list of ABI macros.
|
||||
|
||||
|
||||
.. option:: LIBCXX_HAS_MERGED_TYPEINFO_NAMES_DEFAULT
|
||||
|
||||
**Default**: ``None``. When defined this option overrides the libraries default configuration
|
||||
for whether merged type info names are present.
|
||||
|
||||
|
||||
Build ``std::type_info`` with the assumption that type info names for a type have been fully
|
||||
merged are unique across the entire program. This may not be the case for libraries built with
|
||||
``-Bsymbolic`` or due to compiler or linker bugs (Ex. llvm.org/PR37398).
|
||||
|
||||
When the value is ``ON`` typeinfo comparisons compare only the pointer value, otherwise ``strcmp``
|
||||
is used as a fallback.
|
||||
|
||||
|
||||
.. _LLVM-specific variables:
|
||||
|
||||
LLVM-specific options
|
||||
@ -420,8 +451,12 @@ LLVM-specific options
|
||||
Using Alternate ABI libraries
|
||||
=============================
|
||||
|
||||
In order to implement various features like exceptions, RTTI, ``dynamic_cast`` and
|
||||
more, libc++ requires what we refer to as an ABI library. Typically, that library
|
||||
implements the `Itanium C++ ABI <https://itanium-cxx-abi.github.io/cxx-abi/abi.html>`_.
|
||||
|
||||
.. _libsupcxx:
|
||||
By default, libc++ uses libc++abi as an ABI library. However, it is possible to use
|
||||
other ABI libraries too.
|
||||
|
||||
Using libsupc++ on Linux
|
||||
------------------------
|
||||
@ -451,17 +486,17 @@ You can also figure this out by running
|
||||
End of search list.
|
||||
|
||||
Note that the first two entries happen to be what we are looking for. This
|
||||
may not be correct on other platforms.
|
||||
may not be correct on all platforms.
|
||||
|
||||
We can now run CMake:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ CC=clang CXX=clang++ cmake -G "Unix Makefiles" \
|
||||
-DLIBCXX_CXX_ABI=libstdc++ \
|
||||
-DLIBCXX_CXX_ABI_INCLUDE_PATHS="/usr/include/c++/4.7/;/usr/include/c++/4.7/x86_64-linux-gnu/" \
|
||||
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \
|
||||
<libc++-source-dir>
|
||||
$ cmake -G Ninja -S runtimes -B build \
|
||||
-DLLVM_ENABLE_RUNTIMES="libcxx" \
|
||||
-DLIBCXX_CXX_ABI=libstdc++ \
|
||||
-DLIBCXX_CXX_ABI_INCLUDE_PATHS="/usr/include/c++/4.7/;/usr/include/c++/4.7/x86_64-linux-gnu/"
|
||||
$ ninja -C build install-cxx
|
||||
|
||||
|
||||
You can also substitute ``-DLIBCXX_CXX_ABI=libsupc++``
|
||||
@ -472,16 +507,6 @@ GCC ships libsupc++ separately but only as a static library. If a
|
||||
program also needs to link against libstdc++, it will provide its
|
||||
own copy of libsupc++ and this can lead to subtle problems.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ make cxx
|
||||
$ make install
|
||||
|
||||
You can now run clang with -stdlib=libc++.
|
||||
|
||||
|
||||
.. _libcxxrt_ref:
|
||||
|
||||
Using libcxxrt on Linux
|
||||
------------------------
|
||||
|
||||
@ -493,14 +518,11 @@ We can now run CMake like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ CC=clang CXX=clang++ cmake -G "Unix Makefiles" \
|
||||
-DLIBCXX_CXX_ABI=libcxxrt \
|
||||
-DLIBCXX_CXX_ABI_INCLUDE_PATHS=path/to/libcxxrt-sources/src \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
<libc++-source-directory>
|
||||
$ make cxx
|
||||
$ make install
|
||||
$ cmake -G Ninja -S runtimes -B build \
|
||||
-DLLVM_ENABLE_RUNTIMES="libcxx" \
|
||||
-DLIBCXX_CXX_ABI=libcxxrt \
|
||||
-DLIBCXX_CXX_ABI_INCLUDE_PATHS=path/to/libcxxrt-sources/src
|
||||
$ ninja -C build install-cxx
|
||||
|
||||
Unfortunately you can't simply run clang with "-stdlib=libc++" at this point, as
|
||||
clang is set up to link for libc++ linked to libsupc++. To get around this
|
||||
@ -518,32 +540,4 @@ situations will give the same result:
|
||||
|
||||
$ clang++ -stdlib=libc++ helloworld.cpp -lcxxrt
|
||||
|
||||
.. _`libcxxrt`: https://github.com/pathscale/libcxxrt/
|
||||
|
||||
|
||||
Using a local ABI library installation
|
||||
---------------------------------------
|
||||
|
||||
.. warning::
|
||||
This is not recommended in almost all cases.
|
||||
|
||||
These instructions should only be used when you can't install your ABI library.
|
||||
|
||||
Normally you must link libc++ against a ABI shared library that the
|
||||
linker can find. If you want to build and test libc++ against an ABI
|
||||
library not in the linker's path you need to set
|
||||
``-DLIBCXX_CXX_ABI_LIBRARY_PATH=/path/to/abi/lib`` when configuring CMake.
|
||||
|
||||
An example build using libc++abi would look like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ CC=clang CXX=clang++ cmake \
|
||||
-DLIBCXX_CXX_ABI=libc++abi \
|
||||
-DLIBCXX_CXX_ABI_INCLUDE_PATHS="/path/to/libcxxabi/include" \
|
||||
-DLIBCXX_CXX_ABI_LIBRARY_PATH="/path/to/libcxxabi-build/lib" \
|
||||
path/to/libcxx
|
||||
$ make
|
||||
|
||||
When testing libc++ LIT will automatically link against the proper ABI
|
||||
library.
|
||||
.. _`libcxxrt`: https://github.com/libcxxrt/libcxxrt
|
||||
|
88
docs/Contributing.rst
Normal file
88
docs/Contributing.rst
Normal file
@ -0,0 +1,88 @@
|
||||
.. _ContributingToLibcxx:
|
||||
|
||||
======================
|
||||
Contributing to libc++
|
||||
======================
|
||||
|
||||
This file contains notes about various tasks and processes specific to contributing
|
||||
to libc++. If this is your first time contributing, please also read `this document
|
||||
<https://www.llvm.org/docs/Contributing.html>`__ on general rules for contributing to LLVM.
|
||||
|
||||
For libc++, please make sure you follow `these instructions <https://www.llvm.org/docs/Phabricator.html#requesting-a-review-via-the-command-line>`_
|
||||
for submitting a code review from the command-line using ``arc``, since we have some
|
||||
automation (e.g. CI) that depends on the review being submitted that way.
|
||||
|
||||
If you plan on contributing to libc++, it can be useful to join the ``#libcxx`` channel
|
||||
on `LLVM's Discord server <https://discord.gg/jzUbyP26tQ>`__.
|
||||
|
||||
Looking for pre-existing reviews
|
||||
================================
|
||||
|
||||
Before you start working on any feature, please take a look at the open reviews
|
||||
to avoid duplicating someone else's work. You can do that by going to the website
|
||||
where code reviews are held, `Differential <https://reviews.llvm.org/differential>`__,
|
||||
and clicking on ``Libc++ Open Reviews`` in the sidebar to the left. If you see
|
||||
that your feature is already being worked on, please consider chiming in instead
|
||||
of duplicating work!
|
||||
|
||||
Pre-commit check list
|
||||
=====================
|
||||
|
||||
Before committing or creating a review, please go through this check-list to make
|
||||
sure you don't forget anything:
|
||||
|
||||
- Do you have tests for every public class and/or function you're adding or modifying?
|
||||
- Did you update the synopsis of the relevant headers?
|
||||
- Did you update the relevant files to track implementation status (in ``docs/Status/``)?
|
||||
- Did you mark all functions and type declarations with the :ref:`proper visibility macro <visibility-macros>`?
|
||||
- If you added a header:
|
||||
|
||||
- Did you add it to ``include/module.modulemap.in``?
|
||||
- Did you add it to ``include/CMakeLists.txt``?
|
||||
- If it's a public header, did you add a test under ``test/libcxx`` that the new header defines ``_LIBCPP_VERSION``? See ``test/libcxx/algorithms/version.pass.cpp`` for an example. NOTE: This should be automated.
|
||||
- If it's a public header, did you update ``utils/generate_header_inclusion_tests.py``?
|
||||
|
||||
- Did you add the relevant feature test macro(s) for your feature? Did you update the ``generate_feature_test_macro_components.py`` script with it?
|
||||
- Did you run the ``libcxx-generate-files`` target and verify its output?
|
||||
|
||||
The review process
|
||||
==================
|
||||
|
||||
After uploading your patch, you should see that the "libc++" review group is automatically
|
||||
added as a reviewer for your patch. Once the group is marked as having approved your patch,
|
||||
you can commit it. However, if you get an approval very quickly for a significant patch,
|
||||
please try to wait a couple of business days before committing to give the opportunity for
|
||||
other reviewers to chime in. If you need someone else to commit the patch for you, please
|
||||
mention it and provide your ``Name <email@domain>`` for us to attribute the commit properly.
|
||||
|
||||
Note that the rule for accepting as the "libc++" review group is to wait for two members
|
||||
of the group to have approved the patch, excluding the patch author. This is not a hard
|
||||
rule -- for very simple patches, use your judgement. The `"libc++" review group <https://reviews.llvm.org/project/members/64/>`__
|
||||
consists of frequent libc++ contributors with a good understanding of the project's
|
||||
guidelines -- if you would like to be added to it, please reach out on Discord.
|
||||
|
||||
Post-release check list
|
||||
=======================
|
||||
|
||||
After branching for an LLVM release:
|
||||
|
||||
1. Update ``_LIBCPP_VERSION`` in ``libcxx/include/__config``
|
||||
2. Update the version number in ``libcxx/docs/conf.py``
|
||||
3. Update ``_LIBCPPABI_VERSION`` in ``libcxxabi/include/cxxabi.h``
|
||||
4. Update ``_LIBUNWIND_VERSION`` in ``libunwind/include/__libunwind_config.h``
|
||||
|
||||
Exporting new symbols from the library
|
||||
======================================
|
||||
|
||||
When exporting new symbols from libc++, you must update the ABI lists located in ``lib/abi``.
|
||||
To test whether the lists are up-to-date, please run the target ``check-cxx-abilist``.
|
||||
To regenerate the lists, use the target ``generate-cxx-abilist``.
|
||||
The ABI lists must be updated for all supported platforms; currently Linux and
|
||||
Apple. If you don't have access to one of these platforms, you can download an
|
||||
updated list from the failed build at
|
||||
`Buildkite <https://buildkite.com/llvm-project/libcxx-ci>`__.
|
||||
Look for the failed build and select the ``artifacts`` tab. There, download the
|
||||
abilist for the platform, e.g.:
|
||||
|
||||
* C++20 for the Linux platform.
|
||||
* MacOS C++20 for the Apple platform.
|
@ -3,15 +3,22 @@
|
||||
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.
|
||||
Libc++ aims to preserve a stable ABI to avoid subtle bugs when code built under the old ABI
|
||||
is linked with code built under the new ABI. At the same time, libc++ wants to make
|
||||
ABI-breaking improvements and bugfixes in scenarios where the user doesn't mind ABI breaks.
|
||||
|
||||
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.
|
||||
To support both cases, libc++ allows specifying an ABI version at
|
||||
build time. The version is defined with CMake option ``LIBCXX_ABI_VERSION``.
|
||||
Currently supported values are ``1`` (the stable default)
|
||||
and ``2`` (the unstable "next" version). At some point "ABI version 2" will be
|
||||
frozen and new ABI-breaking changes will start being applied to version ``3``;
|
||||
but this has not happened yet.
|
||||
|
||||
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.
|
||||
To always use the most cutting-edge, most unstable ABI (which is currently ``2``
|
||||
but at some point will become ``3``), set the CMake option ``LIBCXX_ABI_UNSTABLE``.
|
||||
|
||||
Internally, each ABI-changing feature is placed under its own C++ macro,
|
||||
``_LIBCPP_ABI_XXX``. These macros' definitions are controlled by the C++ macro
|
||||
``_LIBCPP_ABI_VERSION``, which is controlled by the ``LIBCXX_ABI_VERSION`` set
|
||||
at build time. Libc++ does not intend users to interact with these C++ macros
|
||||
directly.
|
||||
|
797
docs/DesignDocs/AtomicDesign.rst
Normal file
797
docs/DesignDocs/AtomicDesign.rst
Normal file
@ -0,0 +1,797 @@
|
||||
|
||||
====================
|
||||
``<atomic>`` Design
|
||||
====================
|
||||
|
||||
There were originally 3 designs under consideration. They differ in where most
|
||||
of the implementation work is done. The functionality exposed to the customer
|
||||
should be identical (and conforming) for all three designs.
|
||||
|
||||
|
||||
Design A: Minimal work for the library
|
||||
======================================
|
||||
The compiler supplies all of the intrinsics as described below. This list of
|
||||
intrinsics roughly parallels the requirements of the C and C++ atomics proposals.
|
||||
The C and C++ library implementations simply drop through to these intrinsics.
|
||||
Anything the platform does not support in hardware, the compiler
|
||||
arranges for a (compiler-rt) library call to be made which will do the job with
|
||||
a mutex, and in this case ignoring the memory ordering parameter (effectively
|
||||
implementing ``memory_order_seq_cst``).
|
||||
|
||||
Ultimate efficiency is preferred over run time error checking. Undefined
|
||||
behavior is acceptable when the inputs do not conform as defined below.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// In every intrinsic signature below, type* atomic_obj may be a pointer to a
|
||||
// volatile-qualified type. Memory ordering values map to the following meanings:
|
||||
// memory_order_relaxed == 0
|
||||
// memory_order_consume == 1
|
||||
// memory_order_acquire == 2
|
||||
// memory_order_release == 3
|
||||
// memory_order_acq_rel == 4
|
||||
// memory_order_seq_cst == 5
|
||||
|
||||
// type must be trivially copyable
|
||||
// type represents a "type argument"
|
||||
bool __atomic_is_lock_free(type);
|
||||
|
||||
// type must be trivially copyable
|
||||
// Behavior is defined for mem_ord = 0, 1, 2, 5
|
||||
type __atomic_load(const type* atomic_obj, int mem_ord);
|
||||
|
||||
// type must be trivially copyable
|
||||
// Behavior is defined for mem_ord = 0, 3, 5
|
||||
void __atomic_store(type* atomic_obj, type desired, int mem_ord);
|
||||
|
||||
// type must be trivially copyable
|
||||
// Behavior is defined for mem_ord = [0 ... 5]
|
||||
type __atomic_exchange(type* atomic_obj, type desired, int mem_ord);
|
||||
|
||||
// type must be trivially copyable
|
||||
// Behavior is defined for mem_success = [0 ... 5],
|
||||
// mem_failure <= mem_success
|
||||
// mem_failure != 3
|
||||
// mem_failure != 4
|
||||
bool __atomic_compare_exchange_strong(type* atomic_obj,
|
||||
type* expected, type desired,
|
||||
int mem_success, int mem_failure);
|
||||
|
||||
// type must be trivially copyable
|
||||
// Behavior is defined for mem_success = [0 ... 5],
|
||||
// mem_failure <= mem_success
|
||||
// mem_failure != 3
|
||||
// mem_failure != 4
|
||||
bool __atomic_compare_exchange_weak(type* atomic_obj,
|
||||
type* expected, type desired,
|
||||
int mem_success, int mem_failure);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
// Behavior is defined for mem_ord = [0 ... 5]
|
||||
type __atomic_fetch_add(type* atomic_obj, type operand, int mem_ord);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
// Behavior is defined for mem_ord = [0 ... 5]
|
||||
type __atomic_fetch_sub(type* atomic_obj, type operand, int mem_ord);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
// Behavior is defined for mem_ord = [0 ... 5]
|
||||
type __atomic_fetch_and(type* atomic_obj, type operand, int mem_ord);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
// Behavior is defined for mem_ord = [0 ... 5]
|
||||
type __atomic_fetch_or(type* atomic_obj, type operand, int mem_ord);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
// Behavior is defined for mem_ord = [0 ... 5]
|
||||
type __atomic_fetch_xor(type* atomic_obj, type operand, int mem_ord);
|
||||
|
||||
// Behavior is defined for mem_ord = [0 ... 5]
|
||||
void* __atomic_fetch_add(void** atomic_obj, ptrdiff_t operand, int mem_ord);
|
||||
void* __atomic_fetch_sub(void** atomic_obj, ptrdiff_t operand, int mem_ord);
|
||||
|
||||
// Behavior is defined for mem_ord = [0 ... 5]
|
||||
void __atomic_thread_fence(int mem_ord);
|
||||
void __atomic_signal_fence(int mem_ord);
|
||||
|
||||
If desired the intrinsics taking a single ``mem_ord`` parameter can default
|
||||
this argument to 5.
|
||||
|
||||
If desired the intrinsics taking two ordering parameters can default ``mem_success``
|
||||
to 5, and ``mem_failure`` to ``translate_memory_order(mem_success)`` where
|
||||
``translate_memory_order(mem_success)`` is defined as:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
int translate_memory_order(int o) {
|
||||
switch (o) {
|
||||
case 4:
|
||||
return 2;
|
||||
case 3:
|
||||
return 0;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
Below are representative C++ implementations of all of the operations. Their
|
||||
purpose is to document the desired semantics of each operation, assuming
|
||||
``memory_order_seq_cst``. This is essentially the code that will be called
|
||||
if the front end calls out to compiler-rt.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
template <class T>
|
||||
T __atomic_load(T const volatile* obj) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
return *obj;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void __atomic_store(T volatile* obj, T desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
*obj = desr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_exchange(T volatile* obj, T desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj = desr;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool __atomic_compare_exchange_strong(T volatile* obj, T* exp, T desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) // if (*obj == *exp)
|
||||
{
|
||||
std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); // *obj = desr;
|
||||
return true;
|
||||
}
|
||||
std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); // *exp = *obj;
|
||||
return false;
|
||||
}
|
||||
|
||||
// May spuriously return false (even if *obj == *exp)
|
||||
template <class T>
|
||||
bool __atomic_compare_exchange_weak(T volatile* obj, T* exp, T desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) // if (*obj == *exp)
|
||||
{
|
||||
std::memcpy(const_cast<T*>(obj), &desr, sizeof(T)); // *obj = desr;
|
||||
return true;
|
||||
}
|
||||
std::memcpy(exp, const_cast<T*>(obj), sizeof(T)); // *exp = *obj;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_add(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj += operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_sub(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj -= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_and(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj &= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_or(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj |= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_xor(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj ^= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
void* __atomic_fetch_add(void* volatile* obj, ptrdiff_t operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
void* r = *obj;
|
||||
(char*&)(*obj) += operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
void* __atomic_fetch_sub(void* volatile* obj, ptrdiff_t operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
void* r = *obj;
|
||||
(char*&)(*obj) -= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
void __atomic_thread_fence() {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
}
|
||||
|
||||
void __atomic_signal_fence() {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
}
|
||||
|
||||
|
||||
Design B: Something in between
|
||||
==============================
|
||||
This is a variation of design A which puts the burden on the library to arrange
|
||||
for the correct manipulation of the run time memory ordering arguments, and only
|
||||
calls the compiler for well-defined memory orderings. I think of this design as
|
||||
the worst of A and C, instead of the best of A and C. But I offer it as an
|
||||
option in the spirit of completeness.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// type must be trivially copyable
|
||||
bool __atomic_is_lock_free(const type* atomic_obj);
|
||||
|
||||
// type must be trivially copyable
|
||||
type __atomic_load_relaxed(const volatile type* atomic_obj);
|
||||
type __atomic_load_consume(const volatile type* atomic_obj);
|
||||
type __atomic_load_acquire(const volatile type* atomic_obj);
|
||||
type __atomic_load_seq_cst(const volatile type* atomic_obj);
|
||||
|
||||
// type must be trivially copyable
|
||||
type __atomic_store_relaxed(volatile type* atomic_obj, type desired);
|
||||
type __atomic_store_release(volatile type* atomic_obj, type desired);
|
||||
type __atomic_store_seq_cst(volatile type* atomic_obj, type desired);
|
||||
|
||||
// type must be trivially copyable
|
||||
type __atomic_exchange_relaxed(volatile type* atomic_obj, type desired);
|
||||
type __atomic_exchange_consume(volatile type* atomic_obj, type desired);
|
||||
type __atomic_exchange_acquire(volatile type* atomic_obj, type desired);
|
||||
type __atomic_exchange_release(volatile type* atomic_obj, type desired);
|
||||
type __atomic_exchange_acq_rel(volatile type* atomic_obj, type desired);
|
||||
type __atomic_exchange_seq_cst(volatile type* atomic_obj, type desired);
|
||||
|
||||
// type must be trivially copyable
|
||||
bool __atomic_compare_exchange_strong_relaxed_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_consume_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_consume_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_acquire_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_acquire_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_acquire_acquire(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_release_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_release_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_release_acquire(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_acq_rel_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_acq_rel_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_acq_rel_acquire(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_seq_cst_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_seq_cst_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_seq_cst_acquire(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_strong_seq_cst_seq_cst(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
|
||||
// type must be trivially copyable
|
||||
bool __atomic_compare_exchange_weak_relaxed_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_consume_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_consume_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_acquire_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_acquire_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_acquire_acquire(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_release_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_release_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_release_acquire(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_acq_rel_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_acq_rel_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_acq_rel_acquire(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_seq_cst_relaxed(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_seq_cst_consume(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_seq_cst_acquire(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
bool __atomic_compare_exchange_weak_seq_cst_seq_cst(volatile type* atomic_obj,
|
||||
type* expected,
|
||||
type desired);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
type __atomic_fetch_add_relaxed(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_add_consume(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_add_acquire(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_add_release(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_add_acq_rel(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_add_seq_cst(volatile type* atomic_obj, type operand);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
type __atomic_fetch_sub_relaxed(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_sub_consume(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_sub_acquire(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_sub_release(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_sub_acq_rel(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_sub_seq_cst(volatile type* atomic_obj, type operand);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
type __atomic_fetch_and_relaxed(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_and_consume(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_and_acquire(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_and_release(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_and_acq_rel(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_and_seq_cst(volatile type* atomic_obj, type operand);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
type __atomic_fetch_or_relaxed(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_or_consume(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_or_acquire(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_or_release(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_or_acq_rel(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_or_seq_cst(volatile type* atomic_obj, type operand);
|
||||
|
||||
// type is one of: char, signed char, unsigned char, short, unsigned short, int,
|
||||
// unsigned int, long, unsigned long, long long, unsigned long long,
|
||||
// char16_t, char32_t, wchar_t
|
||||
type __atomic_fetch_xor_relaxed(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_xor_consume(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_xor_acquire(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_xor_release(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_xor_acq_rel(volatile type* atomic_obj, type operand);
|
||||
type __atomic_fetch_xor_seq_cst(volatile type* atomic_obj, type operand);
|
||||
|
||||
void* __atomic_fetch_add_relaxed(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_add_consume(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_add_acquire(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_add_release(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_add_acq_rel(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_add_seq_cst(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
|
||||
void* __atomic_fetch_sub_relaxed(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_sub_consume(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_sub_acquire(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_sub_release(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_sub_acq_rel(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
void* __atomic_fetch_sub_seq_cst(void* volatile* atomic_obj, ptrdiff_t operand);
|
||||
|
||||
void __atomic_thread_fence_relaxed();
|
||||
void __atomic_thread_fence_consume();
|
||||
void __atomic_thread_fence_acquire();
|
||||
void __atomic_thread_fence_release();
|
||||
void __atomic_thread_fence_acq_rel();
|
||||
void __atomic_thread_fence_seq_cst();
|
||||
|
||||
void __atomic_signal_fence_relaxed();
|
||||
void __atomic_signal_fence_consume();
|
||||
void __atomic_signal_fence_acquire();
|
||||
void __atomic_signal_fence_release();
|
||||
void __atomic_signal_fence_acq_rel();
|
||||
void __atomic_signal_fence_seq_cst();
|
||||
|
||||
Design C: Minimal work for the front end
|
||||
========================================
|
||||
The ``<atomic>`` header is one of the most closely coupled headers to the compiler.
|
||||
Ideally when you invoke any function from ``<atomic>``, it should result in highly
|
||||
optimized assembly being inserted directly into your application -- assembly that
|
||||
is not otherwise representable by higher level C or C++ expressions. The design of
|
||||
the libc++ ``<atomic>`` header started with this goal in mind. A secondary, but
|
||||
still very important goal is that the compiler should have to do minimal work to
|
||||
facilitate the implementation of ``<atomic>``. Without this second goal, then
|
||||
practically speaking, the libc++ ``<atomic>`` header would be doomed to be a
|
||||
barely supported, second class citizen on almost every platform.
|
||||
|
||||
Goals:
|
||||
|
||||
- Optimal code generation for atomic operations
|
||||
- Minimal effort for the compiler to achieve goal 1 on any given platform
|
||||
- Conformance to the C++0X draft standard
|
||||
|
||||
The purpose of this document is to inform compiler writers what they need to do
|
||||
to enable a high performance libc++ ``<atomic>`` with minimal effort.
|
||||
|
||||
The minimal work that must be done for a conforming ``<atomic>``
|
||||
----------------------------------------------------------------
|
||||
The only "atomic" operations that must actually be lock free in
|
||||
``<atomic>`` are represented by the following compiler intrinsics:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
__atomic_flag__ __atomic_exchange_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
__atomic_flag__ result = *obj;
|
||||
*obj = desr;
|
||||
return result;
|
||||
}
|
||||
|
||||
void __atomic_store_seq_cst(__atomic_flag__ volatile* obj, __atomic_flag__ desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
*obj = desr;
|
||||
}
|
||||
|
||||
Where:
|
||||
|
||||
- If ``__has_feature(__atomic_flag)`` evaluates to 1 in the preprocessor then
|
||||
the compiler must define ``__atomic_flag__`` (e.g. as a typedef to ``int``).
|
||||
- If ``__has_feature(__atomic_flag)`` evaluates to 0 in the preprocessor then
|
||||
the library defines ``__atomic_flag__`` as a typedef to ``bool``.
|
||||
- To communicate that the above intrinsics are available, the compiler must
|
||||
arrange for ``__has_feature`` to return 1 when fed the intrinsic name
|
||||
appended with an '_' and the mangled type name of ``__atomic_flag__``.
|
||||
|
||||
For example if ``__atomic_flag__`` is ``unsigned int``:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// __has_feature(__atomic_flag) == 1
|
||||
// __has_feature(__atomic_exchange_seq_cst_j) == 1
|
||||
// __has_feature(__atomic_store_seq_cst_j) == 1
|
||||
|
||||
typedef unsigned int __atomic_flag__;
|
||||
|
||||
unsigned int __atomic_exchange_seq_cst(unsigned int volatile*, unsigned int) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void __atomic_store_seq_cst(unsigned int volatile*, unsigned int) {
|
||||
// ...
|
||||
}
|
||||
|
||||
That's it! Compiler writers do the above and you've got a fully conforming
|
||||
(though sub-par performance) ``<atomic>`` header!
|
||||
|
||||
|
||||
Recommended work for a higher performance ``<atomic>``
|
||||
------------------------------------------------------
|
||||
It would be good if the above intrinsics worked with all integral types plus
|
||||
``void*``. Because this may not be possible to do in a lock-free manner for
|
||||
all integral types on all platforms, a compiler must communicate each type that
|
||||
an intrinsic works with. For example, if ``__atomic_exchange_seq_cst`` works
|
||||
for all types except for ``long long`` and ``unsigned long long`` then:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
__has_feature(__atomic_exchange_seq_cst_b) == 1 // bool
|
||||
__has_feature(__atomic_exchange_seq_cst_c) == 1 // char
|
||||
__has_feature(__atomic_exchange_seq_cst_a) == 1 // signed char
|
||||
__has_feature(__atomic_exchange_seq_cst_h) == 1 // unsigned char
|
||||
__has_feature(__atomic_exchange_seq_cst_Ds) == 1 // char16_t
|
||||
__has_feature(__atomic_exchange_seq_cst_Di) == 1 // char32_t
|
||||
__has_feature(__atomic_exchange_seq_cst_w) == 1 // wchar_t
|
||||
__has_feature(__atomic_exchange_seq_cst_s) == 1 // short
|
||||
__has_feature(__atomic_exchange_seq_cst_t) == 1 // unsigned short
|
||||
__has_feature(__atomic_exchange_seq_cst_i) == 1 // int
|
||||
__has_feature(__atomic_exchange_seq_cst_j) == 1 // unsigned int
|
||||
__has_feature(__atomic_exchange_seq_cst_l) == 1 // long
|
||||
__has_feature(__atomic_exchange_seq_cst_m) == 1 // unsigned long
|
||||
__has_feature(__atomic_exchange_seq_cst_Pv) == 1 // void*
|
||||
|
||||
Note that only the ``__has_feature`` flag is decorated with the argument
|
||||
type. The name of the compiler intrinsic is not decorated, but instead works
|
||||
like a C++ overloaded function.
|
||||
|
||||
Additionally, there are other intrinsics besides ``__atomic_exchange_seq_cst``
|
||||
and ``__atomic_store_seq_cst``. They are optional. But if the compiler can
|
||||
generate faster code than provided by the library, then clients will benefit
|
||||
from the compiler writer's expertise and knowledge of the targeted platform.
|
||||
|
||||
Below is the complete list of *sequentially consistent* intrinsics, and
|
||||
their library implementations. Template syntax is used to indicate the desired
|
||||
overloading for integral and ``void*`` types. The template does not represent a
|
||||
requirement that the intrinsic operate on **any** type!
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// T is one of:
|
||||
// bool, char, signed char, unsigned char, short, unsigned short,
|
||||
// int, unsigned int, long, unsigned long,
|
||||
// long long, unsigned long long, char16_t, char32_t, wchar_t, void*
|
||||
|
||||
template <class T>
|
||||
T __atomic_load_seq_cst(T const volatile* obj) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
return *obj;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void __atomic_store_seq_cst(T volatile* obj, T desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
*obj = desr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_exchange_seq_cst(T volatile* obj, T desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj = desr;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool __atomic_compare_exchange_strong_seq_cst_seq_cst(T volatile* obj, T* exp, T desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0) {
|
||||
std::memcpy(const_cast<T*>(obj), &desr, sizeof(T));
|
||||
return true;
|
||||
}
|
||||
std::memcpy(exp, const_cast<T*>(obj), sizeof(T));
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool __atomic_compare_exchange_weak_seq_cst_seq_cst(T volatile* obj, T* exp, T desr) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
if (std::memcmp(const_cast<T*>(obj), exp, sizeof(T)) == 0)
|
||||
{
|
||||
std::memcpy(const_cast<T*>(obj), &desr, sizeof(T));
|
||||
return true;
|
||||
}
|
||||
std::memcpy(exp, const_cast<T*>(obj), sizeof(T));
|
||||
return false;
|
||||
}
|
||||
|
||||
// T is one of:
|
||||
// char, signed char, unsigned char, short, unsigned short,
|
||||
// int, unsigned int, long, unsigned long,
|
||||
// long long, unsigned long long, char16_t, char32_t, wchar_t
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_add_seq_cst(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj += operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_sub_seq_cst(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj -= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_and_seq_cst(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj &= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_or_seq_cst(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj |= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T __atomic_fetch_xor_seq_cst(T volatile* obj, T operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
T r = *obj;
|
||||
*obj ^= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
void* __atomic_fetch_add_seq_cst(void* volatile* obj, ptrdiff_t operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
void* r = *obj;
|
||||
(char*&)(*obj) += operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
void* __atomic_fetch_sub_seq_cst(void* volatile* obj, ptrdiff_t operand) {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
void* r = *obj;
|
||||
(char*&)(*obj) -= operand;
|
||||
return r;
|
||||
}
|
||||
|
||||
void __atomic_thread_fence_seq_cst() {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
}
|
||||
|
||||
void __atomic_signal_fence_seq_cst() {
|
||||
unique_lock<mutex> _(some_mutex);
|
||||
}
|
||||
|
||||
One should consult the (currently draft) `C++ Standard <https://wg21.link/n3126>`_
|
||||
for the details of the definitions for these operations. For example,
|
||||
``__atomic_compare_exchange_weak_seq_cst_seq_cst`` is allowed to fail
|
||||
spuriously while ``__atomic_compare_exchange_strong_seq_cst_seq_cst`` is not.
|
||||
|
||||
If on your platform the lock-free definition of ``__atomic_compare_exchange_weak_seq_cst_seq_cst``
|
||||
would be the same as ``__atomic_compare_exchange_strong_seq_cst_seq_cst``, you may omit the
|
||||
``__atomic_compare_exchange_weak_seq_cst_seq_cst`` intrinsic without a performance cost. The
|
||||
library will prefer your implementation of ``__atomic_compare_exchange_strong_seq_cst_seq_cst``
|
||||
over its own definition for implementing ``__atomic_compare_exchange_weak_seq_cst_seq_cst``.
|
||||
That is, the library will arrange for ``__atomic_compare_exchange_weak_seq_cst_seq_cst`` to call
|
||||
``__atomic_compare_exchange_strong_seq_cst_seq_cst`` if you supply an intrinsic for the strong
|
||||
version but not the weak.
|
||||
|
||||
Taking advantage of weaker memory synchronization
|
||||
-------------------------------------------------
|
||||
So far, all of the intrinsics presented require a **sequentially consistent** memory ordering.
|
||||
That is, no loads or stores can move across the operation (just as if the library had locked
|
||||
that internal mutex). But ``<atomic>`` supports weaker memory ordering operations. In all,
|
||||
there are six memory orderings (listed here from strongest to weakest):
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
memory_order_seq_cst
|
||||
memory_order_acq_rel
|
||||
memory_order_release
|
||||
memory_order_acquire
|
||||
memory_order_consume
|
||||
memory_order_relaxed
|
||||
|
||||
(See the `C++ Standard <https://wg21.link/n3126>`_ for the detailed definitions of each of these orderings).
|
||||
|
||||
On some platforms, the compiler vendor can offer some or even all of the above
|
||||
intrinsics at one or more weaker levels of memory synchronization. This might
|
||||
lead for example to not issuing an ``mfence`` instruction on the x86.
|
||||
|
||||
If the compiler does not offer any given operation, at any given memory ordering
|
||||
level, the library will automatically attempt to call the next highest memory
|
||||
ordering operation. This continues up to ``seq_cst``, and if that doesn't
|
||||
exist, then the library takes over and does the job with a ``mutex``. This
|
||||
is a compile-time search and selection operation. At run time, the application
|
||||
will only see the few inlined assembly instructions for the selected intrinsic.
|
||||
|
||||
Each intrinsic is appended with the 7-letter name of the memory ordering it
|
||||
addresses. For example a ``load`` with ``relaxed`` ordering is defined by:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
T __atomic_load_relaxed(const volatile T* obj);
|
||||
|
||||
And announced with:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
__has_feature(__atomic_load_relaxed_b) == 1 // bool
|
||||
__has_feature(__atomic_load_relaxed_c) == 1 // char
|
||||
__has_feature(__atomic_load_relaxed_a) == 1 // signed char
|
||||
...
|
||||
|
||||
The ``__atomic_compare_exchange_strong(weak)`` intrinsics are parameterized
|
||||
on two memory orderings. The first ordering applies when the operation returns
|
||||
``true`` and the second ordering applies when the operation returns ``false``.
|
||||
|
||||
Not every memory ordering is appropriate for every operation. ``exchange``
|
||||
and the ``fetch_XXX`` operations support all 6. But ``load`` only supports
|
||||
``relaxed``, ``consume``, ``acquire`` and ``seq_cst``. ``store`` only supports
|
||||
``relaxed``, ``release``, and ``seq_cst``. The ``compare_exchange`` operations
|
||||
support the following 16 combinations out of the possible 36:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
relaxed_relaxed
|
||||
consume_relaxed
|
||||
consume_consume
|
||||
acquire_relaxed
|
||||
acquire_consume
|
||||
acquire_acquire
|
||||
release_relaxed
|
||||
release_consume
|
||||
release_acquire
|
||||
acq_rel_relaxed
|
||||
acq_rel_consume
|
||||
acq_rel_acquire
|
||||
seq_cst_relaxed
|
||||
seq_cst_consume
|
||||
seq_cst_acquire
|
||||
seq_cst_seq_cst
|
||||
|
||||
Again, the compiler supplies intrinsics only for the strongest orderings where
|
||||
it can make a difference. The library takes care of calling the weakest
|
||||
supplied intrinsic that is as strong or stronger than the customer asked for.
|
||||
|
||||
Note about ABI
|
||||
==============
|
||||
With any design, the (back end) compiler writer should note that the decision to
|
||||
implement lock-free operations on any given type (or not) is an ABI-binding decision.
|
||||
One can not change from treating a type as not lock free, to lock free (or vice-versa)
|
||||
without breaking your ABI.
|
||||
|
||||
For example:
|
||||
|
||||
**TU1.cpp**:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
extern atomic<long long> A;
|
||||
int foo() { return A.compare_exchange_strong(w, x); }
|
||||
|
||||
|
||||
**TU2.cpp**:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
extern atomic<long long> A;
|
||||
void bar() { return A.compare_exchange_strong(y, z); }
|
||||
|
||||
If only **one** of these calls to ``compare_exchange_strong`` is implemented with
|
||||
mutex-locked code, then that mutex-locked code will not be executed mutually
|
||||
exclusively of the one implemented in a lock-free manner.
|
@ -1,98 +0,0 @@
|
||||
===================
|
||||
Availability Markup
|
||||
===================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
Libc++ is used as a system library on macOS and iOS (amongst others). In order
|
||||
for users to be able to compile a binary that is intended to be deployed to an
|
||||
older version of the platform, clang provides the
|
||||
`availability attribute <https://clang.llvm.org/docs/AttributeReference.html#availability>`_
|
||||
that can be placed on declarations to describe the lifecycle of a symbol in the
|
||||
library.
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
When a new feature is introduced that requires dylib support, a macro should be
|
||||
created in include/__config to mark this feature as unavailable for all the
|
||||
systems. For example::
|
||||
|
||||
// Define availability macros.
|
||||
#if defined(_LIBCPP_USE_AVAILABILITY_APPLE)
|
||||
# define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS __attribute__((unavailable))
|
||||
#else if defined(_LIBCPP_USE_AVAILABILITY_SOME_OTHER_VENDOR)
|
||||
# define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS __attribute__((unavailable))
|
||||
#else
|
||||
# define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
|
||||
#endif
|
||||
|
||||
When the library is updated by the platform vendor, the markup can be updated.
|
||||
For example::
|
||||
|
||||
#define _LIBCPP_AVAILABILITY_SHARED_MUTEX \
|
||||
__attribute__((availability(macosx,strict,introduced=10.12))) \
|
||||
__attribute__((availability(ios,strict,introduced=10.0))) \
|
||||
__attribute__((availability(tvos,strict,introduced=10.0))) \
|
||||
__attribute__((availability(watchos,strict,introduced=3.0)))
|
||||
|
||||
In the source code, the macro can be added on a class if the full class requires
|
||||
type info from the library for example::
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
|
||||
class _LIBCPP_EXCEPTION_ABI _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS bad_optional_access
|
||||
: public std::logic_error {
|
||||
|
||||
or on a particular symbol:
|
||||
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE void operator delete(void* __p, std::size_t __sz) _NOEXCEPT;
|
||||
|
||||
Furthermore, a lit feature should be added to match that availability macro,
|
||||
so that tests depending on that feature can be marked to XFAIL if the feature
|
||||
is not supported. This way, the test suite will work on platforms that have
|
||||
not shipped the feature yet. This can be done by adding the appropriate lit
|
||||
feature in test/config.py.
|
||||
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
Some parameters can be passed to lit to run the test-suite and exercise the
|
||||
availability.
|
||||
|
||||
* The `platform` parameter controls the deployment target. For example lit can
|
||||
be invoked with `--param=platform=macosx10.12`. Default is the current host.
|
||||
* The `use_system_cxx_lib` parameter indicates to use another library than the
|
||||
just built one. Invoking lit with `--param=use_system_cxx_lib=true` will run
|
||||
the test-suite against the host system library. Alternatively a path to the
|
||||
directory containing a specific prebuilt libc++ can be used, for example:
|
||||
`--param=use_system_cxx_lib=/path/to/macOS/10.12/`.
|
||||
|
||||
Tests can be marked as XFAIL based on multiple features made available by lit:
|
||||
|
||||
|
||||
* if `--param=platform=macosx10.12` is passed, the following features will be available:
|
||||
|
||||
- availability=macosx
|
||||
- availability=macosx10.12
|
||||
|
||||
This feature is used to XFAIL a test that *is* using a class or a method marked
|
||||
as unavailable *and* that is expected to *fail* if deployed on an older system.
|
||||
|
||||
* if `use_system_cxx_lib` and `--param=platform=macosx10.12` are passed to lit,
|
||||
the following features will also be available:
|
||||
|
||||
- with_system_cxx_lib=macosx
|
||||
- with_system_cxx_lib=macosx10.12
|
||||
- with_system_cxx_lib=x86_64-apple-macosx10.12
|
||||
|
||||
This feature is used to XFAIL a test that is *not* using a class or a method
|
||||
marked as unavailable *but* that is expected to fail if deployed on an older
|
||||
system. For example, if the test exhibits a bug in the libc on a particular
|
||||
system version, or if the test uses a symbol that is not available on an
|
||||
older version of the dylib (but for which there is no availability markup,
|
||||
otherwise the XFAIL should use `availability` above).
|
@ -1,6 +1,6 @@
|
||||
=======================================================
|
||||
Capturing configuration information during installation
|
||||
=======================================================
|
||||
==================================================
|
||||
Capturing configuration information in the headers
|
||||
==================================================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@ -8,79 +8,61 @@ Capturing configuration information during installation
|
||||
The Problem
|
||||
===========
|
||||
|
||||
Currently the libc++ supports building the library with a number of different
|
||||
configuration options. Unfortunately all of that configuration information is
|
||||
lost when libc++ is installed. In order to support "persistent"
|
||||
configurations libc++ needs a mechanism to capture the configuration options
|
||||
in the INSTALLED headers.
|
||||
libc++ supports building the library with a number of different configuration options.
|
||||
In order to support persistent configurations and reduce arbitrary preprocessor logic
|
||||
in the headers, libc++ has a mechanism to capture configuration options in the
|
||||
installed headers so they can be used in the rest of the code.
|
||||
|
||||
|
||||
Design Goals
|
||||
============
|
||||
|
||||
* The solution should not INSTALL any additional headers. We don't want an extra
|
||||
#include slowing everybody down.
|
||||
* The solution should be simple, consistent and robust to avoid subtle bugs.
|
||||
|
||||
* The solution should not unduly affect libc++ developers. The problem is limited
|
||||
to installed versions of libc++ and the solution should be as well.
|
||||
* Developers should test the code the same way it will be deployed -- in other words,
|
||||
the headers used to run tests should be the same that we install in order
|
||||
to avoid bugs creeping up.
|
||||
|
||||
* The solution should not modify any existing headers EXCEPT during installation.
|
||||
It makes developers lives harder if they have to regenerate the libc++ headers
|
||||
every time they are modified.
|
||||
|
||||
* The solution should not make any of the libc++ headers dependent on
|
||||
files generated by the build system. The headers should be able to compile
|
||||
out of the box without any modification.
|
||||
|
||||
* The solution should not have ANY effect on users who don't need special
|
||||
configuration options. The vast majority of users will never need this so it
|
||||
shouldn't cost them.
|
||||
* It should allow different targets or flavors of the library to use a different
|
||||
configuration without having to duplicate all the libc++ headers.
|
||||
|
||||
|
||||
The Solution
|
||||
============
|
||||
|
||||
When you first configure libc++ using CMake we check to see if we need to
|
||||
capture any options. If we haven't been given any "persistent" options then
|
||||
we do NOTHING.
|
||||
When you first configure libc++ using CMake, a ``__config_site`` file is generated
|
||||
to capture the various configuration options you selected. The ``__config`` header
|
||||
used by all other headers includes this ``__config_site`` header first in order to
|
||||
get the correct configuration.
|
||||
|
||||
Otherwise we create a custom installation rule that modifies the installed __config
|
||||
header. The rule first generates a dummy "__config_site" header containing the required
|
||||
#defines. The contents of the dummy header are then prepended to the installed
|
||||
__config header. By manually prepending the files we avoid the cost of an
|
||||
extra #include and we allow the __config header to be ignorant of the extra
|
||||
configuration all together. An example "__config" header generated when
|
||||
-DLIBCXX_ENABLE_THREADS=OFF is given to CMake would look something like:
|
||||
The ``__config_site`` header is hence the only place where persistent configuration
|
||||
is stored in the library. That header essentially reflects how the vendor configured
|
||||
the library. As we evolve the library, we can lift configuration options into that
|
||||
header in order to reduce arbitrary hardcoded choices elsewhere in the code. For
|
||||
example, instead of assuming that a specific platform doesn't provide some functionality,
|
||||
we can create a generic macro to guard it and vendors can define the macro when
|
||||
configuring the library on that platform. This makes the "carve off" reusable in
|
||||
other circumstances instead of tying it tightly to a single platform.
|
||||
|
||||
.. code-block:: cpp
|
||||
Furthermore, the Clang driver now looks for headers in a target-specific directory
|
||||
for libc++. By installing the ``__config_site`` header (and only that header) to
|
||||
this target-specific directory, it is possible to share the libc++ headers for
|
||||
multiple targets, and only duplicate the persistent information located in the
|
||||
``__config_site`` header. For example:
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
.. code-block:: bash
|
||||
|
||||
#ifndef _LIBCPP_CONFIG_SITE
|
||||
#define _LIBCPP_CONFIG_SITE
|
||||
include/c++/v1/
|
||||
vector
|
||||
map
|
||||
etc...
|
||||
|
||||
/* #undef _LIBCPP_HAS_NO_GLOBAL_FILESYSTEM_NAMESPACE */
|
||||
/* #undef _LIBCPP_HAS_NO_STDIN */
|
||||
/* #undef _LIBCPP_HAS_NO_STDOUT */
|
||||
#define _LIBCPP_HAS_NO_THREADS
|
||||
/* #undef _LIBCPP_HAS_NO_MONOTONIC_CLOCK */
|
||||
/* #undef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS */
|
||||
include/<targetA>/c++/v1/
|
||||
__config_site
|
||||
|
||||
#endif
|
||||
// -*- C++ -*-
|
||||
//===--------------------------- __config ---------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
include/<targetB>/c++/v1/
|
||||
__config_site
|
||||
|
||||
#ifndef _LIBCPP_CONFIG
|
||||
#define _LIBCPP_CONFIG
|
||||
When compiling for ``targetA``, Clang will use the ``__config_site`` inside
|
||||
``include/<targetA>/c++/v1/``, and the corresponding ``__config_site`` for
|
||||
``targetB``.
|
||||
|
@ -7,85 +7,55 @@ Debug Mode
|
||||
|
||||
.. _using-debug-mode:
|
||||
|
||||
Using Debug Mode
|
||||
================
|
||||
Using the debug mode
|
||||
====================
|
||||
|
||||
Libc++ provides a debug mode that enables assertions meant to detect incorrect
|
||||
usage of the standard library. By default these assertions are disabled but
|
||||
they can be enabled using the ``_LIBCPP_DEBUG`` macro.
|
||||
Libc++ provides a debug mode that enables special debugging checks meant to detect
|
||||
incorrect usage of the standard library. These checks are disabled by default, but
|
||||
they can be enabled by vendors when building the library by using ``LIBCXX_ENABLE_DEBUG_MODE``.
|
||||
|
||||
**_LIBCPP_DEBUG** Macro
|
||||
-----------------------
|
||||
Since the debug mode has ABI implications, users should compile their whole program,
|
||||
including any dependent libraries, against a Standard library configured identically
|
||||
with respect to the debug mode. In other words, they should not mix code built against
|
||||
a Standard library with the debug mode enabled with code built against a Standard library
|
||||
where the debug mode is disabled.
|
||||
|
||||
**_LIBCPP_DEBUG**:
|
||||
This macro is used to enable assertions and iterator debugging checks within
|
||||
libc++. By default it is undefined.
|
||||
Furthermore, users should not rely on a stable ABI being provided when the debug mode is
|
||||
enabled -- we reserve the right to change the ABI at any time. If you need a stable ABI
|
||||
and still want some level of hardening, you should look into enabling :ref:`assertions <assertions-mode>`
|
||||
instead.
|
||||
|
||||
**Values**: ``0``, ``1``
|
||||
The debug mode provides various checks to aid application debugging.
|
||||
|
||||
Defining ``_LIBCPP_DEBUG`` to ``0`` or greater enables most of libc++'s
|
||||
assertions. Defining ``_LIBCPP_DEBUG`` to ``1`` enables "iterator debugging"
|
||||
which provides additional assertions about the validity of iterators used by
|
||||
the program.
|
||||
Comparator consistency checks
|
||||
-----------------------------
|
||||
Libc++ provides some checks for the consistency of comparators passed to algorithms. Specifically,
|
||||
many algorithms such as ``binary_search``, ``merge``, ``next_permutation``, and ``sort``, wrap the
|
||||
user-provided comparator to assert that `!comp(y, x)` whenever `comp(x, y)`. This can cause the
|
||||
user-provided comparator to be evaluated up to twice as many times as it would be without the
|
||||
debug mode, and causes the library to violate some of the Standard's complexity clauses.
|
||||
|
||||
Note that this option has no effect on libc++'s ABI; but it does have broad
|
||||
ODR implications. Users should compile their whole program at the same
|
||||
debugging level.
|
||||
Iterator debugging checks
|
||||
-------------------------
|
||||
The library contains various assertions to check the validity of iterators used
|
||||
by the program. The following containers and classes support iterator debugging:
|
||||
|
||||
Handling Assertion Failures
|
||||
---------------------------
|
||||
|
||||
When a debug assertion fails the assertion handler is called via the
|
||||
``std::__libcpp_debug_function`` function pointer. It is possible to override
|
||||
this function pointer using a different handler function. Libc++ provides a
|
||||
the default handler, ``std::__libcpp_abort_debug_handler``, which aborts the
|
||||
program. The handler may not return. Libc++ can be changed to use a custom
|
||||
assertion handler as follows.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#define _LIBCPP_DEBUG 1
|
||||
#include <string>
|
||||
void my_handler(std::__libcpp_debug_info const&);
|
||||
int main(int, char**) {
|
||||
std::__libcpp_debug_function = &my_handler;
|
||||
|
||||
std::string::iterator bad_it;
|
||||
std::string str("hello world");
|
||||
str.insert(bad_it, '!'); // causes debug assertion
|
||||
// control flow doesn't return
|
||||
}
|
||||
|
||||
Debug Mode Checks
|
||||
=================
|
||||
|
||||
Libc++'s debug mode offers two levels of checking. The first enables various
|
||||
precondition checks throughout libc++. The second additionally enables
|
||||
"iterator debugging" which checks the validity of iterators used by the program.
|
||||
|
||||
Basic Checks
|
||||
============
|
||||
|
||||
These checks are enabled when ``_LIBCPP_DEBUG`` is defined to either 0 or 1.
|
||||
|
||||
The following checks are enabled by ``_LIBCPP_DEBUG``:
|
||||
|
||||
* FIXME: Update this list
|
||||
|
||||
Iterator Debugging Checks
|
||||
=========================
|
||||
|
||||
These checks are enabled when ``_LIBCPP_DEBUG`` is defined to 1.
|
||||
|
||||
The following containers and STL classes support iterator debugging:
|
||||
|
||||
* ``std::string``
|
||||
* ``std::vector<T>`` (``T != bool``)
|
||||
* ``std::list``
|
||||
* ``std::unordered_map``
|
||||
* ``std::unordered_multimap``
|
||||
* ``std::unordered_set``
|
||||
* ``std::unordered_multiset``
|
||||
- ``std::string``
|
||||
- ``std::vector<T>`` (``T != bool``)
|
||||
- ``std::list``
|
||||
- ``std::unordered_map``
|
||||
- ``std::unordered_multimap``
|
||||
- ``std::unordered_set``
|
||||
- ``std::unordered_multiset``
|
||||
|
||||
The remaining containers do not currently support iterator debugging.
|
||||
Patches welcome.
|
||||
|
||||
Randomizing unspecified behavior
|
||||
--------------------------------
|
||||
The library supports the randomization of unspecified behavior. For example, randomizing
|
||||
the relative order of equal elements in ``std::sort`` or randomizing both parts of the
|
||||
partition after calling ``std::nth_element``. This effort helps migrating to potential
|
||||
future faster versions of these algorithms that might not have the exact same behavior.
|
||||
In particular, it makes it easier to deflake tests that depend on unspecified behavior.
|
||||
A seed can be used to make such failures reproducible: use ``_LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED=seed``.
|
||||
|
@ -143,7 +143,8 @@ Most (but not all) of the features of the LFTS were accepted into C++17.
|
||||
`FileSystem TS <https://wg21.link/N4100>`__
|
||||
-------------------------------------------
|
||||
The FileSystem TS was accepted (in totality) for C++17.
|
||||
The FileSystem TS implementation was shipped in namespace ``std`` in LLVM 7.0, and will be removed in LLVM 11.0 (due to the lack of deprecation warnings before LLVM 9.0).
|
||||
The FileSystem TS implementation was shipped in namespace ``std`` in LLVM 7.0, and was
|
||||
removed in LLVM 11.0 (due to the lack of deprecation warnings before LLVM 9.0).
|
||||
|
||||
Parallelism TS `V1 <https://wg21.link/N4507>`__ and `V2 <https://wg21.link/N4706>`__
|
||||
------------------------------------------------------------------------------------
|
||||
@ -152,8 +153,10 @@ We have not yet shipped an implementation of the Parallelism TS.
|
||||
|
||||
`Coroutines TS <https://wg21.link/N4680>`__
|
||||
-------------------------------------------
|
||||
The Coroutines TS is not yet part of a shipping standard.
|
||||
We are shipping (as of v5.0) an implementation of the Coroutines TS in namespace ``std::experimental``.
|
||||
The Coroutines TS was accepted for C++20.
|
||||
An implementation of the Coroutines TS was shipped in LLVM 5.0 in namespace ``std::experimental``,
|
||||
and C++20 Coroutines shipped in LLVM 14.0. The implementation of the Coroutines TS in ``std::experimental``
|
||||
will be removed in LLVM 16.0.
|
||||
|
||||
`Networking TS <https://wg21.link/N4656>`__
|
||||
-------------------------------------------
|
||||
@ -162,13 +165,15 @@ We have not yet shipped an implementation of the Networking TS.
|
||||
|
||||
`Ranges TS <https://wg21.link/N4685>`__
|
||||
---------------------------------------
|
||||
The Ranges TS is not yet part of a shipping standard.
|
||||
We have not yet shipped an implementation of the Ranges TS.
|
||||
The Ranges TS was accepted for C++20.
|
||||
We will not ship an implementation of the Ranges TS, however we are actively working on
|
||||
the implementation of C++20 Ranges.
|
||||
|
||||
`Concepts TS <https://wg21.link/N4641>`__
|
||||
-----------------------------------------
|
||||
The Concepts TS is not yet part of a shipping standard, but it has been adopted into the C++20 working draft.
|
||||
We have not yet shipped an implementation of the Concepts TS.
|
||||
The Concepts TS was accepted for C++20.
|
||||
We will not ship an implementation of the Concepts TS, however we are shipping an
|
||||
implementation of C++20 Concepts.
|
||||
|
||||
`Concurrency TS <https://wg21.link/P0159>`__
|
||||
--------------------------------------------
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user