summaryrefslogtreecommitdiff
path: root/gcc/gcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gcc.c')
-rw-r--r--gcc/gcc.c964
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