Hi Jason, Jason Merrill <ja...@redhat.com> wrote:
> On 11/11/20 3:58 PM, Iain Sandoe wrote: >> 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. >> >> + /* Which standard library to link. >> + 1 = libstdc++ >> + 2 = libc++. */ >> + int which_library = 1; > > Even if this variable is an int, let's introduce an enum for comparing it to > specific values. done - it is also noted that it must track the enum in the opt file. >> @@ -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; > > Why does libc++ need more args than libstdc++? Please add a comment. done (JFTR, it’s because libc++ doesn’t include the abi library for most platforms, so that also has to be appended to the link line). >> +#ifdef GPLUSPLUS_LIBCXX_INCLUDE_DIR >> + /* Pick up libc++ include files, if we have -stdlib=libc++. */ >> + { GPLUSPLUS_LIBCXX_INCLUDE_DIR, "G++", 2, 1, > > If you're going to give cplusplus a non-boolean value, the comment in > cppdefault.h needs to reflect that. done. (re-)tested on x86_64-darwin{11,16,17,19, 20} with the installed libc++ and x86_64-linux-gnu with an LLVM-9 build. Bootstrapped and smoke-tested for libc++ (regular testing for libstdc++). OK for master now? thanks Iain ==== revised patch This option allows the user to specifiy 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. * cppdefault.h (struct default_include): Amend comments to reflect the extended use of the cplusplus field. * 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. (enum stdcxxlib_kind): New. (lang_specific_driver): Allow selection amongst multiple c++ runtime libraries. --- 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 | 74 ++++++++++++++++++++++++++++++++++++++++----- gcc/cppdefault.c | 5 +++ gcc/cppdefault.h | 7 ++++- gcc/doc/invoke.texi | 10 ++++++ gcc/incpath.c | 6 ++-- 10 files changed, 216 insertions(+), 13 deletions(-) diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 178e4eaa513..6847022f108 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -679,6 +679,9 @@ build_tooldir = $(exec_prefix)/$(target_noncanonical) # Directory in which the compiler finds target-independent g++ includes. gcc_gxx_include_dir = @gcc_gxx_include_dir@ gcc_gxx_include_dir_add_sysroot = @gcc_gxx_include_dir_add_sysroot@ +# Directory in which the compiler finds libc++ includes. +gcc_gxx_libcxx_include_dir = @gcc_gxx_libcxx_include_dir@ +gcc_gxx_libcxx_include_dir_add_sysroot = @gcc_gxx_libcxx_include_dir_add_sysroot@ # Directory to search for site-specific includes. local_includedir = $(local_prefix)/include includedir = $(prefix)/include @@ -1185,6 +1188,7 @@ FLAGS_TO_PASS = \ "prefix=$(prefix)" \ "local_prefix=$(local_prefix)" \ "gxx_include_dir=$(gcc_gxx_include_dir)" \ + "gxx_libcxx_include_dir=$(gcc_gxx_libcxx_include_dir)" \ "build_tooldir=$(build_tooldir)" \ "gcc_tooldir=$(gcc_tooldir)" \ "bindir=$(bindir)" \ @@ -3004,6 +3008,8 @@ PREPROCESSOR_DEFINES = \ -DGPLUSPLUS_INCLUDE_DIR_ADD_SYSROOT=$(gcc_gxx_include_dir_add_sysroot) \ -DGPLUSPLUS_TOOL_INCLUDE_DIR=\"$(gcc_gxx_include_dir)/$(target_noncanonical)\" \ -DGPLUSPLUS_BACKWARD_INCLUDE_DIR=\"$(gcc_gxx_include_dir)/backward\" \ + -DGPLUSPLUS_LIBCXX_INCLUDE_DIR=\"$(gcc_gxx_libcxx_include_dir)\" \ + -DGPLUSPLUS_LIBCXX_INCLUDE_DIR_ADD_SYSROOT=$(gcc_gxx_libcxx_include_dir_add_sysroot) \ -DLOCAL_INCLUDE_DIR=\"$(local_includedir)\" \ -DCROSS_INCLUDE_DIR=\"$(CROSS_SYSTEM_HEADER_DIR)\" \ -DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\" \ diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 21d8cd03709..e0c322f61ae 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -2356,6 +2356,20 @@ std=iso9899:2018 C ObjC Alias(std=c17) Conform to the ISO 2017 C standard (published in 2018). +stdlib= +Driver C++ ObjC++ Common 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/config.in b/gcc/config.in index 216505abd2c..10a13cde586 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -240,6 +240,12 @@ standards-compatible mode on s390 targets. */ #undef ENABLE_S390_EXCESS_FLOAT_PRECISION +/* Define if the -stdlib= option should be enabled. */ +#ifndef USED_FOR_TARGET +#undef ENABLE_STDLIB_OPTION +#endif + + /* Define if you want all operations on trees (the basic data structure of the front ends) to be checked for dynamic type safety at runtime. This is moderately expensive. */ diff --git a/gcc/configure b/gcc/configure index fbe92089640..ee9760354b6 100755 --- a/gcc/configure +++ b/gcc/configure @@ -675,6 +675,8 @@ host_xm_defines host_xm_include_list host_xm_file_list host_exeext +gcc_gxx_libcxx_include_dir_add_sysroot +gcc_gxx_libcxx_include_dir gcc_gxx_include_dir_add_sysroot gcc_gxx_include_dir gcc_config_arguments @@ -937,6 +939,7 @@ with_native_system_header_dir with_build_sysroot with_sysroot with_gxx_include_dir +with_gxx_libcxx_include_dir with_cpp_install_dir enable_generated_files_in_srcdir with_gnu_ld @@ -1801,6 +1804,8 @@ Optional Packages: --with-sysroot[=DIR] search for usr/lib, usr/include, et al, within DIR --with-gxx-include-dir=DIR specifies directory to put g++ header files + --with-gxx-libcxx-include-dir=DIR + specifies directory to find libc++ header files --with-cpp-install-dir=DIR install the user visible C preprocessor in DIR (relative to PREFIX) as well as PREFIX/bin @@ -3731,6 +3736,52 @@ 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 + +# Check whether --with-gxx-libcxx-include-dir was given. +if test "${with_gxx_libcxx_include_dir+set}" = set; then : + withval=$with_gxx_libcxx_include_dir; case "${withval}" in +yes) as_fn_error $? "bad value ${withval} given for libc++ include directory" "$LINENO" 5 ;; +no) ;; +*) gcc_gxx_libcxx_include_dir=$with_gxx_libcxx_include_dir ;; +esac +fi + + +# 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 + +$as_echo "#define ENABLE_STDLIB_OPTION 1" >>confdefs.h + +else + $as_echo "#define ENABLE_STDLIB_OPTION 0" >>confdefs.h + +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 + # Check whether --with-cpp_install_dir was given. if test "${with_cpp_install_dir+set}" = set; then : @@ -19186,7 +19237,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 19189 "configure" +#line 19240 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -19292,7 +19343,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 19295 "configure" +#line 19346 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -31175,6 +31226,8 @@ fi + + diff --git a/gcc/configure.ac b/gcc/configure.ac index 89b9981e872..6fcf154d987 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 @@ -7096,6 +7138,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 0f17148ccbd..a8254cd34c9 100644 --- a/gcc/cp/g++spec.c +++ b/gcc/cp/g++spec.c @@ -49,6 +49,34 @@ 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 + +/* The values used here must match those of the stdlib_kind enumeration + in c.opt. */ +enum stdcxxlib_kind +{ + USE_LIBSTDCXX = 1, + USE_LIBCXX = 2 +}; + void lang_specific_driver (struct cl_decoded_option **in_decoded_options, unsigned int *in_decoded_options_count, @@ -59,13 +87,16 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, /* If nonzero, the user gave us the `-p' or `-pg' flag. */ int saw_profile_flag = 0; - /* What do with libstdc++: - -1 means we should not link in libstdc++ - 0 means we should link in libstdc++ if it is needed - 1 means libstdc++ is needed and should be linked in. - 2 means libstdc++ is needed and should be linked statically. */ + /* What action to take for the c++ runtime library: + -1 means we should not link it in. + 0 means we should link it if it is needed. + 1 means it is needed and should be linked in. + 2 means it is needed but should be linked statically. */ int library = 0; + /* Which c++ runtime library to link. */ + stdcxxlib_kind which_library = USE_LIBSTDCXX; + /* 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. */ @@ -194,6 +225,10 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, args[i] |= SKIPOPT; break; + case OPT_stdlib_: + which_library = (stdcxxlib_kind) decoded_options[i].value; + break; + case OPT_SPECIAL_input_file: { int len; @@ -250,6 +285,13 @@ 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; + /* For libc++, on most platforms, the ABI library (usually called libc++abi) + is provided as a separate DSO, which we must also append. + However, a platform might have the ability to forward the ABI library + from libc++, or combine it in some other way; in that case, LIBCXXABI + should be set to NULL to signal that it need not be appended. */ + if (which_library == USE_LIBCXX && LIBCXXABI != NULL) + num_args += 4; new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args); i = 0; @@ -323,9 +365,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 == USE_LIBCXX) + { + 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/cppdefault.h b/gcc/cppdefault.h index a681264f75e..35cf24ec29e 100644 --- a/gcc/cppdefault.h +++ b/gcc/cppdefault.h @@ -36,7 +36,12 @@ struct default_include const char *const fname; /* The name of the directory. */ const char *const component; /* The component containing the directory (see update_path in prefix.c) */ - const char cplusplus; /* Only look here if we're compiling C++. */ + const char cplusplus; /* When this is non-zero, we should only + consider this if we're compiling C++. + When the -stdlib option is configured, this + may take values greater than 1 to indicate + which C++ standard library should be + used. */ const char cxx_aware; /* Includes in this directory don't need to be wrapped in extern "C" when compiling C++. */ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d7d354fc4de..3b8b003c51d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -242,6 +242,7 @@ in the following sections. -fext-numeric-literals @gol -flang-info-include-translate@r{[}=@var{name}@r{]} @gol -flang-info-include-translate-not @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 @@ -3368,6 +3369,15 @@ is used when building the C++ library.) @opindex flang-info-include-translate-not Diagnose include translation events. +@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