diff options
Diffstat (limited to 'gcc/gcc.c')
-rw-r--r-- | gcc/gcc.c | 1399 |
1 files changed, 933 insertions, 466 deletions
diff --git a/gcc/gcc.c b/gcc/gcc.c index 3bff09a5bf6..9535d394ea9 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -162,6 +162,11 @@ static const char *print_prog_name = NULL; static int print_multi_directory; +/* Flag saying to print the relative path we'd use to + find OS libraries given the current compiler flags. */ + +static int print_multi_os_directory; + /* Flag saying to print the list of subdirectories and compiler flags used to select them in a standard form. */ @@ -192,11 +197,21 @@ static int target_help_flag; static int report_times; +/* Nonzero means place this string before uses of /, so that include + and library files can be found in an alternate location. */ + +static const char *target_system_root = TARGET_SYSTEM_ROOT; + /* Nonzero means write "temp" files in source directory and use the source file's name in them, and don't delete them. */ static int save_temps_flag; +/* Nonzero means use pipes to communicate between subprocesses. + Overridden by either of the above two flags. */ + +static int use_pipes; + /* The compiler version. */ static const char *compiler_version; @@ -234,7 +249,7 @@ 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 @@ -275,9 +290,12 @@ static struct compiler *lookup_compiler PARAMS ((const char *, size_t, const cha static char *build_search_list PARAMS ((struct path_prefix *, const char *, int)); static void putenv_from_prefixes PARAMS ((struct path_prefix *, const char *)); static int access_check PARAMS ((const char *, int)); -static char *find_a_file PARAMS ((struct path_prefix *, const char *, int)); +static char *find_a_file PARAMS ((struct path_prefix *, const char *, + int, int)); static void add_prefix PARAMS ((struct path_prefix *, const char *, - const char *, int, int, int *)); + const char *, int, int, int *, int)); +static void add_sysrooted_prefix PARAMS ((struct path_prefix *, const char *, + const char *, int, int, int *, int)); static void translate_options PARAMS ((int *, const char *const **)); static char *skip_whitespace PARAMS ((char *)); static void delete_if_ordinary PARAMS ((const char *)); @@ -286,15 +304,26 @@ 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 inline bool input_suffix_matches PARAMS ((const char *, + const char *)); +static inline bool switch_matches PARAMS ((const char *, + const char *, int)); +static inline void mark_matching_switches PARAMS ((const char *, + const char *, int)); +static inline void process_marked_switches PARAMS ((void)); +static const char *process_brace_body PARAMS ((const char *, const char *, + const char *, int, int)); 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 *)); +static const char *validate_switches PARAMS ((const char *)); static void validate_all_switches PARAMS ((void)); -static void give_switch PARAMS ((int, int, int)); +static inline void validate_switches_from_spec PARAMS ((const char *)); +static void give_switch PARAMS ((int, int)); static int used_arg PARAMS ((const char *, int)); static int default_arg PARAMS ((const char *, int)); static void set_multilib_dir PARAMS ((void)); @@ -354,6 +383,12 @@ or with constant text in a single argument. with a file name chosen once per compilation, without regard to any appended suffix (which was therefore treated just like ordinary text), making such attacks more likely to succeed. + %|SUFFIX + like %g, but if -pipe is in effect, expands simply to "-". + %mSUFFIX + like %g, but if -pipe is in effect, expands to nothing. (We have both + %| and %m to accommodate differences between system assemblers; see + the AS_NEEDS_DASH_FOR_PIPED_INPUT target macro.) %uSUFFIX like %g, but generates a new temporary file name even if %uSUFFIX was already seen. @@ -439,10 +474,15 @@ or with constant text in a single argument. %C process CPP_SPEC as a spec. %1 process CC1_SPEC as a spec. %2 process CC1PLUS_SPEC as a spec. - %| output "-" if the input for the current command is coming from a pipe. %* substitute the variable part of a matched option. (See below.) Note that each comma in the substituted string is replaced by a single space. + %<S remove all occurrences of -S from the command line. + Note - this command is position dependent. % commands in the + spec string before this one will see -S, % commands in the + spec string after this one will not. + %<S* remove all occurrences of all switches beginning with -S from the + command line. %{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. @@ -451,33 +491,40 @@ or with constant text in a single argument. arguments. CC considers `-o foo' as being one switch whose name starts with `o'. %{o*} would substitute this text, including the space; thus, two arguments would be generated. - %{^S*} likewise, but don't put a blank between a switch and any args. %{S*&T*} likewise, but preserve order of S and T options (the order of S and T in the spec is not significant). Can be any number of ampersand-separated variables; for each the wild card is optional. Useful for CPP as %{D*&U*&A*}. - %{S*:X} substitutes X if one or more switches whose names start with -S are - specified to CC. Note that the tail part of the -S option - (i.e. the part matched by the `*') will be substituted for each - occurrence of %* within X. - %{<S} remove all occurrences of -S from the command line. - Note - this option is position dependent. % commands in the - spec string before this option will see -S, % commands in the - spec string after this option will not. - %{S:X} substitutes X, but only if the -S switch was given to CC. - %{!S:X} substitutes X, but only if the -S switch was NOT given to CC. - %{|S:X} like %{S:X}, but if no S switch, substitute `-'. - %{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'. - %{.S:X} substitutes X, but only if processing a file with suffix S. - %{!.S:X} substitutes X, but only if NOT processing a file with suffix S. - %{S|P:X} substitutes X if either -S or -P was given to CC. This may be - combined with ! and . as above binding stronger than the OR. + + %{S:X} substitutes X, if the -S switch was given to CC. + %{!S:X} substitutes X, if the -S switch was NOT given to CC. + %{S*:X} substitutes X if one or more switches whose names start + with -S was given to CC. Normally X is substituted only + once, no matter how many such switches appeared. However, + if %* appears somewhere in X, then X will be substituted + once for each matching switch, with the %* replaced by the + part of that switch that matched the '*'. + %{.S:X} substitutes X, if processing a file with suffix S. + %{!.S:X} substitutes X, if NOT processing a file with suffix S. + + %{S|T:X} substitutes X if either -S or -T was given to CC. This may be + combined with !, ., and * as above binding stronger than the OR. + If %* appears in X, all of the alternatives must be starred, and + only the first matching alternative is substituted. + %{S:X; if S was given to CC, substitutes X; + T:Y; else if T was given to CC, substitutes Y; + :D} else substitutes D. There can be as many clauses as you need. + This may be combined with ., !, |, and * as above. + %(Spec) processes a specification defined in a specs file as *Spec: %[Spec] as above, but put __ around -D arguments -The conditional text X in a %{S:X} or %{!S:X} construct may contain +The conditional text X in a %{S:X} or similar construct may contain other nested % constructs or spaces, or even newlines. They are -processed as usual, as described above. +processed as usual, as described above. Trailing white space in X is +ignored. White space may also appear anywhere on the left side of the +colon in these constructs, except between . or * and the corresponding +word. The -O, -f, -m, and -W switches are handled specifically in these constructs. If another value of -O or the negated form of a -f, -m, or @@ -667,13 +714,16 @@ static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC; static const char *trad_capable_cpp = "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}}\ %{CC:%{!E:%eGNU C does not support -CC without using -E}}\ %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %I\ - %{MD:-MD %W{!o: %b.d}%W{o*:%.d%*}}\ - %{MMD:-MMD %W{!o: %b.d}%W{o*:%.d%*}}\ - %{M} %{MM} %W{MF*} %{MG} %{MP} %{MQ*} %{MT*}\ + %{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}\ %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\ @@ -686,7 +736,7 @@ static const char *cpp_unique_options = 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) %1 %{std*} %{W*&pedantic*} %{w} %{m*} %{f*}\ +"%(cpp_unique_options) %1 %{m*} %{std*} %{ansi} %{W*&pedantic*} %{w} %{f*}\ %{O*} %{undef}"; /* This contains cpp options which are not passed when the preprocessor @@ -697,7 +747,7 @@ static const char *cpp_debug_options = "%{d*}"; 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*}\ - -auxbase%{c|S:%{o*:-strip%*}%{!o*: %b}}%{!c:%{!S: %b}}\ + -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}\ @@ -709,7 +759,11 @@ static const char *asm_options = "%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}"; static const char *invoke_as = -"%{!S:-o %{|!pipe:%g.s} |\n as %(asm_options) %{!pipe:%g.s} %A }"; +#ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT +"%{!S:-o %|.s |\n as %(asm_options) %|.s %A }"; +#else +"%{!S:-o %|.s |\n as %(asm_options) %m.s %A }"; +#endif /* Some compilers have limits on line lengths, and the multilib_select and/or multilib_matches strings can be very long, so we build them at @@ -729,6 +783,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; @@ -841,7 +901,7 @@ static const struct compiler default_compilers[] = %{!fsyntax-only:%(invoke_as)}}}}", 0}, {"-", "%{!E:%e-E required when input is from standard input}\ - %(trad_capable_cpp) %(cpp_options)", 0}, + %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0}, {".h", "@c-header", 0}, {"@c-header", "%{!E:%ecompilation of header file requested} \ @@ -855,10 +915,19 @@ static const struct compiler default_compilers[] = "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0}, {".S", "@assembler-with-cpp", 0}, {"@assembler-with-cpp", +#ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT "%(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}, + %{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\ + as %(asm_debug) %(asm_options) %|.s %A }}}}" +#else + "%(trad_capable_cpp) -lang-asm %(cpp_options)\ + %{E|M|MM:%(cpp_debug_options)}\ + %{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\ + as %(asm_debug) %(asm_options) %m.s %A }}}}" +#endif + , 0}, + #include "specs.h" /* Mark end of table */ {0, 0, 0} @@ -961,6 +1030,7 @@ static const struct option_map option_map[] = {"--print-missing-file-dependencies", "-MG", 0}, {"--print-multi-lib", "-print-multi-lib", 0}, {"--print-multi-directory", "-print-multi-directory", 0}, + {"--print-multi-os-directory", "-print-multi-os-directory", 0}, {"--print-prog-name", "-print-prog-name=", "aj"}, {"--profile", "-p", 0}, {"--profile-blocks", "-a", 0}, @@ -1189,6 +1259,10 @@ translate_options (argcp, argvp) nskip += 1; else if (! strcmp (p, "Xlinker")) nskip += 1; + else if (! strcmp (p, "Xpreprocessor")) + nskip += 1; + else if (! strcmp (p, "Xassembler")) + nskip += 1; /* Watch out for an option at the end of the command line that is missing arguments, and avoid skipping past the end of the @@ -1246,7 +1320,9 @@ struct prefix_list int require_machine_suffix; /* Don't use without machine_suffix. */ /* 2 means try both machine_suffix and just_machine_suffix. */ int *used_flag_ptr; /* 1 if a file was found with this prefix. */ - int priority; /* Sort key - priority within list */ + int priority; /* Sort key - priority within list. */ + int os_multilib; /* 1 if OS multilib scheme should be used, + 0 for GCC multilib scheme. */ }; struct path_prefix @@ -1335,6 +1411,11 @@ static const char *const standard_bindir_prefix = STANDARD_BINDIR_PREFIX; set_multilib_dir based on the compilation options. */ static const char *multilib_dir; + +/* Subdirectory to use for locating libraries in OS conventions. Set by + set_multilib_dir based on the compilation options. */ + +static const char *multilib_os_dir; /* Structure to keep track of the specs that have been defined so far. These are accessed using %(specname) or %[specname] in a compiler @@ -1389,6 +1470,7 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("multilib_extra", &multilib_extra), INIT_STATIC_SPEC ("multilib_matches", &multilib_matches), INIT_STATIC_SPEC ("multilib_exclusions", &multilib_exclusions), + INIT_STATIC_SPEC ("multilib_options", &multilib_options), INIT_STATIC_SPEC ("linker", &linker_name_spec), INIT_STATIC_SPEC ("link_libgcc", &link_libgcc_spec), INIT_STATIC_SPEC ("md_exec_prefix", &md_exec_prefix), @@ -1531,6 +1613,9 @@ init_spec () #else "-lgcc_s%M" #endif +#ifdef USE_LIBUNWIND_EXCEPTIONS + " -lunwind" +#endif , "-lgcc", "-lgcc_eh"); @@ -1836,7 +1921,7 @@ read_specs (filename, main_p) (long) (p1 - buffer + 1)); p[-2] = '\0'; - new_filename = find_a_file (&startfile_prefixes, p1, R_OK); + new_filename = find_a_file (&startfile_prefixes, p1, R_OK, 0); read_specs (new_filename ? new_filename : p1, FALSE); continue; } @@ -1855,7 +1940,7 @@ read_specs (filename, main_p) (long) (p1 - buffer + 1)); p[-2] = '\0'; - new_filename = find_a_file (&startfile_prefixes, p1, R_OK); + new_filename = find_a_file (&startfile_prefixes, p1, R_OK, 0); if (new_filename) read_specs (new_filename, FALSE); else if (verbose_flag) @@ -2151,7 +2236,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. */ @@ -2330,7 +2415,7 @@ make_relative_prefix (progname, bin_prefix, prefix) const char *prefix; { char **prog_dirs, **bin_dirs, **prefix_dirs; - int prog_num, bin_num, prefix_num, std_loc_p; + int prog_num, bin_num, prefix_num; int i, n, common; prog_dirs = split_directories (progname, &prog_num); @@ -2403,7 +2488,6 @@ make_relative_prefix (progname, bin_prefix, prefix) /* 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++) @@ -2414,7 +2498,6 @@ make_relative_prefix (progname, bin_prefix, prefix) 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; @@ -2490,16 +2573,17 @@ access_check (name, mode) Return 0 if not found, otherwise return its name, allocated with malloc. */ static char * -find_a_file (pprefix, name, mode) +find_a_file (pprefix, name, mode, multilib) struct path_prefix *pprefix; const char *name; - int mode; + int mode, multilib; { char *temp; const char *const file_suffix = ((mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : ""); struct prefix_list *pl; int len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1; + const char *multilib_name, *multilib_os_name; #ifdef DEFAULT_ASSEMBLER if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0) @@ -2514,6 +2598,22 @@ find_a_file (pprefix, name, mode) if (machine_suffix) len += strlen (machine_suffix); + multilib_name = name; + multilib_os_name = name; + if (multilib && multilib_os_dir) + { + int len1 = multilib_dir ? strlen (multilib_dir) + 1 : 0; + int len2 = strlen (multilib_os_dir) + 1; + + len += len1 > len2 ? len1 : len2; + if (multilib_dir) + multilib_name = ACONCAT ((multilib_dir, dir_separator_str, name, + NULL)); + if (strcmp (multilib_os_dir, ".") != 0) + multilib_os_name = ACONCAT ((multilib_os_dir, dir_separator_str, name, + NULL)); + } + temp = xmalloc (len); /* Determine the filename to execute (special case for absolute paths). */ @@ -2529,6 +2629,9 @@ find_a_file (pprefix, name, mode) else for (pl = pprefix->plist; pl; pl = pl->next) { + const char *this_name + = pl->os_multilib ? multilib_os_name : multilib_name; + if (machine_suffix) { /* Some systems have a suffix for executable files. @@ -2537,7 +2640,7 @@ find_a_file (pprefix, name, mode) { strcpy (temp, pl->prefix); strcat (temp, machine_suffix); - strcat (temp, name); + strcat (temp, multilib_name); strcat (temp, file_suffix); if (access_check (temp, mode) == 0) { @@ -2547,10 +2650,10 @@ find_a_file (pprefix, name, mode) } } - /* Now try just the name. */ + /* Now try just the multilib_name. */ strcpy (temp, pl->prefix); strcat (temp, machine_suffix); - strcat (temp, name); + strcat (temp, multilib_name); if (access_check (temp, mode) == 0) { if (pl->used_flag_ptr != 0) @@ -2569,7 +2672,7 @@ find_a_file (pprefix, name, mode) { strcpy (temp, pl->prefix); strcat (temp, just_machine_suffix); - strcat (temp, name); + strcat (temp, multilib_name); strcat (temp, file_suffix); if (access_check (temp, mode) == 0) { @@ -2581,7 +2684,7 @@ find_a_file (pprefix, name, mode) strcpy (temp, pl->prefix); strcat (temp, just_machine_suffix); - strcat (temp, name); + strcat (temp, multilib_name); if (access_check (temp, mode) == 0) { if (pl->used_flag_ptr != 0) @@ -2599,7 +2702,7 @@ find_a_file (pprefix, name, mode) if (file_suffix[0] != 0) { strcpy (temp, pl->prefix); - strcat (temp, name); + strcat (temp, this_name); strcat (temp, file_suffix); if (access_check (temp, mode) == 0) { @@ -2610,7 +2713,7 @@ find_a_file (pprefix, name, mode) } strcpy (temp, pl->prefix); - strcat (temp, name); + strcat (temp, this_name); if (access_check (temp, mode) == 0) { if (pl->used_flag_ptr != 0) @@ -2648,13 +2751,15 @@ enum path_prefix_priority 2 means try both machine_suffix and just_machine_suffix. */ static void -add_prefix (pprefix, prefix, component, priority, require_machine_suffix, warn) +add_prefix (pprefix, prefix, component, priority, require_machine_suffix, + warn, os_multilib) struct path_prefix *pprefix; const char *prefix; const char *component; /* enum prefix_priority */ int priority; int require_machine_suffix; int *warn; + int os_multilib; { struct prefix_list *pl, **prev; int len; @@ -2676,6 +2781,7 @@ add_prefix (pprefix, prefix, component, priority, require_machine_suffix, warn) pl->require_machine_suffix = require_machine_suffix; pl->used_flag_ptr = warn; pl->priority = priority; + pl->os_multilib = os_multilib; if (warn) *warn = 0; @@ -2683,6 +2789,33 @@ add_prefix (pprefix, prefix, component, priority, require_machine_suffix, warn) pl->next = (*prev); (*prev) = pl; } + +/* Same as add_prefix, but prepending target_system_root to prefix. */ +static void +add_sysrooted_prefix (pprefix, prefix, component, priority, + require_machine_suffix, warn, os_multilib) + struct path_prefix *pprefix; + const char *prefix; + const char *component; + /* enum prefix_priority */ int priority; + int require_machine_suffix; + int *warn; + int os_multilib; +{ + if (!IS_ABSOLUTE_PATHNAME (prefix)) + abort (); + + if (target_system_root) + { + prefix = concat (target_system_root, prefix, NULL); + /* We have to override this because GCC's notion of sysroot + moves along with GCC. */ + component = "GCC"; + } + + add_prefix (pprefix, prefix, component, priority, + require_machine_suffix, warn, os_multilib); +} /* Execute the command specified by the arguments on the current line of spec. When using pipes, this includes several piped-together commands @@ -2719,7 +2852,7 @@ execute () commands[0].prog = argbuf[0]; /* first command. */ commands[0].argv = &argbuf[0]; - string = find_a_file (&exec_prefixes, commands[0].prog, X_OK); + string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, 0); if (string) commands[0].argv[0] = string; @@ -2733,7 +2866,8 @@ execute () argbuf[i] = 0; /* termination of command args. */ commands[n_commands].prog = argbuf[i + 1]; commands[n_commands].argv = &argbuf[i + 1]; - string = find_a_file (&exec_prefixes, commands[n_commands].prog, X_OK); + string = find_a_file (&exec_prefixes, commands[n_commands].prog, + X_OK, 0); if (string) commands[n_commands].argv[0] = string; n_commands++; @@ -2886,7 +3020,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; } @@ -2918,7 +3052,7 @@ See %s for instructions.", 0 when initialized 1 if the switch is true in a conditional spec, -1 if false (overridden by a later switch) - -2 if this switch should be ignored (used in %{<S}) + -2 if this switch should be ignored (used in %<S) The `validated' field is nonzero if any spec has looked at this switch; if it remains zero at the end of the run, it must be meaningless. */ @@ -3048,9 +3182,12 @@ display_help () fputs (_("\ -print-multi-lib Display the mapping between command line options and\n\ multiple library search directories\n"), stdout); + fputs (_(" -print-multi-os-directory Display the relative path to OS libraries\n"), stdout); fputs (_(" -Wa,<options> Pass comma-separated <options> on to the assembler\n"), stdout); fputs (_(" -Wp,<options> Pass comma-separated <options> on to the preprocessor\n"), stdout); fputs (_(" -Wl,<options> Pass comma-separated <options> on to the linker\n"), stdout); + fputs (_(" -Xassembler <arg> Pass <arg> on to the assembler\n"), stdout); + fputs (_(" -Xpreprocessor <arg> Pass <arg> on to the preprocessor\n"), stdout); fputs (_(" -Xlinker <arg> Pass <arg> on to the linker\n"), stdout); fputs (_(" -save-temps Do not delete intermediate files\n"), stdout); fputs (_(" -pipe Use pipes rather than intermediate files\n"), stdout); @@ -3264,9 +3401,9 @@ process_command (argc, argv) set_std_prefix (gcc_exec_prefix, len); add_prefix (&exec_prefixes, gcc_exec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 0, NULL); + PREFIX_PRIORITY_LAST, 0, NULL, 0); add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 0, NULL); + PREFIX_PRIORITY_LAST, 0, NULL, 0); } /* COMPILER_PATH and LIBRARY_PATH have values @@ -3294,10 +3431,10 @@ process_command (argc, argv) else nstore[endp - startp] = 0; add_prefix (&exec_prefixes, nstore, 0, - PREFIX_PRIORITY_LAST, 0, NULL); + PREFIX_PRIORITY_LAST, 0, NULL, 0); add_prefix (&include_prefixes, concat (nstore, "include", NULL), - 0, PREFIX_PRIORITY_LAST, 0, NULL); + 0, PREFIX_PRIORITY_LAST, 0, NULL, 0); if (*endp == 0) break; endp = startp = endp + 1; @@ -3329,7 +3466,7 @@ process_command (argc, argv) else nstore[endp - startp] = 0; add_prefix (&startfile_prefixes, nstore, NULL, - PREFIX_PRIORITY_LAST, 0, NULL); + PREFIX_PRIORITY_LAST, 0, NULL, 1); if (*endp == 0) break; endp = startp = endp + 1; @@ -3362,7 +3499,7 @@ process_command (argc, argv) else nstore[endp - startp] = 0; add_prefix (&startfile_prefixes, nstore, NULL, - PREFIX_PRIORITY_LAST, 0, NULL); + PREFIX_PRIORITY_LAST, 0, NULL, 1); if (*endp == 0) break; endp = startp = endp + 1; @@ -3462,6 +3599,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" print_multi_lib = 1; else if (! strcmp (argv[i], "-print-multi-directory")) print_multi_directory = 1; + else if (! strcmp (argv[i], "-print-multi-os-directory")) + print_multi_os_directory = 1; else if (! strncmp (argv[i], "-Wa,", 4)) { int prev, j; @@ -3514,6 +3653,20 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" n_infiles++; i++; } + else if (strcmp (argv[i], "-Xpreprocessor") == 0) + { + if (i + 1 == argc) + fatal ("argument to `-Xpreprocessor' is missing"); + + add_preprocessor_option (argv[i+1], strlen (argv[i+1])); + } + else if (strcmp (argv[i], "-Xassembler") == 0) + { + if (i + 1 == argc) + fatal ("argument to `-Xassembler' is missing"); + + add_assembler_option (argv[i+1], strlen (argv[i+1])); + } else if (strcmp (argv[i], "-l") == 0) { if (i + 1 == argc) @@ -3561,6 +3714,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } else if (strcmp (argv[i], "-time") == 0) report_times = 1; + else if (strcmp (argv[i], "-pipe") == 0) + { + /* -pipe has to go into the switches array as well as + setting a flag. */ + use_pipes = 1; + n_switches++; + } else if (strcmp (argv[i], "-###") == 0) { /* This is similar to -v except that there is no execution @@ -3624,7 +3784,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" { if (len == 7) add_prefix (&include_prefixes, "include", NULL, - PREFIX_PRIORITY_B_OPT, 0, NULL); + PREFIX_PRIORITY_B_OPT, 0, NULL, 0); else { char * string = xmalloc (len + 1); @@ -3632,16 +3792,16 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" strncpy (string, value, len - 7); strcpy (string + len - 7, "include"); add_prefix (&include_prefixes, string, NULL, - PREFIX_PRIORITY_B_OPT, 0, NULL); + PREFIX_PRIORITY_B_OPT, 0, NULL, 0); } } add_prefix (&exec_prefixes, value, NULL, - PREFIX_PRIORITY_B_OPT, 0, &warn_B); + PREFIX_PRIORITY_B_OPT, 0, &warn_B, 0); add_prefix (&startfile_prefixes, value, NULL, - PREFIX_PRIORITY_B_OPT, 0, &warn_B); + PREFIX_PRIORITY_B_OPT, 0, &warn_B, 0); add_prefix (&include_prefixes, concat (value, "include", NULL), - NULL, PREFIX_PRIORITY_B_OPT, 0, NULL); + NULL, PREFIX_PRIORITY_B_OPT, 0, NULL, 0); n_switches++; } break; @@ -3763,6 +3923,19 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (have_c && have_o && lang_n_infiles > 1) fatal ("cannot specify -o with -c or -S and multiple compilations"); + if ((save_temps_flag || report_times) && use_pipes) + { + /* -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 + multiple children are running at once. */ + else if (report_times) + error ("warning: -pipe ignored because -time specified"); + + use_pipes = 0; + } + /* Set up the search paths before we go looking for config files. */ /* These come before the md prefixes so that we will find gcc's subcommands @@ -3771,17 +3944,17 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" as well as trying the machine and the version. */ #ifndef OS2 add_prefix (&exec_prefixes, standard_exec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 1, warn_std_ptr); + PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0); add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS", - PREFIX_PRIORITY_LAST, 2, warn_std_ptr); + PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0); add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS", - PREFIX_PRIORITY_LAST, 2, warn_std_ptr); + PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0); #endif add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS", - PREFIX_PRIORITY_LAST, 1, warn_std_ptr); + PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0); add_prefix (&startfile_prefixes, standard_exec_prefix_1, "BINUTILS", - PREFIX_PRIORITY_LAST, 1, warn_std_ptr); + PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0); tooldir_prefix = concat (tooldir_base_prefix, spec_machine, dir_separator_str, NULL); @@ -3804,11 +3977,11 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" add_prefix (&exec_prefixes, concat (gcc_exec_tooldir_prefix, "bin", dir_separator_str, NULL), - NULL, PREFIX_PRIORITY_LAST, 0, NULL); + NULL, PREFIX_PRIORITY_LAST, 0, NULL, 0); add_prefix (&startfile_prefixes, concat (gcc_exec_tooldir_prefix, "lib", dir_separator_str, NULL), - NULL, PREFIX_PRIORITY_LAST, 0, NULL); + NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1); } tooldir_prefix = concat (standard_exec_prefix, spec_machine, @@ -3818,10 +3991,19 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" add_prefix (&exec_prefixes, concat (tooldir_prefix, "bin", dir_separator_str, NULL), - "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL); + "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 0); add_prefix (&startfile_prefixes, concat (tooldir_prefix, "lib", dir_separator_str, NULL), - "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL); + "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1); + + if (target_system_root && gcc_exec_prefix) + { + char *tmp_prefix = make_relative_prefix (argv[0], + standard_bindir_prefix, + target_system_root); + if (tmp_prefix && access_check (tmp_prefix, F_OK) == 0) + target_system_root = tmp_prefix; + } /* More prefixes are enabled in main, after we read the specs file and determine whether this is cross-compilation or not. */ @@ -3871,6 +4053,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" ; else if (! strcmp (argv[i], "-print-multi-directory")) ; + else if (! strcmp (argv[i], "-print-multi-os-directory")) + ; else if (! strcmp (argv[i], "-ftarget-help")) ; else if (! strcmp (argv[i], "-fhelp")) @@ -3910,6 +4094,16 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" infiles[n_infiles].language = "*"; infiles[n_infiles++].name = argv[++i]; } + else if (strcmp (argv[i], "-Xassembler") == 0) + { + infiles[n_infiles].language = "*"; + infiles[n_infiles++].name = argv[++i]; + } + else if (strcmp (argv[i], "-Xpreprocessor") == 0) + { + infiles[n_infiles].language = "*"; + infiles[n_infiles++].name = argv[++i]; + } else if (strcmp (argv[i], "-l") == 0) { /* POSIX allows separation of -l and the lib arg; canonicalize by concatenating -l with its arg */ @@ -3927,17 +4121,6 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" ; else if (strcmp (argv[i], "-time") == 0) ; - else if ((save_temps_flag || report_times) - && strcmp (argv[i], "-pipe") == 0) - { - /* -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 - multiple children are running at once. */ - else if (report_times) - error ("warning: -pipe ignored because -time specified"); - } else if (strcmp (argv[i], "-###") == 0) ; else if (argv[i][0] == '-' && argv[i][1] != 0) @@ -4004,10 +4187,11 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" switches[n_switches].live_cond = SWITCH_OK; switches[n_switches].validated = 0; switches[n_switches].ordering = 0; - /* These are always valid, since gcc.c itself understands it. */ + /* These are always valid, since gcc.c itself understands them. */ if (!strcmp (p, "save-temps") || !strcmp (p, "static-libgcc") - || !strcmp (p, "shared-libgcc")) + || !strcmp (p, "shared-libgcc") + || !strcmp (p, "pipe")) switches[n_switches].validated = 1; else { @@ -4074,7 +4258,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" infiles[n_infiles].name = 0; } -/* Store switches not filtered out by %{<S} in spec in COLLECT_GCC_OPTIONS +/* Store switches not filtered out by %<S in spec in COLLECT_GCC_OPTIONS and place that in the environment. */ static void @@ -4221,6 +4405,45 @@ do_spec_2 (spec) 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 @@ -4267,17 +4490,12 @@ do_spec_1 (spec, inswitch, soft_matched_part) if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|")) { - for (i = 0; i < n_switches; i++) - if (!strcmp (switches[i].part1, "pipe")) - break; - /* A `|' before the newline means use a pipe here, but only if -pipe was specified. Otherwise, execute now and don't pass the `|' as an arg. */ - if (i < n_switches) + if (use_pipes) { input_from_pipe = 1; - switches[i].validated = 1; break; } else @@ -4381,9 +4599,14 @@ do_spec_1 (spec, inswitch, soft_matched_part) continue; #endif /* Try subdirectory if there is one. */ - if (multilib_dir != NULL) + if (multilib_dir != NULL + || (pl->os_multilib && multilib_os_dir != NULL)) { - if (machine_suffix) + const char *multi_dir; + + multi_dir = pl->os_multilib ? multilib_os_dir + : multilib_dir; + if (machine_suffix && multilib_dir) { if (strlen (pl->prefix) + strlen (machine_suffix) >= bufsize) @@ -4406,14 +4629,14 @@ do_spec_1 (spec, inswitch, soft_matched_part) } if (!pl->require_machine_suffix) { - if (is_directory (pl->prefix, multilib_dir, 1)) + if (is_directory (pl->prefix, multi_dir, 1)) { do_spec_1 ("-L", 0, NULL); #ifdef SPACE_AFTER_L_OPTION do_spec_1 (" ", 0, NULL); #endif do_spec_1 (pl->prefix, 1, NULL); - do_spec_1 (multilib_dir, 1, NULL); + do_spec_1 (multi_dir, 1, NULL); /* Make this a separate argument. */ do_spec_1 (" ", 0, NULL); } @@ -4502,10 +4725,10 @@ do_spec_1 (spec, inswitch, soft_matched_part) { struct stat st; - /* If save_temps_flag is off, and the HOST_BIT_BUCKET is defined, - and it is not a directory, and it is writable, use it. - Otherwise, fall through and treat this like any other - temporary file. */ + /* If save_temps_flag is off, and the HOST_BIT_BUCKET is + defined, and it is not a directory, and it is + writable, use it. Otherwise, treat this like any + other temporary file. */ if ((!save_temps_flag) && (stat (HOST_BIT_BUCKET, &st) == 0) && (!S_ISDIR (st.st_mode)) @@ -4518,9 +4741,39 @@ do_spec_1 (spec, inswitch, soft_matched_part) break; } } + goto create_temp_file; + case '|': + if (use_pipes) + { + obstack_1grow (&obstack, '-'); + delete_this_arg = 0; + arg_going = 1; + + /* consume suffix */ + while (*p == '.' || ISALPHA ((unsigned char) *p)) + p++; + if (p[0] == '%' && p[1] == 'O') + p += 2; + + break; + } + goto create_temp_file; + case 'm': + if (use_pipes) + { + /* consume suffix */ + while (*p == '.' || ISALPHA ((unsigned char) *p)) + p++; + if (p[0] == '%' && p[1] == 'O') + p += 2; + + break; + } + goto create_temp_file; case 'g': case 'u': case 'U': + create_temp_file: { struct temp_name *t; int suffix_length; @@ -4603,7 +4856,7 @@ do_spec_1 (spec, inswitch, soft_matched_part) for (t = temp_names; t; t = t->next) if (t->length == suffix_length && strncmp (t->suffix, suffix, suffix_length) == 0 - && t->unique == (c != 'g')) + && t->unique == (c == 'u' || c == 'j')) break; /* Make a new association if needed. %u and %j @@ -4624,7 +4877,7 @@ do_spec_1 (spec, inswitch, soft_matched_part) } else t->suffix = save_string (suffix, suffix_length); - t->unique = (c != 'g'); + t->unique = (c == 'u' || c == 'j'); temp_filename = make_temp_file (t->suffix); temp_filename_length = strlen (temp_filename); t->filename = temp_filename; @@ -5006,6 +5259,14 @@ do_spec_1 (spec, inswitch, soft_matched_part) } break; + case 'R': + /* We assume there is a directory + separator at the end of this string. */ + if (target_system_root) + obstack_grow (&obstack, target_system_root, + strlen (target_system_root)); + break; + case 'S': value = do_spec_1 (startfile_spec, 0, NULL); if (value != 0) @@ -5035,6 +5296,32 @@ do_spec_1 (spec, inswitch, soft_matched_part) } break; + /* Henceforth ignore the option(s) matching the pattern + after the %<. */ + case '<': + { + unsigned len = 0; + int have_wildcard = 0; + int i; + + while (p[len] && p[len] != ' ' && p[len] != '\t') + len++; + + if (p[len-1] == '*') + have_wildcard = 1; + + for (i = 0; i < n_switches; i++) + if (!strncmp (switches[i].part1, p, len - have_wildcard) + && (have_wildcard || switches[i].part1[len] == '\0')) + { + switches[i].live_cond = SWITCH_IGNORE; + switches[i].validated = 1; + } + + p += len; + } + break; + case '*': if (soft_matched_part) { @@ -5191,11 +5478,6 @@ do_spec_1 (spec, inswitch, soft_matched_part) } break; - case '|': - if (input_from_pipe) - do_spec_1 ("-", 0, NULL); - break; - default: error ("spec failure: unrecognized spec option '%c'", c); break; @@ -5217,273 +5499,303 @@ do_spec_1 (spec, inswitch, soft_matched_part) return 0; } -/* Return 0 if we call do_spec_1 and that returns -1. */ +/* Inline subroutine of handle_braces. Returns true if the current + input suffix matches the atom bracketed by ATOM and END_ATOM. */ +static inline bool +input_suffix_matches (atom, end_atom) + const char *atom; + const char *end_atom; +{ + return (input_suffix + && !strncmp (input_suffix, atom, end_atom - atom) + && input_suffix[end_atom - atom] == '\0'); +} -static const char * -handle_braces (p) - const char *p; +/* Inline subroutine of handle_braces. Returns true if a switch + matching the atom bracketed by ATOM and END_ATOM appeared on the + command line. */ +static inline bool +switch_matches (atom, end_atom, starred) + const char *atom; + const char *end_atom; + int starred; { - const char *filter, *body = NULL, *endbody = NULL; - int pipe_p = 0; - int true_once = 0; /* If, in %{a|b:d}, at least one of a,b was seen. */ - int negate; - int suffix; - int include_blanks = 1; - int elide_switch = 0; - int ordered = 0; - - if (*p == '^') - { - /* A '^' after the open-brace means to not give blanks before args. */ - include_blanks = 0; - ++p; - } + int i; + int len = end_atom - atom; + int plen = starred ? len : -1; - if (*p == '|') - { - /* A `|' after the open-brace means, - if the test fails, output a single minus sign rather than nothing. - This is used in %{|!pipe:...}. */ - pipe_p = 1; - ++p; - } + for (i = 0; i < n_switches; i++) + if (!strncmp (switches[i].part1, atom, len) + && (starred || switches[i].part1[len] == '\0') + && check_live_switch (i, plen)) + return true; - if (*p == '<') - { - /* A `<' after the open-brace means that the switch should be - removed from the command-line. */ - elide_switch = 1; - ++p; - } + return false; +} -next_member: - negate = suffix = 0; +/* Inline subroutine of handle_braces. Mark all of the switches which + match ATOM (extends to END_ATOM; STARRED indicates whether there + was a star after the atom) for later processing. */ +static inline void +mark_matching_switches (atom, end_atom, starred) + const char *atom; + const char *end_atom; + int starred; +{ + int i; + int len = end_atom - atom; + int plen = starred ? len : -1; + + for (i = 0; i < n_switches; i++) + if (!strncmp (switches[i].part1, atom, len) + && (starred || switches[i].part1[len] == '\0') + && check_live_switch (i, plen)) + switches[i].ordering = 1; +} - if (*p == '!') - /* A `!' after the open-brace negates the condition: - succeed if the specified switch is not present. */ - negate = 1, ++p; +/* Inline subroutine of handle_braces. Process all the currently + marked switches through give_switch, and clear the marks. */ +static inline void +process_marked_switches () +{ + int i; - if (*p == '.') - /* A `.' after the open-brace means test against the current suffix. */ - { - if (pipe_p) - abort (); + for (i = 0; i < n_switches; i++) + if (switches[i].ordering == 1) + { + switches[i].ordering = 0; + give_switch (i, 0); + } +} - suffix = 1; - ++p; - } +/* Handle a %{ ... } construct. P points just inside the leading {. + Returns a pointer one past the end of the brace block, or 0 + if we call do_spec_1 and that returns -1. */ - if (elide_switch && (negate || pipe_p || suffix)) - { - /* It doesn't make sense to mix elision with other flags. We - could fatal() here, but the standard seems to be to abort. */ - abort (); - } +static const char * +handle_braces (p) + const char *p; +{ + const char *atom, *end_atom; + const char *d_atom = NULL, *d_end_atom = NULL; - next_ampersand: - filter = p; - while (*p != ':' && *p != '}' && *p != '|' && *p != '&') - p++; + bool a_is_suffix; + bool a_is_starred; + bool a_is_negated; + bool a_matched; - if (*p == '|' && (pipe_p || ordered)) - abort (); + bool a_must_be_last = false; + bool ordered_set = false; + bool disjunct_set = false; + bool disj_matched = false; + bool disj_starred = true; + bool n_way_choice = false; + bool n_way_matched = false; - if (!body) +#define SKIP_WHITE() do { while (*p == ' ' || *p == '\t') p++; } while (0) + + do { - if (*p != '}' && *p != '&') - { - int count = 1; - const char *q = p; + if (a_must_be_last) + abort (); - while (*q++ != ':') - continue; - body = q; + /* Scan one "atom" (S in the description above of %{}, possibly + with !, ., or * modifiers). */ + a_matched = a_is_suffix = a_is_starred = a_is_negated = false; - while (count > 0) - { - if (*q == '{') - count++; - else if (*q == '}') - count--; - else if (*q == 0) - fatal ("mismatched braces in specs"); - q++; - } - endbody = q; - } - else - body = p, endbody = p + 1; - } + SKIP_WHITE(); + if (*p == '!') + p++, a_is_negated = true; - if (suffix) - { - int found = (input_suffix != 0 - && (long) strlen (input_suffix) == (long) (p - filter) - && strncmp (input_suffix, filter, p - filter) == 0); + SKIP_WHITE(); + if (*p == '.') + p++, a_is_suffix = true; - if (body[0] == '}') - abort (); + atom = p; + while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '=' + || *p == ',' || *p == '.') + p++; + end_atom = p; - if (negate != found - && do_spec_1 (save_string (body, endbody-body-1), 0, NULL) < 0) - return 0; - } - else if (p[-1] == '*' && (p[0] == '}' || p[0] == '&')) - { - /* Substitute all matching switches as separate args. */ - int i; + if (*p == '*') + p++, a_is_starred = 1; - for (i = 0; i < n_switches; i++) - if (!strncmp (switches[i].part1, filter, p - 1 - filter) - && check_live_switch (i, p - 1 - filter)) - { - if (elide_switch) - { - switches[i].live_cond = SWITCH_IGNORE; - switches[i].validated = 1; - } - else - ordered = 1, switches[i].ordering = 1; - } - } - else - { - /* Test for presence of the specified switch. */ - int i; - int present = 0; + SKIP_WHITE(); + if (*p == '&' || *p == '}') + { + /* Substitute the switch(es) indicated by the current atom. */ + ordered_set = true; + if (disjunct_set || n_way_choice || a_is_negated || a_is_suffix + || atom == end_atom) + abort (); - /* If name specified ends in *, as in {x*:...}, - check for %* and handle that case. */ - if (p[-1] == '*' && !negate) + mark_matching_switches (atom, end_atom, a_is_starred); + + if (*p == '}') + process_marked_switches (); + } + else if (*p == '|' || *p == ':') { - int substitution; - const char *r = body; + /* Substitute some text if the current atom appears as a switch + or suffix. */ + disjunct_set = true; + if (ordered_set) + abort (); - /* First see whether we have %*. */ - substitution = 0; - while (r < endbody) + if (atom == end_atom) { - if (*r == '%' && r[1] == '*') - substitution = 1; - r++; + if (!n_way_choice || disj_matched || *p == '|' + || a_is_negated || a_is_suffix || a_is_starred) + abort (); + + /* An empty term may appear as the last choice of an + N-way choice set; it means "otherwise". */ + a_must_be_last = true; + disj_matched = !n_way_matched; + disj_starred = false; } - /* If we do, handle that case. */ - if (substitution) + else { - /* Substitute all matching switches as separate args. - But do this by substituting for %* - in the text that follows the colon. */ - - unsigned hard_match_len = p - filter - 1; - char *string = save_string (body, endbody - body - 1); - - for (i = 0; i < n_switches; i++) - if (!strncmp (switches[i].part1, filter, hard_match_len) - && check_live_switch (i, -1)) - { - do_spec_1 (string, 0, &switches[i].part1[hard_match_len]); - /* Pass any arguments this switch has. */ - give_switch (i, 1, 1); - suffix_subst = NULL; - } - - /* We didn't match. Try again. */ - if (*p++ == '|') - goto next_member; - return endbody; + if (a_is_suffix && a_is_starred) + abort (); + + if (!a_is_starred) + disj_starred = false; + + /* Don't bother testing this atom if we already have a + match. */ + if (!disj_matched && !n_way_matched) + { + if (a_is_suffix) + a_matched = input_suffix_matches (atom, end_atom); + else + a_matched = switch_matches (atom, end_atom, a_is_starred); + + if (a_matched != a_is_negated) + { + disj_matched = true; + d_atom = atom; + d_end_atom = end_atom; + } + } } - } - /* If name specified ends in *, as in {x*:...}, - check for presence of any switch name starting with x. */ - if (p[-1] == '*') - { - for (i = 0; i < n_switches; i++) + if (*p == ':') { - unsigned hard_match_len = p - filter - 1; + /* Found the body, that is, the text to substitute if the + current disjunction matches. */ + p = process_brace_body (p + 1, d_atom, d_end_atom, disj_starred, + disj_matched && !n_way_matched); + if (p == 0) + return 0; - if (!strncmp (switches[i].part1, filter, hard_match_len) - && check_live_switch (i, hard_match_len)) + /* If we have an N-way choice, reset state for the next + disjunction. */ + if (*p == ';') { - present = 1; - break; + n_way_choice = true; + n_way_matched |= disj_matched; + disj_matched = false; + disj_starred = true; + d_atom = d_end_atom = NULL; } } } - /* Otherwise, check for presence of exact name specified. */ else - { - for (i = 0; i < n_switches; i++) - { - if (!strncmp (switches[i].part1, filter, p - filter) - && switches[i].part1[p - filter] == 0 - && check_live_switch (i, -1)) - { - present = 1; - break; - } - } - } + abort (); + } + while (*p++ != '}'); - /* If it is as desired (present for %{s...}, absent for %{!s...}) - then substitute either the switch or the specified - conditional text. */ - if (present != negate) - { - if (elide_switch) - { - switches[i].live_cond = SWITCH_IGNORE; - switches[i].validated = 1; - } - else if (ordered || *p == '&') - ordered = 1, switches[i].ordering = 1; - else if (*p == '}') - give_switch (i, 0, include_blanks); - else - /* Even if many alternatives are matched, only output once. */ - true_once = 1; - } - else if (pipe_p) + return p; + +#undef SKIP_WHITE +} + +/* Subroutine of handle_braces. Scan and process a brace substitution body + (X in the description of %{} syntax). P points one past the colon; + ATOM and END_ATOM bracket the first atom which was found to be true + (present) in the current disjunction; STARRED indicates whether all + the atoms in the current disjunction were starred (for syntax validation); + MATCHED indicates whether the disjunction matched or not, and therefore + whether or not the body is to be processed through do_spec_1 or just + skipped. Returns a pointer to the closing } or ;, or 0 if do_spec_1 + returns -1. */ + +static const char * +process_brace_body (p, atom, end_atom, starred, matched) + const char *p; + const char *atom; + const char *end_atom; + int starred; + int matched; +{ + const char *body, *end_body; + unsigned int nesting_level; + bool have_subst = false; + + /* Locate the closing } or ;, honoring nested braces. + Trim trailing whitespace. */ + body = p; + nesting_level = 1; + for (;;) + { + if (*p == '{') + nesting_level++; + else if (*p == '}') { - /* Here if a %{|...} conditional fails: output a minus sign, - which means "standard output" or "standard input". */ - do_spec_1 ("-", 0, NULL); - return endbody; + if (!--nesting_level) + break; } + else if (*p == ';' && nesting_level == 1) + break; + else if (*p == '%' && p[1] == '*' && nesting_level == 1) + have_subst = true; + else if (*p == '\0') + abort (); + p++; } + + end_body = p; + while (end_body[-1] == ' ' || end_body[-1] == '\t') + end_body--; - /* We didn't match; try again. */ - if (*p++ == '|') - goto next_member; + if (have_subst && !starred) + abort (); - if (p[-1] == '&') + if (matched) { - body = 0; - goto next_ampersand; - } + /* Copy the substitution body to permanent storage and execute it. + If have_subst is false, this is a simple matter of running the + body through do_spec_1... */ + char *string = save_string (body, end_body - body); + if (!have_subst) + { + if (do_spec_1 (string, 0, NULL) < 0) + return 0; + } + else + { + /* ... but if have_subst is true, we have to process the + body once for each matching switch, with %* set to the + variant part of the switch. */ + unsigned int hard_match_len = end_atom - atom; + int i; - if (ordered) - { - int i; - /* Doing this set of switches later preserves their command-line - ordering. This is needed for e.g. -U, -D and -A. */ - for (i = 0; i < n_switches; i++) - if (switches[i].ordering == 1) - { - switches[i].ordering = 0; - give_switch (i, 0, include_blanks); - } - } - /* Process the spec just once, regardless of match count. */ - else if (true_once) - { - if (do_spec_1 (save_string (body, endbody - body - 1), - 0, NULL) < 0) - return 0; + for (i = 0; i < n_switches; i++) + if (!strncmp (switches[i].part1, atom, hard_match_len) + && check_live_switch (i, hard_match_len)) + { + if (do_spec_1 (string, 0, + &switches[i].part1[hard_match_len]) < 0) + return 0; + /* Pass any arguments this switch has. */ + give_switch (i, 1); + suffix_subst = NULL; + } + } } - return endbody; + return p; } /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch @@ -5568,16 +5880,12 @@ check_live_switch (switchnum, prefix_length) the vector of switches gcc received, which is `switches'. This cannot fail since it never finishes a command line. - If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument. - - If INCLUDE_BLANKS is nonzero, then we include blanks before each argument - of the switch. */ + If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument. */ static void -give_switch (switchnum, omit_first_word, include_blanks) +give_switch (switchnum, omit_first_word) int switchnum; int omit_first_word; - int include_blanks; { if (switches[switchnum].live_cond == SWITCH_IGNORE) return; @@ -5595,8 +5903,7 @@ give_switch (switchnum, omit_first_word, include_blanks) { const char *arg = *p; - if (include_blanks) - do_spec_1 (" ", 0, NULL); + do_spec_1 (" ", 0, NULL); if (suffix_subst) { unsigned length = strlen (arg); @@ -5634,11 +5941,9 @@ find_file (name) char *newname; /* Try multilib_dir if it is defined. */ - if (multilib_dir != NULL) + if (multilib_os_dir != NULL) { - const char *const try = ACONCAT ((multilib_dir, dir_separator_str, name, NULL)); - - newname = find_a_file (&startfile_prefixes, try, R_OK); + newname = find_a_file (&startfile_prefixes, name, R_OK, 1); /* If we don't find it in the multi library dir, then fall through and look for it in the normal places. */ @@ -5646,7 +5951,7 @@ find_file (name) return newname; } - newname = find_a_file (&startfile_prefixes, name, R_OK); + newname = find_a_file (&startfile_prefixes, name, R_OK, 0); return newname ? newname : name; } @@ -5867,6 +6172,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. */ @@ -5881,7 +6192,7 @@ main (argc, argv) spec_version, dir_separator_str, NULL); just_machine_suffix = concat (spec_machine, dir_separator_str, NULL); - specs_file = find_a_file (&startfile_prefixes, "specs", R_OK); + specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, 0); /* Read the specs file unless it is a default one. */ if (specs_file != 0 && strcmp (specs_file, "specs")) read_specs (specs_file, TRUE); @@ -5900,82 +6211,81 @@ 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. - 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 not cross-compiling, look for executables in the standard + places. */ + if (*cross_compile == '0') { if (*md_exec_prefix) { add_prefix (&exec_prefixes, md_exec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 0, NULL); - add_prefix (&startfile_prefixes, md_exec_prefix, "GCC", - PREFIX_PRIORITY_LAST, 0, NULL); + PREFIX_PRIORITY_LAST, 0, NULL, 0); } + } + + /* Look for startfiles in the standard places. */ + 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_sysrooted_prefix (&startfile_prefixes, argbuf[ndx], "BINUTILS", + PREFIX_PRIORITY_LAST, 0, NULL, 1); + } + /* We should eventually get rid of all these and stick to + startfile_prefix_spec exclusively. */ + else if (*cross_compile == '0' || target_system_root) + { + if (*md_exec_prefix) + add_sysrooted_prefix (&startfile_prefixes, md_exec_prefix, "GCC", + PREFIX_PRIORITY_LAST, 0, NULL, 1); if (*md_startfile_prefix) - add_prefix (&startfile_prefixes, md_startfile_prefix, "GCC", - PREFIX_PRIORITY_LAST, 0, NULL); + add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix, + "GCC", PREFIX_PRIORITY_LAST, 0, NULL, 1); if (*md_startfile_prefix_1) - add_prefix (&startfile_prefixes, md_startfile_prefix_1, "GCC", - PREFIX_PRIORITY_LAST, 0, NULL); + add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix_1, + "GCC", PREFIX_PRIORITY_LAST, 0, NULL, 1); /* If standard_startfile_prefix is relative, base it on standard_exec_prefix. This lets us move the installed tree as a unit. If GCC_EXEC_PREFIX is defined, base standard_startfile_prefix on that as well. */ if (IS_ABSOLUTE_PATHNAME (standard_startfile_prefix)) - add_prefix (&startfile_prefixes, standard_startfile_prefix, "BINUTILS", - PREFIX_PRIORITY_LAST, 0, NULL); + add_sysrooted_prefix (&startfile_prefixes, + standard_startfile_prefix, "BINUTILS", + PREFIX_PRIORITY_LAST, 0, NULL, 1); else { if (gcc_exec_prefix) add_prefix (&startfile_prefixes, concat (gcc_exec_prefix, machine_suffix, standard_startfile_prefix, NULL), - NULL, PREFIX_PRIORITY_LAST, 0, NULL); + NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1); add_prefix (&startfile_prefixes, concat (standard_exec_prefix, machine_suffix, standard_startfile_prefix, NULL), - NULL, PREFIX_PRIORITY_LAST, 0, NULL); + NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1); } - add_prefix (&startfile_prefixes, standard_startfile_prefix_1, - "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL); - add_prefix (&startfile_prefixes, standard_startfile_prefix_2, - "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL); + add_sysrooted_prefix (&startfile_prefixes, standard_startfile_prefix_1, + "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1); + add_sysrooted_prefix (&startfile_prefixes, standard_startfile_prefix_2, + "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1); #if 0 /* Can cause surprises, and one can use -B./ instead. */ add_prefix (&startfile_prefixes, "./", NULL, - PREFIX_PRIORITY_LAST, 1, NULL); + PREFIX_PRIORITY_LAST, 1, NULL, 0); #endif } - else - { - if (!IS_ABSOLUTE_PATHNAME (standard_startfile_prefix) - && gcc_exec_prefix) - add_prefix (&startfile_prefixes, - concat (gcc_exec_prefix, machine_suffix, - standard_startfile_prefix, NULL), - "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL); - } - - 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); - } /* Process any user specified specs in the order given on the command line. */ for (uptr = user_specs_head; uptr; uptr = uptr->next) { - char *filename = find_a_file (&startfile_prefixes, uptr->filename, R_OK); + char *filename = find_a_file (&startfile_prefixes, uptr->filename, + R_OK, 0); read_specs (filename ? filename : uptr->filename, FALSE); } @@ -6017,7 +6327,7 @@ main (argc, argv) if (print_prog_name) { - char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK); + char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK, 0); printf ("%s\n", (newname ? newname : print_prog_name)); return (0); } @@ -6037,6 +6347,15 @@ main (argc, argv) return (0); } + if (print_multi_os_directory) + { + if (multilib_os_dir == NULL) + printf (".\n"); + else + printf ("%s\n", multilib_os_dir); + return (0); + } + if (target_help_flag) { /* Print if any target specific options. */ @@ -6054,7 +6373,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); } @@ -6196,7 +6515,7 @@ main (argc, argv) /* We'll use ld if we can't find collect2. */ if (! strcmp (linker_name_spec, "collect2")) { - char *s = find_a_file (&exec_prefixes, "collect2", X_OK); + char *s = find_a_file (&exec_prefixes, "collect2", X_OK, 0); if (s == NULL) linker_name_spec = "ld"; } @@ -6229,7 +6548,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 @@ -6405,91 +6724,117 @@ notice VPARAMS ((const char *msgid, ...)) VA_CLOSE (ap); } +static inline void +validate_switches_from_spec (spec) + const char *spec; +{ + const char *p = spec; + char c; + while ((c = *p++)) + if (c == '%' && (*p == '{' || *p == '<' || (*p == 'W' && *++p == '{'))) + /* We have a switch spec. */ + p = validate_switches (p + 1); +} + static void validate_all_switches () { struct compiler *comp; - const char *p; - char c; struct spec_list *spec; for (comp = compilers; comp->spec; comp++) - { - p = comp->spec; - while ((c = *p++)) - if (c == '%' && (*p == '{' || (*p == 'W' && *++p == '{'))) - /* We have a switch spec. */ - validate_switches (p + 1); - } + validate_switches_from_spec (comp->spec); /* Look through the linked list of specs read from the specs file. */ for (spec = specs; spec; spec = spec->next) - { - p = *(spec->ptr_spec); - while ((c = *p++)) - if (c == '%' && (*p == '{' || (*p == 'W' && *++p == '{'))) - /* We have a switch spec. */ - validate_switches (p + 1); - } + validate_switches_from_spec (*spec->ptr_spec); - p = link_command_spec; - while ((c = *p++)) - if (c == '%' && (*p == '{' || (*p == 'W' && *++p == '{'))) - /* We have a switch spec. */ - validate_switches (p + 1); + validate_switches_from_spec (link_command_spec); } /* Look at the switch-name that comes after START and mark as valid all supplied switches that match it. */ -static void +static const char * validate_switches (start) const char *start; { const char *p = start; - const char *filter; + const char *atom; + size_t len; int i; - int suffix; - - if (*p == '|') - ++p; - + bool suffix = false; + bool starred = false; + +#define SKIP_WHITE() do { while (*p == ' ' || *p == '\t') p++; } while (0) + next_member: + SKIP_WHITE (); + if (*p == '!') - ++p; + p++; - suffix = 0; + SKIP_WHITE (); if (*p == '.') - suffix = 1, ++p; + suffix = true, p++; - filter = p; - while (*p != ':' && *p != '}' && *p != '|' && *p != '&') + atom = p; + while (ISIDNUM (*p) || *p == '-' || *p == '+' || *p == '=' + || *p == ',' || *p == '.') p++; + len = p - atom; - if (suffix) - ; - else if (p[-1] == '*') + if (*p == '*') + starred = true, p++; + + SKIP_WHITE (); + + if (!suffix) { /* Mark all matching switches as valid. */ for (i = 0; i < n_switches; i++) - if (!strncmp (switches[i].part1, filter, p - filter - 1)) + if (!strncmp (switches[i].part1, atom, len) + && (starred || switches[i].part1[len] == 0)) switches[i].validated = 1; } - else + + p++; + if (p[-1] == '|' || p[-1] == '&') + goto next_member; + + if (p[-1] == ':') { - /* Mark an exact matching switch as valid. */ - for (i = 0; i < n_switches; i++) + while (*p && *p != ';' && *p != '}') { - if (!strncmp (switches[i].part1, filter, p - filter) - && switches[i].part1[p - filter] == 0) - switches[i].validated = 1; + if (*p == '%') + { + p++; + if (*p == '{' || *p == '<') + p = validate_switches (p+1); + else if (p[0] == 'W' && p[1] == '{') + p = validate_switches (p+2); + } + p++; } + + p++; + if (p[-1] == ';') + goto next_member; } - if (*p++ == '|' || p[-1] == '&') - goto next_member; + return p; +#undef SKIP_WHITE } +struct mdswitchstr +{ + const char *str; + int len; +}; + +static struct mdswitchstr *mdswitches; +static int n_mdswitches; + /* Check whether a particular argument was used. The first time we canonicalize the switches to keep only the ones we care about. */ @@ -6555,8 +6900,9 @@ used_arg (p, len) xmalloc from calling fatal, and prevents us from re-executing this block of code. */ mswitches - = (struct mswitchstr *) xmalloc ((sizeof (struct mswitchstr)) - * (n_switches ? n_switches : 1)); + = (struct mswitchstr *) + xmalloc (sizeof (struct mswitchstr) + * (n_mdswitches + (n_switches ? n_switches : 1))); for (i = 0; i < n_switches; i++) { int xlen = strlen (switches[i].part1); @@ -6572,6 +6918,57 @@ used_arg (p, len) break; } } + + /* Add MULTILIB_DEFAULTS switches too, as long as they were not present + on the command line nor any options mutually incompatible with + them. */ + for (i = 0; i < n_mdswitches; i++) + { + const char *r; + + for (q = multilib_options; *q != '\0'; q++) + { + while (*q == ' ') + q++; + + r = q; + while (strncmp (q, mdswitches[i].str, mdswitches[i].len) != 0 + || strchr (" /", q[mdswitches[i].len]) == NULL) + { + while (*q != ' ' && *q != '/' && *q != '\0') + q++; + if (*q != '/') + break; + q++; + } + + if (*q != ' ' && *q != '\0') + { + while (*r != ' ' && *r != '\0') + { + q = r; + while (*q != ' ' && *q != '/' && *q != '\0') + q++; + + if (used_arg (r, q - r)) + break; + + if (*q != '/') + { + mswitches[n_mswitches].str = mdswitches[i].str; + mswitches[n_mswitches].len = mdswitches[i].len; + mswitches[n_mswitches].replace = (char *) 0; + mswitches[n_mswitches].rep_len = 0; + n_mswitches++; + break; + } + + r = q + 1; + } + break; + } + } + } } for (i = 0; i < n_mswitches; i++) @@ -6586,25 +6983,11 @@ default_arg (p, len) const char *p; int len; { - const char *start, *end; - - for (start = multilib_defaults; *start != '\0'; start = end + 1) - { - while (*start == ' ' || *start == '\t') - start++; - - if (*start == '\0') - break; - - for (end = start + 1; *end != ' ' && *end != '\t' && *end != '\0'; end++) - ; - - if ((end - start) == len && strncmp (p, start, len) == 0) - return 1; + int i; - if (*end == '\0') - break; - } + for (i = 0; i < n_mdswitches; i++) + if (len == mdswitches[i].len && ! strncmp (p, mdswitches[i].str, len)) + return 1; return 0; } @@ -6626,8 +7009,51 @@ set_multilib_dir () const char *p; unsigned int this_path_len; const char *this_path, *this_arg; + const char *start, *end; int not_arg; - int ok; + int ok, ndfltok, first; + + n_mdswitches = 0; + start = multilib_defaults; + while (*start == ' ' || *start == '\t') + start++; + while (*start != '\0') + { + n_mdswitches++; + while (*start != ' ' && *start != '\t' && *start != '\0') + start++; + while (*start == ' ' || *start == '\t') + start++; + } + + if (n_mdswitches) + { + int i = 0; + + mdswitches + = (struct mdswitchstr *) xmalloc (sizeof (struct mdswitchstr) + * n_mdswitches); + for (start = multilib_defaults; *start != '\0'; start = end + 1) + { + while (*start == ' ' || *start == '\t') + start++; + + if (*start == '\0') + break; + + for (end = start + 1; + *end != ' ' && *end != '\t' && *end != '\0'; end++) + ; + + obstack_grow (&multilib_obstack, start, end - start); + obstack_1grow (&multilib_obstack, 0); + mdswitches[i].str = obstack_finish (&multilib_obstack); + mdswitches[i++].len = end - start; + + if (*end == '\0') + break; + } + } p = multilib_exclusions; while (*p != '\0') @@ -6682,6 +7108,7 @@ set_multilib_dir () ++p; } + first = 1; p = multilib_select; while (*p != '\0') { @@ -6704,6 +7131,7 @@ set_multilib_dir () /* Check the arguments. */ ok = 1; + ndfltok = 1; ++p; while (*p != ';') { @@ -6739,32 +7167,65 @@ set_multilib_dir () there is a more specific library which uses this argument. If this argument is a default, we need not consider that more specific library. */ - if (! default_arg (this_arg, p - this_arg)) - { - ok = used_arg (this_arg, p - this_arg); - if (not_arg) - ok = ! ok; - } + ok = used_arg (this_arg, p - this_arg); + if (not_arg) + ok = ! ok; + + if (! ok) + ndfltok = 0; + + if (default_arg (this_arg, p - this_arg)) + ok = 1; if (*p == ' ') ++p; } - if (ok) + if (ok && first) { if (this_path_len != 1 || this_path[0] != '.') { char *new_multilib_dir = xmalloc (this_path_len + 1); + char *q; + strncpy (new_multilib_dir, this_path, this_path_len); new_multilib_dir[this_path_len] = '\0'; + q = strchr (new_multilib_dir, ':'); + if (q != NULL) + *q = '\0'; multilib_dir = new_multilib_dir; } - break; + first = 0; + } + + if (ndfltok) + { + const char *q = this_path, *end = this_path + this_path_len; + + while (q < end && *q != ':') + q++; + if (q < end) + { + char *new_multilib_os_dir = xmalloc (end - q); + memcpy (new_multilib_os_dir, q + 1, end - q - 1); + new_multilib_os_dir[end - q - 1] = '\0'; + multilib_os_dir = new_multilib_os_dir; + break; + } } ++p; } + + if (multilib_dir == NULL && multilib_os_dir != NULL + && strcmp (multilib_os_dir, ".") == 0) + { + free ((char *) multilib_os_dir); + multilib_os_dir = NULL; + } + else if (multilib_dir != NULL && multilib_os_dir == NULL) + multilib_os_dir = multilib_dir; } /* Print out the multiple library subdirectory selection @@ -6804,6 +7265,12 @@ print_multilib_info () ++p; } + /* When --disable-multilib was used but target defines + MULTILIB_OSDIRNAMES, entries starting with .: are there just + to find multilib_os_dir, so skip them from output. */ + if (this_path[0] == '.' && this_path[1] == ':') + skip = 1; + /* Check for matches with the multilib_exclusions. We don't bother with the '!' in either list. If any of the exclusion rules match all of its options with the select rule, we skip it. */ @@ -6945,7 +7412,7 @@ print_multilib_info () { const char *p1; - for (p1 = last_path; p1 < p; p1++) + for (p1 = last_path; p1 < p && *p1 != ':'; p1++) putchar (*p1); putchar (';'); } |