From c21b3276e4428c6ac755f1fc03eed6a045d4bb44 Mon Sep 17 00:00:00 2001 From: thorpej Date: Tue, 19 Nov 2002 04:37:50 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@59241 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 23 +++++ gcc/config/alpha/netbsd.h | 3 +- gcc/config/netbsd-elf.h | 4 +- gcc/cp/ChangeLog | 4 + gcc/cp/g++spec.c | 6 ++ gcc/cppspec.c | 6 ++ gcc/doc/invoke.texi | 21 +++++ gcc/f/ChangeLog | 4 + gcc/f/g77spec.c | 6 ++ gcc/gcc.c | 235 +++++++++++++++++++++++++++++++++++++++++++++- gcc/gcc.h | 11 +++ gcc/gccspec.c | 6 ++ gcc/java/ChangeLog | 4 + gcc/java/jvspec.c | 6 ++ 14 files changed, 334 insertions(+), 5 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 87eb85b..07ea2be 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2002-11-19 Jason Thorpe + + * 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. + 2002-11-18 Steve Ellcey * config/ia64/hpux_longdouble.h (FIXUNS_TRUNCTFSI2_LIBCALL): New. diff --git a/gcc/config/alpha/netbsd.h b/gcc/config/alpha/netbsd.h index 4dc713b..f56f780 100644 --- a/gcc/config/alpha/netbsd.h +++ b/gcc/config/alpha/netbsd.h @@ -72,7 +72,8 @@ Boston, MA 02111-1307, USA. */ #undef ENDFILE_SPEC #define ENDFILE_SPEC \ "%{ffast-math|funsafe-math-optimizations:crtfm%O%s} \ - %{!shared:crtend%O%s} %{shared:crtendS%O%s}" + %{!shared:crtend%O%s} %{shared:crtendS%O%s} \ + %:if-exists(crtn%O%s)" /* Attempt to enable execute permissions on the stack. */ diff --git a/gcc/config/netbsd-elf.h b/gcc/config/netbsd-elf.h index 40ed3aa..a35f46a 100644 --- a/gcc/config/netbsd-elf.h +++ b/gcc/config/netbsd-elf.h @@ -53,6 +53,7 @@ Boston, MA 02111-1307, USA. */ %{!pg: \ %{p:gcrt0%O%s} \ %{!p:crt0%O%s}}} \ + %:if-exists(crti%O%s) \ %{!shared:crtbegin%O%s} %{shared:crtbeginS%O%s}" @@ -62,7 +63,8 @@ Boston, MA 02111-1307, USA. */ #undef ENDFILE_SPEC #define ENDFILE_SPEC \ - "%{!shared:crtend%O%s} %{shared:crtendS%O%s}" + "%{!shared:crtend%O%s} %{shared:crtendS%O%s} \ + %:if-exists(crtn%O%s)" /* Provide a LINK_SPEC appropriate for NetBSD ELF. Here we provide diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f4f98e0..e3c47ab 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,7 @@ +2002-11-19 Jason Thorpe + + * g++spec.c (lang_specific_spec_functions): New. + 2002-11-15 Kazu Hirata * ChangeLog: Follow spelling conventions. diff --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c index 6e5de08..d462448 100644 --- a/gcc/cp/g++spec.c +++ b/gcc/cp/g++spec.c @@ -307,3 +307,9 @@ int lang_specific_pre_link () /* Not used for C++. */ /* 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 } +}; diff --git a/gcc/cppspec.c b/gcc/cppspec.c index ee19b72..e79968a 100644 --- a/gcc/cppspec.c +++ b/gcc/cppspec.c @@ -238,3 +238,9 @@ int lang_specific_pre_link () /* 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 } +}; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1df52de..45fee6f 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -4967,6 +4967,27 @@ Substitute the variable part of a matched option. See below. 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 diff --git a/gcc/f/ChangeLog b/gcc/f/ChangeLog index cd79362..4960f2f 100644 --- a/gcc/f/ChangeLog +++ b/gcc/f/ChangeLog @@ -1,3 +1,7 @@ +2002-11-19 Jason Thorpe + + * g77spec.c (lang_specific_spec_functions): New. + 2002-11-02 Toon Moene * g77.texi: Correct documentation on generating C++ prototypes diff --git a/gcc/f/g77spec.c b/gcc/f/g77spec.c index 6aea81b..1bf20d2 100644 --- a/gcc/f/g77spec.c +++ b/gcc/f/g77spec.c @@ -562,3 +562,9 @@ int lang_specific_pre_link () /* Not used for F77. */ /* 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 } +}; diff --git a/gcc/gcc.c b/gcc/gcc.c index 291712d..56cb08f 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -292,6 +292,9 @@ static void delete_failure_queue PARAMS ((void)); 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,6 +320,7 @@ static void add_assembler_option PARAMS ((const char *, int)); 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,6 +331,8 @@ static void init_gcc_specs PARAMS ((struct obstack *, #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,6 +456,12 @@ or with constant text in a single argument. %* 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,6 +1451,16 @@ static struct spec_list *extra_specs = (struct spec_list *) 0; 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,6 +1732,15 @@ static int signal_count; 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,6 +2784,9 @@ execute () 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,6 +5152,12 @@ do_spec_1 (spec, inswitch, soft_matched_part) return -1; break; + case ':': + p = handle_spec_function (p); + if (p == 0) + return -1; + break; + case '%': obstack_1grow (&obstack, '%'); break; @@ -5311,10 +5351,179 @@ do_spec_1 (spec, inswitch, soft_matched_part) arg_going = 1; } - /* End of string. */ + /* 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,8 +6106,8 @@ main (argc, argv) signal (SIGCHLD, SIG_DFL); #endif - argbuf_length = 10; - argbuf = (const char **) xmalloc (argbuf_length * sizeof (const char *)); + /* Allocate the argument vector. */ + alloc_args (); obstack_init (&obstack); @@ -7253,3 +7462,23 @@ print_multilib_info () ++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; +} diff --git a/gcc/gcc.h b/gcc/gcc.h index 7703387..feab0ef 100644 --- a/gcc/gcc.h +++ b/gcc/gcc.h @@ -23,6 +23,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #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)); @@ -48,6 +56,9 @@ extern int n_infiles; /* 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. */ extern const char **outfiles; diff --git a/gcc/gccspec.c b/gcc/gccspec.c index 79f3d66..6e538b1 100644 --- a/gcc/gccspec.c +++ b/gcc/gccspec.c @@ -101,3 +101,9 @@ lang_specific_pre_link () /* 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 } +}; diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index e8c9d51..31379a1 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,7 @@ +2002-11-19 Jason Thorpe + + * jvspec.c (lang_specific_spec_functions): New. + 2002-11-18 Tom Tromey Fix for PR java/7912: diff --git a/gcc/java/jvspec.c b/gcc/java/jvspec.c index 8638ac3..c3efe58 100644 --- a/gcc/java/jvspec.c +++ b/gcc/java/jvspec.c @@ -632,3 +632,9 @@ lang_specific_pre_link () } return err; } + +/* Table of language-specific spec functions. */ +const struct spec_function lang_specific_spec_functions[] = +{ + { 0, 0 } +}; -- 2.7.4