2007-04-13 Nathan Froyd * gcc.c (at_file_supplied): New variable. (main): Set it if we expanded argv. (do_spec_1): Pass an @-file to the linker if we were called with an @-file argument. * collect2.c (at_file_supplied): New variable. (response_file): New variable. (collect_exit): Unlink response_file if necessary. (handler): Likewise. (do_wait): Likewise. (main): Set at_file_supplied if we expanded argv. (collect_execute): Pass an @-file to subprocesses if we were called with an @-file argument. Index: collect2.c =================================================================== --- collect2.c (revision 123791) +++ collect2.c (working copy) @@ -202,6 +202,9 @@ static struct head exports; /* list of #endif static struct head frame_tables; /* list of frame unwind info tables */ +static int at_file_supplied; /* Whether to use @file arguments */ +static char *response_file; /* Name of any current response file */ + struct obstack temporary_obstack; char * temporary_firstobj; @@ -302,6 +305,9 @@ collect_exit (int status) if (status != 0 && output_file != 0 && output_file[0]) maybe_unlink (output_file); + if (response_file) + maybe_unlink (response_file); + exit (status); } @@ -393,6 +399,9 @@ handler (int signo) maybe_unlink (export_file); #endif + if (response_file) + maybe_unlink (response_file); + signal (signo, SIG_DFL); raise (signo); } @@ -793,7 +802,15 @@ main (int argc, char **argv) char **object_lst; const char **object; int first_file; - int num_c_args = argc+9; + int num_c_args; + char **old_argv; + + old_argv = argv; + expandargv (&argc, &argv); + if (argv != old_argv) + at_file_supplied = 1; + + num_c_args = argc + 9; no_demangle = !! getenv ("COLLECT_NO_DEMANGLE"); @@ -1513,6 +1530,12 @@ do_wait (const char *prog, struct pex_ob error ("%s returned %d exit status", prog, ret); collect_exit (ret); } + + if (response_file) + { + unlink (response_file); + response_file = NULL; + } } @@ -1525,6 +1548,42 @@ collect_execute (const char *prog, char struct pex_obj *pex; const char *errmsg; int err; + char *response_argv[3]; + char *response_arg = NULL; + + /* If using @file arguments, create a temporary file and put the + contents of argv into it. Then change argv to an array corresponding + to a single argument @FILE, where FILE is the temporary filename. */ + + if (at_file_supplied && argv[0] != NULL) + { + FILE *response_fp; + char **current_argv = argv + 1; + char *argv0 = argv[0]; + + /* Note: we assume argv contains at least one element; this is + checked above. */ + + response_file = make_temp_file (""); + response_fp = fopen (response_file, "w"); + if (!response_fp) + fatal ("could not create response file %s", response_file); + + while (*current_argv) + { + fprintf (response_fp, "%s\n", *current_argv); + current_argv++; + } + + fclose (response_fp); + + response_arg = concat ("@", response_file, NULL); + response_argv[0] = argv0; + response_argv[1] = response_arg; + response_argv[2] = NULL; + + argv = response_argv; + } if (vflag || debug) { @@ -1568,6 +1627,9 @@ collect_execute (const char *prog, char fatal (errmsg); } + if (response_arg) + free (response_arg); + return pex; } Index: gcc.c =================================================================== --- gcc.c (revision 123791) +++ gcc.c (working copy) @@ -127,6 +127,9 @@ static const char dir_separator_str[] = /* Flag set by cppspec.c to 1. */ int is_cpp_driver; +/* Flag set to non-zero if an @file argument has been supplied to gcc. */ +static int at_file_supplied; + /* Flag saying to pass the greatest exit code returned by a sub-process to the calling program. */ static int pass_exit_codes; @@ -5006,9 +5009,37 @@ do_spec_1 (const char *spec, int inswitc int max = n_infiles; max += lang_specific_extra_outfiles; - for (i = 0; i < max; i++) - if (outfiles[i]) - store_arg (outfiles[i], 0, 0); + if (at_file_supplied) + { + /* We are going to expand `%o' to `@FILE', where FILE + is a newly-created temporary filename. The filenames + that would usually be expanded in place of %o will be + written to the temporary file. */ + + char *temp_file = make_temp_file (""); + char *at_argument; + FILE *temp_fp; + + at_argument = concat ("@", temp_file, NULL); + store_arg (at_argument, 0, 0); + + temp_fp = fopen (temp_file, "w"); + if (!temp_fp) + fatal ("could not write temporary response file %s", + temp_file); + + for (i = 0; i < max; i++) + if (outfiles[i]) + fprintf (temp_fp, "%s\n", outfiles[i]); + + fclose (temp_fp); + + record_temp_file (temp_file, 1, 1); + } + else + for (i = 0; i < max; i++) + if (outfiles[i]) + store_arg (outfiles[i], 0, 0); break; } @@ -6090,6 +6121,7 @@ main (int argc, char **argv) char *specs_file; const char *p; struct user_specs *uptr; + char **old_argv = argv; p = argv[0] + strlen (argv[0]); while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) @@ -6100,6 +6132,10 @@ main (int argc, char **argv) expandargv (&argc, &argv); + /* Determine if any expansions were made. */ + if (argv != old_argv) + at_file_supplied = 1; + prune_options (&argc, &argv); #ifdef GCC_DRIVER_HOST_INITIALIZATION