/* Compiler driver program that can handle many languages.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
#include "intl.h"
#include "prefix.h"
#include "gcc.h"
+#include "flags.h"
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#define MIN_FATAL_STATUS 1
+/* Flag set by cppspec.c to 1. */
+int is_cpp_driver;
+
/* Flag saying to pass the greatest exit code returned by a sub-process
to the calling program. */
static int pass_exit_codes;
static int verbose_flag;
+/* Flag indicating whether we should ONLY print the command and
+ arguments (like verbose_flag) without executing the command.
+ Displayed arguments are quoted so that the generated command
+ line is suitable for execution. This is intended for use in
+ shell scripts to capture the driver-generated command line. */
+static int verbose_only_flag;
+
/* Flag indicating to print target specific command line options. */
static int target_help_flag;
switch. The only case we support now is simply appending or deleting a
string to or from the end of the first part of the configuration name. */
-const struct modify_target
+static const struct modify_target
{
const char *const sw;
const enum add_del {ADD, DELETE} add_del;
static int check_live_switch PARAMS ((int, int));
static const char *handle_braces PARAMS ((const char *));
static char *save_string PARAMS ((const char *, int));
+static void set_collect_gcc_options PARAMS ((void));
static int do_spec_1 PARAMS ((const char *, int, const char *));
static const char *find_file PARAMS ((const char *));
static int is_directory PARAMS ((const char *, const char *, int));
static int execute PARAMS ((void));
static void clear_args PARAMS ((void));
static void fatal_error PARAMS ((int));
-static void set_input PARAMS ((const char *));
#ifdef ENABLE_SHARED_LIBGCC
static void init_gcc_specs PARAMS ((struct obstack *,
- const char *,
+ const char *, const char *,
const char *));
#endif
#if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
-static const char *convert_filename PARAMS ((const char *, int));
+static const char *convert_filename PARAMS ((const char *, int, int));
#endif
\f
/* The Specs Language
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.
%1 process CC1_SPEC as a spec.
%2 process CC1PLUS_SPEC as a spec.
treated as compiler output files, and passed to the linker in their
proper position among the other output files. */
\f
-/* Define the macros used for specs %a, %l, %L, %S, %c, %C, %1. */
+/* Define the macros used for specs %a, %l, %L, %S, %C, %1. */
/* config.h can define ASM_SPEC to provide extra args to the assembler
or extra switch-translations. */
#define ENDFILE_SPEC ""
#endif
-/* This spec is used for telling cpp whether char is signed or not. */
-#ifndef SIGNED_CHAR_SPEC
-/* Use #if rather than ?:
- because MIPS C compiler rejects like ?: in initializers. */
-#if DEFAULT_SIGNED_CHAR
-#define SIGNED_CHAR_SPEC "%{funsigned-char:-D__CHAR_UNSIGNED__}"
-#else
-#define SIGNED_CHAR_SPEC "%{!fsigned-char:-D__CHAR_UNSIGNED__}"
-#endif
-#endif
-
#ifndef LINKER_NAME
#define LINKER_NAME "collect2"
#endif
/* Define ASM_DEBUG_SPEC to be a spec suitable for translating '-g'
to the assembler. */
#ifndef ASM_DEBUG_SPEC
-# if defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
-# if PREFERRED_DEBUGGING_FORMAT == DBX_DEBUG
-# define ASM_DEBUG_SPEC "%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}"
-# else
-# define ASM_DEBUG_SPEC "%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}"
-# endif
+# if defined(DBX_DEBUGGING_INFO) && defined(DWARF2_DEBUGGING_INFO) \
+ && defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
+# define ASM_DEBUG_SPEC \
+ (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG \
+ ? "%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}" \
+ : "%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}")
# else
-# define ASM_DEBUG_SPEC ""
+# if defined(DBX_DEBUGGING_INFO) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
+# define ASM_DEBUG_SPEC "%{g*:--gstabs}"
+# endif
+# if defined(DWARF2_DEBUGGING_INFO) && defined(HAVE_AS_GDWARF2_DEBUG_FLAG)
+# define ASM_DEBUG_SPEC "%{g*:--gdwarf2}"
+# endif
# endif
#endif
+#ifndef ASM_DEBUG_SPEC
+# define ASM_DEBUG_SPEC ""
+#endif
/* Here is the spec for running the linker, after compiling all files. */
+/* This is overridable by the target in case they need to specify the
+ -lgcc and -lc order specially, yet not require them to override all
+ of LINK_COMMAND_SPEC. */
+#ifndef LINK_GCC_C_SEQUENCE_SPEC
+#define LINK_GCC_C_SEQUENCE_SPEC "%G %L %G"
+#endif
+
/* -u* was put back because both BSD and SysV seem to support it. */
/* %{static:} simply prevents an error message if the target machine
doesn't handle -static. */
%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t}\
%{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
- %{static:} %{L*} %(link_libgcc) %o %{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
+ %{static:} %{L*} %(link_libgcc) %o %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}}\
%{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
#endif
static const char *cpp_predefines = CPP_PREDEFINES;
static const char *cc1_spec = CC1_SPEC;
static const char *cc1plus_spec = CC1PLUS_SPEC;
-static const char *signed_char_spec = SIGNED_CHAR_SPEC;
+static const char *link_gcc_c_sequence_spec = LINK_GCC_C_SEQUENCE_SPEC;
static const char *asm_spec = ASM_SPEC;
static const char *asm_final_spec = ASM_FINAL_SPEC;
static const char *link_spec = LINK_SPEC;
appropriate -B options. */
static const char *trad_capable_cpp =
-"%{traditional|ftraditional|traditional-cpp:trad}cpp0";
+"%{traditional|ftraditional|traditional-cpp:tradcpp0}\
+ %{!traditional:%{!ftraditional:%{!traditional-cpp:cc1 -E}}}";
-static const char *cpp_options =
+static const char *cpp_unique_options =
"%{C:%{!E:%eGNU C does not support -C without using -E}}\
- %{std*} %{nostdinc*}\
- %{C} %{v} %{I*} %{P} %{$} %I\
- %{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 %*}}\
+ %{CC:%{!E:%eGNU C does not support -CC without using -E}}\
+ %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %{$} %I\
+ %{MD:-MD %W{!o: %b.d}%W{o*:%.d%*}}\
+ %{MMD:-MMD %W{!o: %b.d}%W{o*:%.d%*}}\
+ %{M} %{MM} %W{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
+ %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}}\
%{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3}\
%{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
- %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
%{fno-inline|O0|!O*:-D__NO_INLINE__} %{ffast-math:-D__FAST_MATH__}\
%{fshort-wchar:-U__WCHAR_TYPE__ -D__WCHAR_TYPE__=short\\ unsigned\\ int}\
%{ffreestanding:-D__STDC_HOSTED__=0} %{fno-hosted:-D__STDC_HOSTED__=0}\
- %{!ffreestanding:%{!fno-hosted:-D__STDC_HOSTED__=1}}\
+ %{!ffreestanding:%{!fno-hosted:-D__STDC_HOSTED__=1}} %{remap}\
+ %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\
+ %{E|M|MM:%W{o*}}";
+
+/* This contains cpp options which are common with cc1_options and are passed
+ only when preprocessing only to avoid duplication. */
+static const char *cpp_options =
+"%(cpp_unique_options) %{std*} %{d*} %{W*&pedantic*} %{w}\
%{fshow-column} %{fno-show-column}\
+ %{fsigned-char&funsigned-char}\
%{fleading-underscore} %{fno-leading-underscore}\
- %{fno-operator-names} %{ftabstop=*} %{remap}\
- %{g3:-dD} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*&U*&A*} %{i*} %Z %i\
- %{E:%{!M*:%W{o*}}}";
+ %{fno-operator-names} %{ftabstop=*}";
/* NB: This is shared amongst all front-ends. */
static const char *cc1_options =
"%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\
- %{g*} %{O*} %{W*} %{w} %{pedantic*} %{std*} %{ansi}\
- %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
+ %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi}\
+ %{v:-version} %{pg:-p} %{p} %{f*}\
%{Qn:-fno-ident} %{--help:--help}\
%{--target-help:--target-help}\
%{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
/* The default list of file name suffixes and their compilation specs. */
-static struct compiler default_compilers[] =
+static const struct compiler default_compilers[] =
{
/* Add lists of suffixes of known languages here. If those languages
were not present when we built the driver, we will hit these copies
{".F", "#Fortran", 0}, {".FOR", "#Fortran", 0}, {".FPP", "#Fortran", 0},
{".r", "#Ratfor", 0},
{".p", "#Pascal", 0}, {".pas", "#Pascal", 0},
- {".ch", "#Chill", 0}, {".chi", "#Chill", 0},
{".java", "#Java", 0}, {".class", "#Java", 0},
{".zip", "#Java", 0}, {".jar", "#Java", 0},
/* Next come the entries for C. */
{".c", "@c", 0},
{"@c",
/* cc1 has an integrated ISO C preprocessor. We should invoke the
- external preprocessor if -save-temps or -traditional is given. */
+ external preprocessor if -save-temps is given. */
"%{E|M|MM:%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)}\
%{!E:%{!M:%{!MM:\
- %{save-temps:%(trad_capable_cpp) -lang-c %{ansi:-std=c89}\
- %(cpp_options) %b.i \n\
+ %{traditional|ftraditional:\
+%eGNU C no longer supports -traditional without -E}\
+ %{save-temps|traditional-cpp:%(trad_capable_cpp) \
+ -lang-c %{ansi:-std=c89} %(cpp_options) %b.i \n\
cc1 -fpreprocessed %b.i %(cc1_options)}\
- %{!save-temps:\
- %{traditional|ftraditional|traditional-cpp:\
- tradcpp0 -lang-c %{ansi:-std=c89} %(cpp_options) %{!pipe:%g.i} |\n\
- cc1 -fpreprocessed %{!pipe:%g.i} %(cc1_options)}\
- %{!traditional:%{!ftraditional:%{!traditional-cpp:\
- cc1 -lang-c %{ansi:-std=c89} %(cpp_options) %(cc1_options)}}}}\
+ %{!save-temps:%{!traditional-cpp:\
+ cc1 -lang-c %{ansi:-std=c89} %(cpp_unique_options) %(cc1_options)}}\
%{!fsyntax-only:%(invoke_as)}}}}", 0},
{"-",
"%{!E:%e-E required when input is from standard input}\
%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0},
{".h", "@c-header", 0},
{"@c-header",
- "%{!E:%eCompilation of header file requested} \
+ "%{!E:%ecompilation of header file requested} \
%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0},
{".i", "@cpp-output", 0},
{"@cpp-output",
/* Number of elements in default_compilers, not counting the terminator. */
-static int n_default_compilers
- = (sizeof default_compilers / sizeof (struct compiler)) - 1;
+static const int n_default_compilers = ARRAY_SIZE (default_compilers) - 1;
/* A vector of options to give to the linker.
These options are accumulated by %x,
{"--assemble", "-S", 0},
{"--assert", "-A", "a"},
{"--classpath", "-fclasspath=", "aj"},
- {"--CLASSPATH", "-fCLASSPATH=", "aj"},
+ {"--bootclasspath", "-fbootclasspath=", "aj"},
+ {"--CLASSPATH", "-fclasspath=", "aj"},
{"--comments", "-C", 0},
+ {"--comments-in-macros", "-CC", 0},
{"--compile", "-c", 0},
{"--debug", "-g", "oj"},
{"--define-macro", "-D", "aj"},
{"--use-version", "-V", "a"},
{"--user-dependencies", "-MM", 0},
{"--verbose", "-v", 0},
- {"--version", "-dumpversion", 0},
{"--warn-", "-W", "*j"},
{"--write-dependencies", "-MD", 0},
{"--write-user-dependencies", "-MMD", 0},
if (strlen (option_map[k].name) >= arglen
&& !strncmp (argv[i], option_map[k].name, arglen))
{
- error ("Ambiguous abbreviation %s", argv[i]);
+ error ("ambiguous abbreviation %s", argv[i]);
break;
}
else if (strchr (arginfo, '*') != 0)
{
- error ("Incomplete `%s' option", option_map[j].name);
+ error ("incomplete `%s' option", option_map[j].name);
break;
}
{
if (i + 1 == argc)
{
- error ("Missing argument to `%s' option",
+ error ("missing argument to `%s' option",
option_map[j].name);
break;
}
else if (strchr (arginfo, 'o') == 0)
{
if (arg != 0)
- error ("Extraneous argument to `%s' option",
+ error ("extraneous argument to `%s' option",
option_map[j].name);
arg = 0;
}
INIT_STATIC_SPEC ("invoke_as", &invoke_as),
INIT_STATIC_SPEC ("cpp", &cpp_spec),
INIT_STATIC_SPEC ("cpp_options", &cpp_options),
+ INIT_STATIC_SPEC ("cpp_unique_options", &cpp_unique_options),
INIT_STATIC_SPEC ("trad_capable_cpp", &trad_capable_cpp),
INIT_STATIC_SPEC ("cc1", &cc1_spec),
INIT_STATIC_SPEC ("cc1_options", &cc1_options),
INIT_STATIC_SPEC ("cc1plus", &cc1plus_spec),
+ INIT_STATIC_SPEC ("link_gcc_c_sequence", &link_gcc_c_sequence_spec),
INIT_STATIC_SPEC ("endfile", &endfile_spec),
INIT_STATIC_SPEC ("link", &link_spec),
INIT_STATIC_SPEC ("lib", &lib_spec),
INIT_STATIC_SPEC ("libgcc", &libgcc_spec),
INIT_STATIC_SPEC ("startfile", &startfile_spec),
INIT_STATIC_SPEC ("switches_need_spaces", &switches_need_spaces),
- INIT_STATIC_SPEC ("signed_char", &signed_char_spec),
INIT_STATIC_SPEC ("predefines", &cpp_predefines),
INIT_STATIC_SPEC ("cross_compile", &cross_compile),
INIT_STATIC_SPEC ("version", &compiler_version),
#ifdef ENABLE_SHARED_LIBGCC
static void
-init_gcc_specs (obstack, shared_name, static_name)
+init_gcc_specs (obstack, shared_name, static_name, eh_name)
struct obstack *obstack;
const char *shared_name;
const char *static_name;
+ const char *eh_name;
{
- char buffer[128];
-
- /* If we see -shared-libgcc, then use the shared version. */
- sprintf (buffer, "%%{shared-libgcc:%s %s}", shared_name, static_name);
- obstack_grow (obstack, buffer, strlen (buffer));
- /* If we see -static-libgcc, then use the static 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 %s}}}",
- shared_name, static_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));
+ char *buf;
+
+ buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name,
+ "}%{!static:%{!static-libgcc:",
+ "%{!shared:%{!shared-libgcc:", static_name, " ",
+ eh_name, "}%{shared-libgcc:", shared_name, " ",
+ static_name, "}}%{shared:",
+#ifdef LINK_EH_SPEC
+ "%{shared-libgcc:", shared_name,
+ "}%{!shared-libgcc:", static_name, "}",
+#else
+ shared_name,
+#endif
+ "}}}", NULL);
+
+ obstack_grow (obstack, buf, strlen (buf));
+ free (buf);
}
#endif /* ENABLE_SHARED_LIBGCC */
return; /* Already initialized. */
if (verbose_flag)
- notice ("Using builtin specs.\n");
+ notice ("Using built-in specs.\n");
#ifdef EXTRA_SPECS
extra_specs = (struct spec_list *)
"-lgcc_s%M"
#endif
,
- "-lgcc");
+ "-lgcc",
+ "-lgcc_eh");
p += 5;
in_sep = 0;
}
"-lgcc_s%M"
#endif
,
- "libgcc.a%s");
+ "libgcc.a%s",
+ "libgcc_eh.a%s");
p += 10;
in_sep = 0;
}
asm_spec = obstack_finish (&obstack);
}
#endif
+#ifdef LINK_EH_SPEC
+ /* Prepend LINK_EH_SPEC to whatever link_spec we had before. */
+ obstack_grow (&obstack, LINK_EH_SPEC, sizeof(LINK_EH_SPEC) - 1);
+ obstack_grow0 (&obstack, link_spec, strlen (link_spec));
+ link_spec = obstack_finish (&obstack);
+#endif
specs = sl;
}
A suffix which starts with `*' is a definition for
one of the machine-specific sub-specs. The "suffix" should be
- *asm, *cc1, *cpp, *link, *startfile, *signed_char, etc.
+ *asm, *cc1, *cpp, *link, *startfile, etc.
The corresponding spec is stored in asm_spec, etc.,
rather than in the `compilers' vector.
if (new_filename)
read_specs (new_filename, FALSE);
else if (verbose_flag)
- notice ("Could not find specs file %s\n", p1);
+ notice ("could not find specs file %s\n", p1);
continue;
}
else if (!strncmp (p1, "%rename", sizeof "%rename" - 1)
{
const char *const *j;
- for (j = commands[i].argv; *j; j++)
- fprintf (stderr, " %s", *j);
+ if (verbose_only_flag)
+ {
+ for (j = commands[i].argv; *j; j++)
+ {
+ const char *p;
+ fprintf (stderr, " \"");
+ for (p = *j; *p; ++p)
+ {
+ if (*p == '"' || *p == '\\' || *p == '$')
+ fputc ('\\', stderr);
+ fputc (*p, stderr);
+ }
+ fputc ('"', stderr);
+ }
+ }
+ else
+ for (j = commands[i].argv; *j; j++)
+ fprintf (stderr, " %s", *j);
/* Print a pipe symbol after all but the last command. */
if (i + 1 != n_commands)
fprintf (stderr, "\n");
}
fflush (stderr);
+ if (verbose_only_flag != 0)
+ return 0;
#ifdef DEBUG
notice ("\nGo ahead? (y or n) ");
fflush (stderr);
#if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
/* Convert NAME to a new name if it is the standard suffix. DO_EXE
- is true if we should look for an executable suffix as well. */
+ is true if we should look for an executable suffix. DO_OBJ
+ is true if we should look for an object suffix. */
static const char *
-convert_filename (name, do_exe)
+convert_filename (name, do_exe, do_obj)
const char *name;
int do_exe ATTRIBUTE_UNUSED;
+ int do_obj ATTRIBUTE_UNUSED;
{
#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
int i;
#ifdef HAVE_TARGET_OBJECT_SUFFIX
/* Convert x.o to x.obj if TARGET_OBJECT_SUFFIX is ".obj". */
- if (len > 2
+ if (do_obj && len > 2
&& name[len - 2] == '.'
&& name[len - 1] == 'o')
{
fputs (_(" -save-temps Do not delete intermediate files\n"), stdout);
fputs (_(" -pipe Use pipes rather than intermediate files\n"), stdout);
fputs (_(" -time Time the execution of each subprocess\n"), stdout);
- fputs (_(" -specs=<file> Override builtin specs with the contents of <file>\n"), stdout);
+ fputs (_(" -specs=<file> Override built-in specs with the contents of <file>\n"), stdout);
fputs (_(" -std=<standard> Assume that the input sources are for <standard>\n"), stdout);
fputs (_(" -B <directory> Add <directory> to the compiler's search paths\n"), stdout);
fputs (_(" -b <machine> Run gcc for target <machine>, if installed\n"), stdout);
fputs (_(" -V <version> Run gcc version number <version>, if installed\n"), stdout);
fputs (_(" -v Display the programs invoked by the compiler\n"), stdout);
+ fputs (_(" -### Like -v but options quoted and commands not executed\n"), stdout);
fputs (_(" -E Preprocess only; do not compile, assemble or link\n"), stdout);
fputs (_(" -S Compile only; do not assemble or link\n"), stdout);
fputs (_(" -c Compile and assemble, but do not link\n"), stdout);
fputs (_("\
-x <language> Specify the language of the following input files\n\
Permissable languages include: c c++ assembler none\n\
- 'none' means revert to the default behaviour of\n\
+ 'none' means revert to the default behavior of\n\
guessing the language based on the file's extension\n\
"), stdout);
printf ("%s\n", spec_machine);
exit (0);
}
+ else if (strcmp (argv[i], "-fversion") == 0)
+ {
+ /* translate_options () has turned --version into -fversion. */
+ printf (_("%s (GCC) %s\n"), programname, version_string);
+ fputs (_("Copyright (C) 2002 Free Software Foundation, Inc.\n"),
+ stdout);
+ fputs (_("This is free software; see the source for copying conditions. There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"),
+ stdout);
+ exit (0);
+ }
else if (strcmp (argv[i], "-fhelp") == 0)
{
/* translate_options () has turned --help into -fhelp. */
n_infiles++;
n_switches++;
- add_preprocessor_option ("--help", 6);
+ /* CPP driver cannot obtain switch from cc1_options. */
+ if (is_cpp_driver)
+ add_preprocessor_option ("--help", 6);
add_assembler_option ("--help", 6);
add_linker_option ("--help", 6);
}
n_infiles++;
n_switches++;
- add_preprocessor_option ("--target-help", 13);
+ /* CPP driver cannot obtain switch from cc1_options. */
+ if (is_cpp_driver)
+ add_preprocessor_option ("--target-help", 13);
add_assembler_option ("--target-help", 13);
add_linker_option ("--target-help", 13);
}
}
else if (strcmp (argv[i], "-time") == 0)
report_times = 1;
+ else if (strcmp (argv[i], "-###") == 0)
+ {
+ /* This is similar to -v except that there is no execution
+ of the commands and the echoed arguments are quoted. It
+ is intended for use in shell scripts to capture the
+ driver-generated command line. */
+ verbose_only_flag++;
+ verbose_flag++;
+ }
else if (argv[i][0] == '-' && argv[i][1] != 0)
{
const char *p = &argv[i][1];
#endif
#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
if (p[1] == 0)
- argv[i + 1] = convert_filename (argv[i + 1], ! have_c);
+ argv[i + 1] = convert_filename (argv[i + 1], ! have_c, 0);
else
- argv[i] = convert_filename (argv[i], ! have_c);
+ argv[i] = convert_filename (argv[i], ! have_c, 0);
#endif
goto normal_switch;
#ifdef MODIFY_TARGET_NAME
is_modify_target_name = 0;
- for (j = 0;
- j < sizeof modify_target / sizeof modify_target[0]; j++)
+ for (j = 0; j < ARRAY_SIZE (modify_target); j++)
if (! strcmp (argv[i], modify_target[j].sw))
{
char *new_name
#ifdef MODIFY_TARGET_NAME
is_modify_target_name = 0;
- for (j = 0; j < sizeof modify_target / sizeof modify_target[0]; j++)
+ for (j = 0; j < ARRAY_SIZE (modify_target); j++)
if (! strcmp (argv[i], modify_target[j].sw))
is_modify_target_name = 1;
;
else if (! strcmp (argv[i], "-print-multi-directory"))
;
- else if (strcmp (argv[i], "-ftarget-help") == 0)
- {
- /* Create a dummy input file, so that we can pass --target-help on to
- the various sub-processes. */
- infiles[n_infiles].language = "c";
- infiles[n_infiles++].name = "target-dummy";
-
- /* Preserve the --target-help switch so that it can be caught by
- the cc1 spec string. */
- switches[n_switches].part1 = "--target-help";
- switches[n_switches].args = 0;
- switches[n_switches].live_cond = SWITCH_OK;
- switches[n_switches].validated = 0;
-
- n_switches++;
- }
- else if (strcmp (argv[i], "-fhelp") == 0)
- {
- if (verbose_flag)
- {
- /* Create a dummy input file, so that we can pass --help on to
- the various sub-processes. */
- infiles[n_infiles].language = "c";
- infiles[n_infiles++].name = "help-dummy";
-
- /* Preserve the --help switch so that it can be caught by the
- cc1 spec string. */
- switches[n_switches].part1 = "--help";
- switches[n_switches].args = 0;
- switches[n_switches].live_cond = SWITCH_OK;
- switches[n_switches].validated = 0;
-
- n_switches++;
- }
- }
+ else if (! strcmp (argv[i], "-ftarget-help"))
+ ;
+ else if (! strcmp (argv[i], "-fhelp"))
+ ;
else if (argv[i][0] == '+' && argv[i][1] == 'e')
{
/* Compensate for the +e options to the C++ front-end;
{
/* -save-temps overrides -pipe, so that temp files are produced */
if (save_temps_flag)
- error ("Warning: -pipe ignored because -save-temps specified");
+ 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");
+ error ("warning: -pipe ignored because -time specified");
}
+ else if (strcmp (argv[i], "-###") == 0)
+ ;
else if (argv[i][0] == '-' && argv[i][1] != 0)
{
const char *p = &argv[i][1];
else
{
#ifdef HAVE_TARGET_OBJECT_SUFFIX
- argv[i] = convert_filename (argv[i], 0);
+ argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
#endif
if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0)
}
if (n_infiles == last_language_n_infiles && spec_lang != 0)
- error ("Warning: `-x %s' after last input file has no effect", spec_lang);
+ error ("warning: `-x %s' after last input file has no effect", spec_lang);
+
+ /* Ensure we only invoke each subprocess once. */
+ if (target_help_flag || print_help_list)
+ {
+ n_infiles = 1;
+
+ /* Create a dummy input file, so that we can pass --target-help on to
+ the various sub-processes. */
+ infiles[0].language = "c";
+ infiles[0].name = "help-dummy";
+
+ if (target_help_flag)
+ {
+ switches[n_switches].part1 = "--target-help";
+ switches[n_switches].args = 0;
+ switches[n_switches].live_cond = SWITCH_OK;
+ switches[n_switches].validated = 0;
+
+ n_switches++;
+ }
+
+ if (print_help_list)
+ {
+ switches[n_switches].part1 = "--help";
+ switches[n_switches].args = 0;
+ switches[n_switches].live_cond = SWITCH_OK;
+ switches[n_switches].validated = 0;
+
+ n_switches++;
+ }
+ }
switches[n_switches].part1 = 0;
infiles[n_infiles].name = 0;
}
+
+/* Store switches not filtered out by %{<S} in spec in COLLECT_GCC_OPTIONS
+ and place that in the environment. */
+
+static void
+set_collect_gcc_options ()
+{
+ int i;
+ int first_time;
+
+ /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
+ the compiler. */
+ obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
+ sizeof ("COLLECT_GCC_OPTIONS=") - 1);
+
+ first_time = TRUE;
+ for (i = 0; (int) i < n_switches; i++)
+ {
+ const char *const *args;
+ const char *p, *q;
+ if (!first_time)
+ obstack_grow (&collect_obstack, " ", 1);
+
+ first_time = FALSE;
+
+ /* Ignore elided switches. */
+ if (switches[i].live_cond == SWITCH_IGNORE)
+ continue;
+
+ obstack_grow (&collect_obstack, "'-", 2);
+ q = switches[i].part1;
+ while ((p = strchr (q, '\'')))
+ {
+ obstack_grow (&collect_obstack, q, p - q);
+ obstack_grow (&collect_obstack, "'\\''", 4);
+ q = ++p;
+ }
+ obstack_grow (&collect_obstack, q, strlen (q));
+ obstack_grow (&collect_obstack, "'", 1);
+
+ for (args = switches[i].args; args && *args; args++)
+ {
+ obstack_grow (&collect_obstack, " '", 2);
+ q = *args;
+ while ((p = strchr (q, '\'')))
+ {
+ obstack_grow (&collect_obstack, q, p - q);
+ obstack_grow (&collect_obstack, "'\\''", 4);
+ q = ++p;
+ }
+ obstack_grow (&collect_obstack, q, strlen (q));
+ obstack_grow (&collect_obstack, "'", 1);
+ }
+ }
+ obstack_grow (&collect_obstack, "\0", 1);
+ putenv (obstack_finish (&collect_obstack));
+}
\f
/* Process a spec string, accumulating and running commands. */
static int suffixed_basename_length;
static const char *input_basename;
static const char *input_suffix;
+static struct stat input_stat;
+static int input_stat_set;
/* The compiler used to process the current input file. */
static struct compiler *input_file_compiler;
if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
argbuf_index--;
+ set_collect_gcc_options ();
+
if (argbuf_index > 0)
value = execute ();
}
argbuf_index--;
}
+ set_collect_gcc_options ();
+
if (argbuf_index > 0)
{
value = execute ();
switch (c = *p++)
{
case 0:
- fatal ("Invalid specification! Bug in cc.");
+ fatal ("invalid specification! Bug in cc");
case 'b':
obstack_grow (&obstack, input_basename, basename_length);
case 'g':
case 'u':
case 'U':
- if (save_temps_flag)
- {
- obstack_grow (&obstack, input_basename, basename_length);
- delete_this_arg = 0;
- }
- else
{
struct temp_name *t;
int suffix_length;
}
suffix_length += strlen (TARGET_OBJECT_SUFFIX);
}
+
+ /* If the input_filename has the same suffix specified
+ for the %g, %u, or %U, and -save-temps is specified,
+ we could end up using that file as an intermediate
+ thus clobbering the user's source file (.e.g.,
+ gcc -save-temps foo.s would clobber foo.s with the
+ output of cpp0). So check for this condition and
+ generate a temp file as the intermediate. */
+
+ if (save_temps_flag)
+ {
+ temp_filename_length = basename_length + suffix_length;
+ temp_filename = alloca (temp_filename_length + 1);
+ strncpy ((char *) temp_filename, input_basename, basename_length);
+ strncpy ((char *) temp_filename + basename_length, suffix,
+ suffix_length);
+ *((char *) temp_filename + temp_filename_length) = '\0';
+ if (strcmp (temp_filename, input_filename) != 0)
+ {
+ struct stat st_temp;
+
+ /* Note, set_input() resets input_stat_set to 0. */
+ if (input_stat_set == 0)
+ {
+ input_stat_set = stat (input_filename, &input_stat);
+ if (input_stat_set >= 0)
+ input_stat_set = 1;
+ }
+
+ /* If we have the stat for the input_filename
+ and we can do the stat for the temp_filename
+ then the they could still refer to the same
+ file if st_dev/st_ino's are the same. */
+
+ if (input_stat_set != 1
+ || stat (temp_filename, &st_temp) < 0
+ || input_stat.st_dev != st_temp.st_dev
+ || input_stat.st_ino != st_temp.st_ino)
+ {
+ temp_filename = save_string (temp_filename,
+ temp_filename_length + 1);
+ obstack_grow (&obstack, temp_filename,
+ temp_filename_length);
+ arg_going = 1;
+ break;
+ }
+ }
+ }
/* See if we already have an association of %g/%u/%U and
suffix. */
return value;
break;
- case 'c':
- value = do_spec_1 (signed_char_spec, 0, NULL);
- if (value != 0)
- return value;
- break;
-
case 'C':
{
const char *const spec
/* Catch the case where a spec string contains something like
'%{foo:%*}'. ie there is no * in the pattern on the left
hand side of the :. */
- error ("Spec failure: '%%*' has not been initialised by pattern match");
+ error ("spec failure: '%%*' has not been initialized by pattern match");
break;
/* Process a string found as the value of a spec given by name.
%[...] modifies -D options the way %P does;
%(...) uses the spec unmodified. */
case '[':
- error ("Warning: use of obsolete %%[ operator in specs");
+ error ("warning: use of obsolete %%[ operator in specs");
case '(':
{
const char *name = p;
break;
default:
- error ("Spec failure: Unrecognised spec option '%c'", c);
+ error ("spec failure: unrecognized spec option '%c'", c);
break;
}
break;
else if (*q == '}')
count--;
else if (*q == 0)
- fatal ("Mismatched braces in specs");
+ fatal ("mismatched braces in specs");
q++;
}
endbody = q;
/* Set up the various global variables to indicate that we're processing
the input file named FILENAME. */
-static void
+void
set_input (filename)
const char *filename;
{
}
else
input_suffix = "";
+
+ /* If a spec for 'g', 'u', or 'U' is seen with -save-temps then
+ we will need to do a stat on the input_filename. The
+ INPUT_STAT_SET signals that the stat is needed. */
+ input_stat_set = 0;
}
\f
/* On fatal signals, delete all the temporary files. */
process_command (argc, argv);
- {
- int first_time;
-
- /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
- the compiler. */
- obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
- sizeof ("COLLECT_GCC_OPTIONS=") - 1);
-
- first_time = TRUE;
- for (i = 0; (int) i < n_switches; i++)
- {
- const char *const *args;
- const char *p, *q;
- if (!first_time)
- obstack_grow (&collect_obstack, " ", 1);
-
- first_time = FALSE;
- obstack_grow (&collect_obstack, "'-", 2);
- q = switches[i].part1;
- while ((p = strchr (q, '\'')))
- {
- obstack_grow (&collect_obstack, q, p - q);
- obstack_grow (&collect_obstack, "'\\''", 4);
- q = ++p;
- }
- obstack_grow (&collect_obstack, q, strlen (q));
- obstack_grow (&collect_obstack, "'", 1);
-
- for (args = switches[i].args; args && *args; args++)
- {
- obstack_grow (&collect_obstack, " '", 2);
- q = *args;
- while ((p = strchr (q, '\'')))
- {
- obstack_grow (&collect_obstack, q, p - q);
- obstack_grow (&collect_obstack, "'\\''", 4);
- q = ++p;
- }
- obstack_grow (&collect_obstack, q, strlen (q));
- obstack_grow (&collect_obstack, "'", 1);
- }
- }
- obstack_grow (&collect_obstack, "\0", 1);
- putenv (obstack_finish (&collect_obstack));
- }
-
/* Initialize the vector of specs to just the default.
This means one element containing 0s, as a terminator. */
if (target_help_flag)
{
- /* Print if any target specific options.*/
+ /* Print if any target specific options. */
/* We do not exit here. Instead we have created a fake input file
called 'target-dummy' which needs to be compiled, and we pass this
}
if (n_infiles == added_libraries)
- fatal ("No input files");
+ fatal ("no input files");
/* Make a place to record the compiler output file names
that correspond to the input files. */
void
fancy_abort ()
{
- fatal ("Internal gcc abort.");
+ fatal ("internal gcc abort");
}
\f
/* Output an error message and exit */
{
p = comp->spec;
while ((c = *p++))
- if (c == '%' && *p == '{')
+ if (c == '%' && (*p == '{' || (*p == 'W' && *++p == '{')))
/* We have a switch spec. */
validate_switches (p + 1);
}
{
p = *(spec->ptr_spec);
while ((c = *p++))
- if (c == '%' && *p == '{')
+ if (c == '%' && (*p == '{' || (*p == 'W' && *++p == '{')))
/* We have a switch spec. */
validate_switches (p + 1);
}
p = link_command_spec;
while ((c = *p++))
- if (c == '%' && *p == '{')
+ if (c == '%' && (*p == '{' || (*p == 'W' && *++p == '{')))
/* We have a switch spec. */
validate_switches (p + 1);
}