OSDN Git Service

2010-07-29 Tobias Burnus <burnus@net-b.de>
[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
307   /* Get the driver and options.  */
308   collect_gcc = getenv ("COLLECT_GCC");
309   if (!collect_gcc)
310     fatal ("environment variable COLLECT_GCC must be set");
311
312   /* Set the CFLAGS environment variable.  */
313   collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
314   if (!collect_gcc_options)
315     fatal ("environment variable COLLECT_GCC_OPTIONS must be set");
316
317   /* Count arguments.  */
318   i = 0;
319   for (j = 0; collect_gcc_options[j] != '\0'; ++j)
320     if (collect_gcc_options[j] == '\'')
321       ++i;
322
323   if (i % 2 != 0)
324     fatal ("malformed COLLECT_GCC_OPTIONS");
325
326   /* Initalize the common arguments for the driver.  */
327   new_argv = (const char **) xmalloc ((15 + i / 2 + argc) * sizeof (char *));
328   argv_ptr = new_argv;
329   *argv_ptr++ = collect_gcc;
330   *argv_ptr++ = "-xlto";
331   *argv_ptr++ = "-c";
332   for (j = 0; collect_gcc_options[j] != '\0'; ++j)
333     if (collect_gcc_options[j] == '\'')
334       {
335         char *option;
336
337         ++j;
338         i = j;
339         while (collect_gcc_options[j] != '\'')
340           ++j;
341
342         obstack_init (&env_obstack);
343         obstack_grow (&env_obstack, &collect_gcc_options[i], j - i);
344         obstack_1grow (&env_obstack, 0);
345         option = XOBFINISH (&env_obstack, char *);
346         if (seen_o)
347           {
348             linker_output = option;
349             seen_o = false;
350             continue;
351           }
352
353         /* If we see -o, skip it and skip and record its argument.  */
354         if (option[0] == '-' && option[1] == 'o')
355           {
356             if (option[2] == '\0')
357               seen_o = true;
358             else
359               linker_output = &option[2];
360             continue;
361           }
362
363         if (strcmp (option, "-save-temps") == 0)
364           debug = 1;
365         if (strcmp (option, "-v") == 0)
366           verbose = 1;
367
368         /* We've handled these LTO options, do not pass them on.  */
369         if (strcmp (option, "-flto") == 0)
370           lto_mode = LTO_MODE_LTO;
371         else if (strncmp (option, "-fwhopr", 7) == 0)
372           {
373             lto_mode = LTO_MODE_WHOPR;
374             if (option[7] == '=')
375               {
376                 parallel = atoi (option+8);
377                 if (parallel <= 1)
378                   parallel = 0;
379               }
380           }
381         else
382           *argv_ptr++ = option;
383       }
384
385   if (linker_output)
386     {
387       char *output_dir, *base, *name;
388
389       output_dir = xstrdup (linker_output);
390       base = output_dir;
391       for (name = base; *name; name++)
392         if (IS_DIR_SEPARATOR (*name))
393           base = name + 1;
394       *base = '\0';
395
396       linker_output = &linker_output[base - output_dir];
397       if (*output_dir == '\0')
398         {
399           static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
400           output_dir = current_dir;
401         }
402       *argv_ptr++ = "-dumpdir";
403       *argv_ptr++ = output_dir;
404
405       *argv_ptr++ = "-dumpbase";
406     }
407   else
408     argv_ptr--;
409
410   if (lto_mode == LTO_MODE_LTO)
411     {
412       flto_out = make_temp_file (".lto.o");
413       if (linker_output)
414         argv_ptr[0] = linker_output;
415       argv_ptr[1] = "-o";
416       argv_ptr[2] = flto_out;
417       argv_ptr[3] = "-combine";
418     }
419   else if (lto_mode == LTO_MODE_WHOPR)
420     {
421       const char *list_option = "-fltrans-output-list=";
422       size_t list_option_len = strlen (list_option);
423       char *tmp;
424
425       if (linker_output)
426         {
427           char *dumpbase = (char *) xmalloc (strlen (linker_output)
428                                              + sizeof (".wpa") + 1);
429           strcpy (dumpbase, linker_output);
430           strcat (dumpbase, ".wpa");
431           argv_ptr[0] = dumpbase;
432         }
433
434       if (linker_output && debug)
435         {
436           ltrans_output_file = (char *) xmalloc (strlen (linker_output)
437                                                  + sizeof (".ltrans.out") + 1);
438           strcpy (ltrans_output_file, linker_output);
439           strcat (ltrans_output_file, ".ltrans.out");
440         }
441       else
442         ltrans_output_file = make_temp_file (".ltrans.out");
443       list_option_full = (char *) xmalloc (sizeof (char) *
444                          (strlen (ltrans_output_file) + list_option_len + 1));
445       tmp = list_option_full;
446
447       argv_ptr[1] = tmp;
448       strcpy (tmp, list_option);
449       tmp += list_option_len;
450       strcpy (tmp, ltrans_output_file);
451
452       argv_ptr[2] = "-fwpa";
453       argv_ptr[3] = "-combine";
454     }
455   else
456     fatal ("invalid LTO mode");
457
458   /* Append the input objects and possible preceeding arguments.  */
459   for (i = 1; i < argc; ++i)
460     argv_ptr[3 + i] = argv[i];
461   argv_ptr[3 + i] = NULL;
462
463   fork_execute (CONST_CAST (char **, new_argv));
464
465   if (lto_mode == LTO_MODE_LTO)
466     {
467       printf("%s\n", flto_out);
468       free (flto_out);
469       flto_out = NULL;
470     }
471   else if (lto_mode == LTO_MODE_WHOPR)
472     {
473       FILE *stream = fopen (ltrans_output_file, "r");
474       FILE *mstream = NULL;
475
476       if (!stream)
477         fatal_perror ("fopen: %s", ltrans_output_file);
478
479       /* Parse the list of LTRANS inputs from the WPA stage.  */
480       nr = 0;
481       for (;;)
482         {
483           const unsigned piece = 32;
484           char *output_name = NULL;
485           char *buf, *input_name = (char *)xmalloc (piece);
486           size_t len;
487
488           buf = input_name;
489 cont:
490           if (!fgets (buf, piece, stream))
491             break;
492           len = strlen (input_name);
493           if (input_name[len - 1] != '\n')
494             {
495               input_name = (char *)xrealloc (input_name, len + piece);
496               buf = input_name + len;
497               goto cont;
498             }
499           input_name[len - 1] = '\0';
500
501           if (input_name[0] == '*')
502             output_name = &input_name[1];
503
504           nr++;
505           input_names = (char **)xrealloc (input_names, nr * sizeof (char *));
506           output_names = (char **)xrealloc (output_names, nr * sizeof (char *));
507           input_names[nr-1] = input_name;
508           output_names[nr-1] = output_name;
509         }
510       fclose (stream);
511       maybe_unlink_file (ltrans_output_file);
512       ltrans_output_file = NULL;
513
514       if (parallel)
515         {
516           makefile = make_temp_file (".mk");
517           mstream = fopen (makefile, "w");
518         }
519
520       /* Execute the LTRANS stage for each input file (or prepare a
521          makefile to invoke this in parallel).  */
522       for (i = 0; i < nr; ++i)
523         {
524           char *output_name;
525           char *input_name = input_names[i];
526           /* If it's a pass-through file do nothing.  */
527           if (output_names[i])
528             continue;
529
530           /* Replace the .o suffix with a .ltrans.o suffix and write
531              the resulting name to the LTRANS output list.  */
532           obstack_init (&env_obstack);
533           obstack_grow (&env_obstack, input_name, strlen (input_name) - 2);
534           obstack_grow (&env_obstack, ".ltrans.o", sizeof (".ltrans.o"));
535           output_name = XOBFINISH (&env_obstack, char *);
536
537           /* Adjust the dumpbase if the linker output file was seen.  */
538           if (linker_output)
539             {
540               char *dumpbase
541                   = (char *) xmalloc (strlen (linker_output)
542                                       + sizeof(DUMPBASE_SUFFIX) + 1);
543               snprintf (dumpbase,
544                         strlen (linker_output) + sizeof(DUMPBASE_SUFFIX),
545                         "%s.ltrans%u", linker_output, i);
546               argv_ptr[0] = dumpbase;
547             }
548
549           argv_ptr[1] = "-fltrans";
550           argv_ptr[2] = "-o";
551           argv_ptr[3] = output_name;
552           argv_ptr[4] = input_name;
553           argv_ptr[5] = NULL;
554           if (parallel)
555             {
556               fprintf (mstream, "%s:\n\t@%s ", output_name, new_argv[0]);
557               for (j = 1; new_argv[j] != NULL; ++j)
558                 fprintf (mstream, " '%s'", new_argv[j]);
559               fprintf (mstream, "\n");
560             }
561           else
562             fork_execute (CONST_CAST (char **, new_argv));
563
564           output_names[i] = output_name;
565         }
566       if (parallel)
567         {
568           struct pex_obj *pex;
569           char jobs[32];
570           fprintf (mstream, "all:");
571           for (i = 0; i < nr; ++i)
572             fprintf (mstream, " \\\n\t%s", output_names[i]);
573           fprintf (mstream, "\n");
574           fclose (mstream);
575           /* Avoid passing --jobserver-fd= and similar flags.  */
576           putenv (xstrdup ("MAKEFLAGS="));
577           putenv (xstrdup ("MFLAGS="));
578           new_argv[0] = getenv ("MAKE");
579           if (!new_argv[0])
580             new_argv[0] = "make";
581           new_argv[1] = "-f";
582           new_argv[2] = makefile;
583           snprintf (jobs, 31, "-j%d", parallel);
584           new_argv[3] = jobs;
585           new_argv[4] = "all";
586           new_argv[5] = NULL;
587           pex = collect_execute (CONST_CAST (char **, new_argv));
588           collect_wait (new_argv[0], pex);
589           maybe_unlink_file (makefile);
590           makefile = NULL;
591         }
592       for (i = 0; i < nr; ++i)
593         {
594           fputs (output_names[i], stdout);
595           putc ('\n', stdout);
596           maybe_unlink_file (input_names[i]);
597           free (input_names[i]);
598         }
599       nr = 0;
600       free (output_names);
601       free (input_names);
602       free (list_option_full);
603     }
604   else
605     fatal ("invalid LTO mode");
606
607   obstack_free (&env_obstack, NULL);
608 }
609
610
611 /* Entry point.  */
612
613 int
614 main (int argc, char *argv[])
615 {
616   gcc_init_libintl ();
617
618   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
619     signal (SIGINT, fatal_signal);
620 #ifdef SIGHUP
621   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
622     signal (SIGHUP, fatal_signal);
623 #endif
624   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
625     signal (SIGTERM, fatal_signal);
626 #ifdef SIGPIPE
627   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
628     signal (SIGPIPE, fatal_signal);
629 #endif
630 #ifdef SIGCHLD
631   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
632      receive the signal.  A different setting is inheritable */
633   signal (SIGCHLD, SIG_DFL);
634 #endif
635
636   /* We may be called with all the arguments stored in some file and
637      passed with @file.  Expand them into argv before processing.  */
638   expandargv (&argc, &argv);
639   run_gcc (argc, argv);
640
641   return 0;
642 }