Mercurial > hg > CbC > CbC_gcc
comparison gcc/lto-wrapper.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | 77e2b8dfacca |
children | f6334be47118 |
comparison
equal
deleted
inserted
replaced
56:3c8a44c06a95 | 63:b7f97abdc517 |
---|---|
1 /* Wrapper to call lto. Used by collect2 and the linker plugin. | 1 /* Wrapper to call lto. Used by collect2 and the linker plugin. |
2 Copyright (C) 2009 Free Software Foundation, Inc. | 2 Copyright (C) 2009, 2010 Free Software Foundation, Inc. |
3 | 3 |
4 Factored out of collect2 by Rafael Espindola <espindola@google.com> | 4 Factored out of collect2 by Rafael Espindola <espindola@google.com> |
5 | 5 |
6 This file is part of GCC. | 6 This file is part of GCC. |
7 | 7 |
41 #include "system.h" | 41 #include "system.h" |
42 #include "coretypes.h" | 42 #include "coretypes.h" |
43 #include "tm.h" | 43 #include "tm.h" |
44 #include "intl.h" | 44 #include "intl.h" |
45 #include "libiberty.h" | 45 #include "libiberty.h" |
46 | 46 #include "obstack.h" |
47 int debug; /* true if -debug */ | 47 |
48 int debug; /* true if -save-temps. */ | |
49 int verbose; /* true if -v. */ | |
48 | 50 |
49 enum lto_mode_d { | 51 enum lto_mode_d { |
50 LTO_MODE_NONE, /* Not doing LTO. */ | 52 LTO_MODE_NONE, /* Not doing LTO. */ |
51 LTO_MODE_LTO, /* Normal LTO. */ | 53 LTO_MODE_LTO, /* Normal LTO. */ |
52 LTO_MODE_WHOPR /* WHOPR. */ | 54 LTO_MODE_WHOPR /* WHOPR. */ |
53 }; | 55 }; |
54 | 56 |
55 /* Current LTO mode. */ | 57 /* Current LTO mode. */ |
56 static enum lto_mode_d lto_mode = LTO_MODE_NONE; | 58 static enum lto_mode_d lto_mode = LTO_MODE_NONE; |
57 | 59 |
126 { | 128 { |
127 struct pex_obj *pex; | 129 struct pex_obj *pex; |
128 const char *errmsg; | 130 const char *errmsg; |
129 int err; | 131 int err; |
130 | 132 |
131 if (debug) | 133 if (verbose) |
132 { | 134 { |
133 char **p_argv; | 135 char **p_argv; |
134 const char *str; | 136 const char *str; |
135 | 137 |
136 for (p_argv = argv; (str = *p_argv) != (char *) 0; p_argv++) | 138 for (p_argv = argv; (str = *p_argv) != (char *) 0; p_argv++) |
144 | 146 |
145 pex = pex_init (0, "lto-wrapper", NULL); | 147 pex = pex_init (0, "lto-wrapper", NULL); |
146 if (pex == NULL) | 148 if (pex == NULL) |
147 fatal_perror ("pex_init failed"); | 149 fatal_perror ("pex_init failed"); |
148 | 150 |
149 errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, NULL, | 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, | |
150 NULL, &err); | 155 NULL, &err); |
151 if (errmsg != NULL) | 156 if (errmsg != NULL) |
152 { | 157 { |
153 if (err != 0) | 158 if (err != 0) |
154 { | 159 { |
244 | 249 |
245 maybe_unlink_file (args_name); | 250 maybe_unlink_file (args_name); |
246 free (at_args); | 251 free (at_args); |
247 } | 252 } |
248 | 253 |
254 /* Template of LTRANS dumpbase suffix. */ | |
255 #define DUMPBASE_SUFFIX ".ltrans18446744073709551615" | |
249 | 256 |
250 /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */ | 257 /* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */ |
251 | 258 |
252 static void | 259 static void |
253 run_gcc (unsigned argc, char *argv[]) | 260 run_gcc (unsigned argc, char *argv[]) |
254 { | 261 { |
255 unsigned i; | 262 unsigned i, j; |
256 unsigned new_argc = argc; | |
257 const char **new_argv; | 263 const char **new_argv; |
258 const char **argv_ptr; | 264 const char **argv_ptr; |
259 char *list_option_full = NULL; | 265 char *list_option_full = NULL; |
260 | 266 const char *linker_output = NULL; |
261 new_argc += 8; | 267 const char *collect_gcc_options, *collect_gcc; |
262 new_argv = (const char **) xcalloc (sizeof (char *), new_argc); | 268 struct obstack env_obstack; |
263 | 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 *)); | |
264 argv_ptr = new_argv; | 293 argv_ptr = new_argv; |
265 | 294 *argv_ptr++ = collect_gcc; |
266 *argv_ptr++ = argv[0]; | 295 *argv_ptr++ = "-xlto"; |
267 *argv_ptr++ = "-combine"; | |
268 *argv_ptr++ = "-x"; | |
269 *argv_ptr++ = "lto"; | |
270 *argv_ptr++ = "-c"; | 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 | |
271 if (lto_mode == LTO_MODE_LTO) | 375 if (lto_mode == LTO_MODE_LTO) |
272 { | 376 { |
273 flto_out = make_temp_file (".lto.o"); | 377 flto_out = make_temp_file (".lto.o"); |
274 *argv_ptr++ = "-o"; | 378 if (linker_output) |
275 *argv_ptr++ = flto_out; | 379 argv_ptr[0] = linker_output; |
380 argv_ptr[1] = "-o"; | |
381 argv_ptr[2] = flto_out; | |
382 argv_ptr[3] = "-combine"; | |
276 } | 383 } |
277 else if (lto_mode == LTO_MODE_WHOPR) | 384 else if (lto_mode == LTO_MODE_WHOPR) |
278 { | 385 { |
279 const char *list_option = "-fltrans-output-list="; | 386 const char *list_option = "-fltrans-output-list="; |
280 size_t list_option_len = strlen (list_option); | 387 size_t list_option_len = strlen (list_option); |
281 char *tmp; | 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 } | |
282 | 398 |
283 ltrans_output_file = make_temp_file (".ltrans.out"); | 399 ltrans_output_file = make_temp_file (".ltrans.out"); |
284 list_option_full = (char *) xmalloc (sizeof (char) * | 400 list_option_full = (char *) xmalloc (sizeof (char) * |
285 (strlen (ltrans_output_file) + list_option_len + 1)); | 401 (strlen (ltrans_output_file) + list_option_len + 1)); |
286 tmp = list_option_full; | 402 tmp = list_option_full; |
287 | 403 |
288 *argv_ptr++ = tmp; | 404 argv_ptr[1] = tmp; |
289 strcpy (tmp, list_option); | 405 strcpy (tmp, list_option); |
290 tmp += list_option_len; | 406 tmp += list_option_len; |
291 strcpy (tmp, ltrans_output_file); | 407 strcpy (tmp, ltrans_output_file); |
292 | 408 |
293 *argv_ptr++ = "-fwpa"; | 409 argv_ptr[2] = "-fwpa"; |
410 argv_ptr[3] = "-combine"; | |
294 } | 411 } |
295 else | 412 else |
296 fatal ("invalid LTO mode"); | 413 fatal ("invalid LTO mode"); |
297 | 414 |
298 /* Add inherited GCC options to the LTO back end command line. | 415 /* Append the input objects and possible preceeding arguments. */ |
299 Filter out some obviously inappropriate options that will | 416 for (i = 1; i < argc; ++i) |
300 conflict with the options that we force above. We pass | 417 argv_ptr[3 + i] = argv[i]; |
301 all of the remaining options on to LTO, and let it complain | 418 argv_ptr[3 + i] = NULL; |
302 about any it doesn't like. Note that we invoke LTO via the | |
303 `gcc' driver, so the usual option processing takes place. | |
304 Except for `-flto' and `-fwhopr', we should only filter options that | |
305 are meaningful to `ld', lest an option go silently unclaimed. */ | |
306 for (i = 1; i < argc; i++) | |
307 { | |
308 const char *s = argv[i]; | |
309 | |
310 if (strcmp (s, "-flto") == 0 || strcmp (s, "-fwhopr") == 0) | |
311 /* We've handled this LTO option, don't pass it on. */ | |
312 ; | |
313 else if (*s == '-' && s[1] == 'o') | |
314 { | |
315 /* Drop `-o' and its filename argument. We will use a | |
316 temporary file for the LTO output. The `-o' option | |
317 will be interpreted by the linker. */ | |
318 if (s[2] == '\0') | |
319 i++; | |
320 } | |
321 else | |
322 /* Pass the option or argument to LTO. */ | |
323 *argv_ptr++ = s; | |
324 } | |
325 | |
326 *argv_ptr = NULL; | |
327 | 419 |
328 fork_execute (CONST_CAST (char **, new_argv)); | 420 fork_execute (CONST_CAST (char **, new_argv)); |
329 free (new_argv); | |
330 new_argv = NULL; | |
331 | 421 |
332 if (lto_mode == LTO_MODE_LTO) | 422 if (lto_mode == LTO_MODE_LTO) |
333 { | 423 { |
334 printf("%s\n", flto_out); | 424 printf("%s\n", flto_out); |
335 free (flto_out); | 425 free (flto_out); |
336 flto_out = NULL; | 426 flto_out = NULL; |
337 } | 427 } |
338 else if (lto_mode == LTO_MODE_WHOPR) | 428 else if (lto_mode == LTO_MODE_WHOPR) |
339 { | 429 { |
340 FILE *stream = fopen (ltrans_output_file, "r"); | 430 FILE *stream = fopen (ltrans_output_file, "r"); |
341 int c; | 431 unsigned int nr = 0; |
432 char **input_names = NULL; | |
433 char **output_names = NULL; | |
434 char *makefile = NULL; | |
435 FILE *mstream = NULL; | |
342 | 436 |
343 if (!stream) | 437 if (!stream) |
344 fatal_perror ("fopen: %s", ltrans_output_file); | 438 fatal_perror ("fopen: %s", ltrans_output_file); |
345 | 439 |
346 while ((c = getc (stream)) != EOF) | 440 argv_ptr[1] = "-fltrans"; |
347 putc (c, stdout); | 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); | |
348 fclose (stream); | 544 fclose (stream); |
349 maybe_unlink_file (ltrans_output_file); | 545 maybe_unlink_file (ltrans_output_file); |
350 free (list_option_full); | 546 free (list_option_full); |
351 } | 547 } |
352 else | 548 else |
353 fatal ("invalid LTO mode"); | 549 fatal ("invalid LTO mode"); |
354 } | 550 |
355 | 551 obstack_free (&env_obstack, NULL); |
356 | |
357 /* Parse the command line. Copy any unused argument to GCC_ARGV. ARGC is the | |
358 number of arguments. ARGV contains the arguments. */ | |
359 | |
360 static int | |
361 process_args (int argc, char *argv[], char *gcc_argv[]) | |
362 { | |
363 int i; | |
364 int j = 0; | |
365 | |
366 for (i = 1; i < argc; i ++) | |
367 { | |
368 if (! strcmp (argv[i], "-debug")) | |
369 debug = 1; | |
370 else if (! strcmp (argv[i], "-flto")) | |
371 lto_mode = LTO_MODE_LTO; | |
372 else if (! strcmp (argv[i], "-fwhopr")) | |
373 lto_mode = LTO_MODE_WHOPR; | |
374 else | |
375 { | |
376 gcc_argv[j] = argv[i]; | |
377 j++; | |
378 } | |
379 } | |
380 | |
381 return j; | |
382 } | 552 } |
383 | 553 |
384 | 554 |
385 /* Entry point. */ | 555 /* Entry point. */ |
386 | 556 |
387 int | 557 int |
388 main (int argc, char *argv[]) | 558 main (int argc, char *argv[]) |
389 { | 559 { |
390 char **gcc_argv; | |
391 int gcc_argc; | |
392 | |
393 gcc_init_libintl (); | 560 gcc_init_libintl (); |
394 | 561 |
395 /* We may be called with all the arguments stored in some file and | 562 /* We may be called with all the arguments stored in some file and |
396 passed with @file. Expand them into argv before processing. */ | 563 passed with @file. Expand them into argv before processing. */ |
397 expandargv (&argc, &argv); | 564 expandargv (&argc, &argv); |
398 gcc_argv = (char **) xcalloc (sizeof (char *), argc); | 565 run_gcc (argc, argv); |
399 gcc_argc = process_args (argc, argv, gcc_argv); | |
400 run_gcc (gcc_argc, gcc_argv); | |
401 free (gcc_argv); | |
402 | 566 |
403 return 0; | 567 return 0; |
404 } | 568 } |