diff options
-rw-r--r-- | contrib/gcc/gcc.c | 970 |
1 files changed, 533 insertions, 437 deletions
diff --git a/contrib/gcc/gcc.c b/contrib/gcc/gcc.c index 8f4a71c..42b3094 100644 --- a/contrib/gcc/gcc.c +++ b/contrib/gcc/gcc.c @@ -95,9 +95,6 @@ extern int getrusage PARAMS ((int, struct rusage *)); /* FIXME: when autoconf is fixed, remove the host check - dj */ #if defined(TARGET_EXECUTABLE_SUFFIX) && defined(HOST_EXECUTABLE_SUFFIX) #define HAVE_TARGET_EXECUTABLE_SUFFIX -#else -#undef TARGET_EXECUTABLE_SUFFIX -#define TARGET_EXECUTABLE_SUFFIX "" #endif /* By default there is no special suffix for host executables. */ @@ -124,13 +121,6 @@ extern int getrusage PARAMS ((int, struct rusage *)); static const char dir_separator_str[] = { DIR_SEPARATOR, 0 }; -#define obstack_chunk_alloc xmalloc -#define obstack_chunk_free free - -#ifndef GET_ENV_PATH_LIST -#define GET_ENV_PATH_LIST(VAR,NAME) do { (VAR) = getenv (NAME); } while (0) -#endif - /* Most every one is fine with LIBRARY_PATH. For some, it conflicts. */ #ifndef LIBRARY_PATH_ENV #define LIBRARY_PATH_ENV "LIBRARY_PATH" @@ -220,7 +210,7 @@ static const char *compiler_version; /* The target version specified with -V */ -static const char *spec_version = DEFAULT_TARGET_VERSION; +static const char *const spec_version = DEFAULT_TARGET_VERSION; /* The target machine specified with -b. */ @@ -249,9 +239,9 @@ static const struct modify_target } modify_target[] = MODIFY_TARGET_NAME; #endif - + /* The number of errors that have occurred; the link phase will not be - run if this is non-zero. */ + run if this is nonzero. */ static int error_count = 0; /* Greatest exit code of sub-processes that has been encountered up to @@ -279,11 +269,6 @@ static struct rusage rus, prus; struct path_prefix; static void init_spec PARAMS ((void)); -#ifndef VMS -static char **split_directories PARAMS ((const char *, int *)); -static void free_split_directories PARAMS ((char **)); -static char *make_relative_prefix PARAMS ((const char *, const char *, const char *)); -#endif /* VMS */ static void store_arg PARAMS ((const char *, int, int)); static char *load_specs PARAMS ((const char *)); static void read_specs PARAMS ((const char *, int)); @@ -304,9 +289,14 @@ 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 *)); +static int do_spec_2 PARAMS ((const char *)); +static void do_self_spec PARAMS ((const char *)); static const char *find_file PARAMS ((const char *)); static int is_directory PARAMS ((const char *, const char *, int)); static void validate_switches PARAMS ((const char *)); @@ -327,6 +317,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 @@ -337,6 +328,9 @@ 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 **)); +static const char *if_exists_else_spec_function PARAMS ((int, const char **)); /* The Specs Language @@ -428,7 +422,7 @@ or with constant text in a single argument. and substitute the full name found. %eSTR Print STR as an error message. STR is terminated by a newline. Use this when inconsistent options are detected. - %nSTR Print STR as an notice. STR is terminated by a newline. + %nSTR Print STR as a notice. STR is terminated by a newline. %x{OPTION} Accumulate an option for %X. %X Output the accumulated linker options specified by compilations. %Y Output the accumulated assembler options specified by compilations. @@ -460,6 +454,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. @@ -649,7 +649,11 @@ proper position among the other output files. */ # endif #endif -static const char *asm_debug = ASM_DEBUG_SPEC; +#ifndef STARTFILE_PREFIX_SPEC +# define STARTFILE_PREFIX_SPEC "" +#endif + +static const char *asm_debug; static const char *cpp_spec = CPP_SPEC; static const char *cpp_predefines = CPP_PREDEFINES; static const char *cc1_spec = CC1_SPEC; @@ -666,6 +670,7 @@ static const char *switches_need_spaces = SWITCHES_NEED_SPACES; static const char *linker_name_spec = LINKER_NAME; static const char *link_command_spec = LINK_COMMAND_SPEC; static const char *link_libgcc_spec = LINK_LIBGCC_SPEC; +static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC; /* Standard options to cpp, cc1, and as, to reduce duplication in specs. There should be no need to override these in target dependent files, @@ -673,45 +678,48 @@ static const char *link_libgcc_spec = LINK_LIBGCC_SPEC; of the GCC driver can correctly drive older tool chains with the appropriate -B options. */ +/* When cpplib handles traditional preprocessing, get rid of this, and + call cc1 (or cc1obj in objc/lang-specs.h) from the main specs so + that we default the front end language better. */ static const char *trad_capable_cpp = -"%{traditional|ftraditional|traditional-cpp:trad}cpp0"; +"cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp}"; /* We don't wrap .d files in %W{} since a missing .d file, and 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 = "%{C:%{!E:%eGNU C does not support -C without using -E}}\ - %{nostdinc*} %{C} %{v} %{I*} %{P} %{$} %I\ + %{CC:%{!E:%eGNU C does not support -CC without using -E}}\ + %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %I\ %{MD:-MD %{!o:%b.d}%{o*:%.d%*}}\ %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\ %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\ %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}}\ - %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3 -D__GXX_ABI_VERSION=102}\ + %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3}\ %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\ - %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\ - %{fno-inline|O0|!O*:-D__NO_INLINE__} %{ffast-math:-D__FAST_MATH__}\ - %{ffreestanding:-D__STDC_HOSTED__=0} %{fno-hosted:-D__STDC_HOSTED__=0}\ - %{!ffreestanding:%{!fno-hosted:-D__STDC_HOSTED__=1}} %{remap}\ - %{g3:-dD} %{H} %C\ - %{fshort-wchar:-U__WCHAR_TYPE__ -D__WCHAR_TYPE__=short\\ unsigned\\ int}\ - %{D*&U*&A*} %{i*} %Z %i\ + %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\ %{E|M|MM:%W{o*}}"; /* This contains cpp options which are common with cc1_options and are passed - only when preprocessing only to avoid duplication. */ + only when preprocessing only to avoid duplication. We pass the cc1 spec + options to the preprocessor so that it the cc1 spec may manipulate + options used to set target flags. Those special target flags settings may + in turn cause preprocessor symbols to be defined specially. */ static const char *cpp_options = -"%(cpp_unique_options) %{std*} %{d*} %{W*} %{w} %{pedantic*}\ - %{fshow-column} %{fno-show-column}\ - %{fsigned-char&funsigned-char}\ - %{fleading-underscore} %{fno-leading-underscore}\ - %{fno-operator-names} %{ftabstop=*}"; +"%(cpp_unique_options) %1 %{m*} %{std*} %{ansi} %{W*&pedantic*} %{w} %{f*}\ + %{O*} %{undef}"; + +/* This contains cpp options which are not passed when the preprocessor + output will be used by another program. */ +static const char *cpp_debug_options = "%{d*}"; /* NB: This is shared amongst all front-ends. */ static const char *cc1_options = "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\ - %{g*} %{O*} %{W*} %{w} %{pedantic*} %{std*} %{ansi}\ - %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\ + -auxbase%{c|S:%{o*:-strip %*}%{!o*: %b}}%{!c:%{!S: %b}}\ + %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi}\ + %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\ %{Qn:-fno-ident} %{--help:--help}\ %{--target-help:--target-help}\ %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\ @@ -741,6 +749,12 @@ static const char *multilib_exclusions; static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS; +#ifndef DRIVER_SELF_SPECS +#define DRIVER_SELF_SPECS "" +#endif + +static const char *const driver_self_specs[] = { DRIVER_SELF_SPECS }; + struct user_specs { struct user_specs *next; @@ -749,31 +763,10 @@ struct user_specs static struct user_specs *user_specs_head, *user_specs_tail; -/* This defines which switch letters take arguments. */ - -#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \ - ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \ - || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \ - || (CHAR) == 'I' || (CHAR) == 'm' || (CHAR) == 'x' \ - || (CHAR) == 'L' || (CHAR) == 'A' || (CHAR) == 'V' \ - || (CHAR) == 'B' || (CHAR) == 'b') - #ifndef SWITCH_TAKES_ARG #define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR) #endif -/* This defines which multi-letter switches take arguments. */ - -#define DEFAULT_WORD_SWITCH_TAKES_ARG(STR) \ - (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext") \ - || !strcmp (STR, "Tbss") || !strcmp (STR, "include") \ - || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \ - || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \ - || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \ - || !strcmp (STR, "isystem") || !strcmp (STR, "-param") \ - || !strcmp (STR, "specs") \ - || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ")) - #ifndef WORD_SWITCH_TAKES_ARG #define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR) #endif @@ -841,26 +834,25 @@ static const struct compiler default_compilers[] = {".c", "@c", 0}, {"@c", /* cc1 has an integrated ISO C preprocessor. We should invoke the - external preprocessor if -save-temps or -traditional is given. */ - "%{E|M|MM:%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)}\ + external preprocessor if -save-temps is given. */ + "%{E|M|MM:%(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)}\ %{!E:%{!M:%{!MM:\ - %{save-temps|no-integrated-cpp:%(trad_capable_cpp) -lang-c %{ansi:-std=c89}\ + %{traditional|ftraditional:\ +%eGNU C no longer supports -traditional without -E}\ + %{save-temps|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \ %(cpp_options) %{save-temps:%b.i} %{!save-temps:%g.i} \n\ cc1 -fpreprocessed %{save-temps:%b.i} %{!save-temps:%g.i} %(cc1_options)}\ - %{!save-temps:%{!no-integrated-cpp:\ - %{traditional|ftraditional|traditional-cpp:\ - tradcpp0 -lang-c %{ansi:-std=c89} %(cpp_options) %{!pipe:%g.i} |\n\ - cc1 -fpreprocessed %{!pipe:%g.i} %(cc1_options)}\ - %{!traditional:%{!ftraditional:%{!traditional-cpp:\ - cc1 -lang-c %{ansi:-std=c89} %(cpp_unique_options) %(cc1_options)}}}}}\ + %{!save-temps:%{!traditional-cpp:%{!no-integrated-cpp:\ + cc1 %(cpp_unique_options) %(cc1_options)}}}\ %{!fsyntax-only:%(invoke_as)}}}}", 0}, {"-", "%{!E:%e-E required when input is from standard input}\ - %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0}, + %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0}, {".h", "@c-header", 0}, {"@c-header", "%{!E:%ecompilation of header file requested} \ - %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0}, + %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", + 0}, {".i", "@cpp-output", 0}, {"@cpp-output", "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0}, @@ -870,6 +862,7 @@ static const struct compiler default_compilers[] = {".S", "@assembler-with-cpp", 0}, {"@assembler-with-cpp", "%(trad_capable_cpp) -lang-asm %(cpp_options)\ + %{E|M|MM:%(cpp_debug_options)}\ %{!M:%{!MM:%{!E:%{!S:-o %{|!pipe:%g.s} |\n\ as %(asm_debug) %(asm_options) %{!pipe:%g.s} %A }}}}", 0}, #include "specs.h" @@ -879,8 +872,7 @@ static const struct compiler default_compilers[] = /* Number of elements in default_compilers, not counting the terminator. */ -static int n_default_compilers - = (sizeof default_compilers / sizeof (struct compiler)) - 1; +static const int n_default_compilers = ARRAY_SIZE (default_compilers) - 1; /* A vector of options to give to the linker. These options are accumulated by %x, @@ -930,6 +922,7 @@ static const struct option_map option_map[] = {"--bootclasspath", "-fbootclasspath=", "aj"}, {"--CLASSPATH", "-fclasspath=", "aj"}, {"--comments", "-C", 0}, + {"--comments-in-macros", "-CC", 0}, {"--compile", "-c", 0}, {"--debug", "-g", "oj"}, {"--define-macro", "-D", "aj"}, @@ -1199,7 +1192,7 @@ translate_options (argcp, argvp) nskip += SWITCH_TAKES_ARG (c) - (p[1] != 0); else if (WORD_SWITCH_TAKES_ARG (p)) nskip += WORD_SWITCH_TAKES_ARG (p); - else if ((c == 'B' || c == 'b' || c == 'V' || c == 'x') + else if ((c == 'B' || c == 'b' || c == 'x') && p[1] == 0) nskip += 1; else if (! strcmp (p, "Xlinker")) @@ -1394,6 +1387,7 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("invoke_as", &invoke_as), INIT_STATIC_SPEC ("cpp", &cpp_spec), INIT_STATIC_SPEC ("cpp_options", &cpp_options), + INIT_STATIC_SPEC ("cpp_debug_options", &cpp_debug_options), INIT_STATIC_SPEC ("cpp_unique_options", &cpp_unique_options), INIT_STATIC_SPEC ("trad_capable_cpp", &trad_capable_cpp), INIT_STATIC_SPEC ("cc1", &cc1_spec), @@ -1420,6 +1414,7 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("md_exec_prefix", &md_exec_prefix), INIT_STATIC_SPEC ("md_startfile_prefix", &md_startfile_prefix), INIT_STATIC_SPEC ("md_startfile_prefix_1", &md_startfile_prefix_1), + INIT_STATIC_SPEC ("startfile_prefix_spec", &startfile_prefix_spec), }; #ifdef EXTRA_SPECS /* additional specs needed */ @@ -1439,6 +1434,17 @@ 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 }, + { "if-exists-else", if_exists_else_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. */ @@ -1501,6 +1507,10 @@ init_spec () } #endif + /* Initialize here, not in definition. The IRIX 6 O32 cc sometimes chokes + on ?: in file-scope variable initializations. */ + asm_debug = ASM_DEBUG_SPEC; + for (i = ARRAY_SIZE (static_specs) - 1; i >= 0; i--) { sl = &static_specs[i]; @@ -1539,12 +1549,12 @@ init_spec () { const char *p = libgcc_spec; int in_sep = 1; - + /* Transform the extant libgcc_spec into one that uses the shared libgcc when given the proper command line arguments. */ while (*p) { - if (in_sep && *p == '-' && strncmp (p, "-lgcc", 5) == 0) + if (in_sep && *p == '-' && strncmp (p, "-lgcc", 5) == 0) { init_gcc_specs (&obstack, #ifdef NO_SHARED_LIBGCC_MULTILIB @@ -1706,6 +1716,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 @@ -1889,8 +1908,9 @@ read_specs (filename, main_p) { int name_len; struct spec_list *sl; + struct spec_list *newsl; - /* Get original name */ + /* Get original name. */ p1 += sizeof "%rename"; while (*p1 == ' ' || *p1 == '\t') p1++; @@ -1936,6 +1956,11 @@ read_specs (filename, main_p) if (strcmp (p1, p2) == 0) continue; + for (newsl = specs; newsl; newsl = newsl->next) + if (strcmp (newsl->name, p2) == 0) + fatal ("%s: attempt to rename spec '%s' to already defined spec '%s'", + filename, p1, p2); + if (verbose_flag) { notice ("rename spec %s to %s\n", p1, p2); @@ -2166,7 +2191,7 @@ clear_failure_queue () /* Build a list of search directories from PATHS. PREFIX is a string to prepend to the list. - If CHECK_DIR_P is non-zero we ensure the directory exists. + If CHECK_DIR_P is nonzero we ensure the directory exists. This is used mostly by putenv_from_prefixes so we use `collect_obstack'. It is also used by the --print-search-dirs flag. */ @@ -2240,246 +2265,6 @@ putenv_from_prefixes (paths, env_var) putenv (build_search_list (paths, env_var, 1)); } -#ifndef VMS - -/* FIXME: the location independence code for VMS is hairier than this, - and hasn't been written. */ - -/* Split a filename into component directories. */ - -static char ** -split_directories (name, ptr_num_dirs) - const char *name; - int *ptr_num_dirs; -{ - int num_dirs = 0; - char **dirs; - const char *p, *q; - int ch; - - /* Count the number of directories. Special case MSDOS disk names as part - of the initial directory. */ - p = name; -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) - { - p += 3; - num_dirs++; - } -#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ - - while ((ch = *p++) != '\0') - { - if (IS_DIR_SEPARATOR (ch)) - { - num_dirs++; - while (IS_DIR_SEPARATOR (*p)) - p++; - } - } - - dirs = (char **) xmalloc (sizeof (char *) * (num_dirs + 2)); - - /* Now copy the directory parts. */ - num_dirs = 0; - p = name; -#ifdef HAVE_DOS_BASED_FILE_SYSTEM - if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) - { - dirs[num_dirs++] = save_string (p, 3); - p += 3; - } -#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ - - q = p; - while ((ch = *p++) != '\0') - { - if (IS_DIR_SEPARATOR (ch)) - { - while (IS_DIR_SEPARATOR (*p)) - p++; - - dirs[num_dirs++] = save_string (q, p - q); - q = p; - } - } - - if (p - 1 - q > 0) - dirs[num_dirs++] = save_string (q, p - 1 - q); - - dirs[num_dirs] = NULL; - if (ptr_num_dirs) - *ptr_num_dirs = num_dirs; - - return dirs; -} - -/* Release storage held by split directories. */ - -static void -free_split_directories (dirs) - char **dirs; -{ - int i = 0; - - while (dirs[i] != NULL) - free (dirs[i++]); - - free ((char *) dirs); -} - -/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets - to PREFIX starting with the directory portion of PROGNAME and a relative - pathname of the difference between BIN_PREFIX and PREFIX. - - For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is - /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this - function will return /red/green/blue/../omega. - - If no relative prefix can be found, return NULL. */ - -static char * -make_relative_prefix (progname, bin_prefix, prefix) - const char *progname; - const char *bin_prefix; - const char *prefix; -{ - char **prog_dirs, **bin_dirs, **prefix_dirs; - int prog_num, bin_num, prefix_num, std_loc_p; - int i, n, common; - - prog_dirs = split_directories (progname, &prog_num); - bin_dirs = split_directories (bin_prefix, &bin_num); - - /* If there is no full pathname, try to find the program by checking in each - of the directories specified in the PATH environment variable. */ - if (prog_num == 1) - { - char *temp; - - GET_ENV_PATH_LIST (temp, "PATH"); - if (temp) - { - char *startp, *endp, *nstore; - size_t prefixlen = strlen (temp) + 1; - if (prefixlen < 2) - prefixlen = 2; - - nstore = (char *) alloca (prefixlen + strlen (progname) + 1); - - startp = endp = temp; - while (1) - { - if (*endp == PATH_SEPARATOR || *endp == 0) - { - if (endp == startp) - { - nstore[0] = '.'; - nstore[1] = DIR_SEPARATOR; - nstore[2] = '\0'; - } - else - { - strncpy (nstore, startp, endp - startp); - if (! IS_DIR_SEPARATOR (endp[-1])) - { - nstore[endp - startp] = DIR_SEPARATOR; - nstore[endp - startp + 1] = 0; - } - else - nstore[endp - startp] = 0; - } - strcat (nstore, progname); - if (! access (nstore, X_OK) -#ifdef HAVE_HOST_EXECUTABLE_SUFFIX - || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) -#endif - ) - { - free_split_directories (prog_dirs); - progname = nstore; - prog_dirs = split_directories (progname, &prog_num); - break; - } - - if (*endp == 0) - break; - endp = startp = endp + 1; - } - else - endp++; - } - } - } - - /* Remove the program name from comparison of directory names. */ - prog_num--; - - /* Determine if the compiler is installed in the standard location, and if - so, we don't need to specify relative directories. Also, if argv[0] - doesn't contain any directory specifiers, there is not much we can do. */ - std_loc_p = 0; - if (prog_num == bin_num) - { - for (i = 0; i < bin_num; i++) - { - if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) - break; - } - - if (prog_num <= 0 || i == bin_num) - { - std_loc_p = 1; - free_split_directories (prog_dirs); - free_split_directories (bin_dirs); - prog_dirs = bin_dirs = (char **) 0; - return NULL; - } - } - - prefix_dirs = split_directories (prefix, &prefix_num); - - /* Find how many directories are in common between bin_prefix & prefix. */ - n = (prefix_num < bin_num) ? prefix_num : bin_num; - for (common = 0; common < n; common++) - { - if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) - break; - } - - /* If there are no common directories, there can be no relative prefix. */ - if (common == 0) - { - free_split_directories (prog_dirs); - free_split_directories (bin_dirs); - free_split_directories (prefix_dirs); - return NULL; - } - - /* Build up the pathnames in argv[0]. */ - for (i = 0; i < prog_num; i++) - obstack_grow (&obstack, prog_dirs[i], strlen (prog_dirs[i])); - - /* Now build up the ..'s. */ - for (i = common; i < n; i++) - { - obstack_grow (&obstack, DIR_UP, sizeof (DIR_UP) - 1); - obstack_1grow (&obstack, DIR_SEPARATOR); - } - - /* Put in directories to move over to prefix. */ - for (i = common; i < prefix_num; i++) - obstack_grow (&obstack, prefix_dirs[i], strlen (prefix_dirs[i])); - - free_split_directories (prog_dirs); - free_split_directories (bin_dirs); - free_split_directories (prefix_dirs); - - obstack_1grow (&obstack, '\0'); - return obstack_finish (&obstack); -} -#endif /* VMS */ - /* Check whether NAME can be accessed in MODE. This is like access, except that it never considers directories to be executable. */ @@ -2743,6 +2528,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) @@ -2793,8 +2581,8 @@ execute () { const char *const *j; - if (verbose_only_flag) - { + if (verbose_only_flag) + { for (j = commands[i].argv; *j; j++) { const char *p; @@ -2807,8 +2595,8 @@ execute () } fputc ('"', stderr); } - } - else + } + else for (j = commands[i].argv; *j; j++) fprintf (stderr, " %s", *j); @@ -2819,7 +2607,7 @@ execute () } fflush (stderr); if (verbose_only_flag != 0) - return 0; + return 0; #ifdef DEBUG notice ("\nGo ahead? (y or n) "); fflush (stderr); @@ -2833,6 +2621,33 @@ execute () #endif /* DEBUG */ } +#ifdef ENABLE_VALGRIND_CHECKING + /* Run the each command through valgrind. To simplifiy prepending the + path to valgrind and the option "-q" (for quiet operation unless + something triggers), we allocate a separate argv array. */ + + for (i = 0; i < n_commands; i++) + { + const char **argv; + int argc; + int j; + + for (argc = 0; commands[i].argv[argc] != NULL; argc++) + ; + + argv = alloca ((argc + 3) * sizeof (char *)); + + argv[0] = VALGRIND_PATH; + argv[1] = "-q"; + for (j = 2; j < argc + 2; j++) + argv[j] = commands[i].argv[j - 2]; + argv[j] = NULL; + + commands[i].argv = argv; + commands[i].prog = argv[0]; + } +#endif + /* Run each piped subprocess. */ for (i = 0; i < n_commands; i++) @@ -2925,7 +2740,7 @@ Internal error: %s (program %s)\n\ Please submit a full bug report.\n\ See %s for instructions.", strsignal (WTERMSIG (status)), commands[j].prog, - GCCBUGURL); + bug_report_url); signal_count++; ret_code = -1; } @@ -3003,9 +2818,6 @@ const char **outfiles; /* Used to track if none of the -B paths are used. */ static int warn_B; -/* Used to track if standard path isn't used and -b or -V is specified. */ -static int warn_std; - /* Gives value to pass as "warn" to add_prefix for standard prefixes. */ static int *warn_std_ptr = 0; @@ -3111,7 +2923,7 @@ display_help () fputs (_(" -o <file> Place the output into <file>\n"), stdout); fputs (_("\ -x <language> Specify the language of the following input files\n\ - Permissable languages include: c c++ assembler none\n\ + Permissible languages include: c c++ assembler none\n\ 'none' means revert to the default behavior of\n\ guessing the language based on the file's extension\n\ "), stdout); @@ -3202,7 +3014,7 @@ process_command (argc, argv) int j; #endif - GET_ENV_PATH_LIST (gcc_exec_prefix, "GCC_EXEC_PREFIX"); + GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX"); n_switches = 0; n_infiles = 0; @@ -3221,6 +3033,61 @@ process_command (argc, argv) } } + /* If there is a -V or -b option (or both), process it now, before + trying to interpret the rest of the command line. */ + if (argc > 1 && argv[1][0] == '-' + && (argv[1][1] == 'V' || argv[1][1] == 'b')) + { + const char *new_version = DEFAULT_TARGET_VERSION; + const char *new_machine = DEFAULT_TARGET_MACHINE; + const char *progname = argv[0]; + char **new_argv; + char *new_argv0; + int baselen; + + while (argc > 1 && argv[1][0] == '-' + && (argv[1][1] == 'V' || argv[1][1] == 'b')) + { + char opt = argv[1][1]; + const char *arg; + if (argv[1][2] != '\0') + { + arg = argv[1] + 2; + argc -= 1; + argv += 1; + } + else if (argc > 2) + { + arg = argv[2]; + argc -= 2; + argv += 2; + } + else + fatal ("`-%c' option must have argument", opt); + if (opt == 'V') + new_version = arg; + else + new_machine = arg; + } + + for (baselen = strlen (progname); baselen > 0; baselen--) + if (IS_DIR_SEPARATOR (progname[baselen-1])) + break; + new_argv0 = xmemdup (progname, baselen, + baselen + concat_length (new_version, new_machine, + "-gcc-", NULL) + 1); + strcpy (new_argv0 + baselen, new_machine); + strcat (new_argv0, "-gcc-"); + strcat (new_argv0, new_version); + + new_argv = xmemdup (argv, (argc + 1) * sizeof (argv[0]), + (argc + 1) * sizeof (argv[0])); + new_argv[0] = new_argv0; + + execvp (new_argv0, new_argv); + fatal ("couldn't run `%s': %s", new_argv0, xstrerror (errno)); + } + /* Set up the default search paths. If there is no GCC_EXEC_PREFIX, see if we can create it from the pathname specified in argv[0]. */ @@ -3262,7 +3129,7 @@ process_command (argc, argv) /* COMPILER_PATH and LIBRARY_PATH have values that are lists of directory names with colons. */ - GET_ENV_PATH_LIST (temp, "COMPILER_PATH"); + GET_ENVIRONMENT (temp, "COMPILER_PATH"); if (temp) { const char *startp, *endp; @@ -3297,7 +3164,7 @@ process_command (argc, argv) } } - GET_ENV_PATH_LIST (temp, LIBRARY_PATH_ENV); + GET_ENVIRONMENT (temp, LIBRARY_PATH_ENV); if (temp && *cross_compile == '0') { const char *startp, *endp; @@ -3330,7 +3197,7 @@ process_command (argc, argv) } /* Use LPATH like LIBRARY_PATH (for the CMU build program). */ - GET_ENV_PATH_LIST (temp, "LPATH"); + GET_ENVIRONMENT (temp, "LPATH"); if (temp && *cross_compile == '0') { const char *startp, *endp; @@ -3408,7 +3275,6 @@ process_command (argc, argv) /* Scan argv twice. Here, the first time, just count how many switches there will be in their vector, and how many input files in theirs. - Also parse any switches that determine the configuration name, such as -b. Here we also parse the switches that cc itself uses (e.g. -v). */ for (i = 1; i < argc; i++) @@ -3437,7 +3303,7 @@ process_command (argc, argv) { /* translate_options () has turned --version into -fversion. */ printf (_("%s (GCC) %s\n"), programname, version_string); - fputs (_("Copyright (C) 2002 Free Software Foundation, Inc.\n"), + fputs (_("Copyright (C) 2003 Free Software Foundation, Inc.\n"), stdout); fputs (_("This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"), @@ -3460,20 +3326,20 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" add_linker_option ("--help", 6); } else if (strcmp (argv[i], "-ftarget-help") == 0) - { - /* translate_options() has turned --target-help into -ftarget-help. */ - target_help_flag = 1; + { + /* translate_options() has turned --target-help into -ftarget-help. */ + target_help_flag = 1; - /* We will be passing a dummy file on to the sub-processes. */ - n_infiles++; - n_switches++; + /* We will be passing a dummy file on to the sub-processes. */ + n_infiles++; + n_switches++; /* CPP driver cannot obtain switch from cc1_options. */ if (is_cpp_driver) add_preprocessor_option ("--target-help", 13); - add_assembler_option ("--target-help", 13); - add_linker_option ("--target-help", 13); - } + add_assembler_option ("--target-help", 13); + add_linker_option ("--target-help", 13); + } else if (! strcmp (argv[i], "-pass-exit-codes")) { pass_exit_codes = 1; @@ -3609,15 +3475,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" switch (c) { case 'b': - n_switches++; - if (p[1] == 0 && i + 1 == argc) - fatal ("argument to `-b' is missing"); - if (p[1] == 0) - spec_machine = argv[++i]; - else - spec_machine = p + 1; - - warn_std_ptr = &warn_std; + case 'V': + fatal ("`-%c' must come at the start of the command line", c); break; case 'B': @@ -3650,7 +3509,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" tmp[++ len] = 0; value = tmp; } - + /* As a kludge, if the arg is "[foo/]stageN/", just add "[foo/]include" to the include prefix. */ if ((len == 7 @@ -3693,48 +3552,6 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" verbose_flag++; break; - case 'V': - n_switches++; - if (p[1] == 0 && i + 1 == argc) - fatal ("argument to `-V' is missing"); - if (p[1] == 0) - spec_version = argv[++i]; - else - spec_version = p + 1; - compiler_version = spec_version; - warn_std_ptr = &warn_std; - - /* Validate the version number. Use the same checks - done when inserting it into a spec. - - The format of the version string is - ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)? */ - { - const char *v = compiler_version; - - /* Ignore leading non-digits. i.e. "foo-" in "foo-2.7.2". */ - while (! ISDIGIT (*v)) - v++; - - if (v > compiler_version && v[-1] != '-') - fatal ("invalid version number format"); - - /* Set V after the first period. */ - while (ISDIGIT (*v)) - v++; - - if (*v != '.') - fatal ("invalid version number format"); - - v++; - while (ISDIGIT (*v)) - v++; - - if (*v != 0 && *v != ' ' && *v != '.' && *v != '-') - fatal ("invalid version number format"); - } - break; - case 'S': case 'c': if (p[1] == 0) @@ -3790,8 +3607,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" #ifdef MODIFY_TARGET_NAME is_modify_target_name = 0; - for (j = 0; - j < sizeof modify_target / sizeof modify_target[0]; j++) + for (j = 0; j < ARRAY_SIZE (modify_target); j++) if (! strcmp (argv[i], modify_target[j].sw)) { char *new_name @@ -3824,7 +3640,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (is_modify_target_name) break; -#endif +#endif n_switches++; @@ -3936,7 +3752,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" #ifdef MODIFY_TARGET_NAME is_modify_target_name = 0; - for (j = 0; j < sizeof modify_target / sizeof modify_target[0]; j++) + for (j = 0; j < ARRAY_SIZE (modify_target); j++) if (! strcmp (argv[i], modify_target[j].sw)) is_modify_target_name = 1; @@ -4026,7 +3842,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" /* -save-temps overrides -pipe, so that temp files are produced */ if (save_temps_flag) error ("warning: -pipe ignored because -save-temps specified"); - /* -time overrides -pipe because we can't get correct stats when + /* -time overrides -pipe because we can't get correct stats when multiple children are running at once. */ else if (report_times) error ("warning: -pipe ignored because -time specified"); @@ -4105,7 +3921,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" else { char ch = switches[n_switches].part1[0]; - if (ch == 'V' || ch == 'b' || ch == 'B') + if (ch == 'B') switches[n_switches].validated = 1; } n_switches++; @@ -4281,15 +4097,7 @@ do_spec (spec) { int value; - clear_args (); - arg_going = 0; - delete_this_arg = 0; - this_is_output_file = 0; - this_is_library_file = 0; - input_from_pipe = 0; - suffix_subst = NULL; - - value = do_spec_1 (spec, 0, NULL); + value = do_spec_2 (spec); /* Force out any unfinished command. If -pipe, this forces out the last command if it ended in `|'. */ @@ -4307,6 +4115,60 @@ do_spec (spec) return value; } +static int +do_spec_2 (spec) + const char *spec; +{ + clear_args (); + arg_going = 0; + delete_this_arg = 0; + this_is_output_file = 0; + this_is_library_file = 0; + input_from_pipe = 0; + suffix_subst = NULL; + + return do_spec_1 (spec, 0, NULL); +} + + +/* Process the given spec string and add any new options to the end + of the switches/n_switches array. */ + +static void +do_self_spec (spec) + const char *spec; +{ + do_spec_2 (spec); + do_spec_1 (" ", 0, NULL); + + if (argbuf_index > 0) + { + int i, first; + + first = n_switches; + n_switches += argbuf_index; + switches = xrealloc (switches, + sizeof (struct switchstr) * (n_switches + 1)); + + switches[n_switches] = switches[first]; + for (i = 0; i < argbuf_index; i++) + { + struct switchstr *sw; + + /* Each switch should start with '-'. */ + if (argbuf[i][0] != '-') + abort (); + + sw = &switches[i + first]; + sw->part1 = &argbuf[i][1]; + sw->args = 0; + sw->live_cond = SWITCH_OK; + sw->validated = 0; + sw->ordering = 0; + } + } +} + /* Process the sub-spec SPEC as a portion of a larger spec. This is like processing a whole spec except that we do not initialize at the beginning and we do not supply a @@ -4574,7 +4436,7 @@ do_spec_1 (spec, inswitch, soft_matched_part) } break; case 'n': - /* %nfoo means report an notice with `foo' on stderr. */ + /* %nfoo means report a notice with `foo' on stderr. */ { const char *q = p; char *buf; @@ -4640,7 +4502,7 @@ do_spec_1 (spec, inswitch, soft_matched_part) } suffix_length += strlen (TARGET_OBJECT_SUFFIX); } - + /* If the input_filename has the same suffix specified for the %g, %u, or %U, and -save-temps is specified, we could end up using that file as an intermediate @@ -4648,7 +4510,7 @@ do_spec_1 (spec, inswitch, soft_matched_part) gcc -save-temps foo.s would clobber foo.s with the output of cpp0). So check for this condition and generate a temp file as the intermediate. */ - + if (save_temps_flag) { temp_filename_length = basename_length + suffix_length; @@ -4660,7 +4522,7 @@ do_spec_1 (spec, inswitch, soft_matched_part) if (strcmp (temp_filename, input_filename) != 0) { struct stat st_temp; - + /* Note, set_input() resets input_stat_set to 0. */ if (input_stat_set == 0) { @@ -4668,22 +4530,23 @@ do_spec_1 (spec, inswitch, soft_matched_part) if (input_stat_set >= 0) input_stat_set = 1; } - + /* If we have the stat for the input_filename and we can do the stat for the temp_filename then the they could still refer to the same file if st_dev/st_ino's are the same. */ - + if (input_stat_set != 1 || stat (temp_filename, &st_temp) < 0 || input_stat.st_dev != st_temp.st_dev || input_stat.st_ino != st_temp.st_ino) - { + { temp_filename = save_string (temp_filename, temp_filename_length + 1); obstack_grow (&obstack, temp_filename, temp_filename_length); arg_going = 1; + delete_this_arg = 0; break; } } @@ -4886,8 +4749,8 @@ do_spec_1 (spec, inswitch, soft_matched_part) case 'C': { const char *const spec - = (input_file_compiler->cpp_spec - ? input_file_compiler->cpp_spec + = (input_file_compiler->cpp_spec + ? input_file_compiler->cpp_spec : cpp_spec); value = do_spec_1 (spec, 0, NULL); if (value != 0) @@ -5111,21 +4974,27 @@ 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; - case '.': - { - unsigned len = 0; + case '.': + { + unsigned len = 0; - while (p[len] && p[len] != ' ' && p[len] != '%') - len++; - suffix_subst = save_string (p - 1, len + 1); - p += len; - } + while (p[len] && p[len] != ' ' && p[len] != '%') + len++; + suffix_subst = save_string (p - 1, len + 1); + p += len; + } break; - + case '*': if (soft_matched_part) { @@ -5304,10 +5173,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 * @@ -5824,7 +5862,7 @@ set_input (filename) } else input_suffix = ""; - + /* If a spec for 'g', 'u', or 'U' is seen with -save-temps then we will need to do a stat on the input_filename. The INPUT_STAT_SET signals that the stat is needed. */ @@ -5892,8 +5930,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); @@ -5958,6 +5996,12 @@ main (argc, argv) process_command (argc, argv); + /* Process DRIVER_SELF_SPECS, adding any new options to the end + of the command line. */ + + for (i = 0; i < ARRAY_SIZE (driver_self_specs); i++) + do_self_spec (driver_self_specs[i]); + /* Initialize the vector of specs to just the default. This means one element containing 0s, as a terminator. */ @@ -5995,8 +6039,10 @@ main (argc, argv) if (access (specs_file, R_OK) == 0) read_specs (specs_file, TRUE); - /* If not cross-compiling, look for startfiles in the standard places. */ - if (*cross_compile == '0') + /* If not cross-compiling, look for startfiles in the standard places. + Similarly, don't add the standard prefixes if startfile handling + will be under control of startfile_prefix_spec. */ + if (*cross_compile == '0' && *startfile_prefix_spec == 0) { if (*md_exec_prefix) { @@ -6060,6 +6106,16 @@ main (argc, argv) #endif } + if (*startfile_prefix_spec != 0 + && do_spec_2 (startfile_prefix_spec) == 0 + && do_spec_1 (" ", 0, NULL) == 0) + { + int ndx; + for (ndx = 0; ndx < argbuf_index; ndx++) + add_prefix (&startfile_prefixes, argbuf[ndx], "BINUTILS", + PREFIX_PRIORITY_LAST, 0, NULL, 1); + } + /* Process any user specified specs in the order given on the command line. */ for (uptr = user_specs_head; uptr; uptr = uptr->next) @@ -6153,7 +6209,7 @@ main (argc, argv) if (! verbose_flag) { printf (_("\nFor bug reporting instructions, please see:\n")); - printf ("%s.\n", GCCBUGURL); + printf ("%s.\n", bug_report_url); return (0); } @@ -6234,7 +6290,7 @@ main (argc, argv) input_file_compiler = lookup_compiler (infiles[i].name, input_filename_length, infiles[i].language); - + if (input_file_compiler) { /* Ok, we found an applicable compiler. Run its spec. */ @@ -6328,7 +6384,7 @@ main (argc, argv) if (print_help_list) { printf (("\nFor bug reporting instructions, please see:\n")); - printf ("%s\n", GCCBUGURL); + printf ("%s\n", bug_report_url); } return (signal_count != 0 ? 2 @@ -6373,7 +6429,7 @@ lookup_compiler (name, length, language) && !strcmp (cp->suffix, name + length - strlen (cp->suffix)) )) - break; + break; } #if defined (OS2) ||defined (HAVE_DOS_BASED_FILE_SYSTEM) @@ -7240,3 +7296,43 @@ 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; +} + +/* if-exists-else built-in spec function. + + This is like if-exists, but takes an additional argument which + is returned if the first argument does not exist. */ + +static const char * +if_exists_else_spec_function (argc, argv) + int argc; + const char **argv; +{ + /* Must have exactly two arguments. */ + if (argc != 2) + return NULL; + + if (IS_ABSOLUTE_PATHNAME (argv[0]) && ! access (argv[0], R_OK)) + return argv[0]; + + return argv[1]; +} |