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 31 Oct 2002 17:27:47 -0000 *************** *** 267,272 **** --- 267,273 ---- struct path_prefix; static void init_spec PARAMS ((void)); + static void init_spec_functions PARAMS ((void)); #ifndef VMS static char **split_directories PARAMS ((const char *, int *)); static void free_split_directories PARAMS ((char **)); *************** *** 292,297 **** --- 293,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 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,465 ---- %* 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 (which + are processed as a spec). The return value of the function + is in turn processed as a 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 **** --- 1449,1475 ---- static struct spec_list *specs = (struct spec_list *) 0; + struct spec_function + { + struct spec_function *next; + const char *name; + char *(*func) PARAMS ((int, const char **)); + }; + + /* List of static spec predicates. */ + + #define INIT_STATIC_SPEC_FUNCTION(name, func) \ + { NULL, name, func } + + static struct spec_function static_spec_functions[] = + { + INIT_STATIC_SPEC_FUNCTION ("if-exists", if_exists_spec_function), + }; + + static struct spec_function *spec_functions; + + static int processing_spec_function; + /* Add appropriate libgcc specs to OBSTACK, taking into account various permutations of -shared-libgcc, -shared, and such. */ *************** *** 1609,1614 **** --- 1640,1659 ---- specs = sl; } + /* Initialize the built-in spec predicate functions. */ + + static void + init_spec_functions () + { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (static_spec_functions); i++) + { + static_spec_functions[i].next = spec_functions; + spec_functions = &static_spec_functions[i]; + } + } + /* Change the value of spec NAME to SPEC. If SPEC is empty, then the spec is removed; If the spec starts with a + then SPEC is added to the end of the current spec. */ *************** *** 1710,1715 **** --- 1755,1768 ---- 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 **** --- 2806,2814 ---- 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 **** --- 5174,5185 ---- 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 * --- 5373,5553 ---- 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; ! } ! return 0; } + /* Register a spec function. */ + + void + register_spec_function (name, func) + const char *name; + char *(*func) PARAMS ((int, const char **)); + { + struct spec_function *sf; + + for (sf = spec_functions; sf != NULL; sf = sf->next) + fatal ("duplicate `%s' spec function", name); + + sf = xmalloc (sizeof (*sf)); + sf->name = name; + sf->func = func; + sf->next = spec_functions; + spec_functions = sf; + } + + /* Evaluate a spec function. */ + + static char * + eval_spec_function (func, args) + const char *func, *args; + { + 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; + + + for (sf = spec_functions; sf != NULL; sf = sf->next) + if (strcmp (sf->name, func) == 0) + break; + 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 interpreted at the discretion of the predicate function. The + function returns a pointer to a malloc'd string containing a spec which + we then process, 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 predicate 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); --- 6130,6140 ---- signal (SIGCHLD, SIG_DFL); #endif ! /* Initialize the static spec functions. */ ! init_spec_functions (); ! ! /* Allocate the argument vector. */ ! alloc_args (); obstack_init (&obstack); *************** *** 7252,7255 **** --- 7488,7515 ---- ++p; } + } + + /* if-exists built-in spec function. + + Checks to see if the file specified in ARGS exists. Returns + the expanded pathname if found. */ + + static char * + if_exists_spec_function (argc, argv) + int argc; + const char **argv; + { + + /* Must have only one argument. */ + if (argc != 1) + return NULL; + + /* We check for an absolute pathname because %s expansion returns + the basename if the file is not found. */ + + 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 31 Oct 2002 17:27:47 -0000 *************** *** 25,30 **** --- 25,32 ---- /* These are exported by gcc.c. */ extern int do_spec PARAMS ((const char *)); + extern void register_spec_function PARAMS ((const char *name, + char * (*func) (int, const char **))); extern void record_temp_file PARAMS ((const char *, int, int)); extern void fancy_abort PARAMS ((void)) ATTRIBUTE_NORETURN; extern const char *input_filename; 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 31 Oct 2002 17:27:53 -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