OSDN Git Service

2010-04-30 Richard Guenther <rguenther@suse.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 "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   errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, NULL,
152                     NULL, &err);
153   if (errmsg != NULL)
154     {
155       if (err != 0)
156         {
157           errno = err;
158           fatal_perror (errmsg);
159         }
160       else
161         fatal (errmsg);
162     }
163
164   return pex;
165 }
166
167
168 /* Wait for a process to finish, and exit if a nonzero status is found.
169    PROG is the program name. PEX is the process we should wait for. */
170
171 static int
172 collect_wait (const char *prog, struct pex_obj *pex)
173 {
174   int status;
175
176   if (!pex_get_status (pex, 1, &status))
177     fatal_perror ("can't get program status");
178   pex_free (pex);
179
180   if (status)
181     {
182       if (WIFSIGNALED (status))
183         {
184           int sig = WTERMSIG (status);
185           if (WCOREDUMP (status))
186             fatal ("%s terminated with signal %d [%s], core dumped",
187                    prog, sig, strsignal (sig));
188           else
189             fatal ("%s terminated with signal %d [%s]",
190                    prog, sig, strsignal (sig));
191         }
192
193       if (WIFEXITED (status))
194         fatal ("%s returned %d exit status", prog, WEXITSTATUS (status));
195     }
196
197   return 0;
198 }
199
200
201 /* Unlink a temporary LTRANS file unless requested otherwise.  */
202
203 static void
204 maybe_unlink_file (const char *file)
205 {
206   if (! debug)
207     {
208       if (unlink_if_ordinary (file))
209         fatal_perror ("deleting LTRANS file %s", file);
210     }
211   else
212     fprintf (stderr, "[Leaving LTRANS %s]\n", file);
213 }
214
215
216 /* Execute program ARGV[0] with arguments ARGV. Wait for it to finish.  */
217
218 static void
219 fork_execute (char **argv)
220 {
221   struct pex_obj *pex;
222   char *new_argv[3];
223   char *at_args;
224   FILE *args;
225   int status;
226
227   args_name = make_temp_file (".args");
228   at_args = concat ("@", args_name, NULL);
229   args = fopen (args_name, "w");
230   if (args == NULL)
231     fatal ("failed to open %s", args_name);
232
233   status = writeargv (&argv[1], args);
234
235   if (status)
236     fatal ("could not write to temporary file %s",  args_name);
237
238   fclose (args);
239
240   new_argv[0] = argv[0];
241   new_argv[1] = at_args;
242   new_argv[2] = NULL;
243
244   pex = collect_execute (new_argv);
245   collect_wait (new_argv[0], pex);
246
247   maybe_unlink_file (args_name);
248   free (at_args);
249 }
250
251 /* Template of LTRANS dumpbase suffix.  */
252 #define DUMPBASE_SUFFIX ".ltrans18446744073709551615"
253
254 /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
255
256 static void
257 run_gcc (unsigned argc, char *argv[])
258 {
259   unsigned i, j;
260   const char **new_argv;
261   const char **argv_ptr;
262   char *list_option_full = NULL;
263   const char *linker_output = NULL;
264   const char *collect_gcc_options, *collect_gcc;
265   struct obstack env_obstack;
266   bool seen_o = false;
267
268   /* Get the driver and options.  */
269   collect_gcc = getenv ("COLLECT_GCC");
270   if (!collect_gcc)
271     fatal ("environment variable COLLECT_GCC must be set");
272
273   /* Set the CFLAGS environment variable.  */
274   collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS");
275   if (!collect_gcc_options)
276     fatal ("environment variable COLLECT_GCC_OPTIONS must be set");
277
278   /* Count arguments.  */
279   i = 0;
280   for (j = 0; collect_gcc_options[j] != '\0'; ++j)
281     if (collect_gcc_options[j] == '\'')
282       ++i;
283
284   if (i % 2 != 0)
285     fatal ("malformed COLLECT_GCC_OPTIONS");
286
287   /* Initalize the common arguments for the driver.  */
288   new_argv = (const char **) xmalloc ((15 + i / 2 + argc) * sizeof (char *));
289   argv_ptr = new_argv;
290   *argv_ptr++ = collect_gcc;
291   *argv_ptr++ = "-xlto";
292   *argv_ptr++ = "-c";
293   for (j = 0; collect_gcc_options[j] != '\0'; ++j)
294     if (collect_gcc_options[j] == '\'')
295       {
296         char *option;
297
298         ++j;
299         i = j;
300         while (collect_gcc_options[j] != '\'')
301           ++j;
302
303         obstack_init (&env_obstack);
304         obstack_grow (&env_obstack, &collect_gcc_options[i], j - i);
305         obstack_1grow (&env_obstack, 0);
306         option = XOBFINISH (&env_obstack, char *);
307         if (seen_o)
308           {
309             linker_output = option;
310             seen_o = false;
311             continue;
312           }
313
314         /* If we see -o, skip it and skip and record its argument.  */
315         if (option[0] == '-' && option[1] == 'o')
316           {
317             if (option[2] == '\0')
318               seen_o = true;
319             else
320               linker_output = &option[2];
321             continue;
322           }
323
324         if (strcmp (option, "-save-temps") == 0)
325           debug = 1;
326         if (strcmp (option, "-v") == 0)
327           verbose = 1;
328
329         /* We've handled these LTO options, do not pass them on.  */
330         if (strcmp (option, "-flto") == 0)
331           lto_mode = LTO_MODE_LTO;
332         else if (strcmp (option, "-fwhopr") == 0)
333           lto_mode = LTO_MODE_WHOPR;
334         else
335           *argv_ptr++ = option;
336       }
337
338   if (linker_output)
339     {
340       char *output_dir, *base, *name;
341
342       output_dir = xstrdup (linker_output);
343       base = output_dir;
344       for (name = base; *name; name++)
345         if (IS_DIR_SEPARATOR (*name))
346           base = name + 1;
347       *base = '\0';
348
349       linker_output = &linker_output[base - output_dir];
350       if (*output_dir == '\0')
351         {
352           static char current_dir[] = { '.', DIR_SEPARATOR, '\0' };
353           output_dir = current_dir;
354         }
355       *argv_ptr++ = "-dumpdir";
356       *argv_ptr++ = output_dir;
357
358       *argv_ptr++ = "-dumpbase";
359     }
360   else
361     argv_ptr--;
362
363   if (lto_mode == LTO_MODE_LTO)
364     {
365       flto_out = make_temp_file (".lto.o");
366       if (linker_output)
367         argv_ptr[0] = linker_output;
368       argv_ptr[1] = "-o";
369       argv_ptr[2] = flto_out;
370       argv_ptr[3] = "-combine";
371     }
372   else if (lto_mode == LTO_MODE_WHOPR)
373     {
374       const char *list_option = "-fltrans-output-list=";
375       size_t list_option_len = strlen (list_option);
376       char *tmp;
377
378       if (linker_output)
379         {
380           char *dumpbase = (char *) xmalloc (strlen (linker_output)
381                                              + sizeof(".wpa") + 1);
382           strcpy (dumpbase, linker_output);
383           strcat (dumpbase, ".wpa");
384           argv_ptr[0] = dumpbase;
385         }
386
387       ltrans_output_file = make_temp_file (".ltrans.out");
388       list_option_full = (char *) xmalloc (sizeof (char) *
389                          (strlen (ltrans_output_file) + list_option_len + 1));
390       tmp = list_option_full;
391
392       argv_ptr[1] = tmp;
393       strcpy (tmp, list_option);
394       tmp += list_option_len;
395       strcpy (tmp, ltrans_output_file);
396
397       argv_ptr[2] = "-fwpa";
398       argv_ptr[3] = "-combine";
399     }
400   else
401     fatal ("invalid LTO mode");
402
403   /* Append the input objects and possible preceeding arguments.  */
404   for (i = 1; i < argc; ++i)
405     argv_ptr[3 + i] = argv[i];
406   argv_ptr[3 + i] = NULL;
407
408   fork_execute (CONST_CAST (char **, new_argv));
409
410   if (lto_mode == LTO_MODE_LTO)
411     {
412       printf("%s\n", flto_out);
413       free (flto_out);
414       flto_out = NULL;
415     }
416   else if (lto_mode == LTO_MODE_WHOPR)
417     {
418       FILE *stream = fopen (ltrans_output_file, "r");
419       int nr = 0;
420
421       if (!stream)
422         fatal_perror ("fopen: %s", ltrans_output_file);
423
424       argv_ptr[1] = "-fltrans";
425
426       for (;;)
427         {
428           const unsigned piece = 32;
429           char *output_name;
430           char *buf, *input_name = (char *)xmalloc (piece);
431           size_t len;
432
433           buf = input_name;
434 cont:
435           if (!fgets (buf, piece, stream))
436             break;
437           len = strlen (input_name);
438           if (input_name[len - 1] != '\n')
439             {
440               input_name = (char *)xrealloc (input_name, len + piece);
441               buf = input_name + len;
442               goto cont;
443             }
444           input_name[len - 1] = '\0';
445
446           if (input_name[0] == '*')
447             {
448               continue;
449               output_name = &input_name[1];
450             }
451           else
452             {
453               /* Otherwise, add FILES[I] to lto_execute_ltrans command line
454                  and add the resulting file to LTRANS output list.  */
455
456               /* Replace the .o suffix with a .ltrans.o suffix and write
457                  the resulting name to the LTRANS output list.  */
458               obstack_init (&env_obstack);
459               obstack_grow (&env_obstack, input_name, strlen (input_name) - 2);
460               obstack_grow (&env_obstack, ".ltrans.o", sizeof (".ltrans.o"));
461               output_name = XOBFINISH (&env_obstack, char *);
462
463               if (linker_output)
464                 {
465                   char *dumpbase
466                     = (char *) xmalloc (strlen (linker_output)
467                                         + sizeof(DUMPBASE_SUFFIX) + 1);
468                   snprintf (dumpbase,
469                             strlen (linker_output) + sizeof(DUMPBASE_SUFFIX),
470                             "%s.ltrans%d", linker_output, nr++);
471                   argv_ptr[0] = dumpbase;
472                 }
473
474               argv_ptr[2] = "-o";
475               argv_ptr[3] = output_name;
476               argv_ptr[4] = input_name;
477               argv_ptr[5] = NULL;
478
479               fork_execute (CONST_CAST (char **, new_argv));
480
481               maybe_unlink_file (input_name);
482             }
483
484           fputs (output_name, stdout);
485           putc ('\n', stdout);
486         }
487       fclose (stream);
488       maybe_unlink_file (ltrans_output_file);
489       free (list_option_full);
490     }
491   else
492     fatal ("invalid LTO mode");
493
494   obstack_free (&env_obstack, NULL);
495 }
496
497
498 /* Entry point.  */
499
500 int
501 main (int argc, char *argv[])
502 {
503   gcc_init_libintl ();
504
505   /* We may be called with all the arguments stored in some file and
506      passed with @file.  Expand them into argv before processing.  */
507   expandargv (&argc, &argv);
508   run_gcc (argc, argv);
509
510   return 0;
511 }