diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -485,16 +485,24 @@ set(LIBCXX_DEBUG_BUILD OFF) endif() +if (LIBCXX_TARGETING_MSVC) + string(REGEX MATCH "(^| )/MTd?( |$)" result ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}}) + if ("${result}" STREQUAL "") + set(LIBCXX_MSVC_DYNAMIC_RUNTIME ON) + else() + set(LIBCXX_MSVC_DYNAMIC_RUNTIME OFF) + endif() +endif() + #=============================================================================== # Setup Compiler Flags #=============================================================================== include(HandleLibCXXABI) # Setup the ABI library flags - -# FIXME: Remove all debug flags and flags that change which Windows -# default libraries are linked. Currently we only support linking the -# non-debug DLLs -remove_flags("/D_DEBUG" "/MTd" "/MDd" "/MT" "/Md") +if (LIBCXX_TARGETING_MSVC) + # Remove MSVC runtime related flags. + remove_flags("/MTd" "/MDd" "/MT" "/MD") +endif() # FIXME(EricWF): See the FIXME on LIBCXX_ENABLE_PEDANTIC. # Remove the -pedantic flag and -Wno-pedantic and -pedantic-errors @@ -511,6 +519,19 @@ CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO) + if (LIBCXX_TARGETING_MSVC) + cmake_parse_arguments(ARG "DYNAMIC_RUNTIME" "" "" ${ARGN}) + if (ARG_DYNAMIC_RUNTIME OR LIBCXX_MSVC_DYNAMIC_RUNTIME) + set(opt "/MD") + else() + set(opt "/MT") + endif() + if (LIBCXX_DEBUG_BUILD) + string(APPEND opt "d") + endif() + target_compile_options(${target} PRIVATE ${opt}) + endif() + # 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 exception of z/OS. @@ -774,16 +795,30 @@ endif() if (LIBCXX_TARGETING_MSVC) + cmake_parse_arguments(ARG "DYNAMIC_RUNTIME" "" "" ${ARGN}) + if (LIBCXX_DEBUG_BUILD) set(LIB_SUFFIX "d") else() set(LIB_SUFFIX "") endif() - target_link_libraries(${target} PRIVATE ucrt${LIB_SUFFIX}) # Universal C runtime - target_link_libraries(${target} PRIVATE vcruntime${LIB_SUFFIX}) # C++ runtime - target_link_libraries(${target} PRIVATE msvcrt${LIB_SUFFIX}) # C runtime startup files - target_link_libraries(${target} PRIVATE msvcprt${LIB_SUFFIX}) # C++ standard library. Required for exception_ptr internals. + if (ARG_DYNAMIC_RUNTIME OR LIBCXX_MSVC_DYNAMIC_RUNTIME) + set(UCRT_LIB "ucrt") + set(CXXRT_LIB "vcruntime") + set(CRT_LIB "msvcrt") + set(CXX_LIB "msvcprt") + else() + set(UCRT_LIB "libucrt") + set(CXXRT_LIB "libvcruntime") + set(CRT_LIB "libcmt") + set(CXX_LIB "libcpmt") + endif() + + target_link_libraries(${target} PRIVATE ${UCRT_LIB}${LIB_SUFFIX}) # Universal C runtime + target_link_libraries(${target} PRIVATE ${CXXRT_LIB}${LIB_SUFFIX}) # C++ runtime + target_link_libraries(${target} PRIVATE ${CRT_LIB}${LIB_SUFFIX}) # C runtime startup files + target_link_libraries(${target} PRIVATE ${CXX_LIB}${LIB_SUFFIX}) # C++ standard library. Required for exception_ptr internals. # Required for standards-complaint wide character formatting functions # (e.g. `printfw`/`scanfw`) target_link_libraries(${target} PRIVATE iso_stdio_wide_specifiers) @@ -817,14 +852,6 @@ # Use the ISO conforming behaviour for conversion # in printf, scanf. _CRT_STDIO_ISO_WIDE_SPECIFIERS) - # Clang-cl shared builds don't support the experimental library. - # To avoid linker errors the format_error destructor is inlined for the - # dylib. Users can never use format in this mode. - # TODO FMT Remove when format becomes mainline. - if (LIBCXX_ENABLE_SHARED) - target_compile_definitions(${target} PRIVATE - _LIBCPP_INLINE_FORMAT_ERROR_DTOR) - endif() endif() endfunction() @@ -898,13 +925,13 @@ # Setup all common build flags ================================================= function(cxx_add_common_build_flags target) - cxx_add_basic_build_flags(${target}) + cxx_add_basic_build_flags(${target} ${ARGN}) cxx_add_warning_flags(${target}) cxx_add_windows_flags(${target}) cxx_add_exception_flags(${target}) cxx_add_rtti_flags(${target}) cxx_add_module_flags(${target}) - cxx_link_system_libraries(${target}) + cxx_link_system_libraries(${target} ${ARGN}) endfunction() #=============================================================================== diff --git a/libcxx/include/__format/format_error.h b/libcxx/include/__format/format_error.h --- a/libcxx/include/__format/format_error.h +++ b/libcxx/include/__format/format_error.h @@ -28,14 +28,7 @@ : runtime_error(__s) {} _LIBCPP_HIDE_FROM_ABI explicit format_error(const char* __s) : runtime_error(__s) {} - // TODO FMT Remove when format is no longer experimental. - // Avoids linker errors when building the Clang-cl Windows DLL which doesn't - // support the experimental library. -# ifndef _LIBCPP_INLINE_FORMAT_ERROR_DTOR ~format_error() noexcept override; -# else - ~format_error() noexcept override {} -# endif }; _LIBCPP_NORETURN inline _LIBCPP_HIDE_FROM_ABI void diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -210,7 +210,7 @@ SOVERSION "${LIBCXX_ABI_VERSION}" DEFINE_SYMBOL "" ) - cxx_add_common_build_flags(cxx_shared) + cxx_add_common_build_flags(cxx_shared DYNAMIC_RUNTIME) cxx_set_common_defines(cxx_shared) if(ZOS) @@ -285,6 +285,9 @@ set_target_properties(cxx_shared PROPERTIES APPEND_STRING PROPERTY LINK_FLAGS " /MANIFEST:NO") endif() + if(LIBCXX_TARGETING_MSVC) + target_link_libraries(cxx_shared PRIVATE cxx_experimental_stub) + endif() endif() set(CMAKE_STATIC_LIBRARY_PREFIX "lib") @@ -323,6 +326,12 @@ if (LIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY) target_link_libraries(cxx_static PRIVATE libcxx-abi-static-objects) endif() + + if (LIBCXX_TARGETING_MSVC) + set(LIBCXX_MSVC_EXPERIMENTAL_STATIC ON) + else() + set(LIBCXX_MSVC_EXPERIMENTAL_STATIC OFF) + endif() endif() # Add a meta-target for both libraries. @@ -333,18 +342,39 @@ format.cpp ) -add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES}) -target_link_libraries(cxx_experimental PUBLIC cxx-headers) -if (LIBCXX_ENABLE_SHARED) +if (LIBCXX_TARGETING_MSVC) + add_library(cxx_experimental_stub SHARED ${LIBCXX_EXPERIMENTAL_SOURCES}) + target_link_libraries(cxx_experimental_stub PUBLIC cxx-headers) + + set_target_properties(cxx_experimental_stub + PROPERTIES + COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}" + LINK_FLAGS "/FORCE:UNRESOLVED" + RUNTIME_OUTPUT_NAME "c++experimental" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ) + cxx_add_common_build_flags(cxx_experimental_stub DYNAMIC_RUNTIME) + target_compile_options(cxx_experimental_stub PUBLIC -D_LIBCPP_ENABLE_EXPERIMENTAL) + + add_library(cxx_experimental SHARED ${LIBCXX_EXPERIMENTAL_SOURCES}) + target_link_libraries(cxx_experimental PUBLIC cxx-headers) target_link_libraries(cxx_experimental PRIVATE cxx_shared) else() - target_link_libraries(cxx_experimental PRIVATE cxx_static) -endif() + add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES}) + target_link_libraries(cxx_experimental PUBLIC cxx-headers) + if (LIBCXX_ENABLE_SHARED) + target_link_libraries(cxx_experimental PRIVATE cxx_shared) + else() + target_link_libraries(cxx_experimental PRIVATE cxx_static) + endif() -if (LIBCXX_HERMETIC_STATIC_LIBRARY) - # _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS can be defined in __config_site - # too. Define it in the same way here, to avoid redefinition conflicts. - target_compile_definitions(cxx_experimental PRIVATE _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=) + if (LIBCXX_HERMETIC_STATIC_LIBRARY) + # _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS can be defined in __config_site + # too. Define it in the same way here, to avoid redefinition conflicts. + target_compile_definitions(cxx_experimental PRIVATE _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=) + endif() endif() set_target_properties(cxx_experimental @@ -352,9 +382,27 @@ COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}" OUTPUT_NAME "c++experimental" ) -cxx_add_common_build_flags(cxx_experimental) +cxx_add_common_build_flags(cxx_experimental DYNAMIC_RUNTIME) target_compile_options(cxx_experimental PUBLIC -D_LIBCPP_ENABLE_EXPERIMENTAL) +if (LIBCXX_MSVC_EXPERIMENTAL_STATIC) + add_library(cxx_experimental_static STATIC ${LIBCXX_EXPERIMENTAL_SOURCES}) + target_link_libraries(cxx_experimental_static PUBLIC cxx-headers) + + if (LIBCXX_HERMETIC_STATIC_LIBRARY) + # _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS can be defined in __config_site + # too. Define it in the same way here, to avoid redefinition conflicts. + target_compile_definitions(cxx_experimental_static PRIVATE _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=) + endif() + + set_target_properties(cxx_experimental_static + PROPERTIES + COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}" + OUTPUT_NAME "c++experimental" + ) + cxx_add_common_build_flags(cxx_experimental_static) + target_compile_options(cxx_experimental_static PUBLIC -D_LIBCPP_ENABLE_EXPERIMENTAL) +endif() if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY) set(LIBCXX_EXTERNAL_THREADING_SUPPORT_SOURCES @@ -377,21 +425,22 @@ endif() if (LIBCXX_INSTALL_SHARED_LIBRARY) - install(TARGETS cxx_shared - ARCHIVE DESTINATION ${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx - LIBRARY DESTINATION ${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx - RUNTIME DESTINATION ${LIBCXX_INSTALL_RUNTIME_DIR} COMPONENT cxx) + list(APPEND install_targets cxx_shared) endif() if (LIBCXX_INSTALL_STATIC_LIBRARY) - install(TARGETS cxx_static - ARCHIVE DESTINATION ${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx - LIBRARY DESTINATION ${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx - RUNTIME DESTINATION ${LIBCXX_INSTALL_RUNTIME_DIR} COMPONENT cxx) + list(APPEND install_targets cxx_static) endif() if (LIBCXX_INSTALL_LIBRARY) - install(TARGETS cxx_experimental + list(APPEND install_targets cxx_experimental) + if (LIBCXX_MSVC_EXPERIMENTAL_STATIC) + list(APPEND install_targets cxx_experimental_static) + endif() +endif() + +if (install_targets) + install(TARGETS ${install_targets} LIBRARY DESTINATION ${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx ARCHIVE DESTINATION ${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx RUNTIME DESTINATION ${LIBCXX_INSTALL_RUNTIME_DIR} COMPONENT cxx) @@ -408,6 +457,9 @@ if (NOT CMAKE_CONFIGURATION_TYPES) if(LIBCXX_INSTALL_LIBRARY) set(lib_install_target "cxx;cxx_experimental") + if (LIBCXX_MSVC_EXPERIMENTAL_STATIC) + string(APPEND lib_install_target ";experimental_static") + endif() endif() if(LIBCXX_INSTALL_HEADERS) set(header_install_target install-cxx-headers) diff --git a/libcxx/src/format.cpp b/libcxx/src/format.cpp --- a/libcxx/src/format.cpp +++ b/libcxx/src/format.cpp @@ -10,8 +10,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#ifndef _LIBCPP_INLINE_FORMAT_ERROR_DTOR format_error::~format_error() noexcept = default; -#endif _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/configs/llvm-libc++-shared-clangcl.cfg.in b/libcxx/test/configs/llvm-libc++-shared-clangcl.cfg.in --- a/libcxx/test/configs/llvm-libc++-shared-clangcl.cfg.in +++ b/libcxx/test/configs/llvm-libc++-shared-clangcl.cfg.in @@ -1,14 +1,23 @@ # This testing configuration handles running the test suite against LLVM's libc++ # using a DLL, with Clang-cl on Windows. +runtime_lib = 'msvcprt' +fms_runtime_lib = 'dll' +dbg_include = '' + +if '@LIBCXX_DEBUG_BUILD@' == 'ON': + fms_runtime_lib += '_dbg' + runtime_lib += 'd' + dbg_include = ' -include set_windows_crt_report_mode.h' + lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg') config.substitutions.append(('%{flags}', '--driver-mode=g++')) config.substitutions.append(('%{compile_flags}', - '-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX' + '-fms-runtime-lib=' + fms_runtime_lib + ' -nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX' + dbg_include )) config.substitutions.append(('%{link_flags}', - '-nostdlib -L %{lib} -lc++ -lmsvcrt -lmsvcprt -loldnames' + '-nostartfiles -nostdlib++ -rtlib=compiler-rt -L %{lib} -lc++ -l' + runtime_lib )) config.substitutions.append(('%{exec}', '%{executor} --execdir %T --env PATH=%{lib} -- ' diff --git a/libcxx/test/configs/llvm-libc++-static-clangcl.cfg.in b/libcxx/test/configs/llvm-libc++-static-clangcl.cfg.in --- a/libcxx/test/configs/llvm-libc++-static-clangcl.cfg.in +++ b/libcxx/test/configs/llvm-libc++-static-clangcl.cfg.in @@ -1,14 +1,28 @@ # This testing configuration handles running the test suite against LLVM's libc++ # using a static library, with Clang-cl on Windows. +if '@LIBCXX_MSVC_DYNAMIC_RUNTIME@' == 'ON': + fms_runtime_lib = 'dll' + runtime_lib = 'msvcprt' +else: + fms_runtime_lib = 'static' + runtime_lib = 'libcpmt' + +dbg_include = '' + +if '@LIBCXX_DEBUG_BUILD@' == 'ON': + fms_runtime_lib += '_dbg' + runtime_lib += 'd' + dbg_include = ' -include set_windows_crt_report_mode.h' + lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg') config.substitutions.append(('%{flags}', '--driver-mode=g++')) config.substitutions.append(('%{compile_flags}', - '-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX' + '-fms-runtime-lib=' + fms_runtime_lib + ' -nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS' + dbg_include )) config.substitutions.append(('%{link_flags}', - '-nostdlib -L %{lib} -llibc++ -lmsvcrt -lmsvcprt -loldnames' + '-nostartfiles -nostdlib++ -rtlib=compiler-rt -L %{lib} -llibc++ -l' + runtime_lib )) config.substitutions.append(('%{exec}', '%{executor} --execdir %T -- ' diff --git a/libcxx/test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp b/libcxx/test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp --- a/libcxx/test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp +++ b/libcxx/test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp @@ -91,13 +91,12 @@ void *ret = r1.allocate(50); assert(ret); - assert(globalMemCounter.checkOutstandingNewEq(1)); - assert(globalMemCounter.checkLastNewSizeEq(50)); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkOutstandingNewEq(1)); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkLastNewSizeEq(50)); r1.deallocate(ret, 1); - assert(globalMemCounter.checkOutstandingNewEq(0)); - assert(globalMemCounter.checkDeleteCalledEq(1)); - + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkOutstandingNewEq(0)); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkDeleteCalledEq(1)); } int main(int, char**) diff --git a/libcxx/test/support/set_windows_crt_report_mode.h b/libcxx/test/support/set_windows_crt_report_mode.h --- a/libcxx/test/support/set_windows_crt_report_mode.h +++ b/libcxx/test/support/set_windows_crt_report_mode.h @@ -10,27 +10,32 @@ #ifndef SUPPORT_SET_WINDOWS_CRT_REPORT_MODE_H #define SUPPORT_SET_WINDOWS_CRT_REPORT_MODE_H -#ifndef _DEBUG -#error _DEBUG must be defined when using this header -#endif +#if defined(__cplusplus) && __cplusplus > 199711L +# ifndef _DEBUG +# error _DEBUG must be defined when using this header +# endif -#ifndef _WIN32 -#error This header can only be used when targeting Windows -#endif +# ifndef _WIN32 +# error This header can only be used when targeting Windows +# endif -#include +# include // On Windows in debug builds the default assertion handler opens a new dialog // window which must be dismissed manually by the user. This function overrides // that setting and instead changes the assertion handler to log to stderr // instead. -inline int init_crt_report_mode() { - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); +inline int init_crt_report_mode(void) { + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); return 0; } static int init_crt_anchor = init_crt_report_mode(); +#endif #endif // SUPPORT_SET_WINDOWS_CRT_REPORT_MODE_H diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py --- a/libcxx/utils/libcxx/test/features.py +++ b/libcxx/utils/libcxx/test/features.py @@ -16,6 +16,7 @@ _isAppleClang = lambda cfg: '__apple_build_version__' in compilerMacros(cfg) _isGCC = lambda cfg: '__GNUC__' in compilerMacros(cfg) and '__clang__' not in compilerMacros(cfg) _isMSVC = lambda cfg: '_MSC_VER' in compilerMacros(cfg) +_isMSVCStatic = lambda cfg: _isMSVC(cfg) and '_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS' in compilerMacros(cfg) _msvcVersion = lambda cfg: (int(compilerMacros(cfg)['_MSC_VER']) // 100, int(compilerMacros(cfg)['_MSC_VER']) % 100) def _getSuitableClangTidy(cfg): diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py --- a/libcxx/utils/libcxx/test/params.py +++ b/libcxx/utils/libcxx/test/params.py @@ -7,7 +7,7 @@ #===----------------------------------------------------------------------===## from libcxx.test.dsl import * -from libcxx.test.features import _isMSVC +from libcxx.test.features import _isMSVCStatic import re _warningFlags = [ @@ -176,10 +176,8 @@ # When linking in MSVC mode via the Clang driver, a -l # maps to .lib, so we need to use -llibc++experimental here # to make it link against the static libc++experimental.lib. - # We can't check for the feature 'msvc' in available_features - # as those features are added after processing parameters. AddFeature('c++experimental'), - PrependLinkFlag(lambda cfg: '-llibc++experimental' if _isMSVC(cfg) else '-lc++experimental'), + PrependLinkFlag(lambda cfg: '-llibc++experimental' if _isMSVCStatic(cfg) else '-lc++experimental'), AddCompileFlag('-D_LIBCPP_ENABLE_EXPERIMENTAL'), ] if experimental else [ AddFeature('libcpp-has-no-incomplete-format'),