OSDN Git Service

3dbd96b7cbcbbbf19dac563bf790158c0e90427c
[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 "tm.h"
44 #include "intl.h"
45 #include "libiberty.h"
46 #include "obstack.h"
47
48 int debug;                              /* true if -save-temps.  */
49 int verbose;                            /* true if -v.  */
50
51 enum lto_mode_d {
52   LTO_MODE_NONE,                        /* Not doing LTO.  */
53   LTO_MODE_LTO,                         /* Normal LTO.  */
54   LTO_MODE_WHOPR                        /* WHOPR.  */
55 };
56
57 /* Current LTO mode.  */
58 static enum lto_mode_d lto_mode = LTO_MODE_NONE;
59
60 static char *ltrans_output_file;
61 static char *flto_out;
62 static char *args_name;
63
64 static void maybe_unlink_file (const char *);
65
66 /* Delete tempfiles and exit function.  */
67
68 static void
69 lto_wrapper_exit (int status)
70 {
71   static bool cleanup_done = false;
72   if (!cleanup_done)
73     {
74       /* Setting cleanup_done prevents an infinite loop if one of the
75          calls to maybe_unlink_file fails. */
76       cleanup_done = true;
77
78       if (ltrans_output_file)
79         maybe_unlink_file (ltrans_output_file);
80       if (flto_out)
81         maybe_unlink_file (flto_out);
82       if (args_name)
83         maybe_unlink_file (args_name);
84     }
85   exit (status);
86 }
87
88 /* Just die. CMSGID is the error message. */
89
90 static void __attribute__ ((format (printf, 1, 2)))
91 fatal (const char * cmsgid, ...)
92 {
93   va_list ap;
94
95   va_start (ap, cmsgid);
96   fprintf (stderr, "lto-wrapper: ");
97   vfprintf (stderr, _(cmsgid), ap);
98   fprintf (stderr, "\n");
99   va_end (ap);
100
101   lto_wrapper_exit (FATAL_EXIT_CODE);
102 }
103
104
105 /* Die when sys call fails. CMSGID is the error message.  */
106
107 static void __attribute__ ((format (printf, 1, 2)))
108 fatal_perror (const char *cmsgid, ...)
109 {
110   int e = errno;
111   va_list ap;
112
113   va_start (ap, cmsgid);
114   fprintf (stderr, "lto-wrapper: ");
115   vfprintf (stderr, _(cmsgid), ap);
116   fprintf (stderr, ": %s\n", xstrerror (e));
117   va_end (ap);
118
119   lto_wrapper_exit (FATAL_EXIT_CODE);
120 }
121
122
123 /* Execute a program, and wait for the reply. ARGV are the arguments. The
124    last one must be NULL. */
125
126 static struct pex_obj *
127 collect_execute (char **argv)
128 {
129   struct pex_obj *pex;
130   const char *errmsg;
131   int err;
132
133   if (verbose)
134     {
135       char **p_argv;
136       const char *str;
137
138       for (p_argv = argv; (str = *p_argv) != (char *) 0; p_argv++)
139         fprintf (stderr, " %s", str);
140
141       fprintf (stderr, "\n");
142     }
143
144   fflush (stdout);
145   fflush (stderr);
146
147   pex = pex_init (0, "lto-wrapper", NULL);
148   if (pex == NULL)
149     fatal_perror ("pex_init failed");
150
151   /* Do not use PEX_LAST here, we use our stdout for communicating with
152      collect2 or the linker-plugin.  Any output from the sub-process
153      will confuse that.  */
154   errmsg = pex_run (pex, PEX_SEARCH, argv[0], argv, NULL,
155                     NULL, &err);
156   if (errmsg != NULL)
157     {
158       if (err != 0)
159         {
160           errno = err;
161           fatal_perror (errmsg);
162         }
163       else
164         fatal (errmsg);
165     }
166
167   return pex;
168 }
169
170
171 /* Wait for a process to finish, and exit if a nonzero status is found.
172    PROG is the program name. PEX is the process we should wait for. */
173
174 static int
175 collect_wait (const char *prog, struct pex_obj *pex)
176 {
177   int status;
178
179   if (!pex_get_status (pex, 1, &status))
180     fatal_perror ("can't get program status");
181   pex_free (pex);
182
183   if (status)
184     {
185       if (WIFSIGNALED (status))
186         {
187           int sig = WTERMSIG (status);
188           if (WCOREDUMP (status))
189             fatal ("%s terminated with signal %d [%s], core dumped",
190                    prog, sig, strsignal (sig));
191           else
192             fatal ("%s terminated with signal %d [%s]",
193                    prog, sig, strsignal (sig));
194         }
195
196       if (WIFEXITED (status))
197         fatal ("%s returned %d exit status", prog, WEXITSTATUS (status));
198     }
199
200   return 0;
201 }
202
203
204 /* Unlink a temporary LTRANS file unless requested otherwise.  */
205
206 static void
207 maybe_unlink_file (const char *file)
208 {
209   if (! debug)
210     {
211       if (unlink_if_ordinary (file))
212         fatal_perror ("deleting LTRANS file %s", file);
213     }
214   else
215     fprintf (stderr, "[Leaving LTRANS %s]\n", file);
216 }
217
218
219 /* Execute program ARGV[0] with arguments ARGV. Wait for it to finish.  */
220
221 static void
222 fork_execute (char **argv)
223 {
224   struct pex_obj *pex;
225   char *new_argv[3];
226   char *at_args;
227   FILE *args;
228   int status;
229
230   args_name = make_temp_file (".args");
231   at_args = concat ("@", args_name, NULL);
232   args = fopen (args_name, "w");
233   if (args == NULL)
234     fatal ("failed to open %s", args_name);
235
236   status = writeargv (&argv[1], args);
237
238   if (status)
239     fatal ("could not write to temporary file %s",  args_name);
240
241   fclose (args);
242
243   new_argv[0] = argv[0];
244   new_argv[1] = at_args;
245   new_argv[2] = NULL;
246
247   pex = collect_execute (new_argv);
248   collect_wait (new_argv[0], pex);
249
250   maybe_unlink_file (args_name);
251   free (at_args);
252 }
253
254 /* Template of LTRANS dumpbase suffix.  */
255 #define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
256
257 /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
258
259 static void
260 run_gcc (unsigned argc, char *argv[])
261 {
262   unsigned i, j;
263   const char **new_argv;
264   const char **argv_ptr;
265   char *list_option_full = NULL;
266   const char *linker_output = NULL;
267   const char *collect_gcc_options, *collect_gcc;
268   struct obstack env_obstack;
269   bool seen_o = false;
270   int parallel = 0;
271
272   /* Get the driver and options.  */
273   collect_gcc = getenv ("COLLECT_GCC");
274   if (!collect_gcc)
275     fatal ("environment variable COLLECT_GCC must be set");
276
277   /* Set the CFLAGS environment variable.  */
278   collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
279   if (!collect_gcc_options)
280     fatal ("environment variable COLLECT_GCC_OPTIONS must be set");
281
282   /* Count arguments.  */
283   i = 0;
284   for (j = 0; collect_gcc_options[j] != '\0'; ++j)
285     if (collect_gcc_options[j] == '\'')
286       ++i;
287
288   if (i % 2 != 0)
289     fatal ("malformed COLLECT_GCC_OPTIONS");
290
291   /* Initalize the common arguments for the driver.  */
292   new_argv = (const char **) xmalloc ((15 + i / 2 + argc) * sizeof (char *));
293   argv_ptr = new_argv;
294   *argv_ptr++ = collect_gcc;
295   *argv_ptr++ = "-xlto";
296   *argv_ptr++ = "-c";
297   for (j = 0; collect_gcc_options[j] != '\0'; ++j)
298     if (collect_gcc_options[j] == '\'')
299       {
300         char *option;
301
302         ++j;
303         i = j;
304         while (collect_gcc_options[j] != '\'')
305           ++j;
306
307         obstack_init (&env_obstack);
308         obstack_grow (&env_obstack, &collect_gcc_options[i], j - i);
309         obstack_1grow (&env_obstack, 0);
310         option = XOBFINISH (&env_obstack, char *);
311         if (seen_o)
312           {
313             linker_output = option;
314             seen_o = false;
315             continue;
316           }
317
318         /* If we see -o, skip it and skip and record its argument.  */
319         if (option[0] == '-' && option[1] == 'o')
320           {
321             if (option[2] == '\0')
322               seen_o = true;
323             else
324               linker_output = &option[2];
325             continue;
326           }
327
328         if (strcmp (option, "-save-temps") == 0)
329           debug = 1;
330         if (strcmp (option, "-v") == 0)
331           verbose = 1;
332
333         /* We've handled these LTO options, do not pass them on.  */
334         if (strcmp (option, "-flto") == 0)
335           lto_mode = LTO_MODE_LTO;
336         else if (strncmp (option, "-fwhopr", 7) == 0)
337           {
338             lto_mode = LTO_MODE_WHOPR;
339             if (option[7] == '=')
340               {
341                 parallel = atoi (option+8);
342                 if (parallel <= 1)
343                   parallel = 0;
344               }
345           }
346         else
347           *argv_ptr++ = option;
348       }
349
350   if (linker_output)
351     {
352       char *output_dir, *base, *name;
353
354       output_dir = xstrdup (linker_output);
355       base = output_dir;
356       for (name = base; *name; name++)
357         if (IS_DIR_SEPARATOR (*name))
358           base = name + 1;
359       *base = '\0';
360
361       linker_output = &linker_output[base - output_dir];
362       if (*output_dir == '\0')
363         {
364           static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
365           output_dir = current_dir;
366         }
367       *argv_ptr++ = "-dumpdir";
368       *argv_ptr++ = output_dir;
369
370       *argv_ptr++ = "-dumpbase";
371     }
372   else
373     argv_ptr--;
374
375   if (lto_mode == LTO_MODE_LTO)
376     {
377       flto_out = make_temp_file (".lto.o");
378       if (linker_output)
379         argv_ptr[0] = linker_output;
380       argv_ptr[1] = "-o";
381       argv_ptr[2] = flto_out;
382       argv_ptr[3] = "-combine";
383     }
384   else if (lto_mode == LTO_MODE_WHOPR)
385     {
386       const char *list_option = "-fltrans-output-list=";
387       size_t list_option_len = strlen (list_option);
388       char *tmp;
389
390       if (linker_output)
391         {
392           char *dumpbase = (char *) xmalloc (strlen (linker_output)
393                                              + sizeof(".wpa") + 1);
394           strcpy (dumpbase, linker_output);
395           strcat (dumpbase, ".wpa");
396           argv_ptr[0] = dumpbase;
397         }
398
399       ltrans_output_file = make_temp_file (".ltrans.out");
400       list_option_full = (char *) xmalloc (sizeof (char) *
401                          (strlen (ltrans_output_file) + list_option_len + 1));
402       tmp = list_option_full;
403
404       argv_ptr[1] = tmp;
405       strcpy (tmp, list_option);
406       tmp += list_option_len;
407       strcpy (tmp, ltrans_output_file);
408
409       argv_ptr[2] = "-fwpa";
410       argv_ptr[3] = "-combine";
411     }
412   else
413     fatal ("invalid LTO mode");
414
415   /* Append the input objects and possible preceeding arguments.  */
416   for (i = 1; i < argc; ++i)
417     argv_ptr[3 + i] = argv[i];
418   argv_ptr[3 + i] = NULL;
419
420   fork_execute (CONST_CAST (char **, new_argv));
421
422   if (lto_mode == LTO_MODE_LTO)
423     {
424       printf("%s\n", flto_out);
425       free (flto_out);
426       flto_out = NULL;
427     }
428   else if (lto_mode == LTO_MODE_WHOPR)
429     {
430       FILE *stream = fopen (ltrans_output_file, "r");
431       unsigned int nr = 0;
432       char **input_names = NULL;
433       char **output_names = NULL;
434       char *makefile = NULL;
435       FILE *mstream = NULL;
436
437       if (!stream)
438         fatal_perror ("fopen: %s", ltrans_output_file);
439
440       argv_ptr[1] = "-fltrans";
441
442       if (parallel)
443         {
444           makefile = make_temp_file (".mk");
445           mstream = fopen (makefile, "w");
446         }
447
448       for (;;)
449         {
450           const unsigned piece = 32;
451           char *output_name;
452           char *buf, *input_name = (char *)xmalloc (piece);
453           size_t len;
454
455           buf = input_name;
456 cont:
457           if (!fgets (buf, piece, stream))
458             break;
459           len = strlen (input_name);
460           if (input_name[len - 1] != '\n')
461             {
462               input_name = (char *)xrealloc (input_name, len + piece);
463               buf = input_name + len;
464               goto cont;
465             }
466           input_name[len - 1] = '\0';
467
468           if (input_name[0] == '*')
469             output_name = &input_name[1];
470           else
471             {
472               /* Otherwise, add FILES[I] to lto_execute_ltrans command line
473                  and add the resulting file to LTRANS output list.  */
474
475               /* Replace the .o suffix with a .ltrans.o suffix and write
476                  the resulting name to the LTRANS output list.  */
477               obstack_init (&env_obstack);
478               obstack_grow (&env_obstack, input_name, strlen (input_name) - 2);
479               obstack_grow (&env_obstack, ".ltrans.o", sizeof (".ltrans.o"));
480               output_name = XOBFINISH (&env_obstack, char *);
481
482               if (linker_output)
483                 {
484                   char *dumpbase
485                     = (char *) xmalloc (strlen (linker_output)
486                                         + sizeof(DUMPBASE_SUFFIX) + 1);
487                   snprintf (dumpbase,
488                             strlen (linker_output) + sizeof(DUMPBASE_SUFFIX),
489                             "%s.ltrans%u", linker_output, nr);
490                   argv_ptr[0] = dumpbase;
491                 }
492
493               argv_ptr[2] = "-o";
494               argv_ptr[3] = output_name;
495               argv_ptr[4] = input_name;
496               argv_ptr[5] = NULL;
497
498               if (parallel)
499                 {
500                   fprintf (mstream, "%s:\n\t@%s ", output_name, new_argv[0]);
501                   for (i = 1; new_argv[i] != NULL; ++i)
502                     fprintf (mstream, " '%s'", new_argv[i]);
503                   fprintf (mstream, "\n");
504                 }
505               else
506                 fork_execute (CONST_CAST (char **, new_argv));
507             }
508
509           nr++;
510           input_names = (char **)xrealloc (input_names, nr * sizeof (char *));
511           output_names = (char **)xrealloc (output_names, nr * sizeof (char *));
512           input_names[nr-1] = input_name;
513           output_names[nr-1] = output_name;
514         }
515       if (parallel)
516         {
517           struct pex_obj *pex;
518           char jobs[32];
519           fprintf (mstream, "all:");
520           for (i = 0; i < nr; ++i)
521             fprintf (mstream, " \\\n\t%s", output_names[i]);
522           fprintf (mstream, "\n");
523           fclose (mstream);
524           new_argv[0] = "make";
525           new_argv[1] = "-f";
526           new_argv[2] = makefile;
527           snprintf (jobs, 31, "-j%d", parallel);
528           new_argv[3] = jobs;
529           new_argv[4] = "all";
530           new_argv[5] = NULL;
531           pex = collect_execute (CONST_CAST (char **, new_argv));
532           collect_wait (new_argv[0], pex);
533           maybe_unlink_file (makefile);
534         }
535       for (i = 0; i < nr; ++i)
536         {
537           fputs (output_names[i], stdout);
538           putc ('\n', stdout);
539           maybe_unlink_file (input_names[i]);
540           free (input_names[i]);
541         }
542       free (output_names);
543       free (input_names);
544       fclose (stream);
545       maybe_unlink_file (ltrans_output_file);
546       free (list_option_full);
547     }
548   else
549     fatal ("invalid LTO mode");
550
551   obstack_free (&env_obstack, NULL);
552 }
553
554
555 /* Entry point.  */
556
557 int
558 main (int argc, char *argv[])
559 {
560   gcc_init_libintl ();
561
562   /* We may be called with all the arguments stored in some file and
563      passed with @file.  Expand them into argv before processing.  */
564   expandargv (&argc, &argv);
565   run_gcc (argc, argv);
566
567   return 0;
568 }