[flang-rt] Avoid duplicate definition of std::__libcpp_verbose_abort (#175551)
If a project depends on the Flang runtime and on libc++, linking fails because `std::__libcpp_verbose_abort` is defined in both libraries. Avoid that duplicate definition by defining `_LIBCPP_VERBOSE_ABORT` before including any C++ headers and by renaming that symbol in the Flang runtime to `flang_rt_verbose_abort`. The function that is modified was originally introduced in D158957 to solve an undefined symbol error when linking pure-Fortran projects with the Flang runtime. Providing a definition for that symbol in the Flang runtime might work correctly for ELF or Mach-O if that symbol has weak linkage in libc++. But at least for COFF, this now causes multiple-definition errors for projects that are linking to the Flang runtime and to libc++. The linker errors before this change for Windows/MinGW using Clang+Flang+lld look like this: ``` ld.lld: error: duplicate symbol: std::__1::__libcpp_verbose_abort(char const*, ...) >>> defined at libflang_rt.runtime.a(io-api-minimal.cpp.obj) >>> defined at libc++.dll.a(libc++.dll) ```
This commit is contained in:
parent
9e6bd128f2
commit
e41e7b90f9
@ -238,34 +238,31 @@ function (add_flangrt_library name)
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti -funwind-tables -fno-asynchronous-unwind-tables>
|
||||
)
|
||||
|
||||
# We define our own _GLIBCXX_THROW_OR_ABORT here because, as of
|
||||
# GCC 15.1, the libstdc++ header file <bits/c++config> uses
|
||||
# (void)_EXC in its definition of _GLIBCXX_THROW_OR_ABORT to
|
||||
# silence a warning.
|
||||
#
|
||||
# This is a problem for us because some compilers, specifically
|
||||
# clang, do not always optimize away that (void)_EXC even though
|
||||
# it is unreachable since it occurs after a call to
|
||||
# _builtin_abort(). Because _EXC is typically an object derived
|
||||
# from std::exception, (void)_EXC, when not optimized away,
|
||||
# calls std::exception methods defined in the libstdc++ shared
|
||||
# library. We shouldn't link against that library since our
|
||||
# build version may conflict with the version used by a hybrid
|
||||
# Fortran/C++ application.
|
||||
#
|
||||
# Redefining _GLIBCXX_THROW_OR_ABORT in this manner is not
|
||||
# supported by the maintainers of libstdc++, so future changes
|
||||
# to libstdc++ may require future changes to this build script
|
||||
# and/or future changes to the Fortran runtime source code.
|
||||
target_compile_options(${tgtname} PUBLIC "-D_GLIBCXX_THROW_OR_ABORT(_EXC)=(__builtin_abort())")
|
||||
# Include header at the top of all compilation units to avoid dependency
|
||||
# on the C++ STL (libstdc++ or libc++).
|
||||
target_compile_options(${tgtname} PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:-include${FLANG_RT_SOURCE_DIR}/lib/runtime/stl-overrides.h>"
|
||||
)
|
||||
elseif (MSVC)
|
||||
target_compile_options(${tgtname} PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:/EHs-c- /GR->
|
||||
)
|
||||
|
||||
# Include header at the top of all compilation units to avoid dependency
|
||||
# on the C++ STL (libstdc++ or libc++).
|
||||
target_compile_options(${tgtname} PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:/FI${FLANG_RT_SOURCE_DIR}/lib/runtime/stl-overrides.h>"
|
||||
)
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL")
|
||||
target_compile_options(${tgtname} PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-qnoeh -qnortti>
|
||||
)
|
||||
|
||||
# Include header at the top of all compilation units to avoid dependency
|
||||
# on the C++ STL (libstdc++ or libc++).
|
||||
target_compile_options(${tgtname} PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:-qinclude=${FLANG_RT_SOURCE_DIR}/lib/runtime/stl-overrides.h>"
|
||||
)
|
||||
endif ()
|
||||
|
||||
# Add target specific options if necessary.
|
||||
|
||||
@ -59,6 +59,7 @@ set(supported_sources
|
||||
ragged.cpp
|
||||
reduction.cpp
|
||||
stat.cpp
|
||||
stl-overrides.cpp
|
||||
stop.cpp
|
||||
sum.cpp
|
||||
support.cpp
|
||||
|
||||
@ -146,19 +146,4 @@ bool IODEF(OutputLogical)(Cookie cookie, bool truth) {
|
||||
|
||||
} // namespace Fortran::runtime::io
|
||||
|
||||
#if defined(_LIBCPP_VERBOSE_ABORT)
|
||||
// Provide own definition for `std::__libcpp_verbose_abort` to avoid dependency
|
||||
// on the version provided by libc++.
|
||||
|
||||
void std::__libcpp_verbose_abort(char const *format, ...) noexcept(
|
||||
noexcept(std::__libcpp_verbose_abort(""))) {
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
std::vfprintf(stderr, format, list);
|
||||
va_end(list);
|
||||
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
RT_EXT_API_GROUP_END
|
||||
|
||||
22
flang-rt/lib/runtime/stl-overrides.cpp
Normal file
22
flang-rt/lib/runtime/stl-overrides.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
//===-- lib/runtime/stl-overrides.cpp ---------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
// Provide function that is used in place of `std::__libcpp_verbose_abort` to
|
||||
// avoid dependency on the symbol provided by libc++.
|
||||
void flang_rt_verbose_abort(char const *format, ...) {
|
||||
va_list list;
|
||||
va_start(list, format);
|
||||
std::vfprintf(stderr, format, list);
|
||||
va_end(list);
|
||||
|
||||
std::abort();
|
||||
}
|
||||
38
flang-rt/lib/runtime/stl-overrides.h
Normal file
38
flang-rt/lib/runtime/stl-overrides.h
Normal file
@ -0,0 +1,38 @@
|
||||
//===-- lib/runtime/stl-overrides.h -----------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This file is inserted implicitly to all translation units using -include on
|
||||
// the command line. The reason is that it configures the C++ standard
|
||||
// template library (libc++ or libstdc++) using preprocessor macro definitions
|
||||
// that must appear before any C++ library include.
|
||||
|
||||
// We define our own _GLIBCXX_THROW_OR_ABORT here because, as of GCC 15.1, the
|
||||
// libstdc++ header file <bits/c++config> uses (void)_EXC in its definition of
|
||||
// _GLIBCXX_THROW_OR_ABORT to silence a warning.
|
||||
//
|
||||
// This is a problem for us because some compilers, specifically clang, do not
|
||||
// always optimize away that (void)_EXC even though it is unreachable since it
|
||||
// occurs after a call to _builtin_abort(). Because _EXC is typically an
|
||||
// object derived from std::exception, (void)_EXC, when not optimized away,
|
||||
// calls std::exception methods defined in the libstdc++ shared library. We
|
||||
// shouldn't link against that library since our build version may conflict
|
||||
// with the version used by a hybrid Fortran/C++ application.
|
||||
//
|
||||
// Redefining _GLIBCXX_THROW_OR_ABORT in this manner is not supported by the
|
||||
// maintainers of libstdc++, so future changes to libstdc++ may require future
|
||||
// changes to this build script and/or future changes to the Fortran runtime
|
||||
// source code.
|
||||
#define _GLIBCXX_THROW_OR_ABORT(_EXC) (__builtin_abort())
|
||||
|
||||
// Declare function that is used in place of `std::__libcpp_verbose_abort` to
|
||||
// avoid dependency on the symbol provided by libc++.
|
||||
#ifndef _LIBCPP_VERBOSE_ABORT
|
||||
#define _LIBCPP_VERBOSE_ABORT(...) flang_rt_verbose_abort(__VA_ARGS__)
|
||||
void flang_rt_verbose_abort(char const *format, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user