diff --git a/libcxx/cmake/Modules/HandleExceptionLibrary.cmake b/libcxx/cmake/Modules/HandleExceptionLibrary.cmake new file mode 100644 --- /dev/null +++ b/libcxx/cmake/Modules/HandleExceptionLibrary.cmake @@ -0,0 +1,39 @@ +#=============================================================================== +# Define targets for linking against the selected ABI library +# +# After including this file, the following targets are defined: +# - cxx_exception: A target representing the shared c++_exception library. +# constituting the split from c++ shared library. +# The LIBCXX_EXCEPTION_ZOS_BUILD, which can be defined in +# cache, determines if the library will be built or not. +#=============================================================================== + + +if (LIBCXX_EXCEPTION_ZOS_BUILD) + add_library(cxx_exception SHARED ${exclude_from_all} ${LIBCXX_EXCEPTION_SOURCES} ${LIBCXX_HEADERS}) + target_link_libraries(cxx_exception PUBLIC cxx-headers + PRIVATE ${LIBCXX_LIBRARIES}) + set_target_properties(cxx_exception + PROPERTIES + COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS} -D_LIBCPP_BUILD_EXCEPTION_STANDALONE" + LINK_FLAGS "${LIBCXX_LINK_FLAGS}" + OUTPUT_NAME "c++_exception" + VERSION "${LIBCXX_ABI_VERSION}.0" + SOVERSION "${LIBCXX_ABI_VERSION}" + DEFINE_SYMBOL "" + POSITION_INDEPENDENT_CODE ON + ) + cxx_add_common_build_flags(cxx_exception) + cxx_set_common_defines(cxx_exception) + + add_custom_command(TARGET cxx_exception POST_BUILD + COMMAND + ${LIBCXX_SOURCE_DIR}/utils/zos_rename_dll_side_deck.sh + $ $ "${LIBCXX_EXCEPTION_DLL_NAME}" + COMMENT "Rename dll name inside the side deck file" + WORKING_DIRECTORY $ + ) + + target_link_libraries(cxx_exception PUBLIC libcxx-abi-shared) + list(APPEND LIBCXX_BUILD_TARGETS "cxx_exception") +endif() diff --git a/libcxx/cmake/caches/s390x-ibm-zos-ascii.cmake b/libcxx/cmake/caches/s390x-ibm-zos-ascii.cmake --- a/libcxx/cmake/caches/s390x-ibm-zos-ascii.cmake +++ b/libcxx/cmake/caches/s390x-ibm-zos-ascii.cmake @@ -16,6 +16,8 @@ set(LIBCXX_DLL_NAME CRTEQCXS CACHE STRING "") set(LIBCXX_SHARED_OUTPUT_NAME "c++_a" CACHE STRING "Output name for the shared libc++ runtime library.") +set(LIBCXX_EXCEPTION_ZOS_BUILD OFF CACHE BOOL + "Build libcxx exception library on z/OS as standalone.") set(LIBCXX_CXX_ABI system-libcxxabi CACHE STRING "") set(LIBCXX_ADDITIONAL_COMPILE_FLAGS "-fzos-le-char-mode=ascii" CACHE STRING "") diff --git a/libcxx/cmake/caches/s390x-ibm-zos.cmake b/libcxx/cmake/caches/s390x-ibm-zos.cmake --- a/libcxx/cmake/caches/s390x-ibm-zos.cmake +++ b/libcxx/cmake/caches/s390x-ibm-zos.cmake @@ -12,6 +12,9 @@ # Target Specific set(LIBCXX_DLL_NAME CRTEQCXE CACHE STRING "") +set(LIBCXX_EXCEPTION_DLL_NAME CRTEQCXP CACHE STRING "") +set(LIBCXX_EXCEPTION_ZOS_BUILD ON CACHE BOOL + "Build libcxx exception library on z/OS as standalone.") set(LIBCXXABI_DLL_NAME CRTEQCXA CACHE STRING "") set(LIBCXXABI_ADDITIONAL_LIBRARIES "-Wl,lib/libunwind.x" CACHE STRING "") diff --git a/libcxx/cmake/caches/s390x32-ibm-zos-ascii.cmake b/libcxx/cmake/caches/s390x32-ibm-zos-ascii.cmake --- a/libcxx/cmake/caches/s390x32-ibm-zos-ascii.cmake +++ b/libcxx/cmake/caches/s390x32-ibm-zos-ascii.cmake @@ -16,6 +16,8 @@ set(LIBCXX_DLL_NAME CRTEHCXS CACHE STRING "") set(LIBCXX_SHARED_OUTPUT_NAME "c++_a" CACHE STRING "Output name for the shared libc++ runtime library.") +set(LIBCXX_EXCEPTION_ZOS_BUILD OFF CACHE BOOL + "Build libcxx exception library on z/OS as standalone.") set(LIBCXX_CXX_ABI system-libcxxabi CACHE STRING "") set(LIBCXX_ADDITIONAL_COMPILE_FLAGS "-fzos-le-char-mode=ascii" CACHE STRING "") diff --git a/libcxx/cmake/caches/s390x32-ibm-zos.cmake b/libcxx/cmake/caches/s390x32-ibm-zos.cmake --- a/libcxx/cmake/caches/s390x32-ibm-zos.cmake +++ b/libcxx/cmake/caches/s390x32-ibm-zos.cmake @@ -12,6 +12,9 @@ # Target Specific set(LIBCXX_DLL_NAME CRTEHCXE CACHE STRING "") +set(LIBCXX_EXCEPTION_DLL_NAME CRTEHCXP CACHE STRING "") +set(LIBCXX_EXCEPTION_ZOS_BUILD ON CACHE BOOL + "Build libcxx exception library on z/OS as standalone.") set(LIBCXXABI_DLL_NAME CRTEHCXA CACHE STRING "") diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -637,6 +637,13 @@ # define _VSTD std _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD +#if defined(__MVS__) +#define _LIBCPP_BEGIN_NAMESPACE_EXCEPTION namespace std { +#define _LIBCPP_END_NAMESPACE_EXCEPTION } +#else +#define _LIBCPP_BEGIN_NAMESPACE_EXCEPTION _LIBCPP_BEGIN_NAMESPACE_STD +#define _LIBCPP_END_NAMESPACE_EXCEPTION _LIBCPP_END_NAMESPACE_STD +#endif # if _LIBCPP_STD_VER > 14 # define _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM \ diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -47,6 +47,20 @@ # pragma GCC system_header #endif +_LIBCPP_BEGIN_NAMESPACE_EXCEPTION + +class _LIBCPP_EXCEPTION_ABI bad_weak_ptr + : public std::exception +{ +public: + bad_weak_ptr() _NOEXCEPT = default; + bad_weak_ptr(const bad_weak_ptr&) _NOEXCEPT = default; + virtual ~bad_weak_ptr() _NOEXCEPT; + virtual const char* what() const _NOEXCEPT; +}; + +_LIBCPP_END_NAMESPACE_EXCEPTION + _LIBCPP_BEGIN_NAMESPACE_STD template @@ -125,16 +139,6 @@ #endif } -class _LIBCPP_EXCEPTION_ABI bad_weak_ptr - : public std::exception -{ -public: - bad_weak_ptr() _NOEXCEPT = default; - bad_weak_ptr(const bad_weak_ptr&) _NOEXCEPT = default; - ~bad_weak_ptr() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; -}; - _LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY void __throw_bad_weak_ptr() { diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -59,7 +59,6 @@ typeinfo.cpp utility.cpp valarray.cpp - variant.cpp vector.cpp verbose_abort.cpp ) @@ -132,6 +131,17 @@ endif() endif() +set(LIBCXX_EXCEPTION_SOURCES + exceptions/memory.cpp + exceptions/any.cpp + exceptions/optional.cpp + exceptions/variant.cpp + ) + +if (NOT ZOS) + list(APPEND LIBCXX_SOURCES ${LIBCXX_EXCEPTION_SOURCES}) +endif() + # Add all the headers to the project for IDEs. if (LIBCXX_CONFIGURE_IDE) file(GLOB_RECURSE LIBCXX_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/*) @@ -286,6 +296,8 @@ endif() endif() +include(HandleExceptionLibrary) + set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # Build the static library. diff --git a/libcxx/src/any.cpp b/libcxx/src/any.cpp --- a/libcxx/src/any.cpp +++ b/libcxx/src/any.cpp @@ -8,13 +8,6 @@ #include -namespace std { -const char* bad_any_cast::what() const noexcept { - return "bad any cast"; -} -} - - #include // Preserve std::experimental::any_bad_cast for ABI compatibility diff --git a/libcxx/src/exceptions/any.cpp b/libcxx/src/exceptions/any.cpp new file mode 100644 --- /dev/null +++ b/libcxx/src/exceptions/any.cpp @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +//// +//// 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 "any" + +namespace std { +const char* bad_any_cast::what() const noexcept { return "bad any cast"; } +} diff --git a/libcxx/src/exceptions/memory.cpp b/libcxx/src/exceptions/memory.cpp new file mode 100644 --- /dev/null +++ b/libcxx/src/exceptions/memory.cpp @@ -0,0 +1,19 @@ + +//===----------------------------------------------------------------------===// +//// +//// 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 "memory" + +_LIBCPP_BEGIN_NAMESPACE_EXCEPTION + +bad_weak_ptr::~bad_weak_ptr() noexcept {} + +const char* bad_weak_ptr::what() const noexcept { return "bad_weak_ptr"; } + +_LIBCPP_END_NAMESPACE_EXCEPTION diff --git a/libcxx/src/exceptions/optional.cpp b/libcxx/src/exceptions/optional.cpp new file mode 100644 --- /dev/null +++ b/libcxx/src/exceptions/optional.cpp @@ -0,0 +1,19 @@ + +//===----------------------------------------------------------------------===// +//// +//// 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 "optional" + +namespace std +{ + +bad_optional_access::~bad_optional_access() noexcept = default; + +const char* bad_optional_access::what() const noexcept { return "bad_optional_access"; } + +} // std diff --git a/libcxx/src/variant.cpp b/libcxx/src/exceptions/variant.cpp rename from libcxx/src/variant.cpp rename to libcxx/src/exceptions/variant.cpp diff --git a/libcxx/src/memory.cpp b/libcxx/src/memory.cpp --- a/libcxx/src/memory.cpp +++ b/libcxx/src/memory.cpp @@ -27,14 +27,6 @@ const allocator_arg_t allocator_arg = allocator_arg_t(); -bad_weak_ptr::~bad_weak_ptr() noexcept {} - -const char* -bad_weak_ptr::what() const noexcept -{ - return "bad_weak_ptr"; -} - __shared_count::~__shared_count() { } diff --git a/libcxx/src/optional.cpp b/libcxx/src/optional.cpp --- a/libcxx/src/optional.cpp +++ b/libcxx/src/optional.cpp @@ -9,18 +9,6 @@ #include <__availability> #include -namespace std -{ - -bad_optional_access::~bad_optional_access() noexcept = default; - -const char* bad_optional_access::what() const noexcept { - return "bad_optional_access"; -} - -} // std - - #include // Preserve std::experimental::bad_optional_access for ABI compatibility diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py new file mode 100644 --- /dev/null +++ b/libcxx/utils/libcxx/test/config.py @@ -0,0 +1,473 @@ +#===----------------------------------------------------------------------===## +# +# 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 +# +#===----------------------------------------------------------------------===## + +import copy +import os +import pkgutil +import pipes +import platform +import re +import shlex +import shutil +import sys + +from libcxx.compiler import CXXCompiler +from libcxx.test.target_info import make_target_info +import libcxx.util +import libcxx.test.features +import libcxx.test.newconfig +import libcxx.test.params +import lit + +def loadSiteConfig(lit_config, config, param_name, env_name): + # We haven't loaded the site specific configuration (the user is + # probably trying to run on a test file directly, and either the site + # configuration hasn't been created by the build system, or we are in an + # out-of-tree build situation). + site_cfg = lit_config.params.get(param_name, + os.environ.get(env_name)) + if not site_cfg: + lit_config.warning('No site specific configuration file found!' + ' Running the tests in the default configuration.') + elif not os.path.isfile(site_cfg): + lit_config.fatal( + "Specified site configuration file does not exist: '%s'" % + site_cfg) + else: + lit_config.note('using site specific configuration at %s' % site_cfg) + ld_fn = lit_config.load_config + + # Null out the load_config function so that lit.site.cfg doesn't + # recursively load a config even if it tries. + # TODO: This is one hell of a hack. Fix it. + def prevent_reload_fn(*args, **kwargs): + pass + lit_config.load_config = prevent_reload_fn + ld_fn(config, site_cfg) + lit_config.load_config = ld_fn + +# Extract the value of a numeric macro such as __cplusplus or a feature-test +# macro. +def intMacroValue(token): + return int(token.rstrip('LlUu')) + +class Configuration(object): + # pylint: disable=redefined-outer-name + def __init__(self, lit_config, config): + self.lit_config = lit_config + self.config = config + self.cxx = None + self.cxx_is_clang_cl = None + self.cxx_stdlib_under_test = None + self.project_obj_root = None + self.libcxx_src_root = None + self.libcxx_obj_root = None + self.cxx_library_root = None + self.cxx_runtime_root = None + self.abi_library_root = None + self.link_shared = self.get_lit_bool('enable_shared', default=True) + self.debug_build = self.get_lit_bool('debug_build', default=False) + self.exec_env = dict() + self.use_clang_verify = False + + def get_lit_conf(self, name, default=None): + val = self.lit_config.params.get(name, None) + if val is None: + val = getattr(self.config, name, None) + if val is None: + val = default + return val + + def get_lit_bool(self, name, default=None, env_var=None): + def check_value(value, var_name): + if value is None: + return default + if isinstance(value, bool): + return value + if not isinstance(value, str): + raise TypeError('expected bool or string') + if value.lower() in ('1', 'true'): + return True + if value.lower() in ('', '0', 'false'): + return False + self.lit_config.fatal( + "parameter '{}' should be true or false".format(var_name)) + + conf_val = self.get_lit_conf(name) + if env_var is not None and env_var in os.environ and \ + os.environ[env_var] is not None: + val = os.environ[env_var] + if conf_val is not None: + self.lit_config.warning( + 'Environment variable %s=%s is overriding explicit ' + '--param=%s=%s' % (env_var, val, name, conf_val)) + return check_value(val, env_var) + return check_value(conf_val, name) + + def make_static_lib_name(self, name): + """Return the full filename for the specified library name""" + if self.target_info.is_windows() and not self.target_info.is_mingw(): + assert name == 'c++' # Only allow libc++ to use this function for now. + return 'lib' + name + '.lib' + else: + return 'lib' + name + '.a' + + def configure(self): + self.target_info = make_target_info(self) + self.executor = self.get_lit_conf('executor') + self.configure_cxx() + self.configure_src_root() + self.configure_obj_root() + self.cxx_stdlib_under_test = self.get_lit_conf('cxx_stdlib_under_test', 'libc++') + self.cxx_library_root = self.get_lit_conf('cxx_library_root', self.libcxx_obj_root) + self.abi_library_root = self.get_lit_conf('abi_library_root') or self.cxx_library_root + self.cxx_runtime_root = self.get_lit_conf('cxx_runtime_root', self.cxx_library_root) + self.abi_runtime_root = self.get_lit_conf('abi_runtime_root', self.abi_library_root) + self.configure_compile_flags() + self.configure_link_flags() + self.configure_env() + self.configure_coverage() + self.configure_substitutions() + self.configure_features() + + libcxx.test.newconfig.configure( + libcxx.test.params.DEFAULT_PARAMETERS, + libcxx.test.features.DEFAULT_FEATURES, + self.config, + self.lit_config + ) + + self.lit_config.note("All available features: {}".format(self.config.available_features)) + + def print_config_info(self): + if self.cxx.use_modules: + self.lit_config.note('Using modules flags: %s' % + self.cxx.modules_flags) + if len(self.cxx.warning_flags): + self.lit_config.note('Using warnings: %s' % self.cxx.warning_flags) + show_env_vars = {} + for k,v in self.exec_env.items(): + if k not in os.environ or os.environ[k] != v: + show_env_vars[k] = v + self.lit_config.note('Adding environment variables: %r' % show_env_vars) + self.lit_config.note("Linking against the C++ Library at {}".format(self.cxx_library_root)) + self.lit_config.note("Running against the C++ Library at {}".format(self.cxx_runtime_root)) + self.lit_config.note("Linking against the ABI Library at {}".format(self.abi_library_root)) + self.lit_config.note("Running against the ABI Library at {}".format(self.abi_runtime_root)) + + def configure_cxx(self): + # Gather various compiler parameters. + cxx = self.get_lit_conf('cxx_under_test') + self.cxx_is_clang_cl = cxx is not None and \ + os.path.basename(cxx).startswith('clang-cl') + # If no specific cxx_under_test was given, attempt to infer it as + # clang++. + if cxx is None or self.cxx_is_clang_cl: + search_paths = self.config.environment['PATH'] + if cxx is not None and os.path.isabs(cxx): + search_paths = os.path.dirname(cxx) + clangxx = libcxx.util.which('clang++', search_paths) + if clangxx: + cxx = clangxx + self.lit_config.note( + "inferred cxx_under_test as: %r" % cxx) + elif self.cxx_is_clang_cl: + self.lit_config.fatal('Failed to find clang++ substitution for' + ' clang-cl') + if not cxx: + self.lit_config.fatal('must specify user parameter cxx_under_test ' + '(e.g., --param=cxx_under_test=clang++)') + self.cxx = CXXCompiler(self, cxx) if not self.cxx_is_clang_cl else \ + self._configure_clang_cl(cxx) + self.cxx.compile_env = dict(os.environ) + + def _configure_clang_cl(self, clang_path): + def _split_env_var(var): + return [p.strip() for p in os.environ.get(var, '').split(';') if p.strip()] + + def _prefixed_env_list(var, prefix): + from itertools import chain + return list(chain.from_iterable((prefix, path) for path in _split_env_var(var))) + + assert self.cxx_is_clang_cl + flags = [] + compile_flags = [] + link_flags = _prefixed_env_list('LIB', '-L') + return CXXCompiler(self, clang_path, flags=flags, + compile_flags=compile_flags, + link_flags=link_flags) + + def configure_src_root(self): + self.libcxx_src_root = self.get_lit_conf( + 'libcxx_src_root', os.path.dirname(self.config.test_source_root)) + + def configure_obj_root(self): + self.project_obj_root = self.get_lit_conf('project_obj_root') + self.libcxx_obj_root = self.get_lit_conf('libcxx_obj_root') + if not self.libcxx_obj_root and self.project_obj_root is not None: + possible_roots = [ + os.path.join(self.project_obj_root, 'libcxx'), + os.path.join(self.project_obj_root, 'projects', 'libcxx'), + os.path.join(self.project_obj_root, 'runtimes', 'libcxx'), + ] + for possible_root in possible_roots: + if os.path.isdir(possible_root): + self.libcxx_obj_root = possible_root + break + else: + self.libcxx_obj_root = self.project_obj_root + + def configure_features(self): + if self.target_info.is_windows(): + if self.cxx_stdlib_under_test == 'libc++': + # LIBCXX-WINDOWS-FIXME is the feature name used to XFAIL the + # initial Windows failures until they can be properly diagnosed + # and fixed. This allows easier detection of new test failures + # and regressions. Note: New failures should not be suppressed + # using this feature. (Also see llvm.org/PR32730) + self.config.available_features.add('LIBCXX-WINDOWS-FIXME') + + def configure_compile_flags(self): + self.configure_default_compile_flags() + # Configure extra flags + compile_flags_str = self.get_lit_conf('compile_flags', '') + self.cxx.compile_flags += shlex.split(compile_flags_str) + if self.target_info.is_windows(): + self.cxx.compile_flags += ['-D_CRT_SECURE_NO_WARNINGS'] + # Don't warn about using common but nonstandard unprefixed functions + # like chdir, fileno. + self.cxx.compile_flags += ['-D_CRT_NONSTDC_NO_WARNINGS'] + # Build the tests in the same configuration as libcxx itself, + # to avoid mismatches if linked statically. + self.cxx.compile_flags += ['-D_CRT_STDIO_ISO_WIDE_SPECIFIERS'] + # Required so that tests using min/max don't fail on Windows, + # and so that those tests don't have to be changed to tolerate + # this insanity. + self.cxx.compile_flags += ['-DNOMINMAX'] + additional_flags = self.get_lit_conf('test_compiler_flags') + if additional_flags: + self.cxx.compile_flags += shlex.split(additional_flags) + + def configure_default_compile_flags(self): + # Configure include paths + self.configure_compile_flags_header_includes() + self.target_info.add_cxx_compile_flags(self.cxx.compile_flags) + self.target_info.add_cxx_flags(self.cxx.flags) + # Use verbose output for better errors + self.cxx.flags += ['-v'] + sysroot = self.get_lit_conf('sysroot') + if sysroot: + self.cxx.flags += ['--sysroot=' + sysroot] + gcc_toolchain = self.get_lit_conf('gcc_toolchain') + if gcc_toolchain: + self.cxx.flags += ['--gcc-toolchain=' + gcc_toolchain] + # NOTE: the _DEBUG definition must preceed the triple check because for + # the Windows build of libc++, the forced inclusion of a header requires + # that _DEBUG is defined. Incorrect ordering will result in -target + # being elided. + if self.target_info.is_windows() and self.debug_build: + self.cxx.compile_flags += ['-D_DEBUG'] + + # Add includes for support headers used in the tests. + support_path = os.path.join(self.libcxx_src_root, 'test/support') + self.cxx.compile_flags += ['-I' + support_path] + + # Add includes for the PSTL headers + pstl_src_root = self.get_lit_conf('pstl_src_root') + pstl_obj_root = self.get_lit_conf('pstl_obj_root') + if pstl_src_root is not None and pstl_obj_root is not None: + self.cxx.compile_flags += ['-I' + os.path.join(pstl_src_root, 'include')] + self.cxx.compile_flags += ['-I' + os.path.join(pstl_obj_root, 'generated_headers')] + self.cxx.compile_flags += ['-I' + os.path.join(pstl_src_root, 'test')] + self.config.available_features.add('parallel-algorithms') + + def configure_compile_flags_header_includes(self): + support_path = os.path.join(self.libcxx_src_root, 'test', 'support') + if self.cxx_stdlib_under_test == 'msvc': + self.cxx.compile_flags += [ + '-include', os.path.join(support_path, + 'msvc_stdlib_force_include.h')] + pass + if self.target_info.is_windows() and self.debug_build and \ + self.cxx_stdlib_under_test != 'msvc': + self.cxx.compile_flags += [ + '-include', os.path.join(support_path, + 'set_windows_crt_report_mode.h') + ] + cxx_headers = self.get_lit_conf('cxx_headers') + if cxx_headers is None and self.cxx_stdlib_under_test != 'libc++': + self.lit_config.note('using the system cxx headers') + return + self.cxx.compile_flags += ['-nostdinc++'] + if not os.path.isdir(cxx_headers): + self.lit_config.fatal("cxx_headers='{}' is not a directory.".format(cxx_headers)) + (path, version) = os.path.split(cxx_headers) + (path, cxx) = os.path.split(path) + triple = self.get_lit_conf('target_triple', None) + if triple is not None: + cxx_target_headers = os.path.join(path, triple, cxx, version) + if os.path.isdir(cxx_target_headers): + self.cxx.compile_flags += ['-I' + cxx_target_headers] + self.cxx.compile_flags += ['-I' + cxx_headers] + if self.libcxx_obj_root is not None: + cxxabi_headers = os.path.join(self.libcxx_obj_root, 'include', + 'c++build') + if os.path.isdir(cxxabi_headers): + self.cxx.compile_flags += ['-I' + cxxabi_headers] + + def configure_link_flags(self): + # Configure library path + self.configure_link_flags_cxx_library_path() + self.configure_link_flags_abi_library_path() + + # Configure libraries + if self.cxx_stdlib_under_test == 'libc++': + if self.target_info.is_mingw(): + self.cxx.link_flags += ['-nostdlib++'] + else: + self.cxx.link_flags += ['-nodefaultlibs'] + # FIXME: Handle MSVCRT as part of the ABI library handling. + if self.target_info.is_windows() and not self.target_info.is_mingw(): + self.cxx.link_flags += ['-nostdlib'] + self.configure_link_flags_cxx_library() + self.configure_link_flags_abi_library() + self.configure_extra_library_flags() + elif self.cxx_stdlib_under_test == 'libstdc++': + self.cxx.link_flags += ['-lstdc++fs', '-lm', '-pthread'] + elif self.cxx_stdlib_under_test == 'msvc': + # FIXME: Correctly setup debug/release flags here. + pass + elif self.cxx_stdlib_under_test == 'cxx_default': + self.cxx.link_flags += ['-pthread'] + else: + self.lit_config.fatal('invalid stdlib under test') + + link_flags_str = self.get_lit_conf('link_flags', '') + self.cxx.link_flags += shlex.split(link_flags_str) + + def configure_link_flags_cxx_library_path(self): + if self.cxx_library_root: + self.cxx.link_flags += ['-L' + self.cxx_library_root] + if self.target_info.is_windows() and self.link_shared: + self.add_path(self.cxx.compile_env, self.cxx_library_root) + if self.cxx_runtime_root: + if not self.target_info.is_windows(): + self.cxx.link_flags += ['-Wl,-rpath,' + + self.cxx_runtime_root] + elif self.target_info.is_windows() and self.link_shared: + self.add_path(self.exec_env, self.cxx_runtime_root) + additional_flags = self.get_lit_conf('test_linker_flags') + if additional_flags: + self.cxx.link_flags += shlex.split(additional_flags) + + def configure_link_flags_abi_library_path(self): + # Configure ABI library paths. + if self.abi_library_root: + self.cxx.link_flags += ['-L' + self.abi_library_root] + if self.abi_runtime_root: + if not self.target_info.is_windows(): + self.cxx.link_flags += ['-Wl,-rpath,' + self.abi_runtime_root] + else: + self.add_path(self.exec_env, self.abi_runtime_root) + + def configure_link_flags_cxx_library(self): + if self.link_shared: + self.cxx.link_flags += ['-lc++'] + if self.target_info.is_zos(): + self.cxx.link_flags += ['-lc++_exception'] + else: + if self.cxx_library_root: + libname = self.make_static_lib_name('c++') + abs_path = os.path.join(self.cxx_library_root, libname) + assert os.path.exists(abs_path) and \ + "static libc++ library does not exist" + self.cxx.link_flags += [abs_path] + else: + self.cxx.link_flags += ['-lc++'] + + def configure_link_flags_abi_library(self): + cxx_abi = self.get_lit_conf('cxx_abi', 'libcxxabi') + if cxx_abi == 'libstdc++': + self.cxx.link_flags += ['-lstdc++'] + elif cxx_abi == 'libsupc++': + self.cxx.link_flags += ['-lsupc++'] + elif cxx_abi == 'libcxxabi': + # If the C++ library requires explicitly linking to libc++abi, or + # if we're testing libc++abi itself (the test configs are shared), + # then link it. + testing_libcxxabi = self.get_lit_conf('name', '') == 'libc++abi' + if self.target_info.allow_cxxabi_link() or testing_libcxxabi: + libcxxabi_shared = self.get_lit_bool('libcxxabi_shared', default=True) + if libcxxabi_shared: + self.cxx.link_flags += ['-lc++abi'] + else: + if self.abi_library_root: + libname = self.make_static_lib_name('c++abi') + abs_path = os.path.join(self.abi_library_root, libname) + self.cxx.link_flags += [abs_path] + else: + self.cxx.link_flags += ['-lc++abi'] + elif cxx_abi == 'libcxxrt': + self.cxx.link_flags += ['-lcxxrt'] + elif cxx_abi == 'vcruntime': + debug_suffix = 'd' if self.debug_build else '' + # This matches the set of libraries linked in the toplevel + # libcxx CMakeLists.txt if building targeting msvc. + self.cxx.link_flags += ['-l%s%s' % (lib, debug_suffix) for lib in + ['vcruntime', 'ucrt', 'msvcrt', 'msvcprt']] + # The compiler normally links in oldnames.lib too, but we've + # specified -nostdlib above, so we need to specify it manually. + self.cxx.link_flags += ['-loldnames'] + elif cxx_abi == 'none' or cxx_abi == 'default': + if self.target_info.is_windows(): + debug_suffix = 'd' if self.debug_build else '' + self.cxx.link_flags += ['-lmsvcrt%s' % debug_suffix] + else: + self.lit_config.fatal( + 'C++ ABI setting %s unsupported for tests' % cxx_abi) + + def configure_extra_library_flags(self): + if self.get_lit_bool('cxx_ext_threads', default=False): + self.cxx.link_flags += ['-lc++external_threads'] + self.target_info.add_cxx_link_flags(self.cxx.link_flags) + + def configure_coverage(self): + self.generate_coverage = self.get_lit_bool('generate_coverage', False) + if self.generate_coverage: + self.cxx.flags += ['-g', '--coverage'] + self.cxx.compile_flags += ['-O0'] + + def quote(self, s): + if platform.system() == 'Windows': + return lit.TestRunner.quote_windows_command([s]) + return pipes.quote(s) + + def configure_substitutions(self): + sub = self.config.substitutions + sub.append(('%{cxx}', self.quote(self.cxx.path))) + flags = self.cxx.flags + (self.cxx.modules_flags if self.cxx.use_modules else []) + compile_flags = self.cxx.compile_flags + (self.cxx.warning_flags if self.cxx.use_warnings else []) + sub.append(('%{flags}', ' '.join(map(self.quote, flags)))) + sub.append(('%{compile_flags}', ' '.join(map(self.quote, compile_flags)))) + sub.append(('%{link_flags}', ' '.join(map(self.quote, self.cxx.link_flags)))) + sub.append(('%{install}', self.quote(self.config.install_root))) + + codesign_ident = self.get_lit_conf('llvm_codesign_identity', '') + env_vars = ' '.join('%s=%s' % (k, self.quote(v)) for (k, v) in self.exec_env.items()) + exec_args = [ + '--execdir %T', + '--codesign_identity "{}"'.format(codesign_ident), + '--env {}'.format(env_vars) + ] + sub.append(('%{exec}', '{} {} -- '.format(self.executor, ' '.join(exec_args)))) + + def configure_env(self): + self.config.environment = dict(os.environ) + + def add_path(self, dest_env, new_path): + self.target_info.add_path(dest_env, new_path)