OSDN Git Service

2010-10-26 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / lto-wrapper.c
1 /* Wrapper to call lto.  Used by collect2 and the linker plugin.
2    Copyright (C) 2009, 2010 Free Software Foundation, Inc.
3
4    Factored out of collect2 by Rafael Espindola <espindola@google.com>
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3.  If not see
20 <http://www.gnu.org/licenses/>.  */
21
22
23 /* This program is passed a gcc, a list of gcc arguments and a list of
24    object files containing IL. It scans the argument list to check if
25    we are in whopr mode or not modifies the arguments and needed and
26    prints a list of output files on stdout.
27
28    Example:
29
30    $ lto-wrapper gcc/xgcc -B gcc a.o b.o -o test -flto
31
32    The above will print something like
33    /tmp/ccwbQ8B2.lto.o
34
35    If -fwhopr is used instead, more than one file might be produced
36    ./ccXj2DTk.lto.ltrans.o
37    ./ccCJuXGv.lto.ltrans.o
38 */
39
40 #include "config.h"
41 #include "system.h"
42 #include "coretypes.h"
43 #include <errno.h>
44 #include <signal.h>
45 #if ! defined( SIGCHLD ) && defined( SIGCLD )
46 #  define SIGCHLD SIGCLD
47 #endif
48 #include "intl.h"
49 #include "libiberty.h"
50 #include "obstack.h"
51
52 #ifndef HAVE_KILL
53 #define kill(p,s) raise(s)
54 #endif
55
56 int debug;                              /* true if -save-temps.  */
57 int verbose;                            /* true if -v.  */
58
59 enum lto_mode_d {
60   LTO_MODE_NONE,                        /* Not doing LTO.  */
61   LTO_MODE_LTO,                         /* Normal LTO.  */
62   LTO_MODE_WHOPR                        /* WHOPR.  */
63 };
64
65 /* Current LTO mode.  */
66 static enum lto_mode_d lto_mode = LTO_MODE_NONE;
67
68 static char *ltrans_output_file;
69 static char *flto_out;
70 static char *args_name;
71 static unsigned int nr;
72 static char **input_names;
73 static char **output_names;
74 static char *makefile;
75
76 static void maybe_unlink_file (const char *);
77
78  /* Delete tempfiles.  */
79
80 static void
81 lto_wrapper_cleanup (void)
82 {
83   static bool cleanup_done = false;
84   unsigned int i;
85
86   if (cleanup_done)
87     return;
88
89   /* Setting cleanup_done prevents an infinite loop if one of the
90      calls to maybe_unlink_file fails. */
91   cleanup_done = true;
92
93   if (ltrans_output_file)
94     maybe_unlink_file (ltrans_output_file);
95   if (flto_out)
96     maybe_unlink_file (flto_out);
97   if (args_name)
98     maybe_unlink_file (args_name);
99   if (makefile)
100     maybe_unlink_file (makefile);
101   for (i = 0; i < nr; ++i)
102     {
103       maybe_unlink_file (input_names[i]);
104       if (output_names[i])
105         maybe_unlink_file (output_names[i]);
106     }
107 }
108
109 static void
110 fatal_signal (int signum)
111 {
112   signal (signum, SIG_DFL);
113   lto_wrapper_cleanup ();
114   /* Get the same signal again, this time not handled,
115      so its normal effect occurs.  */
116   kill (getpid (), signum);
117 }
118
119 /* Just die. CMSGID is the error message. */
120
121 static void __attribute__ ((format (printf, 1, 2)))
122 fatal (const char * cmsgid, ...)
123 {
124   va_list ap;
125
126   va_start (ap, cmsgid);
127   fprintf (stderr, "lto-wrapper: ");
128   vfprintf (stderr, _(cmsgid), ap);
129   fprintf (stderr, "\n");
130   va_end (ap);
131
132   lto_wrapper_cleanup ();
133   exit (FATAL_EXIT_CODE);
134 }
135
136
137 /* Die when sys call fails. CMSGID is the error message.  */
138
139 static void __attribute__ ((format (printf, 1, 2)))
140 fatal_perror (const char *cmsgid, ...)
141 {
142   int e = errno;
143   va_list ap;
144
145   va_start (ap, cmsgid);
146   fprintf (stderr, "lto-wrapper: ");
147   vfprintf (stderr, _(cmsgid), ap);
148   fprintf (stderr, ": %s\n", xstrerror (e));
149   va_end (ap);
150
151   lto_wrapper_cleanup ();
152   exit (FATAL_EXIT_CODE);
153 }
154
155
156 /* Execute a program, and wait for the reply. ARGV are the arguments. The
157    last one must be NULL. */
158
159 static struct pex_obj *
160 collect_execute (char **argv)
161 {
162   struct pex_obj *pex;
163   const char *errmsg;
164   int err;
165
166   if (verbose)
167     {
168       char **p_argv;
169       const char *str;
170
171       for (p_argv = argv; (str = *p_argv) != (char *) 0; p_argv++)
172         fprintf (stderr, " %s", str);
173
174       fprintf (stderr, "\n");
175     }
176
177   fflush (stdout);
178   fflush (stderr);
179
180   pex = pex_init (0, "lto-wrapper", NULL);
181   if (pex == NULL)
182     fatal_perror ("pex_init failed");
183
184   /* Do not use PEX_LAST here, we use our stdout for communicating with
185      collect2 or the linker-plugin.  Any output from the sub-process
186      will confuse that.  */
187   errmsg = pex_run (pex, PEX_SEARCH, argv[0], argv, NULL,
188                     NULL, &err);
189   if (errmsg != NULL)
190     {
191       if (err != 0)
192         {
193           errno = err;
194           fatal_perror (errmsg);
195         }
196       else
197         fatal (errmsg);
198     }
199
200   return pex;
201 }
202
203
204 /* Wait for a process to finish, and exit if a nonzero status is found.
205    PROG is the program name. PEX is the process we should wait for. */
206
207 static int
208 collect_wait (const char *prog, struct pex_obj *pex)
209 {
210   int status;
211
212   if (!pex_get_status (pex, 1, &status))
213     fatal_perror ("can't get program status");
214   pex_free (pex);
215
216   if (status)
217     {
218       if (WIFSIGNALED (status))
219         {
220           int sig = WTERMSIG (status);
221           if (WCOREDUMP (status))
222             fatal ("%s terminated with signal %d [%s], core dumped",
223                    prog, sig, strsignal (sig));
224           else
225             fatal ("%s terminated with signal %d [%s]",
226                    prog, sig, strsignal (sig));
227         }
228
229       if (WIFEXITED (status))
230         fatal ("%s returned %d exit status", prog, WEXITSTATUS (status));
231     }
232
233   return 0;
234 }
235
236
237 /* Unlink a temporary LTRANS file unless requested otherwise.  */
238
239 static void
240 maybe_unlink_file (const char *file)
241 {
242   if (! debug)
243     {
244       if (unlink_if_ordinary (file)
245           && errno != ENOENT)
246         fatal_perror ("deleting LTRANS file %s", file);
247     }
248   else
249     fprintf (stderr, "[Leaving LTRANS %s]\n", file);
250 }
251
252
253 /* Execute program ARGV[0] with arguments ARGV. Wait for it to finish.  */
254
255 static void
256 fork_execute (char **argv)
257 {
258   struct pex_obj *pex;
259   char *new_argv[3];
260   char *at_args;
261   FILE *args;
262   int status;
263
264   args_name = make_temp_file (".args");
265   at_args = concat ("@", args_name, NULL);
266   args = fopen (args_name, "w");
267   if (args == NULL)
268     fatal ("failed to open %s", args_name);
269
270   status = writeargv (&argv[1], args);
271
272   if (status)
273     fatal ("could not write to temporary file %s",  args_name);
274
275   fclose (args);
276
277   new_argv[0] = argv[0];
278   new_argv[1] = at_args;
279   new_argv[2] = NULL;
280
281   pex = collect_execute (new_argv);
282   collect_wait (new_argv[0], pex);
283
284   maybe_unlink_file (args_name);
285   args_name = NULL;
286   free (at_args);
287 }
288
289 /* Template of LTRANS dumpbase suffix.  */
290 #define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
291
292 /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
293
294 static void
295 run_gcc (unsigned argc, char *argv[])
296 {
297   unsigned i, j;
298   const char **new_argv;
299   const char **argv_ptr;
300   char *list_option_full = NULL;
301   const char *linker_output = NULL;
302   const char *collect_gcc_options, *collect_gcc;
303   struct obstack env_obstack;
304   bool seen_o = false;
305   int parallel = 0;
306   int jobserver = 0;
307
308   /* Get the driver and options.  */
309   collect_gcc = getenv ("COLLECT_GCC");
310   if (!collect_gcc)
311     fatal ("environment variable COLLECT_GCC must be set");
312
313   /* Set the CFLAGS environment variable.  */
314   collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
315   if (!collect_gcc_options)
316     fatal ("environment variable COLLECT_GCC_OPTIONS must be set");
317
318   /* Count arguments.  */
319   i = 0;
320   for (j = 0; collect_gcc_options[j] != '\0'; ++j)
321     if (collect_gcc_options[j] == '\'')
322       ++i;
323
324   if (i % 2 != 0)
325     fatal ("malformed COLLECT_GCC_OPTIONS");
326
327   /* Initalize the common arguments for the driver.  */
328   new_argv = (const char **) xmalloc ((15 + i / 2 + argc) * sizeof (char *));
329   argv_ptr = new_argv;
330   *argv_ptr++ = collect_gcc;
331   *argv_ptr++ = "-xlto";
332   *argv_ptr++ = "-c";
333   for (j = 0; collect_gcc_options[j] != '\0'; ++j)
334     if (collect_gcc_options[j] == '\'')
335       {
336         char *option;
337
338         ++j;
339         i = j;
340         while (collect_gcc_options[j] != '\'')
341           ++j;
342
343         obstack_init (&env_obstack);
344         obstack_grow (&env_obstack, &collect_gcc_options[i], j - i);
345         obstack_1grow (&env_obstack, 0);
346         option = XOBFINISH (&env_obstack, char *);
347         if (seen_o)
348           {
349             linker_output = option;
350             seen_o = false;
351             continue;
352           }
353
354         /* If we see -o, skip it and skip and record its argument.  */
355         if (option[0] == '-' && option[1] == 'o')
356           {
357             if (option[2] == '\0')
358               seen_o = true;
359             else
360               linker_output = &option[2];
361             continue;
362           }
363
364         if (strcmp (option, "-save-temps") == 0)
365           debug = 1;
366         if (strcmp (option, "-v") == 0)
367           verbose = 1;
368
369         /* We've handled these LTO options, do not pass them on.  */
370         if (strcmp (option, "-flto") == 0)
371           lto_mode = LTO_MODE_LTO;
372         else if (strncmp (option, "-fwhopr", 7) == 0)
373           {
374             lto_mode = LTO_MODE_WHOPR;
375             if (option[7] == '=')
376               {
377                 if (!strcmp (option + 8, "jobserver"))
378                   {
379                     jobserver = 1;
380                     parallel = 1;
381                   }
382                 else
383                   {
384                     parallel = atoi (option+8);
385                     if (parallel <= 1)
386                       parallel = 0;
387                   }
388               }
389           }
390         else
391           *argv_ptr++ = option;
392       }
393
394   if (linker_output)
395     {
396       char *output_dir, *base, *name;
397
398       output_dir = xstrdup (linker_output);
399       base = output_dir;
400       for (name = base; *name; name++)
401         if (IS_DIR_SEPARATOR (*name))
402           base = name + 1;
403       *base = '\0';
404
405       linker_output = &linker_output[base - output_dir];
406       if (*output_dir == '\0')
407         {
408           static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
409           output_dir = current_dir;
410         }
411       *argv_ptr++ = "-dumpdir";
412       *argv_ptr++ = output_dir;
413
414       *argv_ptr++ = "-dumpbase";
415     }
416   else
417     argv_ptr--;
418
419   if (lto_mode == LTO_MODE_LTO)
420     {
421       flto_out = make_temp_file (".lto.o");
422       if (linker_output)
423         argv_ptr[0] = linker_output;
424       argv_ptr[1] = "-o";
425       argv_ptr[2] = flto_out;
426     }
427   else if (lto_mode == LTO_MODE_WHOPR)
428     {
429       const char *list_option = "-fltrans-output-list=";
430       size_t list_option_len = strlen (list_option);
431       char *tmp;
432
433       if (linker_output)
434         {
435           char *dumpbase = (char *) xmalloc (strlen (linker_output)
436                                              + sizeof (".wpa") + 1);
437           strcpy (dumpbase, linker_output);
438           strcat (dumpbase, ".wpa");
439           argv_ptr[0] = dumpbase;
440         }
441
442       if (linker_output && debug)
443         {
444           ltrans_output_file = (char *) xmalloc (strlen (linker_output)
445                                                  + sizeof (".ltrans.out") + 1);
446           strcpy (ltrans_output_file, linker_output);
447           strcat (ltrans_output_file, ".ltrans.out");
448         }
449       else
450         ltrans_output_file = make_temp_file (".ltrans.out");
451       list_option_full = (char *) xmalloc (sizeof (char) *
452                          (strlen (ltrans_output_file) + list_option_len + 1));
453       tmp = list_option_full;
454
455       argv_ptr[1] = tmp;
456       strcpy (tmp, list_option);
457       tmp += list_option_len;
458       strcpy (tmp, ltrans_output_file);
459
460       argv_ptr[2] = "-fwpa";
461     }
462   else
463     fatal ("invalid LTO mode");
464
465   /* Append the input objects and possible preceeding arguments.  */
466   for (i = 1; i < argc; ++i)
467     argv_ptr[2 + i] = argv[i];
468   argv_ptr[2 + i] = NULL;
469
470   fork_execute (CONST_CAST (char **, new_argv));
471
472   if (lto_mode == LTO_MODE_LTO)
473     {
474       printf("%s\n", flto_out);
475       free (flto_out);
476       flto_out = NULL;
477     }
478   else if (lto_mode == LTO_MODE_WHOPR)
479     {
480       FILE *stream = fopen (ltrans_output_file, "r");
481       FILE *mstream = NULL;
482
483       if (!stream)
484         fatal_perror ("fopen: %s", ltrans_output_file);
485
486       /* Parse the list of LTRANS inputs from the WPA stage.  */
487       nr = 0;
488       for (;;)
489         {
490           const unsigned piece = 32;
491           char *output_name = NULL;
492           char *buf, *input_name = (char *)xmalloc (piece);
493           size_t len;
494
495           buf = input_name;
496 cont:
497           if (!fgets (buf, piece, stream))
498             break;
499           len = strlen (input_name);
500           if (input_name[len - 1] != '\n')
501             {
502               input_name = (char *)xrealloc (input_name, len + piece);
503               buf = input_name + len;
504               goto cont;
505             }
506           input_name[len - 1] = '\0';
507
508           if (input_name[0] == '*')
509             output_name = &input_name[1];
510
511           nr++;
512           input_names = (char **)xrealloc (input_names, nr * sizeof (char *));
513           output_names = (char **)xrealloc (output_names, nr * sizeof (char *));
514           input_names[nr-1] = input_name;
515           output_names[nr-1] = output_name;
516         }
517       fclose (stream);
518       maybe_unlink_file (ltrans_output_file);
519       ltrans_output_file = NULL;
520
521       if (parallel)
522         {
523           makefile = make_temp_file (".mk");
524           mstream = fopen (makefile, "w");
525         }
526
527       /* Execute the LTRANS stage for each input file (or prepare a
528          makefile to invoke this in parallel).  */
529       for (i = 0; i < nr; ++i)
530         {
531           char *output_name;
532           char *input_name = input_names[i];
533           /* If it's a pass-through file do nothing.  */
534           if (output_names[i])
535             continue;
536
537           /* Replace the .o suffix with a .ltrans.o suffix and write
538              the resulting name to the LTRANS output list.  */
539           obstack_init (&env_obstack);
540           obstack_grow (&env_obstack, input_name, strlen (input_name) - 2);
541           obstack_grow (&env_obstack, ".ltrans.o", sizeof (".ltrans.o"));
542           output_name = XOBFINISH (&env_obstack, char *);
543
544           /* Adjust the dumpbase if the linker output file was seen.  */
545           if (linker_output)
546             {
547               char *dumpbase
548                   = (char *) xmalloc (strlen (linker_output)
549                                       + sizeof(DUMPBASE_SUFFIX) + 1);
550               snprintf (dumpbase,
551                         strlen (linker_output) + sizeof(DUMPBASE_SUFFIX),
552                         "%s.ltrans%u", linker_output, i);
553               argv_ptr[0] = dumpbase;
554             }
555
556           argv_ptr[1] = "-fltrans";
557           argv_ptr[2] = "-o";
558           argv_ptr[3] = output_name;
559           argv_ptr[4] = input_name;
560           argv_ptr[5] = NULL;
561           if (parallel)
562             {
563               fprintf (mstream, "%s:\n\t@%s ", output_name, new_argv[0]);
564               for (j = 1; new_argv[j] != NULL; ++j)
565                 fprintf (mstream, " '%s'", new_argv[j]);
566               fprintf (mstream, "\n");
567             }
568           else
569             fork_execute (CONST_CAST (char **, new_argv));
570
571           output_names[i] = output_name;
572         }
573       if (parallel)
574         {
575           struct pex_obj *pex;
576           char jobs[32];
577
578           fprintf (mstream, "all:");
579           for (i = 0; i < nr; ++i)
580             fprintf (mstream, " \\\n\t%s", output_names[i]);
581           fprintf (mstream, "\n");
582           fclose (mstream);
583           if (!jobserver)
584             {
585               /* Avoid passing --jobserver-fd= and similar flags 
586                  unless jobserver mode is explicitly enabled.  */
587               putenv (xstrdup ("MAKEFLAGS="));
588               putenv (xstrdup ("MFLAGS="));
589             }
590           new_argv[0] = getenv ("MAKE");
591           if (!new_argv[0])
592             new_argv[0] = "make";
593           new_argv[1] = "-f";
594           new_argv[2] = makefile;
595           i = 3;
596           if (!jobserver)
597             {
598               snprintf (jobs, 31, "-j%d", parallel);
599               new_argv[i++] = jobs;
600             }
601           new_argv[i++] = "all";
602           new_argv[i++] = NULL;
603           pex = collect_execute (CONST_CAST (char **, new_argv));
604           collect_wait (new_argv[0], pex);
605           maybe_unlink_file (makefile);
606           makefile = NULL;
607         }
608       for (i = 0; i < nr; ++i)
609         {
610           fputs (output_names[i], stdout);
611           putc ('\n', stdout);
612           maybe_unlink_file (input_names[i]);
613           free (input_names[i]);
614         }
615       nr = 0;
616       free (output_names);
617       free (input_names);
618       free (list_option_full);
619     }
620   else
621     fatal ("invalid LTO mode");
622
623   obstack_free (&env_obstack, NULL);
624 }
625
626
627 /* Entry point.  */
628
629 int
630 main (int argc, char *argv[])
631 {
632   gcc_init_libintl ();
633
634   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
635     signal (SIGINT, fatal_signal);
636 #ifdef SIGHUP
637   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
638     signal (SIGHUP, fatal_signal);
639 #endif
640   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
641     signal (SIGTERM, fatal_signal);
642 #ifdef SIGPIPE
643   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
644     signal (SIGPIPE, fatal_signal);
645 #endif
646 #ifdef SIGCHLD
647   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
648      receive the signal.  A different setting is inheritable */
649   signal (SIGCHLD, SIG_DFL);
650 #endif
651
652   /* We may be called with all the arguments stored in some file and
653      passed with @file.  Expand them into argv before processing.  */
654   expandargv (&argc, &argv);
655   run_gcc (argc, argv);
656
657   return 0;
658 }