From e7208389c8381feaf8c7c60d975b06c446978006 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Tue, 12 Jun 2018 06:52:55 +0000 Subject: [PATCH] gcc.c: Document new %@{...} sequence. * gcc.c: Document new %@{...} sequence. (LINK_COMMAND_SPEC): Use it for the -L switches. (cpp_unique_options): Use it for the -I switches. (at_file_argbuf): New global variable. (in_at_file): Likewise. (alloc_args): Create at_file_argbuf. (clear_args): Truncate at_file_argbuf. (store_arg): If in_at_file, push the argument onto at_file_argbuf. (open_at_file): New function. (close_at_file): Likewise. (create_at_file): Delete. (do_spec_1) <'i'>: Use open_at_file/close_at_file. <'o'>: Likewise. <'@'>: New case. (validate_switches_from_spec): Deal with %@{...} sequence. (validate_switches): Likewise. (driver::finalize): Call clear_args. From-SVN: r261474 --- gcc/ChangeLog | 20 +++++ gcc/gcc.c | 243 +++++++++++++++++++++++++++----------------------- 2 files changed, 150 insertions(+), 113 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3be9f95c4660..9c9087575e47 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2018-06-12 Eric Botcazou + + * gcc.c: Document new %@{...} sequence. + (LINK_COMMAND_SPEC): Use it for the -L switches. + (cpp_unique_options): Use it for the -I switches. + (at_file_argbuf): New global variable. + (in_at_file): Likewise. + (alloc_args): Create at_file_argbuf. + (clear_args): Truncate at_file_argbuf. + (store_arg): If in_at_file, push the argument onto at_file_argbuf. + (open_at_file): New function. + (close_at_file): Likewise. + (create_at_file): Delete. + (do_spec_1) <'i'>: Use open_at_file/close_at_file. + <'o'>: Likewise. + <'@'>: New case. + (validate_switches_from_spec): Deal with %@{...} sequence. + (validate_switches): Likewise. + (driver::finalize): Call clear_args. + 2018-06-11 Rasmus Villemoes * config/vx-common.h (USE_TM_CLONE_REGISTRY): #define to 0. diff --git a/gcc/gcc.c b/gcc/gcc.c index a631caafd3f7..405d2e38d446 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -476,8 +476,11 @@ or with constant text in a single argument. into the sequence of arguments that %o will substitute later. %V indicates that this compilation produces no "output file". %W{...} - like %{...} but mark last argument supplied within - as a file to be deleted on failure. + like %{...} but marks the last argument supplied within as a file + to be deleted on failure. + %@{...} + like %{...} but puts the result into a FILE and substitutes @FILE + if an @file argument has been supplied. %o substitutes the names of all the output files, with spaces automatically placed around them. You should write spaces around the %o as well or the results are undefined. @@ -1034,7 +1037,7 @@ proper position among the other output files. */ "%{fuse-ld=*:-fuse-ld=%*} " LINK_COMPRESS_DEBUG_SPEC \ "%X %{o*} %{e*} %{N} %{n} %{r}\ %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} \ - %{static|no-pie|static-pie:} %{L*} %(mfwrap) %(link_libgcc) " \ + %{static|no-pie|static-pie:} %@{L*} %(mfwrap) %(link_libgcc) " \ VTABLE_VERIFICATION_SPEC " " SANITIZER_EARLY_SPEC " %o "" \ %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1):\ %:include(libgomp.spec)%(link_gomp)}\ @@ -1109,7 +1112,7 @@ static const char *trad_capable_cpp = therefore no dependency entry, confuses make into thinking a .o file that happens to exist is up-to-date. */ static const char *cpp_unique_options = -"%{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I\ +"%{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %@{I*&F*} %{P} %I\ %{MD:-MD %{!o:%b.d}%{o*:%.d%*}}\ %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\ %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\ @@ -1924,9 +1927,14 @@ set_spec (const char *name, const char *spec, bool user_p) typedef const char *const_char_p; /* For DEF_VEC_P. */ /* Vector of pointers to arguments in the current line of specifications. */ - static vec argbuf; +/* Likewise, but for the current @file. */ +static vec at_file_argbuf; + +/* Whether an @file is currently open. */ +static bool in_at_file = false; + /* Were the options -c, -S or -E passed. */ static int have_c = 0; @@ -1966,6 +1974,7 @@ static void alloc_args (void) { argbuf.create (10); + at_file_argbuf.create (10); } /* Clear out the vector of arguments (after a command is executed). */ @@ -1974,6 +1983,7 @@ static void clear_args (void) { argbuf.truncate (0); + at_file_argbuf.truncate (0); } /* Add one argument to the vector at the end. @@ -1986,7 +1996,10 @@ clear_args (void) static void store_arg (const char *arg, int delete_always, int delete_failure) { - argbuf.safe_push (arg); + if (in_at_file) + at_file_argbuf.safe_push (arg); + else + argbuf.safe_push (arg); if (delete_always || delete_failure) { @@ -1999,6 +2012,67 @@ store_arg (const char *arg, int delete_always, int delete_failure) record_temp_file (arg, delete_always, delete_failure); } } + +/* Open a temporary @file into which subsequent arguments will be stored. */ + +static void +open_at_file (void) +{ + if (in_at_file) + fatal_error (input_location, "cannot open nested response file"); + else + in_at_file = true; +} + +/* Close the temporary @file and add @file to the argument list. */ + +static void +close_at_file (void) +{ + if (!in_at_file) + fatal_error (input_location, "cannot close nonexistent response file"); + + in_at_file = false; + + const unsigned int n_args = at_file_argbuf.length (); + if (n_args == 0) + return; + + char **argv = (char **) alloca (sizeof (char *) * (n_args + 1)); + char *temp_file = make_temp_file (""); + char *at_argument = concat ("@", temp_file, NULL); + FILE *f = fopen (temp_file, "w"); + int status; + unsigned int i; + + /* Copy the strings over. */ + for (i = 0; i < n_args; i++) + argv[i] = CONST_CAST (char *, at_file_argbuf[i]); + argv[i] = NULL; + + at_file_argbuf.truncate (0); + + if (f == NULL) + fatal_error (input_location, "could not open temporary response file %s", + temp_file); + + status = writeargv (argv, f); + + if (status) + fatal_error (input_location, + "could not write to temporary response file %s", + temp_file); + + status = fclose (f); + + if (status == EOF) + fatal_error (input_location, "could not close temporary response file %s", + temp_file); + + store_arg (at_argument, 0, 0); + + record_temp_file (temp_file, !save_temps_flag, !save_temps_flag); +} /* Load specs from a file name named FILENAME, replacing occurrences of various different types of line-endings, \r\n, \n\r and just \r, with @@ -5081,39 +5155,6 @@ spec_path (char *path, void *data) return NULL; } -/* Create a temporary FILE with the contents of ARGV. Add @FILE to the - argument list. */ - -static void -create_at_file (char **argv) -{ - char *temp_file = make_temp_file (""); - char *at_argument = concat ("@", temp_file, NULL); - FILE *f = fopen (temp_file, "w"); - int status; - - if (f == NULL) - fatal_error (input_location, "could not open temporary response file %s", - temp_file); - - status = writeargv (argv, f); - - if (status) - fatal_error (input_location, - "could not write to temporary response file %s", - temp_file); - - status = fclose (f); - - if (EOF == status) - fatal_error (input_location, "could not close temporary response file %s", - temp_file); - - store_arg (at_argument, 0, 0); - - record_temp_file (temp_file, !save_temps_flag, !save_temps_flag); -} - /* True if we should compile INFILE. */ static bool @@ -5526,41 +5567,22 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) case 'i': if (combine_inputs) { + /* We are going to expand `%i' into `@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. */ if (at_file_supplied) - { - /* We are going to expand `%i' 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 **argv; - int n_files = 0; - int j; - - for (i = 0; i < n_infiles; i++) - if (compile_input_file_p (&infiles[i])) - n_files++; - - argv = (char **) alloca (sizeof (char *) * (n_files + 1)); - - /* Copy the strings over. */ - for (i = 0, j = 0; i < n_infiles; i++) - if (compile_input_file_p (&infiles[i])) - { - argv[j] = CONST_CAST (char *, infiles[i].name); - infiles[i].compiled = true; - j++; - } - argv[j] = NULL; + open_at_file (); - create_at_file (argv); - } - else - for (i = 0; (int) i < n_infiles; i++) - if (compile_input_file_p (&infiles[i])) - { - store_arg (infiles[i].name, 0, 0); - infiles[i].compiled = true; - } + for (i = 0; (int) i < n_infiles; i++) + if (compile_input_file_p (&infiles[i])) + { + store_arg (infiles[i].name, 0, 0); + infiles[i].compiled = true; + } + + if (at_file_supplied) + close_at_file (); } else { @@ -5633,45 +5655,20 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) break; case 'o': - { - int max = n_infiles; - max += lang_specific_extra_outfiles; - - if (HAVE_GNU_LD && 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 **argv; - int n_files, j; - - /* Convert OUTFILES into a form suitable for writeargv. */ - - /* Determine how many are non-NULL. */ - for (n_files = 0, i = 0; i < max; i++) - n_files += outfiles[i] != NULL; - - argv = (char **) alloca (sizeof (char *) * (n_files + 1)); - - /* Copy the strings over. */ - for (i = 0, j = 0; i < max; i++) - if (outfiles[i]) - { - argv[j] = CONST_CAST (char *, outfiles[i]); - j++; - } - argv[j] = NULL; - - create_at_file (argv); - } - else - for (i = 0; i < max; i++) - if (outfiles[i]) - store_arg (outfiles[i], 0, 0); - break; - } + /* We are going to expand `%o' into `@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. */ + if (at_file_supplied) + open_at_file (); + + for (i = 0; i < n_infiles + lang_specific_extra_outfiles; i++) + if (outfiles[i]) + store_arg (outfiles[i], 0, 0); + + if (at_file_supplied) + close_at_file (); + break; case 'O': obstack_grow (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX)); @@ -5712,6 +5709,20 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) break; } + case '@': + /* Handle the {...} following the %@. */ + if (*p != '{') + fatal_error (input_location, + "spec %qs has invalid %<%%@%c%>", spec, *p); + if (at_file_supplied) + open_at_file (); + p = handle_braces (p + 1); + if (at_file_supplied) + close_at_file (); + if (p == 0) + return -1; + break; + /* %x{OPTION} records OPTION for %X to output. */ case 'x': { @@ -8501,7 +8512,11 @@ validate_switches_from_spec (const char *spec, bool user) const char *p = spec; char c; while ((c = *p++)) - if (c == '%' && (*p == '{' || *p == '<' || (*p == 'W' && *++p == '{'))) + if (c == '%' + && (*p == '{' + || *p == '<' + || (*p == 'W' && *++p == '{') + || (*p == '@' && *++p == '{'))) /* We have a switch spec. */ p = validate_switches (p + 1, user); } @@ -8583,6 +8598,8 @@ next_member: p = validate_switches (p+1, user_spec); else if (p[0] == 'W' && p[1] == '{') p = validate_switches (p+2, user_spec); + else if (p[0] == '@' && p[1] == '{') + p = validate_switches (p+2, user_spec); } else p++; @@ -10141,7 +10158,7 @@ driver::finalize () processing_spec_function = 0; - argbuf.truncate (0); + clear_args (); have_c = 0; have_o = 0; -- 2.43.5