gcc.c: Document new %@{...} sequence.
authorEric Botcazou <ebotcazou@adacore.com>
Tue, 12 Jun 2018 06:52:55 +0000 (06:52 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Tue, 12 Jun 2018 06:52:55 +0000 (06:52 +0000)
* 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
gcc/gcc.c

index 3be9f95c4660bedb6107327c50610ae70af7e799..9c9087575e47de470d33f7d8ae59b2ae5876a39b 100644 (file)
@@ -1,3 +1,23 @@
+2018-06-12  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * 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  <rasmus.villemoes@prevas.dk>
 
        * config/vx-common.h (USE_TM_CLONE_REGISTRY): #define to 0.
index a631caafd3f706571411f3ce17b7ee4c2b02d128..405d2e38d446c79eeb928f8549d7c7e1a267c02a 100644 (file)
--- 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<const_char_p> argbuf;
 
+/* Likewise, but for the current @file.  */
+static vec<const_char_p> 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);
+}
 \f
 /* 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;