Hi,

A while back I filed a feature request for a build option to use the libc++ 
runtime, with a mostly PoC patch attached.
Such a feature would increase GCC's usability on platforms like Apple's OS for 
Mac, but possibly on FreeBSD too. (And if it's technically possible to use 
Microsoft's runtime that could become another option down the road.)

I've since had the time to test this feature more thoroughly, and have begun 
bringing it into a form where it might be considerable for inclusion. I'm 
attaching a first draft, including only the changes to the driver but none of 
the required changes to the build system yet. I'm doing this in my local 7.2.0 
build, so the patch is against that source, for now. I'm hoping the modified 
files evolve little enough that the patch also applies to the current 
development branch, and that it's thus useful enough to get some constructive 
feedback telling me I'm on the right path here.

I'd also really like to rally some "coworkers" on this, esp. if they're 
familiar with the (rather daunting) configure-and-build system and the 
procedure of "getting a new feature in"!

About the attached patch and approach:

I've copied the clang option syntax for selecting the C++ runtime: 
`-stdlib=libstdc++` or `-stdlib=libc++`, this is to maximise compiler 
compatibility. I think the compiler should be configured to use the platform 
runtime by default, i.e. libc++ on Mac OS X 10.9 and later. Currently this is 
hardwired with #ifdefs but that should probably become a configure setting.

The C++ runtime headerfiles for libc++ will have to found in the appropriate 
location, which will need to be configurable as on Mac they typically live 
inside the Xcode app bundle which is freely relocatable.

There is a catch with using libc++: older versions don't contain the sized 
C++14 new/delete operators (those were provided implicitly by clang). The 
operators are there in the libc++ from LLVM 3.9 and newer, but it appears that 
means that the system libc++ only contains them in Mac OS 10.12 and newer. It 
is of course possible to install a newer version, link to it and run it via 
DYLD_INSERT_LIBRARIES . The other option that appears to work is to use 
libsupc++ as the provider for those operators by including it as the last link 
library, in line with the procedure on llvm.org how to use libc++ on Linux. My 
patch currently adds libsupc++ on 10.11 and earlier; this should also be done 
more properly (though I presume libsupc++ will only be used if it provides 
symbols not already provided by the libraries linked before it).

Thanks,
René Bertin
diff --git gcc/incpath.c
--- gcc/orig.incpath.c	2017-02-20 12:38:16.000000000 +0100
+++ gcc/incpath.c	2017-05-11 19:02:37.000000000 +0200
@@ -129,6 +129,10 @@
   int relocated = cpp_relocated ();
   size_t len;
 
+  if (cxx_stdinc == 2)
+    {
+      add_path (xstrdup ("@LLVMHEADERPATH@"), SYSTEM, true, false);
+    }
   if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0)
     {
       /* Look for directories that start with the standard prefix.
@@ -136,7 +140,7 @@
 	 IPREFIX and search them first.  */
       for (p = cpp_include_defaults; p->fname; p++)
 	{
-	  if (!p->cplusplus || cxx_stdinc)
+	  if (!p->cplusplus || cxx_stdinc == 1)
 	    {
 	      /* Should we be translating sysrooted dirs too?  Assume
 		 that iprefix and sysroot are mutually exclusive, for
@@ -167,7 +171,7 @@
 
   for (p = cpp_include_defaults; p->fname; p++)
     {
-      if (!p->cplusplus || cxx_stdinc)
+      if (!p->cplusplus || cxx_stdinc == 1)
 	{
 	  char *str;
 
@@ -474,6 +478,9 @@
   /* CPATH and language-dependent environment variables may add to the
      include chain.  */
   add_env_var_paths ("CPATH", BRACKET);
+  /* cxx_stdinc is no longer a bool but also indicates which C++ headers to include */
+  if (stdinc && cxx_stdinc == 2)
+    add_env_var_paths ("LIBCPP_INCLUDE_PATH", SYSTEM);
   add_env_var_paths (lang_env_vars[idx], SYSTEM);
 
   target_c_incpath.extra_pre_includes (sysroot, iprefix, stdinc);
diff --git gcc/cp/g++spec.c
--- gcc/cp/orig.g++spec.c	2017-09-07 22:30:27.000000000 +0200
+++ gcc/cp/g++spec.c	2017-10-31 20:44:58.000000000 +0100
@@ -23,6 +23,10 @@
 #include "tm.h"
 #include "opts.h"
 
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+#endif
+
 /* This bit is set if we saw a `-xfoo' language specification.  */
 #define LANGSPEC	(1<<1)
 /* This bit is set if they did `-lm' or `-lmath'.  */
@@ -48,9 +52,18 @@
 #ifndef LIBSTDCXX
 #define LIBSTDCXX "stdc++"
 #endif
+/* libc++ support: */
+#ifndef LIBCXX
+#define LIBCXX "c++"
+#define LIBCXXABI "c++abi"
+/* using libsupc++ is a hack, probably to be dropped on systems that have a new enough libc++
+   which has `operator delete(void*, unsigned long)` (introduced in libcxx rev. 229281) */
+#define LIBSUPCXX "supc++"
+#endif
 #ifndef LIBSTDCXX_PROFILE
 #define LIBSTDCXX_PROFILE LIBSTDCXX
 #endif
+
 #ifndef LIBSTDCXX_STATIC
 #define LIBSTDCXX_STATIC NULL
 #endif
@@ -65,7 +78,14 @@
   /* If nonzero, the user gave us the `-p' or `-pg' flag.  */
   int saw_profile_flag = 0;
 
-  /* What do with libstdc++:
+#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+	/* TODO the configure script should determine whether the targetted host uses libc++ */
+  int use_libcxx = 1;
+#else
+  int use_libcxx = 0;
+#endif
+
+  /* What do with libstdc++ (or libc++):
      -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.
@@ -141,6 +161,14 @@
 	  library = -1;
 	  break;
 
+	case OPT_stdlib_libc__:
+	  /* use libc++ */
+	  use_libcxx = 1;
+	  break;
+	case OPT_stdlib_libstdc__:
+	  use_libcxx = 0;
+	  break;
+
 	case OPT_l:
 	  if (strcmp (arg, MATH_LIBRARY) == 0)
 	    {
@@ -331,7 +359,7 @@
       j++;
     }
 
-  /* Add `-lstdc++' if we haven't already done so.  */
+  /* Add `-lstdc++' or -lc++ if we haven't already done so.  */
   if (library > 0)
     {
 #ifdef HAVE_LD_STATIC_DYNAMIC
@@ -342,19 +370,44 @@
 	  j++;
 	}
 #endif
-      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.  */
-      if ((static_link || library > 1) && LIBSTDCXX_STATIC != NULL)
-	{
-	  generate_option (OPT_l, LIBSTDCXX_STATIC, 1,
-			   CL_DRIVER, &new_decoded_options[j]);
-	  added_libraries++;
-	  j++;
-	}
+		if (use_libcxx)
+			{
+				generate_option (OPT_l, LIBCXX, 1,
+					  CL_DRIVER, &new_decoded_options[j]);
+				added_libraries++;
+				j++;
+				/* add -lc++abi */
+				generate_option (OPT_l, LIBCXXABI, 1,
+					  CL_DRIVER, &new_decoded_options[j]);
+				added_libraries++;
+				j++;
+#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (!defined(MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
+				/* the system libc++ doesn't have the C++14 sized new/delete operators;
+					 get them from libsup++. This is a bit of a hack but libc++ supports
+					 it.
+					 TODO: use a proper configure-time check to determine if this is required. */
+				generate_option (OPT_l, LIBSUPCXX, 1,
+					  CL_DRIVER, &new_decoded_options[j]);
+				added_libraries++;
+				j++;
+#endif
+			}
+		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.  */
+				 if ((static_link || library > 1) && (LIBSTDCXX_STATIC != NULL))
+				{
+				  generate_option (OPT_l, LIBSTDCXX_STATIC, 1,
+						   CL_DRIVER, &new_decoded_options[j]);
+				  added_libraries++;
+				  j++;
+				}
+			}
 #ifdef HAVE_LD_STATIC_DYNAMIC
       if (library > 1 && !static_link)
 	{
diff --git gcc/c-family/c.opt
--- gcc/c-family/orig.c.opt	2017-03-31 16:24:27.000000000 +0200
+++ gcc/c-family/c.opt	2017-10-31 11:31:59.000000000 +0100
@@ -1992,6 +1992,15 @@
 C ObjC Alias(std=c11)
 Conform to the ISO 2011 C standard.
 
+stdlib=libc++
+C++ ObjC++
+Specify the C++ standard library to use: LLVM libc++
+(default on Mac OS X 10.9 and up)
+
+stdlib=libstdc++
+C++ ObjC++
+Specify the C++ standard library to use: GNU libstdc++
+
 traditional
 Driver
 
diff --git gcc/c-family/c-opts.c
--- gcc/c-family/orig.c-opts.c	2017-01-05 15:17:07.000000000 +0100
+++ gcc/c-family/c-opts.c	2017-10-31 20:45:16.000000000 +0100
@@ -41,6 +41,10 @@
 #include "mkdeps.h"
 #include "dumpfile.h"
 
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+#endif
+
 #ifndef DOLLARS_IN_IDENTIFIERS
 # define DOLLARS_IN_IDENTIFIERS true
 #endif
@@ -87,9 +91,17 @@
 /* Zero disables all standard directories for headers.  */
 static bool std_inc = true;
 
-/* Zero disables the C++-specific standard directories for headers.  */
+/* Zero disables the C++-specific standard directories for headers */
 static bool std_cxx_inc = true;
 
+/* 1 enables the libstdc++ specific standard header directories;
+   2 enables the libc++ specific standard header directories. */
+#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+static int std_cxx_header_type = 2;
+#else
+static int std_cxx_header_type = 1;
+#endif
+
 /* If the quote chain has been split by -I-.  */
 static bool quote_chain_split;
 
@@ -597,7 +609,21 @@
       break;
 
     case OPT_nostdinc__:
-      std_cxx_inc = false;
+      std_cxx_inc = 0;
+      break;
+
+    /* OPT_stdlib_libc__ & OPT_stdlib_libstdc__ are also handled in g++spec.c */
+    case OPT_stdlib_libc__:
+      /* use libc++ */
+      warning (OPT_stdlib_libc__,
+        "using the LLVM/libc++ standard C++ headers");
+      std_cxx_header_type = 2;
+      break;
+
+    case OPT_stdlib_libstdc__:
+      warning (OPT_stdlib_libstdc__,
+        "using the GNU/libstdc++ standard C++ headers");
+      std_cxx_header_type = 1;
       break;
 
     case OPT_o:
@@ -762,7 +788,7 @@
   sanitize_cpp_opts ();
 
   register_include_chains (parse_in, sysroot, iprefix, imultilib,
-			   std_inc, std_cxx_inc && c_dialect_cxx (), verbose);
+			   std_inc, std_cxx_inc && c_dialect_cxx () ? std_cxx_header_type : 0, verbose);
 
 #ifdef C_COMMON_OVERRIDE_OPTIONS
   /* Some machines may reject certain combinations of C

Reply via email to