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 2 Nov 2002 20:55:16 -0000 *************** *** 230,235 **** --- 230,243 ---- *in_argv = new_argv; } + /* Called to look up language-specific spec functions. */ + const struct spec_function * + lang_specific_lookup_spec_function (name) + const char *name ATTRIBUTE_UNUSED; + { + return NULL; /* Not used for cpp. */ + } + /* Called before linking. Returns 0 on success and -1 on failure. */ int lang_specific_pre_link () { 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 2 Nov 2002 20:55:21 -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 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 char *if_exists_spec_function PARAMS ((int, const char **)); /* The Specs Language *************** *** 450,455 **** --- 456,470 ---- %* 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 specified spec function with arguments ARGS. ARGS + is processed as a spec and split into an argument vector in + the normal fashion. The driver then calls the internal function + corresponding to FUNCTION (which is registered with + register_spec_function, or is one of the provided built-ins) + with the argument count and argument vector. The function + returns a malloc'd string, which is then processed as a + spec and free'd, or NULL. %{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 **** --- 1454,1471 ---- 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 }, + #ifdef EXTRA_SPEC_FUNCTIONS + EXTRA_SPEC_FUNCTIONS + #endif + }; + + static int processing_spec_function; + /* Add appropriate libgcc specs to OBSTACK, taking into account various permutations of -shared-libgcc, -shared, and such. */ *************** *** 1710,1715 **** --- 1737,1751 ---- 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 **** --- 2789,2797 ---- 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 **** --- 5157,5168 ---- 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 * --- 5356,5536 ---- 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; + { + const struct spec_function *sf; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(static_spec_functions); i++) + { + sf = &static_spec_functions[i]; + if (strcmp (sf->name, name) == 0) + return sf; + } + + return lang_specific_lookup_spec_function (name); + } + + /* Evaluate a spec function. */ + + static char * + eval_spec_function (func, args) + const char *func, *args; + { + const struct spec_function *sf; + 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 pointer + to a malloc'd 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, *funcval; + const char *endp; + 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 (!(*endp >= 'A' && *endp <= 'Z') + && !(*endp >= 'a' && *endp <= 'z') + && !(*endp >= '0' && *endp <= '9') + && !(*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); + if (funcval != NULL) + free (funcval); + + 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); --- 6113,6120 ---- signal (SIGCHLD, SIG_DFL); #endif ! /* Allocate the argument vector. */ ! alloc_args (); obstack_init (&obstack); *************** *** 7252,7255 **** --- 7468,7494 ---- ++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 char * + if_exists_spec_function (argc, argv) + int argc; + const char **argv; + { + /* Must have only one argument. */ + if (argc != 1) + return NULL; + + if (IS_ABSOLUTE_PATHNAME (argv[0]) && ! access (argv[0], R_OK)) + return (xstrdup (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 2 Nov 2002 20:55:21 -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; + 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)); *************** *** 39,44 **** --- 47,56 ---- /* Called before processing to change/add/remove arguments. */ extern void lang_specific_driver PARAMS ((int *, const char *const **, int *)); + + /* Called to look up language-specific spec functions. */ + extern const struct spec_function *lang_specific_lookup_spec_function + PARAMS ((const char *)); /* Called before linking. Returns 0 on success and -1 on failure. */ extern int lang_specific_pre_link PARAMS ((void)); 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 2 Nov 2002 20:55:22 -0000 *************** *** 92,97 **** --- 92,105 ---- #endif } + /* Called to look up language-specific spec functions. */ + const struct spec_function * + lang_specific_lookup_spec_function (name) + const char *name ATTRIBUTE_UNUSED; + { + return NULL; /* Not used for C. */ + } + /* Called before linking. Returns 0 on success and -1 on failure. */ int lang_specific_pre_link () 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 2 Nov 2002 20:55:28 -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 2 Nov 2002 20:55:28 -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 2 Nov 2002 20:55:29 -0000 *************** *** 299,304 **** --- 299,312 ---- *in_added_libraries = added_libraries; } + /* Called to look up language-specific spec functions. */ + const struct spec_function * + lang_specific_lookup_spec_function (name) + const char *name ATTRIBUTE_UNUSED; + { + return NULL; /* Not used for C++. */ + } + /* Called before linking. Returns 0 on success and -1 on failure. */ int lang_specific_pre_link () /* Not used for C++. */ { 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 2 Nov 2002 20:55:39 -0000 *************** *** 4940,4945 **** --- 4940,4967 ---- Note that each comma in the substituted string is replaced by a single space. + @item %:@var{function}(@var{args}) + Call the spec function @var{function} with arguments @var{args}. + The arguments are processed as a spec and split into an argument + vector in the normal fashion. GCC then calls an internal function + corresponding to @var{function} with the argument vector. The + function then returns a string which is in-turn processed as a spec + and substituted. + + 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: doc/tm.texi =================================================================== RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v retrieving revision 1.179 diff -c -r1.179 tm.texi *** doc/tm.texi 20 Oct 2002 18:52:01 -0000 1.179 --- doc/tm.texi 2 Nov 2002 20:55:49 -0000 *************** *** 339,344 **** --- 339,362 ---- #define CPP_SYSV_DEFAULT "-D_CALL_AIX" @end smallexample + @findex EXTRA_SPEC_FUNCTIONS + @item EXTRA_SPEC_FUNCTIONS + Define this macro to provide any target-specific spec functions. + + The definition should be an initializer for an array of structures, + containing a string constant, that defines the spec function name, and a + pointer to the C function that implements the spec function. + + Do not define this macro if it does not need to do anything. + + The C function that implements the spec function is passed two arguments: + an argument count (of type @code{int}) and an argument vector (of type + @code{const char **}). The function returns a specification string + (of type @code{char *}) which is then processed and substituted at the + spec function call site in the normal fashion, or @code{NULL} if nothing + is to be substituted. Storage for the returned specification string + should be allocated with @code{malloc()}. + @findex LINK_LIBGCC_SPECIAL @item LINK_LIBGCC_SPECIAL Define this macro if the driver program should find the library 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 2 Nov 2002 20:55:49 -0000 *************** *** 554,559 **** --- 554,567 ---- *in_argv = g77_newargv; } + /* Called to look up language-specific spec functions. */ + const struct spec_function * + lang_specific_lookup_spec_function (name) + const char *name ATTRIBUTE_UNUSED; + { + return NULL; /* Not used for F77. */ + } + /* Called before linking. Returns 0 on success and -1 on failure. */ int lang_specific_pre_link () /* Not used for F77. */ { 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 2 Nov 2002 20:55:50 -0000 *************** *** 603,608 **** --- 603,616 ---- *in_added_libraries = added_libraries; } + /* Called to look up language-specific spec functions. */ + const struct spec_function * + lang_specific_lookup_spec_function (name) + const char *name ATTRIBUTE_UNUSED; + { + return NULL; /* Not used for GCJ. */ + } + int lang_specific_pre_link () {