Dependency-generation overhaul (back end only)

Zack Weinberg zack@wolery.cumb.org
Thu Mar 2 18:06:00 GMT 2000


This patch is a complete revamp of the 'back end' of cpp's dependency-
generation code.  It has been isolated from the rest of the library,
and made a good deal more flexible.  This will allow Java to use it,
and will enable the additional -M switches that someone (Tom?) was
asking for awhile back.

I haven't tested this at all yet, but it compiles and it doesn't
segfault in light use.

Note I'm not enamored of the file names, and am open to suggestions
for better choices.

zw

	* mkdeps.c: New file.
	* mkdeps.h: New file.
	* Makefile.in (LIBCPP_OBJS): Add mkdeps.o.
	(cpplib.o, cppinit.o): Depend on mkdeps.h.
	(mkdeps.o): New target.
	* po/POTFILES.in: Add mkdeps.c and mkdeps.h.

	* cppfiles.c (deps_output): Delete function.
	* cppinit.c: Include mkdeps.h.
	(cpp_cleanup): Use deps_free to free deps buffer.
	Uncomment line freeing imp->name.
	(initialize_dependency_output): Use deps_init, deps_add_target,
	and deps_add_dep.
	(cpp_finish): Write out dependencies with deps_write.
	(cpp_handle_option): Don't use CPP_PEDANTIC as an lvalue.
	* cpplib.c: Include mkdeps.h.
	(do_include): Use deps_add_dep.
	* cpplib.h (struct cpp_reader): Add 'struct deps *deps'
	member.  Delete deps_buffer, deps_allocated_size, deps_size,
	and deps_column members.
	(SET_CPP_PEDANTIC): Delete macro.	
	
===================================================================
Index: po/POTFILES.in
--- po/POTFILES.in	2000/02/06 06:57:21	1.15
+++ po/POTFILES.in	2000/03/03 02:01:39
@@ -707,6 +707,8 @@ loop.h
 machmode.h
 mbchar.c
 mbchar.h
+mkdeps.c
+mkdeps.h
 #mips-tdump.c is not yet internationalized
 #mips-tfile.c is not yet internationalized
 objc/objc-act.c
===================================================================
Index: Makefile.in
--- Makefile.in	2000/02/27 12:37:56	1.392
+++ Makefile.in	2000/03/03 01:57:37
@@ -2021,7 +2021,8 @@ cccp.o: cccp.c $(CONFIG_H) intl.h pcp.h 
 	  -c `echo $(srcdir)/cccp.c | sed 's,^\./,,'`
 
 LIBCPP_OBJS =	cpplib.o cpphash.o cpperror.o cppexp.o cppfiles.o \
-		cppinit.o cppulp.o prefix.o version.o mbchar.o @extra_cpp_objs@
+		cppinit.o cppulp.o mkdeps.o \
+		prefix.o version.o mbchar.o @extra_cpp_objs@
 
 # All the other archives built/used by this makefile are for targets.  This
 # one is strictly for the host.
@@ -2038,17 +2039,19 @@ cppmain$(exeext): cppmain.o intl.o libcp
 cppmain.o: cppmain.c $(CONFIG_H) cpplib.h intl.h system.h
 
 cppulp.o:  cppulp.c  $(CONFIG_H) system.h output.h
-cpplib.o:  cpplib.c  $(CONFIG_H) cpplib.h intl.h system.h cpphash.h
+cpplib.o:  cpplib.c  $(CONFIG_H) cpplib.h intl.h system.h cpphash.h mkdeps.h
 cpphash.o: cpphash.c $(CONFIG_H) cpplib.h intl.h system.h cpphash.h version.h
 cpperror.o: cpperror.c $(CONFIG_H) cpplib.h intl.h system.h
 cppexp.o:   cppexp.c   $(CONFIG_H) cpplib.h intl.h system.h
 cppfiles.o: cppfiles.c $(CONFIG_H) cpplib.h intl.h system.h
 
 cppinit.o:  cppinit.c $(CONFIG_H) cpplib.h intl.h system.h \
-		cpphash.h prefix.h output.h Makefile version.h
+		cpphash.h prefix.h output.h Makefile version.h mkdeps.h
 	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 	  $(PREPROCESSOR_DEFINES) \
 	  -c `echo $(srcdir)/cppinit.c | sed 's,^\./,,'`
+
+mkdeps.o: mkdeps.c $(CONFIG_H) system.h mkdeps.h
 
 # Note for the stamp targets, we run the program `true' instead of
 # having an empty command (nothing following the semicolon).
===================================================================
Index: mkdeps.c
--- mkdeps.c	Tue May  5 13:32:27 1998
+++ mkdeps.c	Thu Mar  2 17:57:38 2000
@@ -0,0 +1,228 @@
+/* Dependency generator for Makefile fragments.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Zack Weinberg, Mar 2000
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them.   Help stamp out software-hoarding!  */
+
+#include "config.h"
+#include "system.h"
+#include "mkdeps.h"
+
+static const char *munge	PARAMS ((const char *));
+
+/* Given a filename, quote characters in that filename which are
+   significant to Make.  Note that it's not possible to quote all such
+   characters - e.g. \n, %, *, ?, [, \ (in some contexts), and ~ are
+   not properly handled.  It isn't possible to get this right in any
+   current version of Make.  (??? Still true?  Old comment referred to
+   3.76.1.)  */
+   
+static const char *
+munge (filename)
+     const char *filename;
+{
+  int len;
+  const char *p, *q;
+  char *dst, *buffer;
+
+  for (p = filename, len = 0; *p; p++, len++)
+    {
+      switch (*p)
+	{
+	case ' ':
+	case '\t':
+	  /* GNU make uses a weird quoting scheme for white space.
+	     A space or tab preceded by 2N+1 backslashes represents
+	     N backslashes followed by space; a space or tab
+	     preceded by 2N backslashes represents N backslashes at
+	     the end of a file name; and backslashes in other
+	     contexts should not be doubled.  */
+	  for (q = p - 1; q < filename && q[-1] == '\\';  q--)
+	    len++;
+	  len++;
+	  break;
+
+	case '$':
+	  /* '$' is quoted by doubling it. This can mishandle things
+	     like "$(" but there's no easy fix.  */
+	  len++;
+	  break;
+	}
+    }
+
+  /* Now we know how big to make the buffer.  */
+  buffer = malloc (len + 1);
+
+  for (p = filename, dst = buffer; *p; p++, dst++)
+    {
+      switch (*p)
+	{
+	case ' ':
+	case '\t':
+	  for (q = p - 1; filename < q && q[-1] == '\\';  q--)
+	    *dst++ = '\\';
+	  *dst++ = '\\';
+	  break;
+
+	case '$':
+	  *dst++ = '$';
+	  break;
+
+	default:
+	  /* nothing */;
+	}
+      *dst = *p;
+    }
+
+  *dst = '\0';
+  return buffer;
+}
+
+/* Public routines.  */
+
+struct deps *
+deps_init (void)
+{
+  struct deps *d = (struct deps *) xmalloc (sizeof (struct deps));
+
+  /* Allocate space for the vectors now.  */
+
+  d->targetv = xmalloc (2 * sizeof (const char *));
+  d->depv = xmalloc (8 * sizeof (const char *));
+
+  d->ntargets = 0;
+  d->targets_size = 2;
+  d->ndeps = 0;
+  d->deps_size = 8;
+
+  return d;
+}
+
+void
+deps_free (d)
+     struct deps *d;
+{
+  unsigned int i;
+  for (i = 0; i < d->ntargets; i++)
+    free ((PTR) d->targetv[i]);
+  for (i = 0; i < d->ndeps; i++)
+    free ((PTR) d->depv[i]);
+
+  free (d->targetv);
+  free (d->depv);
+  free (d);
+}
+
+void
+deps_add_target (d, t)
+     struct deps *d;
+     const char *t;
+{
+  t = munge (t);  /* Also makes permanent copy.  */
+
+  if (d->ntargets == d->targets_size)
+    {
+      d->targets_size *= 2;
+      d->targetv = xrealloc (d->targetv,
+			     d->targets_size * sizeof (const char *));
+    }
+  d->targetv[d->ntargets++] = t;
+}
+
+void
+deps_add_dep (d, t)
+     struct deps *d;
+     const char *t;
+{
+  t = munge (t);  /* Also makes permanent copy.  */
+
+  if (d->ndeps == d->deps_size)
+    {
+      d->deps_size *= 2;
+      d->depv = xrealloc (d->depv, d->deps_size * sizeof (const char *));
+    }
+  d->depv[d->ndeps++] = t;
+}
+
+void
+deps_write (d, fp, colmax)
+     const struct deps *d;
+     FILE *fp;
+     unsigned int colmax;
+{
+  unsigned int size, i, column;
+
+  column = 0;
+  if (colmax && colmax < 34)
+    colmax = 34;
+
+  for (i = 0; i < d->ntargets; i++)
+    {
+      size = strlen (d->targetv[i]);
+      column += size;
+      if (colmax && column > colmax)
+	{
+	  fputs (" \\\n ", fp);
+	  column = 1 + size;
+	}
+      if (i)
+	{
+	  putc (' ', fp);
+	  column++;
+	}
+      fputs (d->targetv[i], fp);
+    }
+
+  putc (':', fp);
+  putc (' ', fp);
+  column += 2;
+
+  for (i = 0; i < d->ndeps; i++)
+    {
+      size = strlen (d->depv[i]);
+      column += size;
+      if (colmax && column > colmax)
+	{
+	  fputs (" \\\n ", fp);
+	  column = 1 + size;
+	}
+      if (i)
+	{
+	  putc (' ', fp);
+	  column++;
+	}
+      fputs (d->depv[i], fp);
+    }
+  putc ('\n', fp);
+}
+  
+void
+deps_dummy_targets (d, fp)
+     const struct deps *d;
+     FILE *fp;
+{
+  int i;
+
+  for (i = 1; i < d->ndeps; i++)
+    {
+      fputs (d->depv[i], fp);
+      putc (':', fp);
+      putc ('\n', fp);
+    }
+}
===================================================================
Index: mkdeps.h
--- mkdeps.h	Tue May  5 13:32:27 1998
+++ mkdeps.h	Thu Mar  2 17:57:38 2000
@@ -0,0 +1,66 @@
+/* Dependency generator for Makefile fragments.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Zack Weinberg, Mar 2000
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them.   Help stamp out software-hoarding!  */
+
+#ifndef __GCC_MKDEPS__
+#define __GCC_MKDEPS__
+
+/* This is the data structure used by all the functions in mkdeps.c.
+   It's quite straightforward, but should be treated as opaque.  */
+
+struct deps
+{
+  const char **targetv;
+  unsigned int ntargets;	/* number of slots actually occupied */
+  unsigned int targets_size;	/* amt of allocated space - in words */
+
+  const char **depv;
+  unsigned int ndeps;
+  unsigned int deps_size;
+};
+
+/* Create a deps buffer.  */
+extern struct deps *deps_init	PARAMS ((void));
+
+/* Destroy a deps buffer.  */
+extern void deps_free		PARAMS ((struct deps *));
+
+/* Add a target (appears on left side of the colon) to the deps list. */
+extern void deps_add_target	PARAMS ((struct deps *, const char *));
+
+/* Add a dependency (appears on the right side of the colon) to the
+   deps list.  Dependencies will be printed in the order that they
+   were entered with this function.  By convention, the first
+   dependency entered should be the primary source file.  */
+extern void deps_add_dep	PARAMS ((struct deps *, const char *));
+
+/* Write out a deps buffer to a specified file.  The third argument
+   is the number of columns to word-wrap at (0 means don't wrap).  */
+extern void deps_write		PARAMS ((const struct deps *, FILE *,
+					 unsigned int));
+
+/* For each dependency *except the first*, emit a dummy rule for that
+   file, causing it to depend on nothing.  This is used to work around
+   the intermediate-file deletion misfeature in Make, in some
+   automatic dependency schemes.  */
+extern void deps_dummy_targets	PARAMS ((const struct deps *, FILE *));
+
+#endif
===================================================================
Index: cppfiles.c
--- cppfiles.c	2000/03/02 20:14:32	1.39
+++ cppfiles.c	2000/03/03 01:57:37
@@ -29,10 +29,10 @@ Foundation, 59 Temple Place - Suite 330,
 #include "cpplib.h"
 #include "intl.h"
 
-/* The entry points to this file are: find_include_file, finclude,
-   include_hash, append_include_chain, deps_output, and file_cleanup.
-   file_cleanup is only called through CPP_BUFFER(pfile)->cleanup,
-   so it's static anyway. */
+/* The entry points to this file are: find_include_file,
+   cpp_read_file, finclude, include_hash, append_include_chain, and
+   file_cleanup.  file_cleanup is only called through
+   CPP_BUFFER(pfile)->cleanup, so it's static anyway. */
 
 static struct include_hash *redundant_include_p
 					PARAMS ((cpp_reader *,
@@ -1228,58 +1228,6 @@ initialize_input_buffer (pfile, fd, st)
   tmp = (U_CHAR *) xmalloc (pipe_buf + 2 + 2);
   pfile->input_buffer = tmp;
   pfile->input_buffer_len = pipe_buf;
-}
-
-/* Add output to `deps_buffer' for the -M switch.
-   STRING points to the text to be output.
-   SPACER is ':' for targets, ' ' for dependencies, zero for text
-   to be inserted literally.  */
-
-void
-deps_output (pfile, string, spacer)
-     cpp_reader *pfile;
-     const char *string;
-     int spacer;
-{
-  int size;
-  int cr = 0;
-
-  if (!*string)
-    return;
-
-  size = strlen (string);
-
-#ifndef MAX_OUTPUT_COLUMNS
-#define MAX_OUTPUT_COLUMNS 72
-#endif
-  if (pfile->deps_column > 0
-      && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS)
-    {
-      cr = 5;
-      pfile->deps_column = 0;
-    }
-
-  if (pfile->deps_size + size + cr + 8 > pfile->deps_allocated_size)
-    {
-      pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2;
-      pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer,
-					      pfile->deps_allocated_size);
-    }
-
-  if (cr)
-    {
-      bcopy (" \\\n  ", &pfile->deps_buffer[pfile->deps_size], 5);
-      pfile->deps_size += 5;
-    }
-  
-  if (spacer == ' ' && pfile->deps_column > 0)
-    pfile->deps_buffer[pfile->deps_size++] = ' ';
-  bcopy (string, &pfile->deps_buffer[pfile->deps_size], size);
-  pfile->deps_size += size;
-  pfile->deps_column += size + 1;  /* count spacer too */
-  if (spacer == ':')
-    pfile->deps_buffer[pfile->deps_size++] = ':';
-  pfile->deps_buffer[pfile->deps_size] = 0;
 }
 
 /* Simplify a path name in place, deleting redundant components.  This
===================================================================
Index: cppinit.c
--- cppinit.c	2000/03/02 20:14:32	1.46
+++ cppinit.c	2000/03/03 01:57:37
@@ -29,6 +29,7 @@ Foundation, 59 Temple Place - Suite 330,
 #include "prefix.h"
 #include "intl.h"
 #include "version.h"
+#include "mkdeps.h"
 
 /* Predefined symbols, built-in macros, and the default include path. */
 
@@ -446,13 +447,6 @@ cpp_cleanup (pfile)
       pfile->token_buffer = NULL;
     }
 
-  if (pfile->deps_buffer)
-    {
-      free (pfile->deps_buffer);
-      pfile->deps_buffer = NULL;
-      pfile->deps_allocated_size = 0;
-    }
-
   if (pfile->input_buffer)
     {
       free (pfile->input_buffer);
@@ -461,6 +455,9 @@ cpp_cleanup (pfile)
       pfile->input_buffer_len = 0;
     }
 
+  if (pfile->deps)
+    deps_free (pfile->deps);
+
   while (pfile->if_stack)
     {
       IF_STACK_FRAME *temp = pfile->if_stack;
@@ -474,10 +471,8 @@ cpp_cleanup (pfile)
       while (imp)
 	{
 	  struct include_hash *next = imp->next;
-#if 0
-	  /* This gets freed elsewhere - I think. */
-	  free (imp->name);
-#endif
+
+	  free ((PTR) imp->name);
 	  free (imp);
 	  imp = next;
 	}
@@ -614,17 +609,13 @@ initialize_dependency_output (pfile)
       opts->print_deps_append = 1;
     }
 
-  /* Print the expected object file name as the target of this Make-rule.  */
-  pfile->deps_allocated_size = 200;
-  pfile->deps_buffer = (char *) xmalloc (pfile->deps_allocated_size);
-  pfile->deps_buffer[0] = 0;
-  pfile->deps_size = 0;
-  pfile->deps_column = 0;
+  pfile->deps = deps_init ();
 
+  /* Print the expected object file name as the target of this Make-rule.  */
   if (opts->deps_target)
-    deps_output (pfile, opts->deps_target, ':');
+    deps_add_target (pfile->deps, opts->deps_target);
   else if (*opts->in_fname == 0)
-    deps_output (pfile, "-", ':');
+    deps_add_target (pfile->deps, "-");
   else
     {
       char *p, *q, *r;
@@ -655,10 +646,10 @@ initialize_dependency_output (pfile)
 
       /* Supply our own suffix.  */
       strcpy (q, OBJECT_SUFFIX);
-
-      deps_output (pfile, p, ':');
-      deps_output (pfile, opts->in_fname, ' ');
+      deps_add_target (pfile->deps, p);
     }
+  if (opts->in_fname)
+    deps_add_dep (pfile->deps, opts->in_fname);
 }
 
 /* And another subroutine.  This one sets up the standard include path.  */
@@ -931,29 +922,25 @@ cpp_finish (pfile)
     cpp_ice (pfile, "buffers still stacked in cpp_finish");
   cpp_pop_buffer (pfile);
 
-  if (opts->print_deps)
+  /* Don't write the deps file if preprocessing has failed.  */
+  if (opts->print_deps && pfile->errors == 0)
     {
       /* Stream on which to print the dependency information.  */
       FILE *deps_stream = 0;
 
-      /* Don't actually write the deps file if compilation has failed.  */
-      if (pfile->errors == 0)
-	{
-	  const char *deps_mode = opts->print_deps_append ? "a" : "w";
-	  if (opts->deps_file == 0)
-	    deps_stream = stdout;
-	  else if ((deps_stream = fopen (opts->deps_file, deps_mode)) == 0)
-	    cpp_notice_from_errno (pfile, opts->deps_file);
+      const char *deps_mode = opts->print_deps_append ? "a" : "w";
+      if (opts->deps_file == 0)
+	deps_stream = stdout;
+      else if ((deps_stream = fopen (opts->deps_file, deps_mode)) == 0)
+	cpp_notice_from_errno (pfile, opts->deps_file);
 
-	  if (deps_stream)
+      if (deps_stream)
+	{
+	  deps_write (pfile->deps, deps_stream, 72);
+	  if (opts->deps_file)
 	    {
-	      fputs (pfile->deps_buffer, deps_stream);
-	      putc ('\n', deps_stream);
-	      if (opts->deps_file)
-		{
-		  if (ferror (deps_stream) || fclose (deps_stream) != 0)
-		    cpp_fatal (pfile, "I/O error on output");
-		}
+	      if (ferror (deps_stream) || fclose (deps_stream) != 0)
+		cpp_fatal (pfile, "I/O error on output");
 	    }
 	}
     }
@@ -1196,10 +1183,10 @@ cpp_handle_option (pfile, argc, argv)
       
       case 'p':
 	if (!strcmp (argv[i], "-pedantic"))
-	  CPP_PEDANTIC (pfile) = 1;
+	  opts->pedantic = 1;
 	else if (!strcmp (argv[i], "-pedantic-errors"))
 	  {
-	    CPP_PEDANTIC (pfile) = 1;
+	    opts->pedantic = 1;
 	    opts->pedantic_errors = 1;
 	  }
 	break;
===================================================================
Index: cpplib.c
--- cpplib.c	2000/03/03 00:09:21	1.123
+++ cpplib.c	2000/03/03 01:57:38
@@ -25,6 +25,7 @@ Foundation, 59 Temple Place - Suite 330,
 #include "cpplib.h"
 #include "cpphash.h"
 #include "intl.h"
+#include "mkdeps.h"
 
 #define SKIP_WHITE_SPACE(p) do { while (is_hspace(*p)) p++; } while (0)
 
@@ -1212,7 +1213,7 @@ do_include (pfile, keyword)
 				       (pfile->system_include_depth > 0)))
         {
 	  if (!angle_brackets)
-	    deps_output (pfile, ftok, ' ');
+	    deps_add_dep (pfile->deps, ftok);
 	  else
 	    {
 	      char *p;
@@ -1232,7 +1233,7 @@ do_include (pfile, keyword)
 		  strcat (p, "/");
 	        }
 	      strcat (p, ftok);
-	      deps_output (pfile, p, ' ');
+	      deps_add_dep (pfile->deps, p);
 	    }
 	}
       /* If -M was specified, and this header file won't be added to
@@ -1254,7 +1255,7 @@ do_include (pfile, keyword)
   /* For -M, add the file to the dependencies on its first inclusion. */
   if (!before && (CPP_PRINT_DEPS (pfile)
 		  > (angle_brackets || (pfile->system_include_depth > 0))))
-    deps_output (pfile, ihash->name, ' ');
+    deps_add_dep (pfile->deps, ihash->name);
 
   /* Handle -H option.  */
   if (CPP_OPTIONS(pfile)->print_include_names)
===================================================================
Index: cpplib.h
--- cpplib.h	2000/03/03 00:09:22	1.61
+++ cpplib.h	2000/03/03 01:57:38
@@ -228,17 +228,8 @@ struct cpp_reader
   struct tm *timebuf;
 
   /* Buffer of -M output.  */
-  char *deps_buffer;
+  struct deps *deps;
 
-  /* Number of bytes allocated in above.  */
-  int deps_allocated_size;
-
-  /* Number of bytes used.  */
-  int deps_size;
-
-  /* Number of bytes since the last newline.  */
-  int deps_column;
-
   /* A buffer and a table, used only by read_and_prescan (in cppfiles.c)
      which are allocated once per cpp_reader object to keep them off the
      stack and avoid setup costs.  */
@@ -514,8 +505,6 @@ struct cpp_options {
 #define CPP_PEDANTIC(PFILE) \
   (CPP_OPTIONS (PFILE)->pedantic && !CPP_BUFFER (pfile)->system_header_p)
 
-#define SET_CPP_PEDANTIC(PFILE) (CPP_OPTIONS (PFILE)->pedantic = 1)
-
 /* List of directories to look for include files in. */
 struct file_name_list
 {
@@ -713,8 +702,6 @@ extern int find_include_file		PARAMS ((c
 extern int finclude			PARAMS ((cpp_reader *, int,
 					        struct include_hash *));
 extern int cpp_read_file		PARAMS ((cpp_reader *, const char *));
-extern void deps_output			PARAMS ((cpp_reader *,
-						const char *, int));
 extern struct include_hash *include_hash PARAMS ((cpp_reader *, const char *, int));
 
 #ifdef __cplusplus


More information about the Gcc-patches mailing list