[PATCH/RFA] spec functions

Jason R Thorpe thorpej@wasabisystems.com
Sun Nov 3 12:54:00 GMT 2002


On Sat, Nov 02, 2002 at 09:16:11PM -0800, Zack Weinberg wrote:

 > and then you can process them both identically in lookup_spec_function,
 > by scanning until you reach the terminator, and you don't need a count
 > variable.

Done.

	* gcc.c (The Specs Language): Document spec functions.
	(static_spec_functions, lookup_spec_function)
	(eval_spec_function, handle_spec_function)
	(if_exists_spec_function, alloc_args): New.
	(execute): Abort if processing_spec_function is true.
	(do_spec_1): Hand off spec to handle_spec_function if %:
	is encountered.  If processing_spec_function is true,
	end any pending argument when the end of the string is reached.
	(main): Use alloc_args to allocate the initial argument vector.
	* gcc.h (struct spec_function): New.  
	(lang_specific_spec_functions): New extern.
 
	* config/netbsd-elf.h (STARTFILE_SPEC): Add if-exists(crti%O%s).
	(ENDFILE_SPEC): Add if-exists(crtn%O%s).
	* config/alpha/netbsd.h (ENDFILE_SPEC): Likewise.

	* doc/invoke.texi: Document spec functions.

	* cppspec.c (lang_specific_spec_functions): New.
	* gccspec.c: Likewise.

	* g++spec.c (lang_specific_spec_functions): New.

	* g77spec.c (lang_specific_spec_functions): New.

	* jvspec.c (lang_specific_spec_functions): New.

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>
-------------- next part --------------
Index: cppspec.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppspec.c,v
retrieving revision 1.17
diff -c -r1.17 cppspec.c
*** cppspec.c	22 May 2002 22:02:16 -0000	1.17
--- cppspec.c	3 Nov 2002 20:52:12 -0000
***************
*** 238,240 ****
--- 238,246 ----
  
  /* Number of extra output files that lang_specific_pre_link may generate.  */
  int lang_specific_extra_outfiles = 0;  /* Not used for cpp.  */
+ 
+ /* Table of language-specific spec functions.  */
+ const struct spec_function lang_specific_spec_functions[] =
+ {
+   { 0, 0 }
+ };
Index: gcc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcc.c,v
retrieving revision 1.344
diff -c -r1.344 gcc.c
*** gcc.c	14 Oct 2002 07:15:38 -0000	1.344
--- gcc.c	3 Nov 2002 20:52:18 -0000
***************
*** 292,297 ****
--- 292,300 ----
  static void clear_failure_queue PARAMS ((void));
  static int check_live_switch	PARAMS ((int, int));
  static const char *handle_braces PARAMS ((const char *));
+ static const struct spec_function *lookup_spec_function PARAMS ((const char *));
+ static const char *eval_spec_function	PARAMS ((const char *, const char *));
+ static const char *handle_spec_function PARAMS ((const char *));
  static char *save_string	PARAMS ((const char *, int));
  static void set_collect_gcc_options PARAMS ((void));
  static int do_spec_1		PARAMS ((const char *, int, const char *));
***************
*** 317,322 ****
--- 320,326 ----
  static void add_linker_option		PARAMS ((const char *, int));
  static void process_command		PARAMS ((int, const char *const *));
  static int execute			PARAMS ((void));
+ static void alloc_args			PARAMS ((void));
  static void clear_args			PARAMS ((void));
  static void fatal_error			PARAMS ((int));
  #ifdef ENABLE_SHARED_LIBGCC
***************
*** 327,332 ****
--- 331,338 ----
  #if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
  static const char *convert_filename	PARAMS ((const char *, int, int));
  #endif
+ 
+ static const char *if_exists_spec_function PARAMS ((int, const char **));
  
  /* The Specs Language
  
***************
*** 450,455 ****
--- 456,467 ----
   %*	substitute the variable part of a matched option.  (See below.)
  	Note that each comma in the substituted string is replaced by
  	a single space.
+  %:function(args)
+ 	Call the named function FUNCTION, passing it ARGS.  ARGS is
+ 	first processed as a nested spec string, then split into an
+ 	argument vector in the usual fashion.  The function returns
+ 	a string which is processed as if it had appeared literally
+ 	as part of the current spec.
   %{S}   substitutes the -S switch, if that switch was given to CC.
  	If that switch was not specified, this substitutes nothing.
  	Here S is a metasyntactic variable.
***************
*** 1439,1444 ****
--- 1451,1466 ----
  
  static struct spec_list *specs = (struct spec_list *) 0;
  
+ /* List of static spec functions.  */
+ 
+ static const struct spec_function static_spec_functions[] =
+ {
+   { "if-exists",		if_exists_spec_function },
+   { 0, 0 }
+ };
+ 
+ static int processing_spec_function;
+ 
  /* Add appropriate libgcc specs to OBSTACK, taking into account
     various permutations of -shared-libgcc, -shared, and such.  */
  
***************
*** 1710,1715 ****
--- 1732,1746 ----
  
  static const char *programname;
  
+ /* Allocate the argument vector.  */
+ 
+ static void
+ alloc_args ()
+ {
+   argbuf_length = 10;
+   argbuf = (const char **) xmalloc (argbuf_length * sizeof (const char *));
+ }
+ 
  /* Clear out the vector of arguments (after a command is executed).  */
  
  static void
***************
*** 2753,2758 ****
--- 2784,2792 ----
  
    struct command *commands;	/* each command buffer with above info.  */
  
+   if (processing_spec_function)
+     abort ();
+ 
    /* Count # of piped commands.  */
    for (n_commands = 1, i = 0; i < argbuf_index; i++)
      if (strcmp (argbuf[i], "|") == 0)
***************
*** 5118,5123 ****
--- 5152,5163 ----
  	      return -1;
  	    break;
  
+ 	  case ':':
+ 	    p = handle_spec_function (p);
+ 	    if (p == 0)
+ 	      return -1;
+ 	    break;
+ 
  	  case '%':
  	    obstack_1grow (&obstack, '%');
  	    break;
***************
*** 5311,5320 ****
  	arg_going = 1;
        }
  
!   /* End of string.  */
    return 0;
  }
  
  /* Return 0 if we call do_spec_1 and that returns -1.  */
  
  static const char *
--- 5351,5529 ----
  	arg_going = 1;
        }
  
!   /* End of string.  If we are processing a spec function, we need to
!      end any pending argument.  */
!   if (processing_spec_function && arg_going)
!     {
!       obstack_1grow (&obstack, 0);
!       string = obstack_finish (&obstack);
!       if (this_is_library_file)
!         string = find_file (string);
!       store_arg (string, delete_this_arg, this_is_output_file);
!       if (this_is_output_file)
!         outfiles[input_file_number] = string;
!       arg_going = 0;
!     }
! 
    return 0;
  }
  
+ /* Look up a spec function.  */
+ 
+ static const struct spec_function *
+ lookup_spec_function (name)
+      const char *name;
+ {
+   static const struct spec_function * const spec_function_tables[] =
+   {
+     static_spec_functions,
+     lang_specific_spec_functions,
+   };
+   const struct spec_function *sf;
+   unsigned int i;
+ 
+   for (i = 0; i < ARRAY_SIZE (spec_function_tables); i++)
+     {
+       for (sf = spec_function_tables[i]; sf->name != NULL; sf++)
+ 	if (strcmp (sf->name, name) == 0)
+ 	  return sf;
+     }
+ 
+   return NULL;
+ }
+ 
+ /* Evaluate a spec function.  */
+ 
+ static const char *
+ eval_spec_function (func, args)
+      const char *func, *args;
+ {
+   const struct spec_function *sf;
+   const char *funcval;
+ 
+   /* Saved spec processing context.  */
+   int save_argbuf_index;
+   int save_argbuf_length;
+   const char **save_argbuf;
+ 
+   int save_arg_going;
+   int save_delete_this_arg;
+   int save_this_is_output_file;
+   int save_this_is_library_file;
+   int save_input_from_pipe;
+   const char *save_suffix_subst;
+ 
+ 
+   sf = lookup_spec_function (func);
+   if (sf == NULL)
+     fatal ("unknown spec function `%s'", func);
+ 
+   /* Push the spec processing context.  */
+   save_argbuf_index = argbuf_index;
+   save_argbuf_length = argbuf_length;
+   save_argbuf = argbuf;
+ 
+   save_arg_going = arg_going;
+   save_delete_this_arg = delete_this_arg;
+   save_this_is_output_file = this_is_output_file;
+   save_this_is_library_file = this_is_library_file;
+   save_input_from_pipe = input_from_pipe;
+   save_suffix_subst = suffix_subst;
+ 
+   /* Create a new spec processing context, and build the function
+      arguments.  */
+ 
+   alloc_args ();
+   if (do_spec_2 (args) < 0)
+     fatal ("error in args to spec function `%s'", func);
+ 
+   /* argbuf_index is an index for the next argument to be inserted, and
+      so contains the count of the args already inserted.  */
+ 
+   funcval = (*sf->func) (argbuf_index, argbuf);
+ 
+   /* Pop the spec processing context.  */
+   argbuf_index = save_argbuf_index;
+   argbuf_length = save_argbuf_length;
+   free (argbuf);
+   argbuf = save_argbuf;
+ 
+   arg_going = save_arg_going;
+   delete_this_arg = save_delete_this_arg;
+   this_is_output_file = save_this_is_output_file;
+   this_is_library_file = save_this_is_library_file;
+   input_from_pipe = save_input_from_pipe;
+   suffix_subst = save_suffix_subst;
+ 
+   return funcval;
+ }
+ 
+ /* Handle a spec function call of the form:
+ 
+    %:function(args)
+ 
+    ARGS is processed as a spec in a separate context and split into an
+    argument vector in the normal fashion.  The function returns a string
+    containing a spec which we then process in the caller's context, or
+    NULL if no processing is required.  */
+ 
+ static const char *
+ handle_spec_function (p)
+      const char *p;
+ {
+   char *func, *args;
+   const char *endp, *funcval;
+   int count;
+ 
+   processing_spec_function++;
+ 
+   /* Get the function name.  */
+   for (endp = p; *endp != '\0'; endp++)
+     {
+       if (*endp == '(')		/* ) */
+         break;
+       /* Only allow [A-Za-z0-9], -, and _ in function names.  */
+       if (!ISALNUM (*endp) && !(*endp == '-' || *endp == '_'))
+ 	fatal ("malformed spec function name");
+     }
+   if (*endp != '(')		/* ) */
+     fatal ("no arguments for spec function");
+   func = save_string (p, endp - p);
+   p = ++endp;
+ 
+   /* Get the arguments.  */
+   for (count = 0; *endp != '\0'; endp++)
+     {
+       /* ( */
+       if (*endp == ')')
+ 	{
+ 	  if (count == 0)
+ 	    break;
+ 	  count--;
+ 	}
+       else if (*endp == '(')	/* ) */
+ 	count++;
+     }
+   /* ( */
+   if (*endp != ')')
+     fatal ("malformed spec function arguments");
+   args = save_string (p, endp - p);
+   p = ++endp;
+ 
+   /* p now points to just past the end of the spec function expression.  */
+ 
+   funcval = eval_spec_function (func, args);
+   if (funcval != NULL && do_spec_1 (funcval, 0, NULL) < 0)
+     p = NULL;
+ 
+   free (func);
+   free (args);
+ 
+   processing_spec_function--;
+ 
+   return p;
+ }
+ 
  /* Return 0 if we call do_spec_1 and that returns -1.  */
  
  static const char *
***************
*** 5897,5904 ****
    signal (SIGCHLD, SIG_DFL);
  #endif
  
!   argbuf_length = 10;
!   argbuf = (const char **) xmalloc (argbuf_length * sizeof (const char *));
  
    obstack_init (&obstack);
  
--- 6106,6113 ----
    signal (SIGCHLD, SIG_DFL);
  #endif
  
!   /* Allocate the argument vector.  */
!   alloc_args ();
  
    obstack_init (&obstack);
  
***************
*** 7252,7255 ****
--- 7461,7484 ----
  
        ++p;
      }
+ }
+ 
+ /* if-exists built-in spec function.
+ 
+    Checks to see if the file specified by the absolute pathname in
+    ARGS exists.  Returns that pathname if found.
+ 
+    The usual use for this function is to check for a library file
+    (whose name has been expanded with %s).  */
+ 
+ static const char *
+ if_exists_spec_function (argc, argv)
+      int argc;
+      const char **argv;
+ {
+   /* Must have only one argument.  */
+   if (argc == 1 && IS_ABSOLUTE_PATHNAME (argv[0]) && ! access (argv[0], R_OK))
+     return argv[0];
+ 
+   return NULL;
  }
Index: gcc.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcc.h,v
retrieving revision 1.11
diff -c -r1.11 gcc.h
*** gcc.h	28 Nov 2001 17:34:54 -0000	1.11
--- gcc.h	3 Nov 2002 20:52:18 -0000
***************
*** 23,28 ****
--- 23,36 ----
  
  #include "version.h"
  
+ /* The mapping of a spec function name to the C function that
+    implements it.  */
+ struct spec_function
+ {       
+   const char *name;
+   const char *(*func) PARAMS ((int, const char **));
+ };
+ 
  /* These are exported by gcc.c.  */
  extern int do_spec PARAMS ((const char *));
  extern void record_temp_file PARAMS ((const char *, int, int));
***************
*** 47,52 ****
--- 55,63 ----
  
  /* Number of extra output files that lang_specific_pre_link may generate.  */
  extern int lang_specific_extra_outfiles;
+ 
+ /* Table of language-specific spec functions.  */
+ extern const struct spec_function lang_specific_spec_functions[];
  
  /* A vector of corresponding output files is made up later.  */
  
Index: gccspec.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gccspec.c,v
retrieving revision 1.8
diff -c -r1.8 gccspec.c
*** gccspec.c	4 Jun 2002 11:30:26 -0000	1.8
--- gccspec.c	3 Nov 2002 20:52:18 -0000
***************
*** 101,103 ****
--- 101,109 ----
  
  /* Number of extra output files that lang_specific_pre_link may generate.  */
  int lang_specific_extra_outfiles = 0;  /* Not used for C.  */
+ 
+ /* Table of language-specific spec functions.  */ 
+ const struct spec_function lang_specific_spec_functions[] =
+ {
+   { 0, 0 }
+ };
Index: config/netbsd-elf.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/netbsd-elf.h,v
retrieving revision 1.3
diff -c -r1.3 netbsd-elf.h
*** config/netbsd-elf.h	8 Jun 2002 06:07:11 -0000	1.3
--- config/netbsd-elf.h	3 Nov 2002 20:52:24 -0000
***************
*** 53,58 ****
--- 53,59 ----
       %{!pg:			\
         %{p:gcrt0%O%s}		\
         %{!p:crt0%O%s}}}		\
+    %:if-exists(crti%O%s)	\
     %{!shared:crtbegin%O%s} %{shared:crtbeginS%O%s}"
  
  
***************
*** 62,68 ****
  
  #undef ENDFILE_SPEC
  #define ENDFILE_SPEC		\
!   "%{!shared:crtend%O%s} %{shared:crtendS%O%s}"
  
  
  /* Provide a LINK_SPEC appropriate for NetBSD ELF.  Here we provide
--- 63,70 ----
  
  #undef ENDFILE_SPEC
  #define ENDFILE_SPEC		\
!   "%{!shared:crtend%O%s} %{shared:crtendS%O%s} \
!    %:if-exists(crtn%O%s)"
  
  
  /* Provide a LINK_SPEC appropriate for NetBSD ELF.  Here we provide
Index: config/alpha/netbsd.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/netbsd.h,v
retrieving revision 1.16
diff -c -r1.16 netbsd.h
*** config/alpha/netbsd.h	18 Oct 2002 23:10:34 -0000	1.16
--- config/alpha/netbsd.h	3 Nov 2002 20:52:24 -0000
***************
*** 72,78 ****
  #undef ENDFILE_SPEC
  #define ENDFILE_SPEC		\
    "%{ffast-math|funsafe-math-optimizations:crtfm%O%s} \
!    %{!shared:crtend%O%s} %{shared:crtendS%O%s}"
  
  
  /* Attempt to enable execute permissions on the stack.  */
--- 72,79 ----
  #undef ENDFILE_SPEC
  #define ENDFILE_SPEC		\
    "%{ffast-math|funsafe-math-optimizations:crtfm%O%s} \
!    %{!shared:crtend%O%s} %{shared:crtendS%O%s} \
!    %:if-exists(crtn%O%s)"
  
  
  /* Attempt to enable execute permissions on the stack.  */
Index: cp/g++spec.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/g++spec.c,v
retrieving revision 1.30
diff -c -r1.30 g++spec.c
*** cp/g++spec.c	21 Sep 2002 12:51:54 -0000	1.30
--- cp/g++spec.c	3 Nov 2002 20:52:25 -0000
***************
*** 307,309 ****
--- 307,315 ----
  
  /* Number of extra output files that lang_specific_pre_link may generate.  */
  int lang_specific_extra_outfiles = 0;  /* Not used for C++.  */
+ 
+ /* Table of language-specific spec functions.  */ 
+ const struct spec_function lang_specific_spec_functions[] =
+ {
+   { 0, 0 }
+ };
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.197
diff -c -r1.197 invoke.texi
*** doc/invoke.texi	31 Oct 2002 03:13:44 -0000	1.197
--- doc/invoke.texi	3 Nov 2002 20:52:35 -0000
***************
*** 4940,4945 ****
--- 4940,4966 ----
  Note that each comma in the substituted string is replaced by
  a single space.
  
+ @item %:@var{function}(@var{args})
+ Call the named function @var{function}, passing it @var{args}.
+ @var{args} is first processed as a nested spec string, then split
+ into an argument vector in the usual fashion.  The function returns
+ a string which is processed as if it had appeared literally as part
+ of the current spec.
+ 
+ The following built-in spec functions are provided:
+ 
+ @table @code
+ @item @code{if-exists}
+ The @code{if-exists} spec function takes one argument, an absolute
+ pathname to a file.  If the file exists, @code{if-exists} returns the
+ pathname.  Here is a small example of its usage:
+ 
+ @smallexample
+ *startfile:
+ crt0%O%s %:if-exists(crti%O%s) crtbegin%O%s
+ @end smallexample
+ @end table
+ 
  @item %@{@code{S}@}
  Substitutes the @code{-S} switch, if that switch was given to GCC@.
  If that switch was not specified, this substitutes nothing.  Note that
Index: f/g77spec.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/f/g77spec.c,v
retrieving revision 1.38
diff -c -r1.38 g77spec.c
*** f/g77spec.c	24 Sep 2002 03:44:33 -0000	1.38
--- f/g77spec.c	3 Nov 2002 20:52:36 -0000
***************
*** 562,564 ****
--- 562,570 ----
  
  /* Number of extra output files that lang_specific_pre_link may generate. */
  int lang_specific_extra_outfiles = 0;  /* Not used for F77. */
+ 
+ /* Table of language-specific spec functions.  */ 
+ const struct spec_function lang_specific_spec_functions[] =
+ {
+   { 0, 0 }
+ };
Index: java/jvspec.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jvspec.c,v
retrieving revision 1.58
diff -c -r1.58 jvspec.c
*** java/jvspec.c	30 Sep 2002 14:57:43 -0000	1.58
--- java/jvspec.c	3 Nov 2002 20:52:36 -0000
***************
*** 632,634 ****
--- 632,640 ----
      }
    return err;
  }
+ 
+ /* Table of language-specific spec functions.  */ 
+ const struct spec_function lang_specific_spec_functions[] =
+ {
+   { 0, 0 }
+ };


More information about the Gcc-patches mailing list