This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[lto][patch] Add a wrapper to share code among collect2 and the linker plugin


The attached patch moves some code from collect2 to a new wrapper that
will also be used by the linker plugin. This avoids code duplication
between the plugin and collect2. The new wrapper has some code
duplication with collect2, but it is mostly uninteresting code (things
like fatal, and fatal_perror).

It produces some noise in the failing test cases since now collect2
reports on the lto-wrapper failure.

2008-11-28  Rafael Avila de Espindola  <espindola@google.com>

	* Makefile.in (MOSTLYCLEANFILES, native): Add lto-wrapper$(exeext)
	(lto-wrapper$(exeext)): New.
	(lto-wrapper.o): New.
	* collect2.c (maybe_run_lto_and_relink): Execute lto-wrapper.
	(collect_execute): Add flags argument. Pass flags to pex_run. Update
	all callers.
	* collect2.h (collect_execute): Add flags argument.
	* gcc.c (main): Set the COLLECT_LTO_WRAPPER environment variable.
	* lto-wrapper.c: New.
	* tlink.c (tlink_execute): Update call to collect_execute.


Cheers,
-- 
Rafael Avila de Espindola

Google | Gordon House | Barrow Street | Dublin 4 | Ireland
Registered in Dublin, Ireland | Registration Number: 368047
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 915364f..d0263d6 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1367,7 +1367,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
  xgcc$(exeext) cpp$(exeext) cc1$(exeext) cc1*-dummy$(exeext) $(EXTRA_PASSES) \
  $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \
  protoize$(exeext) unprotoize$(exeext) \
- $(SPECS) collect2$(exeext) \
+ $(SPECS) collect2$(exeext) lto-wrapper$(exeext) \
  gcov-iov$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \
  *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a libgcc.mk
 
@@ -1619,7 +1619,7 @@ rest.encap: $(STMP_FIXPROTO) lang.rest.encap
 # This is what is made with the host's compiler
 # whether making a cross compiler or not.
 native: config.status auto-host.h build-@POSUB@ $(LANGUAGES) \
-	$(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(COLLECT2)
+	$(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(COLLECT2) lto-wrapper$(exeext)
 
 # Define the names for selecting languages in LANGUAGES.
 c: cc1$(exeext)
@@ -1910,6 +1910,12 @@ collect2.o : collect2.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) intl.h \
 tlink.o: tlink.c $(DEMANGLE_H) $(HASHTAB_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(OBSTACK_H) collect2.h intl.h
 
+lto-wrapper$(exeext): lto-wrapper.o $(LIBIBERTY)
+	$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o T$@ lto-wrapper.o $(LIBIBERTY)
+	mv -f T$@ $@
+
+lto-wrapper.o: lto-wrapper.c $(CONFIG_H) $(SYSTEM_H)
+
 # A file used by all variants of C.
 
 c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
diff --git a/gcc/collect2.c b/gcc/collect2.c
index 2a3bb66..f58438b 100644
--- a/gcc/collect2.c
+++ b/gcc/collect2.c
@@ -878,7 +878,12 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
       const char **p, **q, **r;
       const char **lto_o_ptr;
       struct lto_object *list;
-      char *ltrans_output_file = NULL;
+      char *lto_wrapper = getenv ("COLLECT_LTO_WRAPPER");
+      struct pex_obj *pex;
+      const char *prog = "lto-wrapper";
+
+      if (!lto_wrapper)
+	fatal ("lto wrapper not found");
 
       /* There is at least one object file containing LTO info,
          so we need to run the LTO back end and relink.  */
@@ -907,51 +912,8 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
       lto_c_argv = (char **) xcalloc (sizeof (char *), num_lto_c_args);
       lto_c_ptr = (const char **) lto_c_argv;
 
+      *lto_c_ptr++ = lto_wrapper;
       *lto_c_ptr++ = c_file_name;
-      *lto_c_ptr++ = "-combine";
-      *lto_c_ptr++ = "-x";
-      *lto_c_ptr++ = "lto";
-      *lto_c_ptr++ = "-c";
-      if (lto_mode == LTO_MODE_LTO)
-	{
-	  lto_o_files = XNEWVEC (char *, 2);
-	  lto_o_files[0] = make_temp_file (".lto.o");
-	  lto_o_files[1] = NULL;
-
-	  *lto_c_ptr++ = "-o";
-	  *lto_c_ptr++ = lto_o_files[0];
-	}
-      else if (lto_mode == LTO_MODE_WHOPR)
-	{
-	  const char *list_option = "-fltrans-output-list=";
-	  size_t list_option_len = strlen (list_option);
-	  char *tmp;
-
-	  ltrans_output_file = make_temp_file(".ltrans.out");
-	  tmp = XNEWVEC (char,
-			 strlen (ltrans_output_file) + list_option_len + 1);
-	  *lto_c_ptr++ = tmp;
-	  strcpy (tmp, list_option);
-	  tmp += list_option_len;
-	  strcpy (tmp, ltrans_output_file);
-
-	  *lto_c_ptr++ = "-fwpa";
-
-	  /* Save intermediate WPA files in lto1 if debug.  */
-	  if (debug)
-	    putenv (xstrdup ("WPA_SAVE_LTRANS=1"));
-	}
-      else
-	fatal ("invalid LTO mode");
-
-      /* Add inherited GCC options to the LTO back end command line.
-         Filter out some obviously inappropriate options that will
-         conflict with  the options that we force above.  We pass
-         all of the remaining options on to LTO, and let it complain
-         about any it doesn't like. Note that we invoke LTO via the
-         `gcc' driver, so the usual option processing takes place.
-         Except for `-flto' and `-fwhopr', we should only filter options that
-	 are meaningful to `ld', lest an option go silently unclaimed.  */
 
       cp = opts;
 
@@ -959,73 +921,55 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
         {
           const char *s = extract_string (&cp);
 
-          if (strcmp (s, "-flto") == 0 || strcmp (s, "-fwhopr") == 0)
-            /* We've handled this LTO option, don't pass it on.  */
-            ;
-          else if (strcmp (s, "-o") == 0)
-            {
-              /* Drop `-o' and its filename argument.  We will use a
-                 temporary file for the LTO output.  The `-o' option
-                 will be interpreted by the linker.  */
-              if (cp && *cp)
-                s = extract_string (&cp);
-            }
-          else
-            /* Pass the option or argument to LTO.  */
-            *lto_c_ptr++ = xstrdup (s);
+	  /* Pass the option or argument to the wrapper.  */
+	  *lto_c_ptr++ = xstrdup (s);
         }
       obstack_free (&temporary_obstack, temporary_firstobj);
 
-      /* Add LTO objects to the LTO command line.  */
+      /* Add LTO objects to the wrapper command line.  */
       for (list = lto_objects.first; list; list = list->next)
 	*lto_c_ptr++ = list->name;
 
       *lto_c_ptr = NULL;
 
       /* Run the LTO back end.  */
-      fork_execute ("gcc", lto_c_argv);
-
-      /* Read in the list of output file names.  */
-      if (lto_mode == LTO_MODE_WHOPR)
-	{
-	  int c;
-	  FILE *stream;
-	  size_t i, num_files;
-	  char *start, *end;
-
-	  stream = fopen (ltrans_output_file, "r");
-	  if (!stream)
-	    fatal_perror ("fopen: %s", ltrans_output_file);
-
-	  num_files = 0;
-	  while ((c = getc (stream)) != EOF)
-	    {
-	      obstack_1grow (&temporary_obstack, c);
-	      if (c == '\n')
-		++num_files;
-	    }
+      pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH);
+      {
+	int c;
+	FILE *stream;
+	size_t i, num_files;
+	char *start, *end;
 
-	  if (fclose (stream))
-	    fatal_perror ("fclose: %s", ltrans_output_file);
+	stream = pex_read_output (pex, 0);
+	gcc_assert (stream);
 
-	  lto_o_files = XNEWVEC (char *, num_files + 1);
-	  lto_o_files[num_files] = NULL;
+	num_files = 0;
+	while ((c = getc (stream)) != EOF)
+	  {
+	    obstack_1grow (&temporary_obstack, c);
+	    if (c == '\n')
+	      ++num_files;
+	  }
 
-	  start = XOBFINISH (&temporary_obstack, char *);
-	  for (i = 0; i < num_files; ++i)
-	    {
-	      end = start;
-	      while (*end != '\n')
-		++end;
-	      *end = '\0';
+	lto_o_files = XNEWVEC (char *, num_files + 1);
+	lto_o_files[num_files] = NULL;
+	start = XOBFINISH (&temporary_obstack, char *);
+	for (i = 0; i < num_files; ++i)
+	  {
+	    end = start;
+	    while (*end != '\n')
+	      ++end;
+	    *end = '\0';
 
-	      lto_o_files[i] = xstrdup (start);
+	    lto_o_files[i] = xstrdup (start);
 
-	      start = end + 1;
-	    }
+	    start = end + 1;
+	  }
 
-	  obstack_free (&temporary_obstack, temporary_firstobj);
-	}
+	obstack_free (&temporary_obstack, temporary_firstobj);
+      }
+      do_wait (prog, pex);
+      pex = NULL;
 
       /* After running the LTO back end, we will relink, substituting
 	 the LTO output for the object files that we submitted to the
@@ -1077,9 +1021,6 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
          optimized by the LTO with the temporary file generated by the LTO.  */
       fork_execute ("ld", lto_ld_argv);
 
-      /* Clean up the temporary file.  */
-      if (ltrans_output_file)
-	maybe_unlink (ltrans_output_file);
       maybe_unlink_list (lto_o_files);
     }
   else if (force)
@@ -1923,7 +1864,7 @@ do_wait (const char *prog, struct pex_obj *pex)
 
 struct pex_obj *
 collect_execute (const char *prog, char **argv, const char *outname,
-		 const char *errname)
+		 const char *errname, int flags)
 {
   struct pex_obj *pex;
   const char *errmsg;
@@ -1999,7 +1940,7 @@ collect_execute (const char *prog, char **argv, const char *outname,
   if (pex == NULL)
     fatal_perror ("pex_init failed");
 
-  errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, outname,
+  errmsg = pex_run (pex, flags, argv[0], argv, outname,
 		    errname, &err);
   if (errmsg != NULL)
     {
@@ -2023,7 +1964,7 @@ fork_execute (const char *prog, char **argv)
 {
   struct pex_obj *pex;
 
-  pex = collect_execute (prog, argv, NULL, NULL);
+  pex = collect_execute (prog, argv, NULL, NULL, PEX_LAST | PEX_SEARCH);
   do_wait (prog, pex);
 }
 
diff --git a/gcc/collect2.h b/gcc/collect2.h
index 3990b4f..81113cf 100644
--- a/gcc/collect2.h
+++ b/gcc/collect2.h
@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 extern void do_tlink (char **, char **);
 
 extern struct pex_obj *collect_execute (const char *, char **, const char *,
-					const char *);
+					const char *, int flags);
 
 extern void collect_exit (int) ATTRIBUTE_NORETURN;
 
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 618e78e..2051c82 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -6336,6 +6336,7 @@ main (int argc, char **argv)
   const char *p;
   struct user_specs *uptr;
   char **old_argv = argv;
+  char *lto_wrapper;
 
   /* Initialize here, not in definition.  The IRIX 6 O32 cc sometimes chokes
      on ?: in file-scope variable initializations.  */
@@ -6431,14 +6432,6 @@ main (int argc, char **argv)
     multilib_defaults = XOBFINISH (&multilib_obstack, const char *);
   }
 
-  /* Set up to remember the pathname of gcc and any options
-     needed for collect.  We use argv[0] instead of programname because
-     we need the complete pathname.  */
-  obstack_init (&collect_obstack);
-  obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
-  obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
-  xputenv (XOBFINISH (&collect_obstack, char *));
-
 #ifdef INIT_ENVIRONMENT
   /* Set up any other necessary machine specific environment variables.  */
   xputenv (INIT_ENVIRONMENT);
@@ -6615,6 +6608,28 @@ main (int argc, char **argv)
      the subdirectory based on the options.  */
   set_multilib_dir ();
 
+  /* Set up to remember the pathname of gcc and any options
+     needed for collect.  We use argv[0] instead of programname because
+     we need the complete pathname.  */
+  obstack_init (&collect_obstack);
+  obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
+  obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
+  xputenv (XOBFINISH (&collect_obstack, char *));
+
+  /* Set up to remember the pathname of the lto wrapper. */
+
+  lto_wrapper = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
+  if (lto_wrapper)
+    {
+      obstack_init (&collect_obstack);
+      obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
+		    sizeof ("COLLECT_LTO_WRAPPER=") - 1);
+      obstack_grow (&collect_obstack, lto_wrapper, strlen (lto_wrapper) + 1);
+      xputenv (XOBFINISH (&collect_obstack, char *));
+      free (lto_wrapper);
+      lto_wrapper = NULL;
+    }
+
   /* Warn about any switches that no pass was interested in.  */
 
   for (i = 0; (int) i < n_switches; i++)
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
new file mode 100644
index 0000000..6e41e8f
--- /dev/null
+++ b/gcc/lto-wrapper.c
@@ -0,0 +1,269 @@
+#include "config.h"
+#include "system.h"
+
+int debug;				/* true if -debug */
+
+enum lto_mode_d {
+  LTO_MODE_NONE,			/* Not doing LTO. */
+  LTO_MODE_LTO,				/* Normal LTO. */
+  LTO_MODE_WHOPR			/* WHOPR. */
+};
+
+static enum lto_mode_d lto_mode = LTO_MODE_NONE; /* current LTO mode. */
+
+/* Just die.  */
+
+static void __attribute__ ((format (printf, 1, 2)))
+fatal (const char * cmsgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, cmsgid);
+  fprintf (stderr, "collect2: ");
+  vfprintf (stderr, cmsgid, ap);
+  fprintf (stderr, "\n");
+  va_end (ap);
+
+  exit (FATAL_EXIT_CODE);
+}
+
+/* Die when sys call fails.  */
+
+static void __attribute__ ((format (printf, 1, 2)))
+fatal_perror (const char * cmsgid, ...)
+{
+  int e = errno;
+  va_list ap;
+
+  va_start (ap, cmsgid);
+  fprintf (stderr, "collect2: ");
+  vfprintf (stderr, cmsgid, ap);
+  fprintf (stderr, ": %s\n", xstrerror (e));
+  va_end (ap);
+
+  exit (FATAL_EXIT_CODE);
+}
+
+/* Execute a program, and wait for the reply.  */
+
+static struct pex_obj *
+collect_execute (char **argv)
+{
+  struct pex_obj *pex;
+  const char *errmsg;
+  int err;
+  char *response_arg = NULL;
+  char *response_argv[3] ATTRIBUTE_UNUSED;
+
+  if (debug)
+    {
+      char **p_argv;
+      const char *str;
+
+      for (p_argv = argv; (str = *p_argv) != (char *) 0; p_argv++)
+	fprintf (stderr, " %s", str);
+
+      fprintf (stderr, "\n");
+    }
+
+  fflush (stdout);
+  fflush (stderr);
+
+  pex = pex_init (0, "collect2", NULL);
+  if (pex == NULL)
+    fatal_perror ("pex_init failed");
+
+  errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, NULL,
+		    NULL, &err);
+  if (errmsg != NULL)
+    {
+      if (err != 0)
+	{
+	  errno = err;
+	  fatal_perror (errmsg);
+	}
+      else
+	fatal (errmsg);
+    }
+
+  if (response_arg)
+    free (response_arg);
+
+  return pex;
+}
+
+/* Wait for a process to finish, and exit if a nonzero status is found.  */
+
+static int
+collect_wait (const char *prog, struct pex_obj *pex)
+{
+  int status;
+
+  if (!pex_get_status (pex, 1, &status))
+    fatal_perror ("can't get program status");
+  pex_free (pex);
+
+  if (status)
+    {
+      if (WIFSIGNALED (status))
+	{
+	  int sig = WTERMSIG (status);
+	  fatal ("%s terminated with signal %d [%s]%s",
+		 prog, sig, strsignal(sig),
+		 WCOREDUMP(status) ? ", core dumped" : "");
+	}
+
+      if (WIFEXITED (status))
+	fatal ("%s returned %d exit status", prog, WEXITSTATUS (status));
+    }
+  return 0;
+}
+
+static void
+fork_execute (char **argv)
+{
+  struct pex_obj *pex;
+
+  pex = collect_execute (argv);
+  collect_wait (argv[0], pex);
+}
+
+static void
+run_gcc(unsigned argc, char *argv[])
+{
+  unsigned i;
+  unsigned new_argc = argc;
+  char **new_argv;
+  const char **argv_ptr;
+  char *ltrans_output_file = NULL;
+  char *flto_out = NULL;
+  char *list_option_full = NULL;
+
+  new_argc += 8;
+  new_argv = (char **) xcalloc (sizeof (char *), new_argc);
+
+  argv_ptr = (const char **) new_argv;
+
+  *argv_ptr++ = argv[0];
+  *argv_ptr++ = "-combine";
+  *argv_ptr++ = "-x";
+  *argv_ptr++ = "lto";
+  *argv_ptr++ = "-c";
+  if (lto_mode == LTO_MODE_LTO)
+    {
+      flto_out = make_temp_file (".lto.o");
+      *argv_ptr++ = "-o";
+      *argv_ptr++ = flto_out;
+    }
+  else if (lto_mode == LTO_MODE_WHOPR)
+    {
+      const char *list_option = "-fltrans-output-list=";
+      size_t list_option_len = strlen (list_option);
+      char *tmp;
+
+      ltrans_output_file = make_temp_file(".ltrans.out");
+      list_option_full = (char *) xmalloc (sizeof (char) *
+		         (strlen (ltrans_output_file) + list_option_len + 1));
+      tmp = list_option_full;
+
+      *argv_ptr++ = tmp;
+      strcpy (tmp, list_option);
+      tmp += list_option_len;
+      strcpy (tmp, ltrans_output_file);
+
+      *argv_ptr++ = "-fwpa";
+
+    }
+  else
+    fatal ("invalid LTO mode");
+
+  /* Add inherited GCC options to the LTO back end command line.
+     Filter out some obviously inappropriate options that will
+     conflict with  the options that we force above.  We pass
+     all of the remaining options on to LTO, and let it complain
+     about any it doesn't like. Note that we invoke LTO via the
+     `gcc' driver, so the usual option processing takes place.
+     Except for `-flto' and `-fwhopr', we should only filter options that
+     are meaningful to `ld', lest an option go silently unclaimed.  */
+
+  for (i = 1; i < argc; i++)
+    {
+      const char *s = argv[i];
+
+      if (strcmp (s, "-flto") == 0 || strcmp (s, "-fwhopr") == 0)
+	/* We've handled this LTO option, don't pass it on.  */
+	;
+      else if (strcmp (s, "-o") == 0)
+	{
+	  /* Drop `-o' and its filename argument.  We will use a
+	     temporary file for the LTO output.  The `-o' option
+	     will be interpreted by the linker.  */
+	  i++;
+	}
+      else
+	/* Pass the option or argument to LTO.  */
+	*argv_ptr++ = s;
+    }
+
+  *argv_ptr = NULL;
+
+  fork_execute (new_argv);
+  free (new_argv);
+  new_argv = NULL;
+
+  if (lto_mode == LTO_MODE_LTO)
+    {
+      printf("%s\n", flto_out);
+      free (flto_out);
+      flto_out = NULL;
+    }
+  else if (lto_mode == LTO_MODE_WHOPR)
+    {
+      FILE *stream = fopen (ltrans_output_file, "r");
+      int c;
+
+      if (!stream)
+	fatal_perror ("fopen: %s", ltrans_output_file);
+
+      while ((c = getc (stream)) != EOF)
+	putc (c, stdout);
+      fclose (stream);
+      free (ltrans_output_file);
+      free (list_option_full);
+    }
+  else
+    fatal ("invalid LTO mode");
+}
+
+static int
+process_args (int argc, char *argv[], char *gcc_argv[])
+{
+  int i;
+  int j = 0;
+
+  for (i = 1; i < argc; i ++)
+    {
+      if (! strcmp (argv[i], "-debug"))
+	debug = 1;
+      else if (! strcmp (argv[i], "-flto"))
+	lto_mode = LTO_MODE_LTO;
+      else if (! strcmp (argv[i], "-fwhopr"))
+	lto_mode = LTO_MODE_WHOPR;
+      else
+	{
+	  gcc_argv[j] = argv[i];
+	  j++;
+	}
+    }
+  return j;
+}
+
+int
+main (int argc, char *argv[])
+{
+  char **gcc_argv = (char **) xcalloc(sizeof (char*), argc);
+  int gcc_argc = process_args (argc, argv, gcc_argv);
+  run_gcc (gcc_argc, gcc_argv);
+  free (gcc_argv);
+  return 0;
+}
diff --git a/gcc/tlink.c b/gcc/tlink.c
index 51f3717..8ac32ba 100644
--- a/gcc/tlink.c
+++ b/gcc/tlink.c
@@ -282,7 +282,7 @@ tlink_execute (const char *prog, char **argv, const char *outname,
 {
   struct pex_obj *pex;
 
-  pex = collect_execute (prog, argv, outname, errname);
+  pex = collect_execute (prog, argv, outname, errname, PEX_LAST | PEX_SEARCH);
   return collect_wait (prog, pex);
 }
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]