/* Compiler driver program that can handle many languages.
- Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
\f
#include "config.h"
-#include <sys/types.h>
-#include <ctype.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#ifndef NO_SYS_FILE_H
-#include <sys/file.h> /* May get R_OK, etc. on some systems. */
-#endif
-
-#include "obstack.h"
-#include "gansidecl.h"
-
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
-#include <stdio.h>
+#include "system.h"
+#include <signal.h>
+#include <sys/stat.h>
+
+#include "gansidecl.h"
+#include "obstack.h"
-#ifndef R_OK
-#define R_OK 4
-#define W_OK 2
-#define X_OK 1
-#endif
/* ??? Need to find a GCC header to put these in. */
extern int pexecute PROTO ((const char *, char * const *, const char *,
const char *, char **, char **, int));
extern int pwait PROTO ((int, int *, int));
extern char *update_path PROTO((char *, char *));
+extern void set_std_prefix PROTO((char *, int));
/* Flag arguments to pexecute. */
#define PEXECUTE_FIRST 1
#define PEXECUTE_LAST 2
#define exit __posix_exit
#endif
-/* Define O_RDONLY if the system hasn't defined it for us. */
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-
#ifdef USG
#define vfork fork
#endif /* USG */
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern char *getenv ();
-
-extern char *choose_temp_base PROTO((void));
-
-#ifndef errno
-extern int errno;
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ENV_VALUE = getenv (ENV_NAME)
#endif
-#ifndef HAVE_STRERROR
-extern int sys_nerr;
-extern char *sys_errlist[];
-#else
-extern char *strerror();
+extern char *my_strerror PROTO((int));
+
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
#endif
/* If a stage of compilation returns an exit status >= 1,
static void init_spec PROTO((void));
static void read_specs PROTO((char *, int));
static void set_spec PROTO((char *, char *));
-static struct compiler *lookup_compiler PROTO((char *, int, char *));
+static struct compiler *lookup_compiler PROTO((char *, size_t, char *));
static char *build_search_list PROTO((struct path_prefix *, char *, int));
static void putenv_from_prefixes PROTO((struct path_prefix *, char *));
static char *find_a_file PROTO((struct path_prefix *, char *, int));
static char *handle_braces PROTO((char *));
static char *save_string PROTO((char *, int));
static char *concat PVPROTO((char *, ...));
-static int do_spec PROTO((char *));
+extern int do_spec PROTO((char *));
static int do_spec_1 PROTO((char *, int, char *));
static char *find_file PROTO((char *));
static int is_directory PROTO((char *, char *, int));
static void pfatal_with_name PROTO((char *));
static void perror_with_name PROTO((char *));
static void pfatal_pexecute PROTO((char *, char *));
-#ifdef HAVE_VPRINTF
static void fatal PVPROTO((char *, ...));
static void error PVPROTO((char *, ...));
-#else
-/* We must not provide any prototype here, even if ANSI C. */
-static void fatal PROTO(());
-static void error PROTO(());
-#endif
void fancy_abort ();
char *xmalloc ();
char *xrealloc ();
+
+#ifdef LANG_SPECIFIC_DRIVER
+/* Called before processing to change/add/remove arguments. */
+extern void lang_specific_driver PROTO ((void (*) PVPROTO((char *, ...)), int *, char ***, int *));
+
+/* Called before linking. Returns 0 on success and -1 on failure. */
+extern int lang_specific_pre_link ();
+
+/* Number of extra output files that lang_specific_pre_link may generate. */
+extern int lang_specific_extra_outfiles;
+#endif
\f
/* Specs are strings containing lines, each of which (if not blank)
is made up of a program name, and arguments separated by spaces.
%{|!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.
%(Spec) processes a specification defined in a specs file as *Spec:
%[Spec] as above, but put __ around -D arguments
value is ignored, except with {S*} where S is just one letter; this
passes all matching options.
-The character | is used to indicate that a command should be piped to
-the following command, but only if -pipe is specified.
+The character | at the beginning of the predicate text is used to indicate
+that a command should be piped to the following command, but only if -pipe
+is specified.
Note that it is built into CC which switches take arguments and which
do not. You might think it would be useful to generalize this to
#endif
#endif
+#ifndef LINKER_NAME
+#define LINKER_NAME "collect2"
+#endif
+
static char *cpp_spec = CPP_SPEC;
static char *cpp_predefines = CPP_PREDEFINES;
static char *cc1_spec = CC1_SPEC;
static char *endfile_spec = ENDFILE_SPEC;
static char *startfile_spec = STARTFILE_SPEC;
static char *switches_need_spaces = SWITCHES_NEED_SPACES;
+static char *linker_name_spec = LINKER_NAME;
/* 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
#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
#endif
\f
+
+#ifdef HAVE_EXECUTABLE_SUFFIX
+/* This defines which switches stop a full compilation. */
+#define DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR) \
+ ((CHAR) == 'c' || (CHAR) == 'S')
+
+#ifndef SWITCH_CURTAILS_COMPILATION
+#define SWITCH_CURTAILS_COMPILATION(CHAR) \
+ DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR)
+#endif
+#endif
+
/* Record the mapping from file suffixes for compilation specs. */
struct compiler
were not present when we built the driver, we will hit these copies
and be given a more meaningful error than "file not used since
linking is not done". */
- {".cc", "#C++"}, {".cxx", "#C++"}, {".cpp", "#C++"}, {".c++", "#C++"},
- {".C", "#C++"}, {".ads", "#Ada"}, {".adb", "#Ada"}, {".ada", "#Ada"},
- {".f", "#Fortran"}, {".for", "#Fortran"}, {".F", "#Fortran"},
- {".fpp", "#Fortran"},
- {".p", "#Pascal"}, {".pas", "#Pascal"},
+ {".cc", {"#C++"}}, {".cxx", {"#C++"}}, {".cpp", {"#C++"}}, {".c++", {"#C++"}},
+ {".C", {"#C++"}}, {".ads", {"#Ada"}}, {".adb", {"#Ada"}}, {".ada", {"#Ada"}},
+ {".f", {"#Fortran"}}, {".for", {"#Fortran"}}, {".F", {"#Fortran"}},
+ {".fpp", {"#Fortran"}},
+ {".p", {"#Pascal"}}, {".pas", {"#Pascal"}},
/* Next come the entries for C. */
- {".c", "@c"},
+ {".c", {"@c"}},
{"@c",
- "cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ {
+#if USE_CPPLIB
+ "%{E|M|MM:cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ %{C:%{!E:%eGNU C does not support -C without using -E}}\
+ %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
+ %{ansi:-trigraphs -D__STRICT_ANSI__}\
+ %{!undef:%{!ansi:%p} %P} %{trigraphs} \
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
+ %{traditional-cpp:-traditional}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
+ %i %{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}}\n}\
+ %{!E:%{!M:%{!MM:cc1 %i %1 \
+ -lang-c%{ansi:89} %{nostdinc*} %{A*} %{I*} %I\
+ %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a*}\
+ %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
+ %{ansi:-trigraphs -D__STRICT_ANSI__}\
+ %{!undef:%{!ansi:%p} %P} %{trigraphs} \
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{H} %C %{D*} %{U*} %{i*} %Z\
+ %{ftraditional:-traditional}\
+ %{traditional-cpp:-traditional}\
+ %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
+ %{aux-info*}\
+ %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
+ %{!pipe:%g.s} %A\n }}}}"
+ }},
+#else /* ! USE_CPPLIB */
+ "cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
%{ansi:-trigraphs -D__STRICT_ANSI__}\
%{!undef:%{!ansi:%p} %P} %{trigraphs} \
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
+ %{!pipe:%g.s} %A\n }}}}"
+ }},
+#endif /* ! USE_CPPLIB */
{"-",
- "%{E:cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ {"%{E:cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
%{ansi:-trigraphs -D__STRICT_ANSI__}\
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %W{o*}}\
- %{!E:%e-E required when input is from standard input}"},
- {".m", "@objective-c"},
+ %{!E:%e-E required when input is from standard input}"}},
+ {".m", {"@objective-c"}},
{"@objective-c",
- "cpp -lang-objc %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ {"cpp -lang-objc %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__OBJC__ -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
%{ansi:-trigraphs -D__STRICT_ANSI__}\
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
- "%{!M:%{!MM:%{!E:cc1obj %{!pipe:%g.i} %1 \
+ "%{!M:%{!MM:%{!E:cc1obj %{!pipe:%g.i} %1 \
%{!Q:-quiet} -dumpbase %b.m %{d*} %{m*} %{a*}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*} \
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
- {".h", "@c-header"},
+ %{!pipe:%g.s} %A\n }}}}"}},
+ {".h", {"@c-header"}},
{"@c-header",
- "%{!E:%eCompilation of header file requested} \
+ {"%{!E:%eCompilation of header file requested} \
cpp %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
%{ansi:-trigraphs -D__STRICT_ANSI__}\
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
- %i %W{o*}"},
- {".i", "@cpp-output"},
+ %i %W{o*}"}},
+ {".i", {"@cpp-output"}},
{"@cpp-output",
- "%{!M:%{!MM:%{!E:cc1 %i %1 %{!Q:-quiet} %{d*} %{m*} %{a*}\
+ {"%{!M:%{!MM:%{!E:cc1 %i %1 %{!Q:-quiet} %{d*} %{m*} %{a*}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
%{aux-info*}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
- {".s", "@assembler"},
+ %{!pipe:%g.s} %A\n }}}}"}},
+ {".s", {"@assembler"}},
{"@assembler",
- "%{!M:%{!MM:%{!E:%{!S:as %a %Y\
+ {"%{!M:%{!MM:%{!E:%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %i %A\n }}}}"},
- {".S", "@assembler-with-cpp"},
+ %i %A\n }}}}"}},
+ {".S", {"@assembler-with-cpp"}},
{"@assembler-with-cpp",
- "cpp -lang-asm %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ {"cpp -lang-asm %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG} %{trigraphs}\
-undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.s}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
- "%{!M:%{!MM:%{!E:%{!S:as %a %Y\
+ "%{!M:%{!MM:%{!E:%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
+ %{!pipe:%g.s} %A\n }}}}"}},
#include "specs.h"
/* Mark end of table */
- {0, 0}
+ {0, {0}}
};
/* Number of elements in default_compilers, not counting the terminator. */
/* Don't generate -L options. */
static char *link_command_spec = "\
%{!fsyntax-only: \
- %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{!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*} %o\
/* Use -L. */
static char *link_command_spec = "\
%{!fsyntax-only: \
- %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{!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*} %D %o\
/* Find a mapping that applies to this option. */
for (j = 0; j < sizeof (option_map) / sizeof (option_map[0]); j++)
{
- int optlen = strlen (option_map[j].name);
- int arglen = strlen (argv[i]);
- int complen = arglen > optlen ? optlen : arglen;
+ size_t optlen = strlen (option_map[j].name);
+ size_t arglen = strlen (argv[i]);
+ size_t complen = arglen > optlen ? optlen : arglen;
char *arginfo = option_map[j].arg_info;
if (arginfo == 0)
INIT_STATIC_SPEC ("multilib_defaults", &multilib_defaults),
INIT_STATIC_SPEC ("multilib_extra", &multilib_extra),
INIT_STATIC_SPEC ("multilib_matches", &multilib_matches),
+ INIT_STATIC_SPEC ("linker", &linker_name_spec),
};
#ifdef EXTRA_SPECS /* additional specs needed */
}
old_spec = *(sl->ptr_spec);
- *(sl->ptr_spec) = ((spec[0] == '+' && isspace (spec[1]))
+ *(sl->ptr_spec) = ((spec[0] == '+' && ISSPACE (spec[1]))
? concat (old_spec, spec + 1, NULL_PTR)
: save_string (spec, strlen (spec)));
static int argbuf_index;
+/* We want this on by default all the time now. */
+#define MKTEMP_EACH_FILE
+
+#ifdef MKTEMP_EACH_FILE
+
+extern char *make_temp_file PROTO((void));
+
/* This is the list of suffixes and codes (%g/%u/%U) and the associated
- temp file. Used only if MKTEMP_EACH_FILE. */
+ temp file. */
static struct temp_name {
char *suffix; /* suffix associated with the code. */
int filename_length; /* strlen (filename). */
struct temp_name *next;
} *temp_names;
+#else
+extern char *choose_temp_base PROTO((void));
+#endif
+
/* Number of commands executed so far. */
while (*p1 == ' ' || *p1 == '\t')
p1++;
- if (! isalpha (*p1))
+ if (! ISALPHA (*p1))
fatal ("specs %%rename syntax malformed after %d characters",
p1 - buffer);
p2 = p1;
- while (*p2 && !isspace (*p2))
+ while (*p2 && !ISSPACE (*p2))
p2++;
if (*p2 != ' ' && *p2 != '\t')
while (*p2 == ' ' || *p2 == '\t')
p2++;
- if (! isalpha (*p2))
+ if (! ISALPHA (*p2))
fatal ("specs %%rename syntax malformed after %d characters",
p2 - buffer);
/* Get new spec name */
p3 = p2;
- while (*p3 && !isspace (*p3))
+ while (*p3 && !ISSPACE (*p3))
p3++;
if (p3 != p-1)
fatal ("specs file malformed after %d characters", p - buffer);
p1 = p;
- /* Find next blank line. */
- while (*p1 && !(*p1 == '\n' && p1[1] == '\n'))
+ /* Find next blank line or end of string. */
+ while (*p1 && !(*p1 == '\n' && (p1[1] == '\n' || p1[1] == '\0')))
p1++;
/* Specs end at the blank line and do not include the newline. */
}
}
-/* Get rid of all prefixes built up so far in *PLISTP. */
-
-static void
-free_path_prefix (pprefix)
- struct path_prefix *pprefix;
-{
- struct prefix_list *pl = pprefix->plist;
- struct prefix_list *temp;
-
- while (pl)
- {
- temp = pl;
- pl = pl->next;
- free (temp->prefix);
- free ((char *) temp);
- }
-
- pprefix->plist = (struct prefix_list *) 0;
-}
\f
/* Execute the command specified by the arguments on the current line of spec.
When using pipes, this includes several piped-together commands
commands[0].prog = argbuf[0]; /* first command. */
commands[0].argv = &argbuf[0];
string = find_a_file (&exec_prefixes, commands[0].prog, X_OK);
+
if (string)
commands[0].argv[0] = string;
for (n_commands = 1, i = 0; i < argbuf_index; i++)
if (strcmp (argbuf[i], "|") == 0)
{ /* each command. */
-#if defined (__MSDOS__) || (defined (_WIN32) && ! defined (__CYGWIN32__)) || defined (OS2) || defined (VMS)
+#if defined (__MSDOS__) || (defined (_WIN32) && defined (__CYGWIN32_)) || defined (OS2) || defined (VMS)
fatal ("-pipe not supported");
#endif
argbuf[i] = 0; /* termination of command args. */
static int n_infiles;
+/* This counts the number of libraries added by LANG_SPECIFIC_DRIVER, so that
+ we can tell if there were any user supplied any files or libraries. */
+
+static int added_libraries;
+
/* And a vector of corresponding output files is made up later. */
static char **outfiles;
int have_o = 0;
int lang_n_infiles = 0;
- gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX");
+ GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX");
n_switches = 0;
n_infiles = 0;
+ added_libraries = 0;
/* Figure compiler version from version string. */
if (gcc_exec_prefix)
{
+ int len = strlen (gcc_exec_prefix);
+ if (len > sizeof ("/lib/gcc-lib/")-1
+ && (gcc_exec_prefix[len-1] == '/'
+ || gcc_exec_prefix[len-1] == DIR_SEPARATOR))
+ {
+ temp = gcc_exec_prefix + len - sizeof ("/lib/gcc-lib/") + 1;
+ if ((*temp == '/' || *temp == DIR_SEPARATOR)
+ && strncmp (temp+1, "lib", 3) == 0
+ && (temp[4] == '/' || temp[4] == DIR_SEPARATOR)
+ && strncmp (temp+5, "gcc-lib", 7) == 0)
+ len -= sizeof ("/lib/gcc-lib/") - 1;
+ }
+
+ set_std_prefix (gcc_exec_prefix, len);
add_prefix (&exec_prefixes, gcc_exec_prefix, "GCC", 0, 0, NULL_PTR);
add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC", 0, 0, NULL_PTR);
}
/* COMPILER_PATH and LIBRARY_PATH have values
that are lists of directory names with colons. */
- temp = getenv ("COMPILER_PATH");
+ GET_ENVIRONMENT (temp, "COMPILER_PATH");
if (temp)
{
char *startp, *endp;
}
}
- temp = getenv ("LIBRARY_PATH");
+ GET_ENVIRONMENT (temp, "LIBRARY_PATH");
if (temp && *cross_compile == '0')
{
char *startp, *endp;
}
/* Use LPATH like LIBRARY_PATH (for the CMU build program). */
- temp = getenv ("LPATH");
+ GET_ENVIRONMENT (temp, "LPATH");
if (temp && *cross_compile == '0')
{
char *startp, *endp;
#ifdef LANG_SPECIFIC_DRIVER
/* Do language-specific adjustment/addition of flags. */
- lang_specific_driver (fatal, &argc, &argv);
+ lang_specific_driver (fatal, &argc, &argv, &added_libraries);
#endif
/* Scan argv twice. Here, the first time, just count how many switches
}
else if (! strcmp (argv[i], "-dumpversion"))
{
- printf ("%s\n", version_string);
+ printf ("%s\n", spec_version);
exit (0);
}
else if (! strcmp (argv[i], "-dumpmachine"))
case 'B':
{
- int *temp = (int *) xmalloc (sizeof (int));
char *value;
if (p[1] == 0 && i + 1 == argc)
fatal ("argument to `-B' is missing");
&& (value[len - 8] == '/'
|| value[len - 8] == DIR_SEPARATOR)))
&& strncmp (value + len - 7, "stage", 5) == 0
- && isdigit (value[len - 2])
+ && ISDIGIT (value[len - 2])
&& (value[len - 1] == '/'
|| value[len - 1] == DIR_SEPARATOR))
{
spec_version = p + 1;
compiler_version = spec_version;
warn_std_ptr = &warn_std;
+
+ /* Validate the version number. Use the same checks
+ done when inserting it into a spec.
+
+ The format of the version string is
+ ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)? */
+ {
+ char *v = compiler_version;
+
+ /* Ignore leading non-digits. i.e. "foo-" in "foo-2.7.2". */
+ while (! ISDIGIT (*v))
+ v++;
+
+ if (v > compiler_version && v[-1] != '-')
+ fatal ("invalid version number format");
+
+ /* Set V after the first period. */
+ while (ISDIGIT (*v))
+ v++;
+
+ if (*v != '.')
+ fatal ("invalid version number format");
+
+ v++;
+ while (ISDIGIT (*v))
+ v++;
+
+ if (*v != 0 && *v != ' ' && *v != '.' && *v != '-')
+ fatal ("invalid version number format");
+ }
break;
+ case 'S':
case 'c':
if (p[1] == 0)
{
case 'o':
have_o = 1;
+#if defined(HAVE_EXECUTABLE_SUFFIX)
+ if (! have_c)
+ {
+ int skip;
+
+ /* Forward scan, just in case -S or -c is specified
+ after -o. */
+ int j = i + 1;
+ if (p[1] == 0)
+ ++j;
+ while (j < argc)
+ {
+ if (argv[j][0] == '-')
+ {
+ if (SWITCH_CURTAILS_COMPILATION (argv[j][1])
+ && argv[j][2] == 0)
+ {
+ have_c = 1;
+ break;
+ }
+ else if (skip = SWITCH_TAKES_ARG (argv[j][1]))
+ j += skip - (argv[j][2] != 0);
+ else if (skip = WORD_SWITCH_TAKES_ARG (argv[j] + 1))
+ j += skip;
+ }
+ j++;
+ }
+ }
+#endif
#if defined(HAVE_EXECUTABLE_SUFFIX) || defined(HAVE_OBJECT_SUFFIX)
- argv[i] = convert_filename (argv[i], 1);
if (p[1] == 0)
- argv[i+1] = convert_filename (argv[i+1], 1);
+ argv[i+1] = convert_filename (argv[i+1], ! have_c);
+ else
+ argv[i] = convert_filename (argv[i], ! have_c);
#endif
goto normal_switch;
}
if (have_c && have_o && lang_n_infiles > 1)
- fatal ("cannot specify -o with -c and multiple compilations");
+ fatal ("cannot specify -o with -c or -S and multiple compilations");
/* Set up the search paths before we go looking for config files. */
for (j = 4; argv[i][j]; j++)
if (argv[i][j] == ',')
{
- infiles[n_infiles].language = 0;
+ infiles[n_infiles].language = "*";
infiles[n_infiles++].name
= save_string (argv[i] + prev, j - prev);
prev = j + 1;
}
/* Record the part after the last comma. */
- infiles[n_infiles].language = 0;
+ infiles[n_infiles].language = "*";
infiles[n_infiles++].name = argv[i] + prev;
}
else if (strcmp (argv[i], "-Xlinker") == 0)
{
- infiles[n_infiles].language = 0;
+ infiles[n_infiles].language = "*";
infiles[n_infiles++].name = argv[++i];
}
else if (strncmp (argv[i], "-l", 2) == 0)
{
- infiles[n_infiles].language = 0;
+ infiles[n_infiles].language = "*";
infiles[n_infiles++].name = argv[i];
}
else if (strcmp (argv[i], "-specs") == 0)
sans all directory names, and basename_length is the number
of characters starting there excluding the suffix .c or whatever. */
-static char *input_filename;
+char *input_filename;
static int input_file_number;
-static int input_filename_length;
+size_t input_filename_length;
static int basename_length;
static char *input_basename;
static char *input_suffix;
/* Process the spec SPEC and run the commands specified therein.
Returns 0 if the spec is successfully processed; -1 if failed. */
-static int
+int
do_spec (spec)
char *spec;
{
char *string;
int value;
- while (c = *p++)
+ while ((c = *p++))
/* If substituting a switch, treat all chars like letters.
Otherwise, NL, SPC, TAB and % are special. */
switch (inswitch ? 'a' : c)
case 'D':
{
struct prefix_list *pl = startfile_prefixes.plist;
- int bufsize = 100;
+ size_t bufsize = 100;
char *buffer = (char *) xmalloc (bufsize);
int idx;
In 2.4, do something about that. */
struct temp_name *t;
char *suffix = p;
- while (*p == '.' || isalpha (*p)
+ while (*p == '.' || ISALPHA (*p)
|| (p[0] == '%' && p[1] == 'O'))
p++;
t->length = p - suffix;
t->suffix = save_string (suffix, p - suffix);
t->unique = (c != 'g');
- temp_filename = choose_temp_base ();
+ temp_filename = make_temp_file ();
temp_filename_length = strlen (temp_filename);
t->filename = temp_filename;
t->filename_length = temp_filename_length;
*x++ = *y++;
if (*y != '_'
- || (*(y+1) != '_' && ! isupper (*(y+1))))
+ || (*(y+1) != '_' && ! ISUPPER (*(y+1))))
{
/* Stick __ at front of macro name. */
*x++ = '_';
y += 2;
if (*y != '_'
- || (*(y+1) != '_' && ! isupper (*(y+1))))
+ || (*(y+1) != '_' && ! ISUPPER (*(y+1))))
{
/* Stick -D__ at front of macro name. */
*x++ = '-';
char *x = (char *) alloca (strlen (name) * 2 + 1);
char *buf = x;
char *y = name;
+ int flag = 0;
/* Copy all of NAME into BUF, but put __ after
every -D and at the end of each arg, */
while (1)
{
- int flag;
-
if (! strncmp (y, "-D", 2))
{
*x++ = '-';
([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)? */
/* Ignore leading non-digits. i.e. "foo-" in "foo-2.7.2". */
- while (! isdigit (*v))
+ while (! ISDIGIT (*v))
v++;
if (v > compiler_version && v[-1] != '-')
abort ();
if (c1 == '2')
{
/* Set V after the first period. */
- while (isdigit (*v))
+ while (ISDIGIT (*v))
v++;
if (*v != '.')
abort ();
/* Set Q at the next period or at the end. */
q = v;
- while (isdigit (*q))
+ while (ISDIGIT (*q))
q++;
if (*q != 0 && *q != ' ' && *q != '.' && *q != '-')
abort ();
handle_braces (p)
register char *p;
{
- register char *q;
- char *filter;
+ char *filter, *body = NULL, *endbody;
int pipe_p = 0;
- int negate = 0;
- int suffix = 0;
+ int negate;
+ int suffix;
int include_blanks = 1;
if (*p == '^')
This is used in %{|!pipe:...}. */
pipe_p = 1, ++p;
+next_member:
+ negate = suffix = 0;
+
if (*p == '!')
/* A `!' after the open-brace negates the condition:
succeed if the specified switch is not present. */
}
filter = p;
- while (*p != ':' && *p != '}') p++;
- if (*p != '}')
+ while (*p != ':' && *p != '}' && *p != '|') p++;
+
+ if (*p == '|' && pipe_p)
+ abort ();
+
+ if (!body)
{
- register int count = 1;
- q = p + 1;
- while (count > 0)
- {
- if (*q == '{')
- count++;
- else if (*q == '}')
- count--;
- else if (*q == 0)
- abort ();
- q++;
+ if (*p != '}')
+ {
+ register int count = 1;
+ register char *q = p;
+
+ while (*q++ != ':') continue;
+ body = q;
+
+ while (count > 0)
+ {
+ if (*q == '{')
+ count++;
+ else if (*q == '}')
+ count--;
+ else if (*q == 0)
+ abort ();
+ q++;
+ }
+ endbody = q;
}
+ else
+ body = p, endbody = p+1;
}
- else
- q = p + 1;
if (suffix)
{
&& strlen (input_suffix) == p - filter
&& strncmp (input_suffix, filter, p - filter) == 0);
- if (p[0] == '}')
+ if (body[0] == '}')
abort ();
if (negate != found
- && do_spec_1 (save_string (p + 1, q - p - 2), 0, NULL_PTR) < 0)
+ && do_spec_1 (save_string (body, endbody-body-1), 0, NULL_PTR) < 0)
return 0;
-
- return q;
}
else if (p[-1] == '*' && p[0] == '}')
{
if (p[-1] == '*' && !negate)
{
int substitution;
- char *r = p;
+ char *r = body;
/* First see whether we have %*. */
substitution = 0;
- while (r < q)
+ while (r < endbody)
{
if (*r == '%' && r[1] == '*')
substitution = 1;
in the text that follows the colon. */
unsigned hard_match_len = p - filter - 1;
- char *string = save_string (p + 1, q - p - 2);
+ char *string = save_string (body, endbody - body - 1);
for (i = 0; i < n_switches; i++)
if (!strncmp (switches[i].part1, filter, hard_match_len)
give_switch (i, 1, 1);
}
- return q;
+ /* We didn't match. Try again. */
+ if (*p++ == '|')
+ goto next_member;
+ return endbody;
}
}
}
}
- /* If it is as desired (present for %{s...}, absent for %{-s...})
+ /* If it is as desired (present for %{s...}, absent for %{!s...})
then substitute either the switch or the specified
conditional text. */
if (present != negate)
}
else
{
- if (do_spec_1 (save_string (p + 1, q - p - 2), 0, NULL_PTR) < 0)
+ if (do_spec_1 (save_string (body, endbody - body - 1),
+ 0, NULL_PTR) < 0)
return 0;
}
}
/* Here if a %{|...} conditional fails: output a minus sign,
which means "standard output" or "standard input". */
do_spec_1 ("-", 0, NULL_PTR);
+ return endbody;
}
}
- return q;
+ /* We didn't match; try again. */
+ if (*p++ == '|')
+ goto next_member;
+
+ return endbody;
}
\f
/* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
int argc;
char **argv;
{
- register int i;
- int j;
+ register size_t i;
+ size_t j;
int value;
int linker_was_run = 0;
char *explicit_link_files;
/* Choose directory for temp files. */
+#ifndef MKTEMP_EACH_FILE
temp_filename = choose_temp_base ();
temp_filename_length = strlen (temp_filename);
+#endif
/* Make a table of what switches there are (switches, n_switches).
Make a table of specified input files (infiles, n_infiles).
process_command (argc, argv);
{
- int i;
int first_time;
/* Build COLLECT_GCC_OPTIONS to have all of the options specified to
first_time = FALSE;
obstack_grow (&collect_obstack, "'-", 2);
q = switches[i].part1;
- while (p = (char *) index (q,'\''))
+ while ((p = index (q,'\'')))
{
obstack_grow (&collect_obstack, q, p-q);
obstack_grow (&collect_obstack, "'\\''", 4);
{
obstack_grow (&collect_obstack, " '", 2);
q = *args;
- while (p = (char *) index (q,'\''))
+ while ((p = index (q,'\'')))
{
obstack_grow (&collect_obstack, q, p-q);
obstack_grow (&collect_obstack, "'\\''", 4);
as a unit. If GCC_EXEC_PREFIX is defined, base
standard_startfile_prefix on that as well. */
if (*standard_startfile_prefix == '/'
- || *standard_startfile_prefix == DIR_SEPARATOR)
+ || *standard_startfile_prefix == DIR_SEPARATOR
+ || *standard_startfile_prefix == '$'
+#ifdef __MSDOS__
+ /* Check for disk name on MS-DOS-based systems. */
+ || (standard_startfile_prefix[1] == ':'
+ && (standard_startfile_prefix[2] == DIR_SEPARATOR
+ || standard_startfile_prefix[2] == '/'))
+#endif
+ )
add_prefix (&startfile_prefixes, standard_startfile_prefix, "BINUTILS",
0, 0, NULL_PTR);
else
exit (0);
}
- if (n_infiles == 0)
+ if (n_infiles == added_libraries)
fatal ("No input files");
/* Make a place to record the compiler output file names
that correspond to the input files. */
- outfiles = (char **) xmalloc (n_infiles * sizeof (char *));
+ i = n_infiles;
+#ifdef LANG_SPECIFIC_DRIVER
+ i += lang_specific_extra_outfiles;
+#endif
+ outfiles = (char **) xmalloc (i * sizeof (char *));
bzero ((char *) outfiles, n_infiles * sizeof (char *));
/* Record which files were specified explicitly as link input. */
clear_failure_queue ();
}
+#ifdef LANG_SPECIFIC_DRIVER
+ if (error_count == 0
+ && lang_specific_pre_link ())
+ error_count++;
+#endif
+
/* Run ld to link all the compiler output files. */
if (error_count == 0)
{
int tmp = execution_count;
- int i;
- int first_time;
+ /* We'll use ld if we can't find collect2. */
+ if (! strcmp (linker_name_spec, "collect2"))
+ {
+ char *s = find_a_file (&exec_prefixes, "collect2", X_OK);
+ if (s == NULL)
+ linker_name_spec = "ld";
+ }
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH=");
/* Find the proper compilation spec for the file name NAME,
whose length is LENGTH. LANGUAGE is the specified language,
- or 0 if none specified. */
+ or 0 if this file is to be passed to the linker. */
static struct compiler *
lookup_compiler (name, length, language)
char *name;
- int length;
+ size_t length;
char *language;
{
struct compiler *cp;
- /* Look for the language, if one is spec'd. */
+ /* If this was specified by the user to be a linker input, indicate that. */
+ if (language != 0 && language[0] == '*')
+ return 0;
+
+ /* Otherwise, look for the language, if one is spec'd. */
if (language != 0)
{
for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
- {
- if (language != 0)
- {
- if (cp->suffix[0] == '@'
- && !strcmp (cp->suffix + 1, language))
- return cp;
- }
- }
+ if (cp->suffix[0] == '@' && !strcmp (cp->suffix + 1, language))
+ return cp;
+
error ("language %s not recognized", language);
+ return 0;
}
/* Look for a suffix. */
{
if (/* The suffix `-' matches only the file name `-'. */
(!strcmp (cp->suffix, "-") && !strcmp (name, "-"))
- ||
- (strlen (cp->suffix) < length
- /* See if the suffix matches the end of NAME. */
+ || (strlen (cp->suffix) < length
+ /* See if the suffix matches the end of NAME. */
#ifdef OS2
- && (!strcmp (cp->suffix,
- name + length - strlen (cp->suffix))
- || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
- && !strcasecmp (cp->suffix,
- name + length - strlen (cp->suffix)))))
+ && ((!strcmp (cp->suffix,
+ name + length - strlen (cp->suffix))
+ || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
+ && !strcasecmp (cp->suffix,
+ name + length - strlen (cp->suffix)))
#else
- && !strcmp (cp->suffix,
- name + length - strlen (cp->suffix))))
+ && !strcmp (cp->suffix,
+ name + length - strlen (cp->suffix))
#endif
+ ))
{
if (cp->spec[0][0] == '@')
{
struct compiler *new;
+
/* An alias entry maps a suffix to a language.
Search for the language; pass 0 for NAME and LENGTH
to avoid infinite recursion if language not found.
(char *) new->spec, sizeof new->spec);
return new;
}
+
/* A non-alias entry: return it. */
return cp;
}
char *errmsg_fmt;
char *errmsg_arg;
{
+ int save_errno = errno;
+
if (errmsg_arg)
{
/* Space for trailing '\0' is in %s. */
errmsg_fmt = msg;
}
- fatal ("%s: %s", errmsg_fmt, my_strerror (errno));
+ fatal ("%s: %s", errmsg_fmt, my_strerror (save_errno));
}
/* More 'friendly' abort that prints the line and file.
fatal ("Internal gcc abort.");
}
\f
-#ifdef HAVE_VPRINTF
-
/* Output an error message and exit */
static void
fprintf (stderr, "\n");
}
-
-#else /* not HAVE_VPRINTF */
-
-static void
-fatal (msg, arg1, arg2)
- char *msg, *arg1, *arg2;
-{
- error (msg, arg1, arg2);
- delete_temp_files ();
- exit (1);
-}
-
-static void
-error (msg, arg1, arg2)
- char *msg, *arg1, *arg2;
-{
- fprintf (stderr, "%s: ", programname);
- fprintf (stderr, msg, arg1, arg2);
- fprintf (stderr, "\n");
-}
-
-#endif /* not HAVE_VPRINTF */
-
\f
static void
validate_all_switches ()
for (comp = compilers; comp->spec[0]; comp++)
{
- int i;
+ size_t i;
for (i = 0; i < sizeof comp->spec / sizeof comp->spec[0] && comp->spec[i]; i++)
{
p = comp->spec[i];
- while (c = *p++)
+ while ((c = *p++))
if (c == '%' && *p == '{')
/* We have a switch spec. */
validate_switches (p + 1);
for (spec = specs; spec ; spec = spec->next)
{
p = *(spec->ptr_spec);
- while (c = *p++)
+ while ((c = *p++))
if (c == '%' && *p == '{')
/* We have a switch spec. */
validate_switches (p + 1);
}
p = link_command_spec;
- while (c = *p++)
+ while ((c = *p++))
if (c == '%' && *p == '{')
/* We have a switch spec. */
validate_switches (p + 1);
}
\f
/* Check whether a particular argument was used. The first time we
- canonialize the switches to keep only the ones we care about. */
+ canonicalize the switches to keep only the ones we care about. */
static int
used_arg (p, len)
int len;
{
char *start, *end;
- int i;
for (start = multilib_defaults; *start != '\0'; start = end+1)
{
if ((end - start) == len && strncmp (p, start, len) == 0)
return 1;
+
+ if (*end == '\0')
+ break;
}
return 0;