OSDN Git Service

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