diff mbox

Create a library for tools like collect2 and lto-wrapper (1/2)

Message ID 537DE6E7.7090908@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt May 22, 2014, noon UTC
For offloading which is being implemented on the gomp4 branch, we're 
about to introduce new mkoffload programs. These are going to require a 
lot of functionality that's already present in lto-wrapper and collect2, 
I've decided to make a new set of utility functions that can be linked 
in with these programs.

This is the first step, splitting off code from lto-wrapper into a new 
collect-utils.c file. The next step will replace some of these with 
almost-identical ones from collect2 and make that tool also link with 
collect-utils.

Bootstrapped and tested on x86_64-linux, ok for trunk?


Bernd
diff mbox

Patch

commit 1faf8f4aa2f81be4a0b0db8c89933e9c5bd2abcb
Author: Bernd Schmidt <bernds@codesourcery.com>
Date:   Wed May 21 15:15:45 2014 +0200

    Make a collect-utils library for use by tools like collect2 and lto-wrapper.
    
        	* Makefile.in (ALL_HOST_BACKEND_OBJS): Add collect-utils.o.
        	(lto-wrapper$(exeext)): Link with collect-utils.o.
        	* collect-utils.c: New file.
        	* collect-utils.h: New file.
        	* lto-wrapper.c: Include "collect-utils.h".
        	(args_name): Delete variable.
        	(tool_name): New variable.
        	(tool_cleanup): New function.
        	(maybe_unlink): Renamed from maybe_unlink_file.  All callers changed.
        	(lto_wrapper_cleanup, fatal_signal, fatal, fatal_perror,
        	collect_execute, collect_wait, fork_execute): Remove functions.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e74bb67..ad9df57 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1490,7 +1490,7 @@  ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS))
 ALL_HOST_BACKEND_OBJS = $(GCC_OBJS) $(OBJS) $(OBJS-libcommon) \
   $(OBJS-libcommon-target) @TREEBROWSER@ main.o c-family/cppspec.o \
   $(COLLECT2_OBJS) $(EXTRA_GCC_OBJS) $(GCOV_OBJS) $(GCOV_DUMP_OBJS) \
-  lto-wrapper.o
+  lto-wrapper.o collect-utils.o
 
 # This lists all host object files, whether they are included in this
 # compilation or not.
@@ -1909,9 +1909,10 @@  collect2$(exeext): $(COLLECT2_OBJS) $(LIBDEPS)
 CFLAGS-collect2.o += -DTARGET_MACHINE=\"$(target_noncanonical)\" \
 	@TARGET_SYSTEM_ROOT_DEFINE@
 
-lto-wrapper$(exeext): lto-wrapper.o ggc-none.o libcommon-target.a $(LIBDEPS)
+LTO_WRAPPER_OBJS = lto-wrapper.o collect-utils.o ggc-none.o
+lto-wrapper$(exeext): $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBDEPS)
 	+$(LINKER) $(ALL_COMPILERFLAGS) $(LDFLAGS) -o T$@ \
-	    lto-wrapper.o ggc-none.o libcommon-target.a $(LIBS)
+	   $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBS)
 	mv -f T$@ $@
 
 # Files used by all variants of C or by the stand-alone pre-processor.
diff --git a/gcc/collect-utils.c b/gcc/collect-utils.c
new file mode 100644
index 0000000..22d90a4
--- /dev/null
+++ b/gcc/collect-utils.c
@@ -0,0 +1,259 @@ 
+/* Utility functions used by tools like collect2 and lto-wrapper.
+   Copyright (C) 2009-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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 3, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "obstack.h"
+#include "opts.h"
+#include "options.h"
+#include "simple-object.h"
+#include "lto-section-names.h"
+#include "collect-utils.h"
+
+static char *response_file;
+
+bool debug;
+bool verbose;
+
+/* Delete tempfiles.  */
+
+void
+utils_cleanup (void)
+{
+  static bool cleanup_done = false;
+
+  if (cleanup_done)
+    return;
+
+  /* Setting cleanup_done prevents an infinite loop if one of the
+     calls to maybe_unlink fails. */
+  cleanup_done = true;
+
+  if (response_file)
+    maybe_unlink (response_file);
+  tool_cleanup ();
+}
+
+/* Notify user of a non-error.  */
+void
+notice (const char *cmsgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, cmsgid);
+  vfprintf (stderr, _(cmsgid), ap);
+  va_end (ap);
+}
+
+void
+fatal_signal (int signum)
+{
+  signal (signum, SIG_DFL);
+  utils_cleanup ();
+  /* Get the same signal again, this time not handled,
+     so its normal effect occurs.  */
+  kill (getpid (), signum);
+}
+
+/* Just die. CMSGID is the error message. */
+
+void __attribute__ ((format (printf, 1, 2)))
+fatal (const char * cmsgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, cmsgid);
+  fprintf (stderr, "%s: ", tool_name);
+  vfprintf (stderr, _(cmsgid), ap);
+  fprintf (stderr, "\n");
+  va_end (ap);
+
+  utils_cleanup ();
+  exit (FATAL_EXIT_CODE);
+}
+
+
+/* Die when sys call fails. CMSGID is the error message.  */
+
+void __attribute__ ((format (printf, 1, 2)))
+fatal_perror (const char *cmsgid, ...)
+{
+  int e = errno;
+  va_list ap;
+
+  va_start (ap, cmsgid);
+  fprintf (stderr, "%s: ", tool_name);
+  vfprintf (stderr, _(cmsgid), ap);
+  fprintf (stderr, ": %s\n", xstrerror (e));
+  va_end (ap);
+
+  utils_cleanup ();
+  exit (FATAL_EXIT_CODE);
+}
+
+
+/* Execute a program, and wait for the reply. ARGV are the arguments. The
+   last one must be NULL. */
+
+struct pex_obj *
+collect_execute (char **argv)
+{
+  struct pex_obj *pex;
+  const char *errmsg;
+  int err;
+
+  if (verbose)
+    {
+      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, tool_name, NULL);
+  if (pex == NULL)
+    fatal_perror ("pex_init failed");
+
+  /* Do not use PEX_LAST here, we use our stdout for communicating with
+     collect2 or the linker-plugin.  Any output from the sub-process
+     will confuse that.  */
+  errmsg = pex_run (pex, PEX_SEARCH, argv[0], argv, NULL,
+		    NULL, &err);
+  if (errmsg != NULL)
+    {
+      if (err != 0)
+	{
+	  errno = err;
+	  fatal_perror (errmsg);
+	}
+      else
+	fatal (errmsg);
+    }
+
+  return pex;
+}
+
+
+/* Wait for a process to finish, and exit if a nonzero status is found.
+   PROG is the program name. PEX is the process we should wait for. */
+
+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);
+	  if (WCOREDUMP (status))
+	    fatal ("%s terminated with signal %d [%s], core dumped",
+		   prog, sig, strsignal (sig));
+	  else
+	    fatal ("%s terminated with signal %d [%s]",
+		   prog, sig, strsignal (sig));
+	}
+
+      if (WIFEXITED (status))
+	fatal ("%s returned %d exit status", prog, WEXITSTATUS (status));
+    }
+
+  return 0;
+}
+
+void
+do_wait (const char *prog, struct pex_obj *pex)
+{
+  int ret = collect_wait (prog, pex);
+  if (ret != 0)
+    {
+      error ("%s returned %d exit status", prog, ret);
+      exit (ret);
+    }
+
+  if (response_file && !debug)
+    {
+      unlink (response_file);
+      response_file = NULL;
+    }
+}
+
+/* Unlink a temporary LTRANS file unless requested otherwise.  */
+
+void
+maybe_unlink_file (const char *file)
+{
+  if (!debug)
+    {
+      if (unlink_if_ordinary (file)
+	  && errno != ENOENT)
+	fatal_perror ("deleting file %s", file);
+    }
+  else
+    fprintf (stderr, "[Leaving %s]\n", file);
+}
+
+
+/* Execute program ARGV[0] with arguments ARGV. Wait for it to finish.  */
+
+void
+fork_execute (char **argv)
+{
+  struct pex_obj *pex;
+  char *new_argv[3];
+  char *at_args;
+  FILE *args;
+  int status;
+
+  response_file = make_temp_file (".args");
+  at_args = concat ("@", response_file, NULL);
+  args = fopen (response_file, "w");
+  if (args == NULL)
+    fatal ("failed to open %s", response_file);
+
+  status = writeargv (&argv[1], args);
+
+  if (status)
+    fatal ("could not write to temporary file %s",  response_file);
+
+  fclose (args);
+
+  new_argv[0] = argv[0];
+  new_argv[1] = at_args;
+  new_argv[2] = NULL;
+
+  pex = collect_execute (new_argv);
+  do_wait (new_argv[0], pex);
+
+  free (at_args);
+}
diff --git a/gcc/collect-utils.h b/gcc/collect-utils.h
new file mode 100644
index 0000000..ea57b6b
--- /dev/null
+++ b/gcc/collect-utils.h
@@ -0,0 +1,44 @@ 
+/* Utility functions used by tools like collect2 and lto-wrapper.
+   Copyright (C) 2009-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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 3, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Provided in collect-utils.c.  */
+extern void notice (const char *, ...)
+  __attribute__ ((format (printf, 1, 2)));
+extern void fatal_signal (int);
+extern void fatal (const char *, ...)
+  __attribute__ ((format (printf, 1, 2)));
+extern void fatal_perror (const char *, ...)
+  __attribute__ ((format (printf, 1, 2)));
+
+extern struct pex_obj *collect_execute (char **);
+extern int collect_wait (const char *, struct pex_obj *);
+extern void do_wait (const char *, struct pex_obj *);
+extern void fork_execute (char **);
+extern void utils_cleanup (void);
+
+extern bool debug;
+extern bool verbose;
+
+/* Provided by the tool itself.  */
+
+/* The name of the tool, printed in error messages.  */
+extern const char tool_name[];
+/* Called by utils_cleanup.  */
+extern void tool_cleanup (void);
+extern void maybe_unlink (const char *);
diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c
index f59d74e..9a04f93 100644
--- a/gcc/lto-wrapper.c
+++ b/gcc/lto-wrapper.c
@@ -47,9 +47,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "options.h"
 #include "simple-object.h"
 #include "lto-section-names.h"
-
-int debug;				/* true if -save-temps.  */
-int verbose;				/* true if -v.  */
+#include "collect-utils.h"
 
 enum lto_mode_d {
   LTO_MODE_NONE,			/* Not doing LTO.  */
@@ -62,177 +60,38 @@  static enum lto_mode_d lto_mode = LTO_MODE_NONE;
 
 static char *ltrans_output_file;
 static char *flto_out;
-static char *args_name;
 static unsigned int nr;
 static char **input_names;
 static char **output_names;
 static char *makefile;
 
-static void maybe_unlink_file (const char *);
+const char tool_name[] = "lto-wrapper";
 
- /* Delete tempfiles.  */
+/* Delete tempfiles.  Called from utils_cleanup.  */
 
-static void
-lto_wrapper_cleanup (void)
+void
+tool_cleanup (void)
 {
-  static bool cleanup_done = false;
   unsigned int i;
 
-  if (cleanup_done)
-    return;
-
-  /* Setting cleanup_done prevents an infinite loop if one of the
-     calls to maybe_unlink_file fails. */
-  cleanup_done = true;
-
   if (ltrans_output_file)
-    maybe_unlink_file (ltrans_output_file);
+    maybe_unlink (ltrans_output_file);
   if (flto_out)
-    maybe_unlink_file (flto_out);
-  if (args_name)
-    maybe_unlink_file (args_name);
+    maybe_unlink (flto_out);
   if (makefile)
-    maybe_unlink_file (makefile);
+    maybe_unlink (makefile);
   for (i = 0; i < nr; ++i)
     {
-      maybe_unlink_file (input_names[i]);
+      maybe_unlink (input_names[i]);
       if (output_names[i])
-	maybe_unlink_file (output_names[i]);
-    }
-}
-
-static void
-fatal_signal (int signum)
-{
-  signal (signum, SIG_DFL);
-  lto_wrapper_cleanup ();
-  /* Get the same signal again, this time not handled,
-     so its normal effect occurs.  */
-  kill (getpid (), signum);
-}
-
-/* Just die. CMSGID is the error message. */
-
-static void __attribute__ ((format (printf, 1, 2)))
-fatal (const char * cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-  fprintf (stderr, "lto-wrapper: ");
-  vfprintf (stderr, _(cmsgid), ap);
-  fprintf (stderr, "\n");
-  va_end (ap);
-
-  lto_wrapper_cleanup ();
-  exit (FATAL_EXIT_CODE);
-}
-
-
-/* Die when sys call fails. CMSGID is the error message.  */
-
-static void __attribute__ ((format (printf, 1, 2)))
-fatal_perror (const char *cmsgid, ...)
-{
-  int e = errno;
-  va_list ap;
-
-  va_start (ap, cmsgid);
-  fprintf (stderr, "lto-wrapper: ");
-  vfprintf (stderr, _(cmsgid), ap);
-  fprintf (stderr, ": %s\n", xstrerror (e));
-  va_end (ap);
-
-  lto_wrapper_cleanup ();
-  exit (FATAL_EXIT_CODE);
-}
-
-
-/* Execute a program, and wait for the reply. ARGV are the arguments. The
-   last one must be NULL. */
-
-static struct pex_obj *
-collect_execute (char **argv)
-{
-  struct pex_obj *pex;
-  const char *errmsg;
-  int err;
-
-  if (verbose)
-    {
-      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, "lto-wrapper", NULL);
-  if (pex == NULL)
-    fatal_perror ("pex_init failed");
-
-  /* Do not use PEX_LAST here, we use our stdout for communicating with
-     collect2 or the linker-plugin.  Any output from the sub-process
-     will confuse that.  */
-  errmsg = pex_run (pex, PEX_SEARCH, argv[0], argv, NULL,
-		    NULL, &err);
-  if (errmsg != NULL)
-    {
-      if (err != 0)
-	{
-	  errno = err;
-	  fatal_perror (errmsg);
-	}
-      else
-	fatal (errmsg);
+	maybe_unlink (output_names[i]);
     }
-
-  return pex;
 }
 
-
-/* Wait for a process to finish, and exit if a nonzero status is found.
-   PROG is the program name. PEX is the process we should wait for. */
-
-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);
-	  if (WCOREDUMP (status))
-	    fatal ("%s terminated with signal %d [%s], core dumped",
-		   prog, sig, strsignal (sig));
-	  else
-	    fatal ("%s terminated with signal %d [%s]",
-		   prog, sig, strsignal (sig));
-	}
-
-      if (WIFEXITED (status))
-	fatal ("%s returned %d exit status", prog, WEXITSTATUS (status));
-    }
-
-  return 0;
-}
-
-
 /* Unlink a temporary LTRANS file unless requested otherwise.  */
 
-static void
-maybe_unlink_file (const char *file)
+void
+maybe_unlink (const char *file)
 {
   if (! debug)
     {
@@ -244,43 +103,6 @@  maybe_unlink_file (const char *file)
     fprintf (stderr, "[Leaving LTRANS %s]\n", file);
 }
 
-
-/* Execute program ARGV[0] with arguments ARGV. Wait for it to finish.  */
-
-static void
-fork_execute (char **argv)
-{
-  struct pex_obj *pex;
-  char *new_argv[3];
-  char *at_args;
-  FILE *args;
-  int status;
-
-  args_name = make_temp_file (".args");
-  at_args = concat ("@", args_name, NULL);
-  args = fopen (args_name, "w");
-  if (args == NULL)
-    fatal ("failed to open %s", args_name);
-
-  status = writeargv (&argv[1], args);
-
-  if (status)
-    fatal ("could not write to temporary file %s",  args_name);
-
-  fclose (args);
-
-  new_argv[0] = argv[0];
-  new_argv[1] = at_args;
-  new_argv[2] = NULL;
-
-  pex = collect_execute (new_argv);
-  collect_wait (new_argv[0], pex);
-
-  maybe_unlink_file (args_name);
-  args_name = NULL;
-  free (at_args);
-}
-
 /* Template of LTRANS dumpbase suffix.  */
 #define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
 
@@ -906,7 +728,7 @@  cont:
 	  output_names[nr-1] = output_name;
 	}
       fclose (stream);
-      maybe_unlink_file (ltrans_output_file);
+      maybe_unlink (ltrans_output_file);
       ltrans_output_file = NULL;
 
       if (parallel)
@@ -965,7 +787,7 @@  cont:
 	  else
 	    {
 	      fork_execute (CONST_CAST (char **, new_argv));
-	      maybe_unlink_file (input_name);
+	      maybe_unlink (input_name);
 	    }
 
 	  output_names[i] = output_name;
@@ -1002,10 +824,10 @@  cont:
 	  new_argv[i++] = NULL;
 	  pex = collect_execute (CONST_CAST (char **, new_argv));
 	  collect_wait (new_argv[0], pex);
-	  maybe_unlink_file (makefile);
+	  maybe_unlink (makefile);
 	  makefile = NULL;
 	  for (i = 0; i < nr; ++i)
-	    maybe_unlink_file (input_names[i]);
+	    maybe_unlink (input_names[i]);
 	}
       for (i = 0; i < nr; ++i)
 	{