diff options
author | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-12-16 18:23:00 +0000 |
---|---|---|
committer | zack <zack@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-12-16 18:23:00 +0000 |
commit | 805e22b2051e9c6a75377ea6599654d7415da483 (patch) | |
tree | c259697c448b0c6f548f153c48c46a8d7a75970f /gcc/gcc.c | |
parent | 2c27ce73ee2229b0871c4ccad2342d8a4be85eff (diff) | |
download | gcc-805e22b2051e9c6a75377ea6599654d7415da483.tar.gz |
Merge basic-improvements-branch to trunk
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@60174 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gcc.c')
-rw-r--r-- | gcc/gcc.c | 964 |
1 files changed, 596 insertions, 368 deletions
diff --git a/gcc/gcc.c b/gcc/gcc.c index b05367326ff..3f37fce6d9f 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -72,6 +72,8 @@ compilation is specified by a string called a "spec". */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include <signal.h> #if ! defined( SIGCHLD ) && defined( SIGCLD ) # define SIGCHLD SIGCLD @@ -197,11 +199,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; @@ -279,6 +291,8 @@ 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 *, 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 *)); @@ -287,6 +301,15 @@ 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 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 *)); @@ -297,9 +320,10 @@ 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)); @@ -363,6 +387,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. @@ -448,10 +478,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. %:function(args) Call the named function FUNCTION, passing it ARGS. ARGS is first processed as a nested spec string, then split into an @@ -466,33 +501,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 @@ -727,7 +769,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 @@ -879,10 +925,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} @@ -1214,6 +1269,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 @@ -1575,6 +1634,9 @@ init_spec () #else "-lgcc_s%M" #endif +#ifdef USE_LIBUNWIND_EXCEPTIONS + " -lunwind" +#endif , "-lgcc", "-lgcc_eh"); @@ -2519,6 +2581,33 @@ add_prefix (pprefix, prefix, component, priority, require_machine_suffix, 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 @@ -2785,7 +2874,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. */ @@ -2919,6 +3008,8 @@ display_help () 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); @@ -3384,6 +3475,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) @@ -3431,6 +3536,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 @@ -3633,6 +3745,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 @@ -3693,6 +3818,15 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" concat (tooldir_prefix, "lib", dir_separator_str, 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. */ @@ -3782,6 +3916,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 */ @@ -3799,17 +3943,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) @@ -3876,10 +4009,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 { @@ -3946,7 +4080,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 @@ -4178,17 +4312,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 @@ -4418,10 +4547,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)) @@ -4434,9 +4563,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; @@ -4520,7 +4679,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 @@ -4541,7 +4700,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; @@ -4923,6 +5082,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) @@ -4958,6 +5125,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) { @@ -5114,11 +5307,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; @@ -5309,273 +5497,303 @@ handle_spec_function (p) return p; } -/* 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 @@ -5660,16 +5878,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; @@ -5687,8 +5901,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); @@ -5996,34 +6209,51 @@ 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, 0); - add_prefix (&startfile_prefixes, md_exec_prefix, "GCC", - 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, 1); + 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, 1); + 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, 1); + add_sysrooted_prefix (&startfile_prefixes, + standard_startfile_prefix, "BINUTILS", + PREFIX_PRIORITY_LAST, 0, NULL, 1); else { if (gcc_exec_prefix) @@ -6038,34 +6268,15 @@ main (argc, argv) NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1); } - add_prefix (&startfile_prefixes, standard_startfile_prefix_1, - "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1); - add_prefix (&startfile_prefixes, standard_startfile_prefix_2, - "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1); + 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, 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, 1); - } - - 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. */ @@ -6511,89 +6722,106 @@ 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 |