resending - the first & second attempt didn’t seem to make it to gcc-patches.
Hi
This option allows the user to specify alternate C++ runtime libraries,
for example when a platform uses libc++ as the installed C++ runtime.
It is the same spelling as a clang option that allows that to use libstdc++.
I have had this patch for some time now (more than a year) on Darwin
branches.
For Darwin [>=11] (and I expect modern FreeBSD) the fact that the installed
C++ runtime is libc++ means conflicts can and do occur when using G++.
I expect that the facility will also be useful for folks who regularly try to
ensure that GCC and clang stay compatible, it is a credit to that effort that
the replacement is pretty much “drop in”.
Testing:
The patch applies without regression on *darwin* and x86_64-linux-gnu.
That doesn’t say much about whether it does what’s intended, of course,
and testing in-tree is not a viable option (it would need a lot of work, not
to mention the fact that it depends on an external source base). So I’ve
tested this quite extensively on x86 Darwin and Linux.
It’s a lot easier to use an LLVM branch >= 9 for this since there is a
missing __cxa symbol before that (I originally used LLVM-7 for ‘reasons’).
Since coroutines was committed to GCC we have a <coroutine> header
where the libc++ implementation is still using the <experimental/coroutine>
version, so that one needs to account for this.
Here’s an LLVM-9 tree with an added <coroutine> header (as an example)
https://github.com/iains/llvm-project/tree/9.0.1-gcc-stdlib
(in case someone wants to try this out in the near future; I don’t think that
LLVM-10 will be much different, at least the coroutine header is unchanged
there)
I’ve used this ‘in anger’ on Darwin to build a toolset which includes a
number
of C++ heavy applications (e.g. LLVM, cmake, etc) and it allowed some of
these to work effectively where it had not been possible before.
One can also do an “installed test” of g++
for that there are (a relatively modest number of) test fails.
AFAICT, there is nothing significant there - some tests fail because the
output
isn’t expecting to see libc++ __1 inline namespace, some fail because libc++
(as per current branches) doesn’t allow use with GCC + std=c++98, some
are warning diagnostics etc.
[how compatible libc++ is, is somewhat independent of the patch itself; but
it seems “very compatible” is a starting assessment].
phew… description longer than patch, it seems.
OK for master?
thanks
Iain
—— commit message
This option allows the user to specify alternate C++ runtime libraries,
for example when a platform uses libc++ as the installed C++ runtime.
We introduce the command line option: -stdlib= which is the user-facing
mechanism to select the C++ runtime to be used when compiling and linking
code. This is the same option spelling as that used by clang to allow the
use of libstdc++.
The availability (and thus function) of the option are a configure-time
choice using the configuration control:
--with-gxx-libcxx-include-dir=
Specification of the path for the libc++ headers, enables the -stdlib=
option (using the path as given), default values are set when the path
is unconfigured.
If --with-gxx-libcxx-include-dir is given together with --with-sysroot=,
then we test to see if the include path starts with the sysroot and, if so,
record the sysroot-relative component as the local path. At runtime, we
prepend the sysroot that is actually active.
At link time, we use the C++ runtime in force and (if that is libc++) also
append the libc++abi ABI library. As for other cases, if a target sets the
name pointer for the ABI library to NULL the G++ driver will omit it from
the link line.
gcc/ChangeLog:
* configure.ac: Add gxx-libcxx-include-dir handled
in the same way as the regular cxx header directory.
* Makefile.in: Regenerated.
* config.in: Likewise.
* configure: Likewise.
* cppdefault.c: Pick up libc++ headers if the option
is enabled.
* incpath.c (add_standard_paths): Allow for multiple
c++ header include path variants.
* doc/invoke.texi: Document the -stdlib= option.
gcc/c-family/ChangeLog:
* c.opt: Add -stdlib= option and enumerations for
libstdc++ and libc++.
gcc/cp/ChangeLog:
* g++spec.c (LIBCXX, LIBCXX_PROFILE, LIBCXX_STATIC): New.
(LIBCXXABI, LIBCXXABI_PROFILE, LIBCXXABI_STATIC): New.
(lang_specific_driver): Allow selection amongst multiple
c++ libraries to be added to the link command.
---
gcc/Makefile.in | 6 +++++
gcc/c-family/c.opt | 14 +++++++++++
gcc/config.in | 6 +++++
gcc/configure | 57 +++++++++++++++++++++++++++++++++++++++++++--
gcc/configure.ac | 44 ++++++++++++++++++++++++++++++++++
gcc/cp/g++spec.c | 53 ++++++++++++++++++++++++++++++++++++++---
gcc/cppdefault.c | 5 ++++
gcc/doc/invoke.texi | 11 +++++++++
gcc/incpath.c | 6 +++--
9 files changed, 195 insertions(+), 7 deletions(-)
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index fe16357db85..5fada472db1 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2269,6 +2269,20 @@ std=iso9899:2018
C ObjC Alias(std=c17)
Conform to the ISO 2017 C standard (published in 2018).
+stdlib=
+Driver C++ ObjC++ Common Report Condition(ENABLE_STDLIB_OPTION)
Var(flag_stdlib_kind) Joined Enum(stdlib_kind) RejectNegative Init(1)
+-stdlib=[libstdc++|libc++] The standard library to be used for C++ headers
+and runtime.
+
+Enum
+Name(stdlib_kind) Type(int)
+
+EnumValue
+Enum(stdlib_kind) String(libstdc++) Value(1)
+
+EnumValue
+Enum(stdlib_kind) String(libc++) Value(2)
+
traditional
Driver
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 73034bb902b..56b32de4c68 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -228,6 +228,48 @@ elif test "${with_sysroot+set}" = set; then
fi
fi
+# Configuration for an alternate set of C++ headers.
+gcc_gxx_libcxx_include_dir=
+# Specify the alternate g++ header file directory
+AC_ARG_WITH(gxx-libcxx-include-dir,
+[AS_HELP_STRING([--with-gxx-libcxx-include-dir=DIR],
+ [specifies directory to find libc++ header files])],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for libc++ include
directory) ;;
+no) ;;
+*) gcc_gxx_libcxx_include_dir=$with_gxx_libcxx_include_dir ;;
+esac])
+
+# If both --with-sysroot and --with-gxx-libcxx-include-dir are passed, we
+# check to see if the latter starts with the former and, upon success,
compute
+# gcc_gxx_libcxx_include_dir as relative to the sysroot.
+gcc_gxx_libcxx_include_dir_add_sysroot=0
+
+if test x${gcc_gxx_libcxx_include_dir} != x; then
+ AC_DEFINE(ENABLE_STDLIB_OPTION, 1,
+ [Define if the -stdlib= option should be enabled.])
+else
+ AC_DEFINE(ENABLE_STDLIB_OPTION, 0)
+fi
+# ??? This logic must match
libstdc++-v3/acinclude.m4:GLIBCXX_EXPORT_INSTALL_INFO.
+if test x${gcc_gxx_libcxx_include_dir} = x; then
+ if test x${enable_version_specific_runtime_libs} = xyes; then
+ gcc_gxx_libcxx_include_dir='${libsubdir}/libc++_include/c++/v1'
+ else
+ libcxx_incdir='libc++_include/c++/$(version)/v1'
+ if test x$host != x$target; then
+ libcxx_incdir="$target_alias/$libcxx_incdir"
+ fi
+
gcc_gxx_libcxx_include_dir="\$(libsubdir)/\$(libsubdir_to_prefix)$libcxx_incdir"
+ fi
+elif test "${with_sysroot+set}" = set; then
+ gcc_gxx_libcxx_without_sysroot=`expr "${gcc_gxx_libcxx_include_dir}" :
"${with_sysroot}"'\(.*\)'`
+ if test "${gcc_gxx_libcxx_without_sysroot}"; then
+ gcc_gxx_libcxx_include_dir="${gcc_gxx_libcxx_without_sysroot}"
+ gcc_gxx_libcxx_include_dir_add_sysroot=1
+ fi
+fi
+
AC_ARG_WITH(cpp_install_dir,
[AC_HELP_STRING([--with-cpp-install-dir=DIR],
[install the user visible C preprocessor in DIR
@@ -6872,6 +6914,8 @@ AC_SUBST(float_h_file)
AC_SUBST(gcc_config_arguments)
AC_SUBST(gcc_gxx_include_dir)
AC_SUBST(gcc_gxx_include_dir_add_sysroot)
+AC_SUBST(gcc_gxx_libcxx_include_dir)
+AC_SUBST(gcc_gxx_libcxx_include_dir_add_sysroot)
AC_SUBST(host_exeext)
AC_SUBST(host_xm_file_list)
AC_SUBST(host_xm_include_list)
diff --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c
index 0ab63bcd211..a2f5c7d3cc7 100644
--- a/gcc/cp/g++spec.c
+++ b/gcc/cp/g++spec.c
@@ -55,6 +55,26 @@ along with GCC; see the file COPYING3. If not see
#define LIBSTDCXX_STATIC NULL
#endif
+#ifndef LIBCXX
+#define LIBCXX "c++"
+#endif
+#ifndef LIBCXX_PROFILE
+#define LIBCXX_PROFILE LIBCXX
+#endif
+#ifndef LIBCXX_STATIC
+#define LIBCXX_STATIC NULL
+#endif
+
+#ifndef LIBCXXABI
+#define LIBCXXABI "c++abi"
+#endif
+#ifndef LIBCXXABI_PROFILE
+#define LIBCXXABI_PROFILE LIBCXXABI
+#endif
+#ifndef LIBCXXABI_STATIC
+#define LIBCXXABI_STATIC NULL
+#endif
+
void
lang_specific_driver (struct cl_decoded_option **in_decoded_options,
unsigned int *in_decoded_options_count,
@@ -72,6 +92,11 @@ lang_specific_driver (struct cl_decoded_option
**in_decoded_options,
2 means libstdc++ is needed and should be linked statically. */
int library = 0;
+ /* Which standard library to link.
+ 1 = libstdc++
+ 2 = libc++. */
+ int which_library = 1;
+
/* The number of arguments being added to what's in argv, other than
libraries. We use this to track the number of times we've inserted
-xc++/-xnone. */
@@ -208,6 +233,10 @@ lang_specific_driver (struct cl_decoded_option
**in_decoded_options,
args[i] |= SKIPOPT;
break;
+ case OPT_stdlib_:
+ which_library = decoded_options[i].value;
+ break;
+
case OPT_SPECIAL_input_file:
{
int len;
@@ -264,6 +293,8 @@ lang_specific_driver (struct cl_decoded_option
**in_decoded_options,
/* Add one for shared_libgcc or extra static library. */
num_args = argc + added + need_math + (library > 0) * 4 + 1;
+ if (which_library > 1 && LIBCXXABI != NULL)
+ num_args += 4;
new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args);
i = 0;
@@ -343,9 +374,25 @@ lang_specific_driver (struct cl_decoded_option
**in_decoded_options,
j++;
}
#endif
- generate_option (OPT_l,
- saw_profile_flag ? LIBSTDCXX_PROFILE : LIBSTDCXX, 1,
- CL_DRIVER, &new_decoded_options[j]);
+ if (which_library == 2)
+ {
+ generate_option (OPT_l,
+ saw_profile_flag ? LIBCXX_PROFILE : LIBCXX, 1,
+ CL_DRIVER, &new_decoded_options[j]);
+ if (LIBCXXABI != NULL)
+ {
+ j++;
+ added_libraries++;
+ generate_option (OPT_l,
+ saw_profile_flag ? LIBCXXABI_PROFILE
+ : LIBCXXABI, 1,
+ CL_DRIVER, &new_decoded_options[j]);
+ }
+ }
+ else
+ generate_option (OPT_l,
+ saw_profile_flag ? LIBSTDCXX_PROFILE : LIBSTDCXX, 1,
+ CL_DRIVER, &new_decoded_options[j]);
added_libraries++;
j++;
/* Add target-dependent static library, if necessary. */
diff --git a/gcc/cppdefault.c b/gcc/cppdefault.c
index af38cc494ea..eb6f94162cd 100644
--- a/gcc/cppdefault.c
+++ b/gcc/cppdefault.c
@@ -55,6 +55,11 @@ const struct default_include cpp_include_defaults[]
{ GPLUSPLUS_BACKWARD_INCLUDE_DIR, "G++", 1, 1,
GPLUSPLUS_INCLUDE_DIR_ADD_SYSROOT, 0 },
#endif
+#ifdef GPLUSPLUS_LIBCXX_INCLUDE_DIR
+ /* Pick up libc++ include files, if we have -stdlib=libc++. */
+ { GPLUSPLUS_LIBCXX_INCLUDE_DIR, "G++", 2, 1,
+ GPLUSPLUS_LIBCXX_INCLUDE_DIR_ADD_SYSROOT, 0 },
+#endif
#ifdef GCC_INCLUDE_DIR
/* This is the dir for gcc's private headers. */
{ GCC_INCLUDE_DIR, "GCC", 0, 0, 0, 0 },
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 8d0d2136831..a14a25c330f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -233,6 +233,7 @@ in the following sections.
-fvisibility-inlines-hidden @gol
-fvisibility-ms-compat @gol
-fext-numeric-literals @gol
+-stdlib=@var{libstdc++,libc++} @gol
-Wabi-tag -Wcatch-value -Wcatch-value=@var{n} @gol
-Wno-class-conversion -Wclass-memaccess @gol
-Wcomma-subscript -Wconditionally-supported @gol
@@ -3285,6 +3286,16 @@ for ISO C++11 onwards (@option{-std=c++11}, ...).
Do not search for header files in the standard directories specific to
C++, but do still search the other standard directories. (This option
is used when building the C++ library.)
+
+@item -stdlib=@var{libstdc++,libc++}
+@opindex stdlib
+When G++ is configured to support this option, it allows specification of
+alternate C++ runtime libraries. Two options are available: @var{libstdc++}
+(the default, native C++ runtime for G++) and @var{libc++} which is the
+C++ runtime installed on some operating systems (e.g. Darwin versions from
+Darwin11 onwards). The option switches G++ to use the headers from the
+specified library and to emit @code{-lstdc++} or @code{-lc++} respectively,
+when a C++ runtime is required for linking.
@end table
In addition, these warning options have meanings only for C++ programs:
diff --git a/gcc/incpath.c b/gcc/incpath.c
index 8437939bf1e..14593a1f4c3 100644
--- a/gcc/incpath.c
+++ b/gcc/incpath.c
@@ -137,7 +137,8 @@ add_standard_paths (const char *sysroot, const char
*iprefix,
IPREFIX and search them first. */
for (p = cpp_include_defaults; p->fname; p++)
{
- if (!p->cplusplus || cxx_stdinc)
+ if (p->cplusplus == 0
+ || (cxx_stdinc && (p->cplusplus == flag_stdlib_kind)))
{
/* Should we be translating sysrooted dirs too? Assume
that iprefix and sysroot are mutually exclusive, for
@@ -168,7 +169,8 @@ add_standard_paths (const char *sysroot, const char
*iprefix,
for (p = cpp_include_defaults; p->fname; p++)
{
- if (!p->cplusplus || cxx_stdinc)
+ if (p->cplusplus == 0
+ || (cxx_stdinc && (p->cplusplus == flag_stdlib_kind)))
{
char *str;
--
2.24.1