/* Compiler driver program that can handle many languages.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000 Free Software Foundation, Inc.
+ 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
static void clear_args PARAMS ((void));
static void fatal_error PARAMS ((int));
static void set_input PARAMS ((const char *));
+static void init_gcc_specs PARAMS ((struct obstack *,
+ const char *,
+ const char *));
\f
/* Specs are strings containing lines, each of which (if not blank)
is made up of a program name, and arguments separated by spaces.
of a temporary file, just like %u. This temporary file is not
meant for communication between processes, but rather as a junk
disposal mechanism.
+ %.SUFFIX
+ substitutes .SUFFIX for the suffixes of a matched switch's args when
+ it is subsequently output with %*. SUFFIX is terminated by the next
+ space or %.
%d marks the argument containing or following the %d as a
temporary file name, so that that file will be deleted if CC exits
successfully. Unlike %g, this contributes no text to the argument.
and substitute the full name found.
%eSTR Print STR as an error message. STR is terminated by a newline.
Use this when inconsistent options are detected.
+ %nSTR Print STR as an notice. STR is terminated by a newline.
%x{OPTION} Accumulate an option for %X.
%X Output the accumulated linker options specified by compilations.
%Y Output the accumulated assembler options specified by compilations.
%l process LINK_SPEC as a spec.
%L process LIB_SPEC as a spec.
%G process LIBGCC_SPEC as a spec.
+ %M output multilib_dir with directory separators replaced with "_";
+ if multilib_dir is not set or is ".", output "".
%S process STARTFILE_SPEC as a spec. A capital S is actually used here.
%E process ENDFILE_SPEC as a spec. A capital E is actually used here.
%c process SIGNED_CHAR_SPEC as a spec.
- %C process CPP_SPEC as a spec. A capital C is actually used here.
+ %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.
"%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{std*} %{nostdinc*}\
%{C} %{v} %{I*} %{P} %{$} %I\
- %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ %{MD:-M -MF %W{!o: %b.d}%W{o*:%.d%*}}\
+ %{MMD:-MM -MF %W{!o: %b.d}%W{o*:%.d%*}}\
+ %{M} %{MM} %W{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{M|MD|MM|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}\
%c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
%{!ffreestanding:%{!fno-hosted:-D__STDC_HOSTED__=1}}\
%{fshow-column} %{fno-show-column}\
%{fleading-underscore} %{fno-leading-underscore}\
- %{ftabstop=*}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*&U*&A*} %{i*} %Z %i\
- %{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}}";
+ %{fno-operator-names} %{ftabstop=*} %{remap}\
+ %{g3:-dD} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*&U*&A*} %{i*} %Z %i\
+ %{E:%{!M*:%W{o*}}}";
/* NB: This is shared amongst all front-ends. */
static const char *cc1_options =
|| !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
|| !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
|| !strcmp (STR, "isystem") || !strcmp (STR, "specs") \
- || !strcmp (STR, "MF") || !strcmp (STR, "MT"))
+ || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ"))
#ifndef WORD_SWITCH_TAKES_ARG
#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
whose names end in this suffix. */
const char *spec; /* To use this compiler, run this spec. */
+
+ const char *cpp_spec; /* If non-NULL, substitute this spec
+ for `%C', rather than the usual
+ cpp_spec. */
};
/* Pointer to a vector of `struct compiler' that gives the spec for
static struct spec_list *specs = (struct spec_list *) 0;
\f
+/* Add appropriate libgcc specs to OBSTACK, taking into account
+ various permutations of -shared-libgcc, -shared, and such. */
+
+static void
+init_gcc_specs (obstack, shared_name, static_name)
+ struct obstack *obstack;
+ const char *shared_name;
+ const char *static_name;
+{
+ char buffer[128];
+
+ /* If we see -shared-libgcc, then use the shared version. */
+ sprintf (buffer, "%%{shared-libgcc:%s}", shared_name);
+ obstack_grow (obstack, buffer, strlen (buffer));
+ /* If we see -static-libgcc, then use the shared version. */
+ sprintf (buffer, "%%{static-libgcc:%s}", static_name);
+ obstack_grow (obstack, buffer, strlen (buffer));
+ /* Otherwise, if we see -shared, then use the shared version. */
+ sprintf (buffer,
+ "%%{!shared-libgcc:%%{!static-libgcc:%%{shared:%s}}}",
+ shared_name);
+ obstack_grow (obstack, buffer, strlen (buffer));
+ /* Otherwise, use the static version. */
+ sprintf (buffer,
+ "%%{!shared-libgcc:%%{!static-libgcc:%%{!shared:%s}}}",
+ static_name);
+ obstack_grow (obstack, buffer, strlen (buffer));
+}
+
/* Initialize the specs lookup routines. */
static void
next = sl;
}
+#ifdef ENABLE_SHARED_LIBGCC
+ /* ??? If neither -shared-libgcc nor --static-libgcc was
+ seen, then we should be making an educated guess. Some proposed
+ heuristics for ELF include:
+
+ (1) If "-Wl,--export-dynamic", then it's a fair bet that the
+ program will be doing dynamic loading, which will likely
+ need the shared libgcc.
+
+ (2) If "-ldl", then it's also a fair bet that we're doing
+ dynamic loading.
+
+ (3) For each ET_DYN we're linking against (either through -lfoo
+ or /some/path/foo.so), check to see whether it or one of
+ its dependancies depends on a shared libgcc.
+
+ (4) If "-shared"
+
+ If the runtime is fixed to look for program headers instead
+ of calling __register_frame_info at all, for each object,
+ use the shared libgcc if any EH symbol referenced.
+
+ If crtstuff is fixed to not invoke __register_frame_info
+ automatically, for each object, use the shared libgcc if
+ any non-empty unwind section found.
+
+ Doing any of this probably requires invoking an external program to
+ do the actual object file scanning. */
+ {
+ const char *p = libgcc_spec;
+ int in_sep = 1;
+
+ /* Transform the extant libgcc_spec into one that uses the shared libgcc
+ when given the proper command line arguments. */
+ while (*p)
+ {
+ if (in_sep && *p == '-' && strncmp (p, "-lgcc", 5) == 0)
+ {
+ init_gcc_specs (&obstack,
+#ifdef NO_SHARED_LIBGCC_MULTILIB
+ "-lgcc_s"
+#else
+ "-lgcc_s%M"
+#endif
+ ,
+ "-lgcc");
+ p += 5;
+ in_sep = 0;
+ }
+ else if (in_sep && *p == 'l' && strncmp (p, "libgcc.a%s", 10) == 0)
+ {
+ /* Ug. We don't know shared library extensions. Hope that
+ systems that use this form don't do shared libraries. */
+ init_gcc_specs (&obstack,
+#ifdef NO_SHARED_LIBGCC_MULTILIB
+ "-lgcc_s"
+#else
+ "-lgcc_s%M"
+#endif
+ ,
+ "libgcc.a%s");
+ p += 10;
+ in_sep = 0;
+ }
+ else
+ {
+ obstack_1grow (&obstack, *p);
+ in_sep = (*p == ' ');
+ p += 1;
+ }
+ }
+
+ obstack_1grow (&obstack, '\0');
+ libgcc_spec = obstack_finish (&obstack);
+ }
+#endif
+
specs = sl;
}
\f
}
#endif
-#ifdef HAVE_EXECUTABLE_SUFFIX
+#if defined(HAVE_EXECUTABLE_SUFFIX) && !defined(NO_AUTO_EXE_SUFFIX)
/* If there is no filetype, make it the executable suffix (which includes
the "."). But don't get confused if we have just "-o". */
if (! do_exe || EXECUTABLE_SUFFIX[0] == 0 || (len == 2 && name[0] == '-'))
switches[n_switches].part1 = "--target-help";
switches[n_switches].args = 0;
switches[n_switches].live_cond = SWITCH_OK;
- switches[n_switches].validated = 0;
+ switches[n_switches].validated = 0;
n_switches++;
}
switches[n_switches].part1 = "--help";
switches[n_switches].args = 0;
switches[n_switches].live_cond = SWITCH_OK;
- switches[n_switches].validated = 0;
+ switches[n_switches].validated = 0;
n_switches++;
}
switches[n_switches].live_cond = SWITCH_OK;
switches[n_switches].validated = 0;
- /* This is always valid, since gcc.c itself understands it. */
- if (!strcmp (p, "save-temps"))
+ switches[n_switches].ordering = 0;
+ /* These are always valid, since gcc.c itself understands it. */
+ if (!strcmp (p, "save-temps")
+ || !strcmp (p, "static-libgcc")
+ || !strcmp (p, "shared-libgcc"))
switches[n_switches].validated = 1;
else
{
static const char *input_basename;
static const char *input_suffix;
+/* The compiler used to process the current input file. */
+static struct compiler *input_file_compiler;
+
/* These are variables used within do_spec and do_spec_1. */
/* Nonzero if an arg has been started and not yet terminated
/* Nonzero means that the input of this command is coming from a pipe. */
static int input_from_pipe;
+/* Nonnull means substitute this for any suffix when outputting a switches
+ arguments. */
+static const char *suffix_subst;
+
/* Process the spec SPEC and run the commands specified therein.
Returns 0 if the spec is successfully processed; -1 if failed. */
this_is_output_file = 0;
this_is_library_file = 0;
input_from_pipe = 0;
+ suffix_subst = NULL;
value = do_spec_1 (spec, 0, NULL_PTR);
return -1;
}
break;
+ case 'n':
+ /* %nfoo means report an notice with `foo' on stderr. */
+ {
+ const char *q = p;
+ char *buf;
+ while (*p != 0 && *p != '\n')
+ p++;
+ buf = (char *) alloca (p - q + 1);
+ strncpy (buf, q, p - q);
+ buf[p - q] = 0;
+ notice ("%s\n", buf);
+ if (*p)
+ p++;
+ }
+ break;
case 'j':
{
break;
case 'C':
- value = do_spec_1 (cpp_spec, 0, NULL_PTR);
- if (value != 0)
- return value;
+ {
+ const char* spec
+ = (input_file_compiler->cpp_spec
+ ? input_file_compiler->cpp_spec
+ : cpp_spec);
+ value = do_spec_1 (spec, 0, NULL_PTR);
+ if (value != 0)
+ return value;
+ }
break;
case 'E':
return value;
break;
+ case 'M':
+ if (multilib_dir && strcmp (multilib_dir, ".") != 0)
+ {
+ char *p;
+ const char *q;
+ size_t len;
+
+ len = strlen (multilib_dir);
+ obstack_blank (&obstack, len + 1);
+ p = obstack_next_free (&obstack) - (len + 1);
+
+ *p++ = '_';
+ for (q = multilib_dir; *q ; ++q, ++p)
+ *p = (IS_DIR_SEPARATOR (*q) ? '_' : *q);
+ }
+ break;
+
case 'p':
{
char *x = (char *) alloca (strlen (cpp_predefines) + 1);
obstack_1grow (&obstack, '%');
break;
+ case '.':
+ {
+ unsigned len = 0;
+
+ while (p[len] && p[len] != ' ' && p[len] != '%')
+ len++;
+ suffix_subst = save_string (p - 1, len + 1);
+ p += len;
+ }
+ break;
+
case '*':
if (soft_matched_part)
{
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. */
const char **p;
for (p = switches[switchnum].args; *p; p++)
{
+ const char *arg = *p;
+
if (include_blanks)
do_spec_1 (" ", 0, NULL_PTR);
- do_spec_1 (*p, 1, NULL_PTR);
+ if (suffix_subst)
+ {
+ unsigned length = strlen (arg);
+
+ while (length-- && !IS_DIR_SEPARATOR (arg[length]))
+ if (arg[length] == '.')
+ {
+ ((char *)arg)[length] = 0;
+ break;
+ }
+ do_spec_1 (arg, 1, NULL_PTR);
+ if (!arg[length])
+ {
+ ((char *)arg)[length] = '.';
+ do_spec_1 (suffix_subst, 1, NULL_PTR);
+ }
+ }
+ else
+ do_spec_1 (arg, 1, NULL_PTR);
}
}
--p;
programname = p;
+ xmalloc_set_program_name (programname);
+
#ifdef GCC_DRIVER_HOST_INITIALIZATION
/* Perform host dependant initialization when needed. */
GCC_DRIVER_HOST_INITIALIZATION;
#endif
+/* LC_CTYPE determines the character set used by the terminal so it has be set
+ to output messages correctly. */
+
#ifdef HAVE_LC_MESSAGES
+ setlocale (LC_CTYPE, "");
setlocale (LC_MESSAGES, "");
+#else
+ setlocale (LC_ALL, "");
#endif
+
(void) bindtextdomain (PACKAGE, localedir);
(void) textdomain (PACKAGE);
if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
signal (SIGPIPE, fatal_error);
#endif
+ /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
+ receive the signal. A different setting is inheritable */
+ signal (SIGCHLD, SIG_DFL);
argbuf_length = 10;
argbuf = (const char **) xmalloc (argbuf_length * sizeof (const char *));
for (i = 0; (int) i < n_infiles; i++)
{
- register struct compiler *cp = 0;
int this_file_error = 0;
/* Tell do_spec what to substitute for %i. */
/* Figure out which compiler from the file's suffix. */
- cp = lookup_compiler (infiles[i].name, input_filename_length,
- infiles[i].language);
-
- if (cp)
+ input_file_compiler
+ = lookup_compiler (infiles[i].name, input_filename_length,
+ infiles[i].language);
+
+ if (input_file_compiler)
{
/* Ok, we found an applicable compiler. Run its spec. */
- if (cp->spec[0] == '#')
+ if (input_file_compiler->spec[0] == '#')
error ("%s: %s compiler not installed on this system",
- input_filename, &cp->spec[1]);
- value = do_spec (cp->spec);
+ input_filename, &input_file_compiler->spec[1]);
+ value = do_spec (input_file_compiler->spec);
if (value < 0)
this_file_error = 1;
}