/* Compiler driver program that can handle many languages.
- Copyright (C) 1987, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
This paragraph is here to try to keep Sun CC from dying.
The number of chars here seems crucial!!!! */
#include <ctype.h>
#include <signal.h>
#include <sys/stat.h>
+#include <errno.h>
+
+#ifndef _WIN32
#include <sys/file.h> /* May get R_OK, etc. on some systems. */
+#endif
#include "config.h"
#include "obstack.h"
+#include "gansidecl.h"
+
#ifdef __STDC__
#include <stdarg.h>
#else
#define X_OK 1
#endif
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
-#ifndef VPROTO
-#ifdef __STDC__
-#define PVPROTO(ARGS) ARGS
-#define VPROTO(ARGS) ARGS
-#define VA_START(va_list,var) va_start(va_list,var)
-#else
-#define PVPROTO(ARGS) ()
-#define VPROTO(ARGS) (va_alist) va_dcl
-#define VA_START(va_list,var) va_start(va_list)
-#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));
+/* Flag arguments to pexecute. */
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
+
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
#endif
-
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
+#ifndef WTERMSIG
+#define WTERMSIG(S) ((S) & 0x7f)
#endif
-
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
+#ifndef WIFEXITED
+#define WIFEXITED(S) (((S) & 0xff) == 0)
#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
#endif
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
+/* 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 */
-/* On MSDOS, write temp files in current dir
- because there's no place else we can expect to use. */
-#ifdef __MSDOS__
-#ifndef P_tmpdir
-#define P_tmpdir "."
-#endif
-#endif
-
/* Test if something is a normal file. */
#ifndef S_ISREG
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define EXECUTABLE_SUFFIX ""
#endif
+/* By default, the suffix for object files is ".o". */
+#ifdef OBJECT_SUFFIX
+#define HAVE_OBJECT_SUFFIX
+#else
+#define OBJECT_SUFFIX ".o"
+#endif
+
/* By default, colon separates directories in a path. */
#ifndef PATH_SEPARATOR
#define PATH_SEPARATOR ':'
#endif
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+static char dir_separator_str[] = {DIR_SEPARATOR, 0};
+
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern void free ();
extern char *getenv ();
-extern int errno, sys_nerr;
+extern char *choose_temp_base PROTO((void));
+
+#ifndef errno
+extern int errno;
+#endif
+
+#ifndef HAVE_STRERROR
+extern int sys_nerr;
#if defined(bsd4_4)
extern const char *const sys_errlist[];
#else
extern char *sys_errlist[];
#endif
-
-extern int execv (), execvp ();
+#else
+extern char *strerror();
+#endif
/* If a stage of compilation returns an exit status >= 1,
compilation of that file ceases. */
#define MIN_FATAL_STATUS 1
+/* Flag saying to print the directories gcc will search through looking for
+ programs, libraries, etc. */
+
+static int print_search_dirs;
+
/* Flag saying to print the full filename of this file
as found through our usual search mechanism. */
static char *print_file_name = NULL;
-/* As print_file_name, but search for executable file. */
+/* As print_file_name, but search for executable file. */
static char *print_prog_name = NULL;
+/* Flag saying to print the relative path we'd use to
+ find libgcc.a given the current compiler flags. */
+
+static int print_multi_directory;
+
+/* Flag saying to print the list of subdirectories and
+ compiler flags used to select them in a standard form. */
+
+static int print_multi_lib;
+
/* Flag indicating whether we should print the command and arguments */
static int verbose_flag;
static void set_spec PROTO((char *, char *));
static struct compiler *lookup_compiler PROTO((char *, int, 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 void add_prefix PROTO((struct path_prefix *, char *, int, int, int *));
static char *skip_whitespace PROTO((char *));
static void record_temp_file PROTO((char *, int, int));
+static void delete_if_ordinary PROTO((char *));
+static void delete_temp_files PROTO((void));
+static void delete_failure_queue PROTO((void));
+static void clear_failure_queue PROTO((void));
static int check_live_switch PROTO((int, int));
static char *handle_braces PROTO((char *));
static char *save_string PROTO((char *, int));
-static char *concat PROTO((char *, char *, char *));
+static char *concat PVPROTO((char *, ...));
static int do_spec PROTO((char *));
static int do_spec_1 PROTO((char *, int, char *));
static char *find_file PROTO((char *));
static void validate_switches PROTO((char *));
static void validate_all_switches PROTO((void));
static void give_switch PROTO((int, int));
+static int used_arg PROTO((char *, int));
+static int default_arg PROTO((char *, int));
+static void set_multilib_dir PROTO((void));
+static void print_multilib_info PROTO((void));
static void pfatal_with_name PROTO((char *));
static void perror_with_name PROTO((char *));
-static void perror_exec PROTO((char *));
+static void pfatal_pexecute PROTO((char *, char *));
#ifdef HAVE_VPRINTF
static void fatal PVPROTO((char *, ...));
static void error PVPROTO((char *, ...));
Input files whose names have no recognized suffix are not compiled
at all, but they are included among the output files, so they will
be linked.
+ %O substitutes the suffix for object files.
%p substitutes the standard macro predefinitions for the
current target machine. Use this when running cpp.
%P like %p, but puts `__' before and after the name of each macro.
%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.
+ %Z Output the accumulated preprocessor options specified by compilations.
%v1 Substitute the major version number of GCC.
(For version 2.5.n, this is 2.)
%v2 Substitute the minor version number of GCC.
%A process ASM_FINAL_SPEC as a spec. A capital A is actually
used here. This can be used to run a post-processor after the
assembler has done it's job.
- %D Dump out a -L option for each directory in startfile_prefix.
+ %D Dump out a -L option for each directory in startfile_prefixes.
+ If multilib_dir is set, extra entries are generated with it affixed.
%l process LINK_SPEC as a spec.
%L process LIB_SPEC as a spec.
+ %G process LIBGCC_SPEC as a spec.
%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.
/* config.h can define LIB_SPEC to override the default libraries. */
#ifndef LIB_SPEC
-#define LIB_SPEC "%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"
+#define LIB_SPEC "%{!shared:%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}"
+#endif
+
+/* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
+ included. */
+#ifndef LIBGCC_SPEC
+#if defined(LINK_LIBGCC_SPECIAL) || defined(LINK_LIBGCC_SPECIAL_1)
+/* Have gcc do the search for libgcc.a. */
+#define LIBGCC_SPEC "libgcc.a%s"
+#else
+#define LIBGCC_SPEC "-lgcc"
+#endif
#endif
/* config.h can define STARTFILE_SPEC to override the default crt0 files. */
#ifndef STARTFILE_SPEC
#define STARTFILE_SPEC \
- "%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}"
+ "%{!shared:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}"
#endif
-/* config.h can define SWITCHES_NEED_SPACES to control passing -o and -L.
- Make the string nonempty to require spaces there. */
+/* config.h can define SWITCHES_NEED_SPACES to control which options
+ require spaces between the option and the argument. */
#ifndef SWITCHES_NEED_SPACES
#define SWITCHES_NEED_SPACES ""
#endif
static char *asm_final_spec = ASM_FINAL_SPEC;
static char *link_spec = LINK_SPEC;
static char *lib_spec = LIB_SPEC;
+static char *libgcc_spec = LIBGCC_SPEC;
static char *endfile_spec = ENDFILE_SPEC;
static char *startfile_spec = STARTFILE_SPEC;
static char *switches_need_spaces = SWITCHES_NEED_SPACES;
+/* 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
+ run time. */
+static struct obstack multilib_obstack;
+static char *multilib_select;
+static char *multilib_matches;
+static char *multilib_defaults;
+#include "multilib.h"
+
+/* Check whether a particular argument is a default argument. */
+
+#ifndef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "" }
+#endif
+
+static char *multilib_defaults_raw[] = MULTILIB_DEFAULTS;
+
+#ifdef EXTRA_SPECS
+static struct { char *name, *spec; } extra_specs[] = { EXTRA_SPECS };
+#endif
+
/* This defines which switch letters take arguments. */
-#ifndef SWITCH_TAKES_ARG
-#define SWITCH_TAKES_ARG(CHAR) \
+#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
|| (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
- || (CHAR) == 'I' || (CHAR) == 'm' \
+ || (CHAR) == 'I' || (CHAR) == 'm' || (CHAR) == 'x' \
|| (CHAR) == 'L' || (CHAR) == 'A')
+
+#ifndef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
#endif
/* This defines which multi-letter switches take arguments. */
|| !strcmp (STR, "Tbss") || !strcmp (STR, "include") \
|| !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
|| !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
- || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore"))
+ || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
+ || !strcmp (STR, "isystem"))
#ifndef WORD_SWITCH_TAKES_ARG
#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
static struct compiler default_compilers[] =
{
+ /* Add lists of suffixes of known languages here. If those languages
+ were no present when we built the driver, we will hit these copies
+ and 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"},
+ /* Next come the entries for C. */
{".c", "@c"},
{"@c",
- "cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ "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}\
+ %{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}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{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:cc1 %{!pipe:%g.i} %1 \
- %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a}\
+ %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a*}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
%{aux-info*}\
%{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 %{R} %{j} %{J} %{h} %{d2} %a %Y\
- %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
+ %{!S:as %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
%{!pipe:%g.s} %A\n }}}}"},
{"-",
- "%{E:cpp -lang-c %{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}\
+ %{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}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{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"},
{"@objective-c",
"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}\
+ %{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}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{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 \
- %{!Q:-quiet} -dumpbase %b.m %{d*} %{m*} %{a}\
+ %{!Q:-quiet} -dumpbase %b.m %{d*} %{m*} %{a*}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*} \
-lang-objc %{gen-decls} \
%{aux-info*}\
%{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 %{R} %{j} %{J} %{h} %{d2} %a %Y\
- %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
+ %{!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"},
{"@c-header",
"%{!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} \
+ %{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}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %W{o*}"},
- {".cc", "@c++"},
- {".cxx", "@c++"},
- {".cpp", "@c++"},
- {".C", "@c++"},
- {"@c++",
- "cpp -lang-c++ %{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} \
- -undef -D__GNUC__=%v1 -D__GNUG__=%v1 -D__cplusplus -D__GNUC_MINOR__=%v2\
- %{ansi:-trigraphs -$ -D__STRICT_ANSI__} %{!undef:%{!ansi:%p} %P}\
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
- %{traditional-cpp:-traditional} %{trigraphs}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
- %i %{!M:%{!MM:%{!E:%{!pipe:%g.ii}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
- "%{!M:%{!MM:%{!E:cc1plus %{!pipe:%g.ii} %1 %2\
- %{!Q:-quiet} -dumpbase %b.cc %{d*} %{m*} %{a}\
- %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\
- %{traditional} %{v:-version} %{pg:-p} %{p}\
- %{f*} %{+e*} %{aux-info*}\
- %{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 %{R} %{j} %{J} %{h} %{d2} %a %Y\
- %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
- %{!pipe:%g.s} %A\n }}}}"},
{".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*}\
%{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 %{R} %{j} %{J} %{h} %{d2} %a %Y\
- %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
+ %{!S:as %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
%{!pipe:%g.s} %A\n }}}}"},
- {".ii", "@c++-cpp-output"},
- {"@c++-cpp-output",
- "%{!M:%{!MM:%{!E:cc1plus %i %1 %2 %{!Q:-quiet} %{d*} %{m*} %{a}\
- %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\
- %{traditional} %{v:-version} %{pg:-p} %{p}\
- %{f*} %{+e*} %{aux-info*}\
- %{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 %{R} %{j} %{J} %{h} %{d2} %a %Y\
- %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
- %{!pipe:%g.s} %A\n }}}}"},
{".s", "@assembler"},
{"@assembler",
- "%{!M:%{!MM:%{!E:%{!S:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
- %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
+ "%{!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"},
{"@assembler-with-cpp",
"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} %{trigraphs} \
+ %{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}\
%{traditional-cpp:-traditional}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*}\
+ %{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 %{R} %{j} %{J} %{h} %{d2} %a %Y\
- %{c:%W{o*}%{!o*:-o %w%b.o}}%{!c:-o %d%w%u.o}\
+ "%{!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 }}}}"},
- {".ads", "@ada"},
- {".adb", "@ada"},
- {".ada", "@ada"},
- {"@ada",
- "%{!M:%{!MM:%{!E:gnat1 %{k8:-gnatk8} %{w:-gnatws} %{!Q:-quiet}\
- -dumpbase %b.ada %{g*} %{O*} %{p} %{pg:-p} %{f*}\
- %{d*}\
- %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
- %i %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
- %{!S:%{!gnatc:%{!gnats:as %{R} %{j} %{J} %{h} %{d2} %a %Y\
- %{c:%W{o*}%{!o*:-o %w%b.o}}\
- %{!c:-o %d%w%u.o} %{!pipe:%g.s} %A\n}}}}}} "},
+#include "specs.h"
/* Mark end of table */
{0, 0}
};
/* We want %{T*} after %{L*} and %D so that it can be used to specify linker
scripts which exist in user specified directories, or in standard
directories. */
-#ifdef LINK_LIBGCC_SPECIAL_1
-/* Have gcc do the search for libgcc.a, but generate -L options as usual. */
-static char *link_command_spec = "\
-%{!fsyntax-only: \
- %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
- %{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
- %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
- %{L*} %D %{T*} %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}}";
-#else
#ifdef LINK_LIBGCC_SPECIAL
-/* Have gcc do the search for libgcc.a, and don't generate -L options. */
+/* 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} \
%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
- %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
- %{L*} %{T*} %o %{!nostdlib:libgcc.a%s %L libgcc.a%s %{!A:%E}}\n }}}}}}";
+ %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
+ %{static:} %{L*} %{T*} %o\
+ %{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
+ %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\n }}}}}}";
#else
-/* Use -L and have the linker do the search for -lgcc. */
+/* Use -L. */
static char *link_command_spec = "\
%{!fsyntax-only: \
%{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
- %{!A:%{!nostartfiles:%{!nostdlib:%S}}} %{static:}\
- %{L*} %D %{T*} %o %{!nostdlib:-lgcc %L -lgcc %{!A:%E}}\n }}}}}}";
-#endif
+ %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
+ %{static:} %{L*} %D %{T*} %o\
+ %{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
+ %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\n }}}}}}";
#endif
/* A vector of options to give to the linker.
- These options are accumulated by -Xlinker and -Wl,
+ These options are accumulated by %x,
and substituted into the linker command with %X. */
static int n_linker_options;
static char **linker_options;
/* A vector of options to give to the assembler.
These options are accumulated by -Wa,
- and substituted into the assembler command with %X. */
+ and substituted into the assembler command with %Y. */
static int n_assembler_options;
static char **assembler_options;
+
+/* A vector of options to give to the preprocessor.
+ These options are accumulated by -Wp,
+ and substituted into the preprocessor command with %Z. */
+static int n_preprocessor_options;
+static char **preprocessor_options;
\f
/* Define how to map long options into short ones. */
a => argument required.
o => argument optional.
j => join argument to equivalent, making one word.
- * => allow other text after NAME as an argument. */
+ * => require other text after NAME as an argument. */
char *arg_info;
};
struct option_map option_map[] =
{
- {"--profile-blocks", "-a", 0},
- {"--target", "-b", "a"},
+ {"--all-warnings", "-Wall", 0},
+ {"--ansi", "-ansi", 0},
+ {"--assemble", "-S", 0},
+ {"--assert", "-A", "a"},
+ {"--comments", "-C", 0},
{"--compile", "-c", 0},
+ {"--debug", "-g", "oj"},
+ {"--define-macro", "-D", "a"},
+ {"--dependencies", "-M", 0},
{"--dump", "-d", "a"},
+ {"--dumpbase", "-dumpbase", "a"},
{"--entry", "-e", 0},
- {"--debug", "-g", "oj"},
- {"--include", "-include", "a"},
+ {"--extra-warnings", "-W", 0},
+ {"--for-assembler", "-Wa", "a"},
+ {"--for-linker", "-Xlinker", "a"},
+ {"--force-link", "-u", "a"},
{"--imacros", "-imacros", "a"},
- {"--include-prefix", "-iprefix", "a"},
+ {"--include", "-include", "a"},
+ {"--include-barrier", "-I-", 0},
+ {"--include-directory", "-I", "a"},
{"--include-directory-after", "-idirafter", "a"},
+ {"--include-prefix", "-iprefix", "a"},
{"--include-with-prefix", "-iwithprefix", "a"},
{"--include-with-prefix-before", "-iwithprefixbefore", "a"},
{"--include-with-prefix-after", "-iwithprefix", "a"},
- {"--machine-", "-m", "*j"},
+ {"--language", "-x", "a"},
+ {"--library-directory", "-L", "a"},
{"--machine", "-m", "aj"},
+ {"--machine-", "-m", "*j"},
+ {"--no-line-commands", "-P", 0},
+ {"--no-precompiled-includes", "-noprecomp", 0},
{"--no-standard-includes", "-nostdinc", 0},
{"--no-standard-libraries", "-nostdlib", 0},
- {"--no-precompiled-includes", "-noprecomp", 0},
- {"--output", "-o", "a"},
- {"--profile", "-p", 0},
- {"--quiet", "-q", 0},
- {"--silent", "-q", 0},
- {"--force-link", "-u", "a"},
- {"--verbose", "-v", 0},
- {"--version", "-dumpversion", 0},
{"--no-warnings", "-w", 0},
- {"--language", "-x", "a"},
-
- {"--assert", "-A", "a"},
- {"--prefix", "-B", "a"},
- {"--comments", "-C", 0},
- {"--define-macro", "-D", "a"},
- {"--preprocess", "-E", 0},
- {"--trace-includes", "-H", 0},
- {"--include-directory", "-I", "a"},
- {"--include-barrier", "-I-", 0},
- {"--library-directory", "-L", "a"},
- {"--dependencies", "-M", 0},
- {"--user-dependencies", "-MM", 0},
- {"--write-dependencies", "-MD", 0},
- {"--write-user-dependencies", "-MMD", 0},
{"--optimize", "-O", "oj"},
- {"--no-line-commands", "-P", 0},
- {"--assemble", "-S", 0},
- {"--undefine-macro", "-U", "a"},
- {"--use-version", "-V", "a"},
- {"--for-assembler", "-Wa", "a"},
- {"--extra-warnings", "-W", 0},
- {"--all-warnings", "-Wall", 0},
- {"--warn-", "-W", "*j"},
- {"--for-linker", "-Xlinker", "a"},
-
- {"--ansi", "-ansi", 0},
- {"--traditional", "-traditional", 0},
- {"--traditional-cpp", "-traditional-cpp", 0},
- {"--trigraphs", "-trigraphs", 0},
- {"--pipe", "-pipe", 0},
- {"--dumpbase", "-dumpbase", "a"},
+ {"--output", "-o", "a"},
{"--pedantic", "-pedantic", 0},
{"--pedantic-errors", "-pedantic-errors", 0},
- {"--save-temps", "-save-temps", 0},
- {"--print-libgcc-file-name", "-print-libgcc-file-name", 0},
+ {"--pipe", "-pipe", 0},
+ {"--prefix", "-B", "a"},
+ {"--preprocess", "-E", 0},
+ {"--print-search-dirs", "-print-search-dirs", 0},
{"--print-file-name", "-print-file-name=", "aj"},
+ {"--print-libgcc-file-name", "-print-libgcc-file-name", 0},
+ {"--print-missing-file-dependencies", "-MG", 0},
+ {"--print-multi-lib", "-print-multi-lib", 0},
+ {"--print-multi-directory", "-print-multi-directory", 0},
{"--print-prog-name", "-print-prog-name=", "aj"},
- {"--static", "-static", 0},
+ {"--profile", "-p", 0},
+ {"--profile-blocks", "-a", 0},
+ {"--quiet", "-q", 0},
+ {"--save-temps", "-save-temps", 0},
{"--shared", "-shared", 0},
+ {"--silent", "-q", 0},
+ {"--static", "-static", 0},
{"--symbolic", "-symbolic", 0},
+ {"--target", "-b", "a"},
+ {"--trace-includes", "-H", 0},
+ {"--traditional", "-traditional", 0},
+ {"--traditional-cpp", "-traditional-cpp", 0},
+ {"--trigraphs", "-trigraphs", 0},
+ {"--undefine-macro", "-U", "a"},
+ {"--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},
{"--", "-f", "*j"}
};
\f
int *argcp;
char ***argvp;
{
- int i, j;
+ int i, j, k;
int argc = *argcp;
char **argv = *argvp;
char **newv = (char **) xmalloc ((argc + 2) * 2 * sizeof (char *));
for (j = 0; j < sizeof (option_map) / sizeof (option_map[0]); j++)
{
int optlen = strlen (option_map[j].name);
- int complen = strlen (argv[i]);
+ int arglen = strlen (argv[i]);
+ int complen = arglen > optlen ? optlen : arglen;
char *arginfo = option_map[j].arg_info;
if (arginfo == 0)
arginfo = "";
- if (complen > optlen)
- complen = optlen;
+
if (!strncmp (argv[i], option_map[j].name, complen))
{
- int extra = strlen (argv[i]) > optlen;
char *arg = 0;
- if (extra)
+ if (arglen < optlen)
+ {
+ for (k = j + 1;
+ k < sizeof (option_map) / sizeof (option_map[0]);
+ k++)
+ if (strlen (option_map[k].name) >= arglen
+ && !strncmp (argv[i], option_map[k].name, arglen))
+ {
+ error ("Ambiguous abbreviation %s", argv[i]);
+ break;
+ }
+
+ if (k != sizeof (option_map) / sizeof (option_map[0]))
+ break;
+ }
+
+ if (arglen > optlen)
{
/* If the option has an argument, accept that. */
if (argv[i][optlen] == '=')
arg = argv[i] + optlen + 1;
- /* If this mapping allows extra text at end of name,
+
+ /* If this mapping requires extra text at end of name,
accept that as "argument". */
else if (index (arginfo, '*') != 0)
arg = argv[i] + optlen;
+
/* Otherwise, extra text at end means mismatch.
Try other mappings. */
else
continue;
}
+
else if (index (arginfo, '*') != 0)
- error ("Incomplete `%s' option", option_map[j].name);
+ {
+ error ("Incomplete `%s' option", option_map[j].name);
+ break;
+ }
/* Handle arguments. */
- if (index (arginfo, 'o') != 0)
+ if (index (arginfo, 'a') != 0)
{
if (arg == 0)
{
if (i + 1 == argc)
- error ("Missing argument to `%s' option",
- option_map[j].name);
+ {
+ error ("Missing argument to `%s' option",
+ option_map[j].name);
+ break;
+ }
+
arg = argv[++i];
}
}
else if (index (arginfo, '*') != 0)
;
- else if (index (arginfo, 'a') == 0)
+ else if (index (arginfo, 'o') == 0)
{
if (arg != 0)
error ("Extraneous argument to `%s' option",
/* Store the translation as one argv elt or as two. */
if (arg != 0 && index (arginfo, 'j') != 0)
- newv[newindex++] = concat (option_map[j].equivalent,
- arg, "");
+ newv[newindex++] = concat (option_map[j].equivalent, arg,
+ NULL_PTR);
else if (arg != 0)
{
newv[newindex++] = option_map[j].equivalent;
}
i++;
}
+
/* Handle old-fashioned options--just copy them through,
with their arguments. */
else if (argv[i][0] == '-')
*argcp = newindex;
}
\f
+char *
+my_strerror(e)
+ int e;
+{
+#ifdef HAVE_STRERROR
+
+ return strerror(e);
+
+#else
+
+ static char buffer[30];
+ if (!e)
+ return "cannot access";
+
+ if (e > 0 && e < sys_nerr)
+ return sys_errlist[e];
+
+ sprintf (buffer, "Unknown error %d", e);
+ return buffer;
+#endif
+}
+\f
/* Read compilation specs from a file named FILENAME,
replacing the default ones.
char *filename;
{
int desc;
+ int readlen;
struct stat statbuf;
char *buffer;
register char *p;
fprintf (stderr, "Reading specs from %s\n", filename);
/* Open and stat the file. */
- desc = open (filename, 0, 0);
+ desc = open (filename, O_RDONLY, 0);
if (desc < 0)
pfatal_with_name (filename);
if (stat (filename, &statbuf) < 0)
/* Read contents of file into BUFFER. */
buffer = xmalloc ((unsigned) statbuf.st_size + 1);
- read (desc, buffer, (unsigned) statbuf.st_size);
- buffer[statbuf.st_size] = 0;
+ readlen = read (desc, buffer, (unsigned) statbuf.st_size);
+ if (readlen < 0)
+ pfatal_with_name (filename);
+ buffer[readlen] = 0;
close (desc);
/* Scan BUFFER for specs, putting them in the vector. */
= ((struct compiler *)
xrealloc (compilers, (n_compilers + 2) * sizeof (struct compiler)));
compilers[n_compilers].suffix = suffix;
- bzero (compilers[n_compilers].spec,
+ bzero ((char *) compilers[n_compilers].spec,
sizeof compilers[n_compilers].spec);
compilers[n_compilers].spec[0] = spec;
n_compilers++;
- bzero (&compilers[n_compilers], sizeof compilers[n_compilers]);
+ bzero ((char *) &compilers[n_compilers],
+ sizeof compilers[n_compilers]);
}
if (*suffix == 0)
return p;
}
\f
-/* Structure to keep track of the specs that have been defined so far. These
- are accessed using %(specname) or %[specname] in a compiler or link spec. */
+/* Structure to keep track of the specs that have been defined so far.
+ These are accessed using %(specname) or %[specname] in a compiler
+ or link spec. */
struct spec_list
{
- char *name; /* Name of the spec. */
- char *spec; /* The spec itself. */
- struct spec_list *next; /* Next spec in linked list. */
+ char *name; /* Name of the spec. */
+ char *spec; /* The spec itself. */
+ struct spec_list *next; /* Next spec in linked list. */
};
-/* List of specs that have been defined so far. */
+/* List of specs that have been defined so far. */
static struct spec_list *specs = (struct spec_list *) 0;
\f
/* Change the value of spec NAME to SPEC. If SPEC is empty, then the spec is
removed; If the spec starts with a + then SPEC is added to the end of the
- current spec. */
+ current spec. */
static void
set_spec (name, spec)
old_spec = sl->spec;
if (name && spec[0] == '+' && isspace (spec[1]))
- sl->spec = concat (old_spec, spec + 1, "");
+ sl->spec = concat (old_spec, spec + 1, NULL_PTR);
else
sl->spec = save_string (spec, strlen (spec));
endfile_spec = sl->spec;
else if (! strcmp (name, "lib"))
lib_spec = sl->spec;
+ else if (! strcmp (name, "libgcc"))
+ libgcc_spec = sl->spec;
else if (! strcmp (name, "link"))
link_spec = sl->spec;
else if (! strcmp (name, "predefines"))
switches_need_spaces = sl->spec;
else if (! strcmp (name, "cross_compile"))
cross_compile = atoi (sl->spec);
+ else if (! strcmp (name, "multilib"))
+ multilib_select = sl->spec;
+ else if (! strcmp (name, "multilib_matches"))
+ multilib_matches = sl->spec;
+ else if (! strcmp (name, "multilib_extra"))
+ multilib_extra = sl->spec;
+ else if (! strcmp (name, "multilib_defaults"))
+ multilib_defaults = sl->spec;
+#ifdef EXTRA_SPECS
+ else
+ {
+ int i;
+ for (i = 0; i < sizeof (extra_specs) / sizeof (extra_specs[0]); i++)
+ {
+ if (! strcmp (name, extra_specs[i].name))
+ {
+ extra_specs[i].spec = sl->spec;
+ break;
+ }
+ }
+ }
+#endif
+
/* Free the old spec */
if (old_spec)
free (old_spec);
static char *programname;
\f
-/* Structures to keep track of prefixes to try when looking for files. */
+/* Structures to keep track of prefixes to try when looking for files. */
struct prefix_list
{
- char *prefix; /* String to prepend to the path. */
- struct prefix_list *next; /* Next in linked list. */
+ char *prefix; /* String to prepend to the path. */
+ struct prefix_list *next; /* Next in linked list. */
int require_machine_suffix; /* Don't use without machine_suffix. */
/* 2 means try both machine_suffix and just_machine_suffix. */
int *used_flag_ptr; /* 1 if a file was found with this prefix. */
char *name; /* Name of this list (used in config stuff) */
};
-/* List of prefixes to try when looking for executables. */
+/* List of prefixes to try when looking for executables. */
-static struct path_prefix exec_prefix = { 0, 0, "exec" };
+static struct path_prefix exec_prefixes = { 0, 0, "exec" };
-/* List of prefixes to try when looking for startup (crt0) files. */
+/* List of prefixes to try when looking for startup (crt0) files. */
-static struct path_prefix startfile_prefix = { 0, 0, "startfile" };
+static struct path_prefix startfile_prefixes = { 0, 0, "startfile" };
/* List of prefixes to try when looking for include files. */
-static struct path_prefix include_prefix = { 0, 0, "include" };
+static struct path_prefix include_prefixes = { 0, 0, "include" };
/* Suffix to attach to directories searched for commands.
This looks like `MACHINE/VERSION/'. */
static char *tooldir_base_prefix = TOOLDIR_BASE_PREFIX;
static char *tooldir_prefix;
+/* Subdirectory to use for locating libraries. Set by
+ set_multilib_dir based on the compilation options. */
+
+static char *multilib_dir;
+
/* Clear out the vector of arguments (after a command is executed). */
static void
This prefix comes from the envvar TMPDIR if it is defined;
otherwise, from the P_tmpdir macro if that is defined;
- otherwise, in /usr/tmp or /tmp. */
+ otherwise, in /usr/tmp or /tmp;
+ or finally the current directory if all else fails. */
static char *temp_filename;
/* Delete all the temporary files whose names we previously recorded. */
+static void
+delete_if_ordinary (name)
+ char *name;
+{
+ struct stat st;
+#ifdef DEBUG
+ int i, c;
+
+ printf ("Delete %s? (y or n) ", name);
+ fflush (stdout);
+ i = getchar ();
+ if (i != '\n')
+ while ((c = getchar ()) != '\n' && c != EOF) ;
+ if (i == 'y' || i == 'Y')
+#endif /* DEBUG */
+ if (stat (name, &st) >= 0 && S_ISREG (st.st_mode))
+ if (unlink (name) < 0)
+ if (verbose_flag)
+ perror_with_name (name);
+}
+
static void
delete_temp_files ()
{
register struct temp_file *temp;
for (temp = always_delete_queue; temp; temp = temp->next)
- {
-#ifdef DEBUG
- int i;
- printf ("Delete %s? (y or n) ", temp->name);
- fflush (stdout);
- i = getchar ();
- if (i != '\n')
- while (getchar () != '\n') ;
- if (i == 'y' || i == 'Y')
-#endif /* DEBUG */
- {
- struct stat st;
- if (stat (temp->name, &st) >= 0)
- {
- /* Delete only ordinary files. */
- if (S_ISREG (st.st_mode))
- if (unlink (temp->name) < 0)
- if (verbose_flag)
- perror_with_name (temp->name);
- }
- }
- }
-
+ delete_if_ordinary (temp->name);
always_delete_queue = 0;
}
register struct temp_file *temp;
for (temp = failure_delete_queue; temp; temp = temp->next)
- {
-#ifdef DEBUG
- int i;
- printf ("Delete %s? (y or n) ", temp->name);
- fflush (stdout);
- i = getchar ();
- if (i != '\n')
- while (getchar () != '\n') ;
- if (i == 'y' || i == 'Y')
-#endif /* DEBUG */
- {
- if (unlink (temp->name) < 0)
- if (verbose_flag)
- perror_with_name (temp->name);
- }
- }
+ delete_if_ordinary (temp->name);
}
static void
{
failure_delete_queue = 0;
}
-
-/* Compute a string to use as the base of all temporary file names.
- It is substituted for %g. */
-
-static char *
-choose_temp_base_try (try, base)
-char *try;
-char *base;
-{
- char *rv;
- if (base)
- rv = base;
- else if (try == (char *)0)
- rv = 0;
- else if (access (try, R_OK | W_OK) != 0)
- rv = 0;
- else
- rv = try;
- return rv;
-}
-
-static void
-choose_temp_base ()
-{
- char *base = 0;
- int len;
-
- base = choose_temp_base_try (getenv ("TMPDIR"), base);
- base = choose_temp_base_try (getenv ("TMP"), base);
- base = choose_temp_base_try (getenv ("TEMP"), base);
-
-#ifdef P_tmpdir
- base = choose_temp_base_try (P_tmpdir, base);
-#endif
-
- base = choose_temp_base_try ("/usr/tmp", base);
- base = choose_temp_base_try ("/tmp", base);
-
- /* If all else fails, use the current directory! */
- if (base == (char *)0)
- base = "./";
-
- len = strlen (base);
- temp_filename = xmalloc (len + sizeof("/ccXXXXXX") + 1);
- strcpy (temp_filename, base);
- if (len > 0 && temp_filename[len-1] != '/')
- temp_filename[len++] = '/';
- strcpy (temp_filename + len, "ccXXXXXX");
-
- mktemp (temp_filename);
- temp_filename_length = strlen (temp_filename);
- if (temp_filename_length == 0)
- abort ();
-}
\f
-
/* Routine to add variables to the environment. We do this to pass
the pathname of the gcc driver, and the directories search to the
collect2 program, which is being run as ld. This way, we can be
/* Add a new environment variable */
environ = (char **) xmalloc (sizeof (char *) * (num_envs+2));
*environ = str;
- bcopy (old_environ, environ+1, sizeof (char *) * (num_envs+1));
+ bcopy ((char *) old_environ, (char *) (environ + 1),
+ sizeof (char *) * (num_envs+1));
#endif /* VMS */
}
#endif /* HAVE_PUTENV */
\f
-/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */
+/* Build a list of search directories from PATHS.
+ PREFIX is a string to prepend to the list.
+ If CHECK_DIR_P is non-zero we ensure the directory exists.
+ This is used mostly by putenv_from_prefixes so we use `collect_obstack'.
+ It is also used by the --print-search-dirs flag. */
-static void
-putenv_from_prefixes (paths, env_var)
+static char *
+build_search_list (paths, prefix, check_dir_p)
struct path_prefix *paths;
- char *env_var;
+ char *prefix;
+ int check_dir_p;
{
int suffix_len = (machine_suffix) ? strlen (machine_suffix) : 0;
int just_suffix_len
int first_time = TRUE;
struct prefix_list *pprefix;
- obstack_grow (&collect_obstack, env_var, strlen (env_var));
+ obstack_grow (&collect_obstack, prefix, strlen (prefix));
for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next)
{
int len = strlen (pprefix->prefix);
if (machine_suffix
- && is_directory (pprefix->prefix, machine_suffix, 0))
+ && (!check_dir_p
+ || is_directory (pprefix->prefix, machine_suffix, 0)))
{
if (!first_time)
obstack_1grow (&collect_obstack, PATH_SEPARATOR);
if (just_machine_suffix
&& pprefix->require_machine_suffix == 2
- && is_directory (pprefix->prefix, just_machine_suffix, 0))
+ && (!check_dir_p
+ || is_directory (pprefix->prefix, just_machine_suffix, 0)))
{
if (!first_time)
obstack_1grow (&collect_obstack, PATH_SEPARATOR);
}
}
obstack_1grow (&collect_obstack, '\0');
- putenv (obstack_finish (&collect_obstack));
+ return obstack_finish (&collect_obstack);
}
+/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
+ for collect. */
+
+static void
+putenv_from_prefixes (paths, env_var)
+ struct path_prefix *paths;
+ char *env_var;
+{
+ putenv (build_search_list (paths, env_var, 1));
+}
\f
/* Search for NAME using the prefix list PREFIXES. MODE is passed to
access to check permissions.
- Return 0 if not found, otherwise return its name, allocated with malloc. */
+ Return 0 if not found, otherwise return its name, allocated with malloc. */
static char *
find_a_file (pprefix, name, mode)
/* Determine the filename to execute (special case for absolute paths). */
- if (*name == '/')
+ if (*name == '/' || *name == DIR_SEPARATOR)
{
if (access (name, mode))
{
{
if (machine_suffix)
{
- strcpy (temp, pl->prefix);
- strcat (temp, machine_suffix);
- strcat (temp, name);
- if (access (temp, mode) == 0)
- {
- if (pl->used_flag_ptr != 0)
- *pl->used_flag_ptr = 1;
- return temp;
- }
/* Some systems have a suffix for executable files.
- So try appending that. */
+ So try appending that first. */
if (file_suffix[0] != 0)
{
+ strcpy (temp, pl->prefix);
+ strcat (temp, machine_suffix);
+ strcat (temp, name);
strcat (temp, file_suffix);
if (access (temp, mode) == 0)
{
return temp;
}
}
- }
- /* Certain prefixes are tried with just the machine type,
- not the version. This is used for finding as, ld, etc. */
- if (just_machine_suffix && pl->require_machine_suffix == 2)
- {
+
+ /* Now try just the name. */
strcpy (temp, pl->prefix);
- strcat (temp, just_machine_suffix);
+ strcat (temp, machine_suffix);
strcat (temp, name);
if (access (temp, mode) == 0)
{
*pl->used_flag_ptr = 1;
return temp;
}
+ }
+
+ /* Certain prefixes are tried with just the machine type,
+ not the version. This is used for finding as, ld, etc. */
+ if (just_machine_suffix && pl->require_machine_suffix == 2)
+ {
/* Some systems have a suffix for executable files.
- So try appending that. */
+ So try appending that first. */
if (file_suffix[0] != 0)
{
+ strcpy (temp, pl->prefix);
+ strcat (temp, just_machine_suffix);
+ strcat (temp, name);
strcat (temp, file_suffix);
if (access (temp, mode) == 0)
{
return temp;
}
}
- }
- /* Certain prefixes can't be used without the machine suffix
- when the machine or version is explicitly specified. */
- if (!pl->require_machine_suffix)
- {
+
strcpy (temp, pl->prefix);
+ strcat (temp, just_machine_suffix);
strcat (temp, name);
if (access (temp, mode) == 0)
{
*pl->used_flag_ptr = 1;
return temp;
}
+ }
+
+ /* Certain prefixes can't be used without the machine suffix
+ when the machine or version is explicitly specified. */
+ if (!pl->require_machine_suffix)
+ {
/* Some systems have a suffix for executable files.
- So try appending that. */
+ So try appending that first. */
if (file_suffix[0] != 0)
{
+ strcpy (temp, pl->prefix);
+ strcat (temp, name);
strcat (temp, file_suffix);
if (access (temp, mode) == 0)
{
return temp;
}
}
+
+ strcpy (temp, pl->prefix);
+ strcat (temp, name);
+ if (access (temp, mode) == 0)
+ {
+ if (pl->used_flag_ptr != 0)
+ *pl->used_flag_ptr = 1;
+ return temp;
+ }
}
}
{
if (pl->used_flag_ptr != 0 && !*pl->used_flag_ptr)
{
- error ("file path prefix `%s' never used",
- pl->prefix);
+ if (pl->require_machine_suffix && machine_suffix)
+ error ("file path prefix `%s%s' never used", pl->prefix,
+ machine_suffix);
+ else
+ error ("file path prefix `%s' never used", pl->prefix);
+
/* Prevent duplicate warnings. */
*pl->used_flag_ptr = 1;
}
}
}
-/* Get rid of all prefixes built up so far in *PLISTP. */
+/* Get rid of all prefixes built up so far in *PLISTP. */
static void
free_path_prefix (pprefix)
pprefix->plist = (struct prefix_list *) 0;
}
\f
-/* stdin file number. */
-#define STDIN_FILE_NO 0
-
-/* stdout file number. */
-#define STDOUT_FILE_NO 1
-
-/* value of `pipe': port index for reading. */
-#define READ_PORT 0
-
-/* value of `pipe': port index for writing. */
-#define WRITE_PORT 1
-
-/* Pipe waiting from last process, to be used as input for the next one.
- Value is STDIN_FILE_NO if no pipe is waiting
- (i.e. the next command is the first of a group). */
-
-static int last_pipe_input;
-
-/* Fork one piped subcommand. FUNC is the system call to use
- (either execv or execvp). ARGV is the arg vector to use.
- NOT_LAST is nonzero if this is not the last subcommand
- (i.e. its output should be piped to the next one.) */
-
-#ifndef OS2
-#ifdef __MSDOS__
-
-/* Declare these to avoid compilation error. They won't be called. */
-int execv(const char *a, const char **b){}
-int execvp(const char *a, const char **b){}
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- char *scmd, *rf;
- FILE *argfile;
- int i, el = search_flag ? 0 : 4;
-
- scmd = (char *)malloc (strlen (program) + strlen (temp_filename) + 6 + el);
- rf = scmd + strlen(program) + 2 + el;
- sprintf (scmd, "%s%s @%s.gp", program,
- (search_flag ? "" : ".exe"), temp_filename);
- argfile = fopen (rf, "w");
- if (argfile == 0)
- pfatal_with_name (rf);
-
- for (i=1; argv[i]; i++)
- {
- char *cp;
- for (cp = argv[i]; *cp; cp++)
- {
- if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
- fputc ('\\', argfile);
- fputc (*cp, argfile);
- }
- fputc ('\n', argfile);
- }
- fclose (argfile);
-
- i = system (scmd);
-
- remove (rf);
-
- if (i == -1)
- {
- perror_exec (program);
- return MIN_FATAL_STATUS << 8;
- }
-
- return i << 8;
-}
-
-#else /* not __MSDOS__ */
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- int (*func)() = (search_flag ? execv : execvp);
- int pid;
- int pdes[2];
- int input_desc = last_pipe_input;
- int output_desc = STDOUT_FILE_NO;
- int retries, sleep_interval;
-
- /* If this isn't the last process, make a pipe for its output,
- and record it as waiting to be the input to the next process. */
-
- if (not_last)
- {
- if (pipe (pdes) < 0)
- pfatal_with_name ("pipe");
- output_desc = pdes[WRITE_PORT];
- last_pipe_input = pdes[READ_PORT];
- }
- else
- last_pipe_input = STDIN_FILE_NO;
-
- /* Fork a subprocess; wait and retry if it fails. */
- sleep_interval = 1;
- for (retries = 0; retries < 4; retries++)
- {
- pid = vfork ();
- if (pid >= 0)
- break;
- sleep (sleep_interval);
- sleep_interval *= 2;
- }
-
- switch (pid)
- {
- case -1:
-#ifdef vfork
- pfatal_with_name ("fork");
-#else
- pfatal_with_name ("vfork");
-#endif
- /* NOTREACHED */
- return 0;
-
- case 0: /* child */
- /* Move the input and output pipes into place, if nec. */
- if (input_desc != STDIN_FILE_NO)
- {
- close (STDIN_FILE_NO);
- dup (input_desc);
- close (input_desc);
- }
- if (output_desc != STDOUT_FILE_NO)
- {
- close (STDOUT_FILE_NO);
- dup (output_desc);
- close (output_desc);
- }
-
- /* Close the parent's descs that aren't wanted here. */
- if (last_pipe_input != STDIN_FILE_NO)
- close (last_pipe_input);
-
- /* Exec the program. */
- (*func) (program, argv);
- perror_exec (program);
- exit (-1);
- /* NOTREACHED */
- return 0;
-
- default:
- /* In the parent, after forking.
- Close the descriptors that we made for this child. */
- if (input_desc != STDIN_FILE_NO)
- close (input_desc);
- if (output_desc != STDOUT_FILE_NO)
- close (output_desc);
-
- /* Return child's process number. */
- return pid;
- }
-}
-
-#endif /* not __MSDOS__ */
-#else /* not OS2 */
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- return (search_flag ? spawnv : spawnvp) (1, program, argv);
-}
-#endif /* not OS2 */
-\f
/* Execute the command specified by the arguments on the current line of spec.
When using pipes, this includes several piped-together commands
with `|' between them.
commands[0].prog = argbuf[0]; /* first command. */
commands[0].argv = &argbuf[0];
- string = find_a_file (&exec_prefix, commands[0].prog, X_OK);
+ 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. */
-#ifdef __MSDOS__
- fatal ("-pipe not supported under MS-DOS");
+#if defined (__MSDOS__) || defined (_WIN32) || defined (OS2)
+ fatal ("-pipe not supported");
#endif
argbuf[i] = 0; /* termination of command args. */
commands[n_commands].prog = argbuf[i + 1];
commands[n_commands].argv = &argbuf[i + 1];
- string = find_a_file (&exec_prefix, commands[n_commands].prog, X_OK);
+ string = find_a_file (&exec_prefixes, commands[n_commands].prog, X_OK);
if (string)
commands[n_commands].argv[0] = string;
n_commands++;
/* Run each piped subprocess. */
- last_pipe_input = STDIN_FILE_NO;
for (i = 0; i < n_commands; i++)
{
+ char *errmsg_fmt, *errmsg_arg;
char *string = commands[i].argv[0];
- commands[i].pid = pexecute (string != commands[i].prog,
- string, commands[i].argv,
- i + 1 < n_commands);
+ commands[i].pid = pexecute (string, commands[i].argv,
+ programname, temp_filename,
+ &errmsg_fmt, &errmsg_arg,
+ ((i == 0 ? PEXECUTE_FIRST : 0)
+ | (i + 1 == n_commands ? PEXECUTE_LAST : 0)
+ | (string == commands[i].prog
+ ? PEXECUTE_SEARCH : 0)
+ | (verbose_flag ? PEXECUTE_VERBOSE : 0)));
+
+ if (commands[i].pid == -1)
+ pfatal_pexecute (errmsg_fmt, errmsg_arg);
if (string != commands[i].prog)
free (string);
/* Wait for all the subprocesses to finish.
We don't care what order they finish in;
- we know that N_COMMANDS waits will get them all. */
+ we know that N_COMMANDS waits will get them all.
+ Ignore subprocesses that we don't know about,
+ since they can be spawned by the process that exec'ed us. */
{
int ret_code = 0;
- for (i = 0; i < n_commands; i++)
+ for (i = 0; i < n_commands; )
{
+ int j;
int status;
int pid;
- char *prog = "unknown";
-#ifdef __MSDOS__
- status = pid = commands[i].pid;
-#else
- pid = wait (&status);
-#endif
+ pid = pwait (commands[i].pid, &status, 0);
if (pid < 0)
abort ();
- if (status != 0)
- {
- int j;
- for (j = 0; j < n_commands; j++)
- if (commands[j].pid == pid)
- prog = commands[j].prog;
-
- if ((status & 0x7F) != 0)
- {
- fatal ("Internal compiler error: program %s got fatal signal %d",
- prog, (status & 0x7F));
- signal_count++;
- }
- if (((status & 0xFF00) >> 8) >= MIN_FATAL_STATUS)
- ret_code = -1;
- }
+ for (j = 0; j < n_commands; j++)
+ if (commands[j].pid == pid)
+ {
+ i++;
+ if (status != 0)
+ {
+ if (WIFSIGNALED (status))
+ {
+ fatal ("Internal compiler error: program %s got fatal signal %d",
+ commands[j].prog, WTERMSIG (status));
+ signal_count++;
+ ret_code = -1;
+ }
+ else if (WIFEXITED (status)
+ && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
+ ret_code = -1;
+ }
+ break;
+ }
}
return ret_code;
}
static char **outfiles;
+/* Used to track if none of the -B paths are used. */
+static int warn_B;
+
+/* Used to track if standard path isn't used and -b or -V is specified. */
+static int warn_std;
+
+/* Gives value to pass as "warn" to add_prefix for standard prefixes. */
+static int *warn_std_ptr = 0;
+
/* Create the vector `switches' and its contents.
Store its length in `n_switches'. */
char *temp;
char *spec_lang = 0;
int last_language_n_infiles;
+ int have_c = 0;
+ int have_o = 0;
+ int lang_n_infiles = 0;
gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX");
if (gcc_exec_prefix)
{
- add_prefix (&exec_prefix, gcc_exec_prefix, 0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, gcc_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, gcc_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, gcc_exec_prefix, 0, 0, NULL_PTR);
}
/* COMPILER_PATH and LIBRARY_PATH have values
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
+ strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
+ else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
- strcpy (nstore, "./");
- }
- else if (endp[-1] != '/')
- {
- nstore[endp-startp] = '/';
+ nstore[endp-startp] = DIR_SEPARATOR;
nstore[endp-startp+1] = 0;
}
else
nstore[endp-startp] = 0;
- add_prefix (&exec_prefix, nstore, 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, nstore, 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
}
temp = getenv ("LIBRARY_PATH");
- if (temp)
+ if (temp && ! cross_compile)
{
char *startp, *endp;
char *nstore = (char *) alloca (strlen (temp) + 3);
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
+ strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
+ else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
- strcpy (nstore, "./");
- }
- else if (endp[-1] != '/')
- {
- nstore[endp-startp] = '/';
+ nstore[endp-startp] = DIR_SEPARATOR;
nstore[endp-startp+1] = 0;
}
else
nstore[endp-startp] = 0;
- add_prefix (&startfile_prefix, nstore, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, nstore, 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
/* Use LPATH like LIBRARY_PATH (for the CMU build program). */
temp = getenv ("LPATH");
- if (temp)
+ if (temp && ! cross_compile)
{
char *startp, *endp;
char *nstore = (char *) alloca (strlen (temp) + 3);
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
+ strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
+ else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
- strcpy (nstore, "./");
- }
- else if (endp[-1] != '/')
- {
- nstore[endp-startp] = '/';
+ nstore[endp-startp] = DIR_SEPARATOR;
nstore[endp-startp+1] = 0;
}
else
nstore[endp-startp] = 0;
- add_prefix (&startfile_prefix, nstore, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, nstore, 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
printf ("*endfile:\n%s\n\n", endfile_spec);
printf ("*link:\n%s\n\n", link_spec);
printf ("*lib:\n%s\n\n", lib_spec);
+ printf ("*libgcc:\n%s\n\n", libgcc_spec);
printf ("*startfile:\n%s\n\n", startfile_spec);
printf ("*switches_need_spaces:\n%s\n\n", switches_need_spaces);
printf ("*signed_char:\n%s\n\n", signed_char_spec);
printf ("*predefines:\n%s\n\n", cpp_predefines);
printf ("*cross_compile:\n%d\n\n", cross_compile);
+ printf ("*multilib:\n%s\n\n", multilib_select);
+ printf ("*multilib_defaults:\n%s\n\n", multilib_defaults);
+ printf ("*multilib_extra:\n%s\n\n", multilib_extra);
+ printf ("*multilib_matches:\n%s\n\n", multilib_matches);
+#ifdef EXTRA_SPECS
+ {
+ int j;
+ for (j = 0; j < sizeof (extra_specs) / sizeof (extra_specs[0]); j++)
+ printf ("*%s:\n%s\n\n", extra_specs[j].name,
+ (extra_specs[j].spec) ? extra_specs[j].spec : "");
+ }
+#endif
exit (0);
}
else if (! strcmp (argv[i], "-dumpversion"))
printf ("%s\n", version_string);
exit (0);
}
+ else if (! strcmp (argv[i], "-dumpmachine"))
+ {
+ printf ("%s\n", spec_machine);
+ exit (0);
+ }
+ else if (! strcmp (argv[i], "-print-search-dirs"))
+ print_search_dirs = 1;
else if (! strcmp (argv[i], "-print-libgcc-file-name"))
- print_file_name = "libgcc.a";
+ print_file_name = "libgcc.a";
else if (! strncmp (argv[i], "-print-file-name=", 17))
- print_file_name = argv[i] + 17;
+ print_file_name = argv[i] + 17;
else if (! strncmp (argv[i], "-print-prog-name=", 17))
- print_prog_name = argv[i] + 17;
- else if (! strcmp (argv[i], "-Xlinker"))
- {
- /* Pass the argument of this option to the linker when we link. */
-
- if (i + 1 == argc)
- fatal ("argument to `-Xlinker' is missing");
-
- n_linker_options++;
- if (!linker_options)
- linker_options
- = (char **) xmalloc (n_linker_options * sizeof (char **));
- else
- linker_options
- = (char **) xrealloc (linker_options,
- n_linker_options * sizeof (char **));
-
- linker_options[n_linker_options - 1] = argv[++i];
- }
- else if (! strncmp (argv[i], "-Wl,", 4))
- {
- int prev, j;
- /* Pass the rest of this option to the linker when we link. */
-
- n_linker_options++;
- if (!linker_options)
- linker_options
- = (char **) xmalloc (n_linker_options * sizeof (char **));
- else
- linker_options
- = (char **) xrealloc (linker_options,
- n_linker_options * sizeof (char **));
-
- /* Split the argument at commas. */
- prev = 4;
- for (j = 4; argv[i][j]; j++)
- if (argv[i][j] == ',')
- {
- linker_options[n_linker_options - 1]
- = save_string (argv[i] + prev, j - prev);
- n_linker_options++;
- linker_options
- = (char **) xrealloc (linker_options,
- n_linker_options * sizeof (char **));
- prev = j + 1;
- }
- /* Record the part after the last comma. */
- linker_options[n_linker_options - 1] = argv[i] + prev;
- }
+ print_prog_name = argv[i] + 17;
+ else if (! strcmp (argv[i], "-print-multi-lib"))
+ print_multi_lib = 1;
+ else if (! strcmp (argv[i], "-print-multi-directory"))
+ print_multi_directory = 1;
else if (! strncmp (argv[i], "-Wa,", 4))
{
int prev, j;
/* Record the part after the last comma. */
assembler_options[n_assembler_options - 1] = argv[i] + prev;
}
+ else if (! strncmp (argv[i], "-Wp,", 4))
+ {
+ int prev, j;
+ /* Pass the rest of this option to the preprocessor. */
+
+ n_preprocessor_options++;
+ if (!preprocessor_options)
+ preprocessor_options
+ = (char **) xmalloc (n_preprocessor_options * sizeof (char **));
+ else
+ preprocessor_options
+ = (char **) xrealloc (preprocessor_options,
+ n_preprocessor_options * sizeof (char **));
+
+ /* Split the argument at commas. */
+ prev = 4;
+ for (j = 4; argv[i][j]; j++)
+ if (argv[i][j] == ',')
+ {
+ preprocessor_options[n_preprocessor_options - 1]
+ = save_string (argv[i] + prev, j - prev);
+ n_preprocessor_options++;
+ preprocessor_options
+ = (char **) xrealloc (preprocessor_options,
+ n_preprocessor_options * sizeof (char **));
+ prev = j + 1;
+ }
+ /* Record the part after the last comma. */
+ preprocessor_options[n_preprocessor_options - 1] = argv[i] + prev;
+ }
else if (argv[i][0] == '+' && argv[i][1] == 'e')
/* The +e options to the C++ front-end. */
n_switches++;
- else if (argv[i][0] == '-' && argv[i][1] != 0 && argv[i][1] != 'l')
+ else if (strncmp (argv[i], "-Wl,", 4) == 0)
+ {
+ int j;
+ /* Split the argument at commas. */
+ for (j = 3; argv[i][j]; j++)
+ n_infiles += (argv[i][j] == ',');
+ }
+ else if (strcmp (argv[i], "-Xlinker") == 0)
+ {
+ if (i + 1 == argc)
+ fatal ("argument to `-Xlinker' is missing");
+
+ n_infiles++;
+ i++;
+ }
+ else if (strncmp (argv[i], "-l", 2) == 0)
+ n_infiles++;
+ else if (strcmp (argv[i], "-save-temps") == 0)
+ {
+ save_temps_flag = 1;
+ n_switches++;
+ }
+ else if (argv[i][0] == '-' && argv[i][1] != 0)
{
register char *p = &argv[i][1];
register int c = *p;
spec_machine = argv[++i];
else
spec_machine = p + 1;
+
+ warn_std_ptr = &warn_std;
break;
case 'B':
value = argv[++i];
else
value = p + 1;
- add_prefix (&exec_prefix, value, 1, 0, temp);
- add_prefix (&startfile_prefix, value, 1, 0, temp);
- add_prefix (&include_prefix, concat (value, "include", ""),
- 1, 0, 0);
+ add_prefix (&exec_prefixes, value, 1, 0, &warn_B);
+ add_prefix (&startfile_prefixes, value, 1, 0, &warn_B);
+ add_prefix (&include_prefixes, concat (value, "include", NULL_PTR),
+ 1, 0, NULL_PTR);
/* As a kludge, if the arg is "[foo/]stageN/", just add
- "include" to the include prefix. */
+ "[foo/]include" to the include prefix. */
{
int len = strlen (value);
- if ((len == 7 || (len > 7 && value[len - 8] == '/'))
+ if ((len == 7
+ || (len > 7
+ && (value[len - 8] == '/'
+ || value[len - 8] == DIR_SEPARATOR)))
&& strncmp (value + len - 7, "stage", 5) == 0
&& isdigit (value[len - 2])
- && value[len - 1] == '/')
- add_prefix (&include_prefix, "include", 1, 0, 0);
+ && (value[len - 1] == '/'
+ || value[len - 1] == DIR_SEPARATOR))
+ {
+ if (len == 7)
+ add_prefix (&include_prefixes, "include",
+ 1, 0, NULL_PTR);
+ else
+ {
+ char *string = xmalloc (len + 1);
+ strncpy (string, value, len-7);
+ strcat (string, "include");
+ add_prefix (&include_prefixes, string,
+ 1, 0, NULL_PTR);
+ }
+ }
}
}
break;
else
spec_version = p + 1;
compiler_version = spec_version;
+ warn_std_ptr = &warn_std;
break;
- case 's':
- if (!strcmp (p, "save-temps"))
+ case 'c':
+ if (p[1] == 0)
{
- save_temps_flag = 1;
+ have_c = 1;
n_switches++;
break;
}
+ goto normal_switch;
+
+ case 'o':
+ have_o = 1;
+ goto normal_switch;
+
default:
+ normal_switch:
n_switches++;
if (SWITCH_TAKES_ARG (c) > (p[1] != 0))
}
}
else
- n_infiles++;
+ {
+ n_infiles++;
+ lang_n_infiles++;
+ }
}
+ if (have_c && have_o && lang_n_infiles > 1)
+ fatal ("cannot specify -o with -c and multiple compilations");
+
/* 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
(such as cpp) rather than those of the host system. */
/* Use 2 as fourth arg meaning try just the machine as a suffix,
as well as trying the machine and the version. */
- add_prefix (&exec_prefix, standard_exec_prefix, 0, 2, NULL_PTR);
- add_prefix (&exec_prefix, standard_exec_prefix_1, 0, 2, NULL_PTR);
+#ifndef OS2
+ add_prefix (&exec_prefixes, standard_exec_prefix, 0, 2, warn_std_ptr);
+ add_prefix (&exec_prefixes, standard_exec_prefix_1, 0, 2, warn_std_ptr);
+#endif
- add_prefix (&startfile_prefix, standard_exec_prefix, 0, 1, NULL_PTR);
- add_prefix (&startfile_prefix, standard_exec_prefix_1, 0, 1, NULL_PTR);
+ add_prefix (&startfile_prefixes, standard_exec_prefix, 0, 1, warn_std_ptr);
+ add_prefix (&startfile_prefixes, standard_exec_prefix_1, 0, 1, warn_std_ptr);
- tooldir_prefix = concat (tooldir_base_prefix, spec_machine, "/");
+ tooldir_prefix = concat (tooldir_base_prefix, spec_machine,
+ dir_separator_str, NULL_PTR);
- /* If tooldir is relative, base it on exec_prefix. A relative
+ /* If tooldir is relative, base it on exec_prefixes. A relative
tooldir lets us move the installed tree as a unit.
If GCC_EXEC_PREFIX is defined, then we want to add two relative
directories, so that we can search both the user specified directory
and the standard place. */
- if (*tooldir_prefix != '/')
+ if (*tooldir_prefix != '/' && *tooldir_prefix != DIR_SEPARATOR)
{
if (gcc_exec_prefix)
{
char *gcc_exec_tooldir_prefix
- = concat (concat (gcc_exec_prefix, spec_machine, "/"),
- concat (spec_version, "/", tooldir_prefix),
- "");
+ = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
+ spec_version, dir_separator_str, tooldir_prefix, NULL_PTR);
- add_prefix (&exec_prefix, concat (gcc_exec_tooldir_prefix, "bin", "/"),
+ add_prefix (&exec_prefixes,
+ concat (gcc_exec_tooldir_prefix, "bin",
+ dir_separator_str, NULL_PTR),
0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, concat (gcc_exec_tooldir_prefix, "lib", "/"),
+ add_prefix (&startfile_prefixes,
+ concat (gcc_exec_tooldir_prefix, "lib",
+ dir_separator_str, NULL_PTR),
0, 0, NULL_PTR);
}
- tooldir_prefix = concat (concat (standard_exec_prefix, spec_machine, "/"),
- concat (spec_version, "/", tooldir_prefix),
- "");
+ tooldir_prefix = concat (standard_exec_prefix, spec_machine,
+ dir_separator_str, spec_version,
+ dir_separator_str, tooldir_prefix, NULL_PTR);
}
- add_prefix (&exec_prefix, concat (tooldir_prefix, "bin", "/"),
+ add_prefix (&exec_prefixes,
+ concat (tooldir_prefix, "bin", dir_separator_str, NULL_PTR),
0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, concat (tooldir_prefix, "lib", "/"),
+ add_prefix (&startfile_prefixes,
+ concat (tooldir_prefix, "lib", dir_separator_str, NULL_PTR),
0, 0, NULL_PTR);
/* More prefixes are enabled in main, after we read the specs file
for (i = 1; i < argc; i++)
{
/* Just skip the switches that were handled by the preceding loop. */
- if (!strcmp (argv[i], "-Xlinker"))
- i++;
- else if (! strncmp (argv[i], "-Wl,", 4))
+ if (! strncmp (argv[i], "-Wa,", 4))
;
- else if (! strncmp (argv[i], "-Wa,", 4))
+ else if (! strncmp (argv[i], "-Wp,", 4))
+ ;
+ else if (! strcmp (argv[i], "-print-search-dirs"))
;
else if (! strcmp (argv[i], "-print-libgcc-file-name"))
;
;
else if (! strncmp (argv[i], "-print-prog-name=", 17))
;
+ else if (! strcmp (argv[i], "-print-multi-lib"))
+ ;
+ else if (! strcmp (argv[i], "-print-multi-directory"))
+ ;
else if (argv[i][0] == '+' && argv[i][1] == 'e')
{
/* Compensate for the +e options to the C++ front-end;
switches[n_switches].valid = 0;
n_switches++;
}
- else if (argv[i][0] == '-' && argv[i][1] != 0 && argv[i][1] != 'l')
+ else if (strncmp (argv[i], "-Wl,", 4) == 0)
+ {
+ int prev, j;
+ /* Split the argument at commas. */
+ prev = 4;
+ for (j = 4; argv[i][j]; j++)
+ if (argv[i][j] == ',')
+ {
+ infiles[n_infiles].language = 0;
+ 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++].name = argv[i] + prev;
+ }
+ else if (strcmp (argv[i], "-Xlinker") == 0)
+ {
+ infiles[n_infiles].language = 0;
+ infiles[n_infiles++].name = argv[++i];
+ }
+ else if (strncmp (argv[i], "-l", 2) == 0)
+ {
+ infiles[n_infiles].language = 0;
+ infiles[n_infiles++].name = argv[i];
+ }
+ else if (argv[i][0] == '-' && argv[i][1] != 0)
{
register char *p = &argv[i][1];
register int c = *p;
else
spec_lang = p + 1;
if (! strcmp (spec_lang, "none"))
- /* Suppress the warning if -xnone comes after the last input file,
- because alternate command interfaces like g++ might find it
- useful to place -xnone after each input file. */
+ /* Suppress the warning if -xnone comes after the last input
+ file, because alternate command interfaces like g++ might
+ find it useful to place -xnone after each input file. */
spec_lang = 0;
else
last_language_n_infiles = n_infiles;
/* Null-terminate the vector. */
switches[n_switches].args[j] = 0;
}
- else if (*switches_need_spaces != 0 && (c == 'o' || c == 'L'))
+ else if (index (switches_need_spaces, c))
{
- /* On some systems, ld cannot handle -o or -L without space.
- So split the -o or -L from its argument. */
- switches[n_switches].part1 = (c == 'o' ? "o" : "L");
+ /* On some systems, ld cannot handle some options without
+ a space. So split the option from its argument. */
+ char *part1 = (char *) xmalloc (2);
+ part1[0] = c;
+ part1[1] = '\0';
+
+ switches[n_switches].part1 = part1;
switches[n_switches].args = (char **) xmalloc (2 * sizeof (char *));
switches[n_switches].args[0] = xmalloc (strlen (p));
strcpy (switches[n_switches].args[0], &p[1]);
}
else
{
- if ((argv[i][0] != '-' || argv[i][1] != 'l')
- && strcmp (argv[i], "-")
- && access (argv[i], R_OK) < 0)
+#ifdef HAVE_OBJECT_SUFFIX
+ /* Convert x.o to x.obj if OBJECT_SUFFIX is ".obj". */
+ if (strlen (argv[i]) > 2
+ && argv[i][strlen (argv[i]) - 2] == '.'
+ && argv[i][strlen (argv[i]) - 1] == 'o')
+ {
+ int j;
+
+ for (j = 0; j < strlen (argv[i]) - 2; j++)
+ obstack_1grow (&obstack, argv[i][j]);
+
+ obstack_grow (&obstack, OBJECT_SUFFIX, strlen (OBJECT_SUFFIX));
+ obstack_1grow (&obstack, 0);
+ argv[i] = obstack_finish (&obstack);
+ }
+#endif
+
+ if (strcmp (argv[i], "-") != 0 && access (argv[i], R_OK) < 0)
{
perror_with_name (argv[i]);
error_count++;
switches[n_switches].part1 = 0;
infiles[n_infiles].name = 0;
-
- /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake. */
- if (gcc_exec_prefix)
- {
- temp = (char *) xmalloc (strlen (gcc_exec_prefix) + strlen (spec_version)
- + strlen (spec_machine) + 3);
- strcpy (temp, gcc_exec_prefix);
- strcat (temp, spec_machine);
- strcat (temp, "/");
- strcat (temp, spec_version);
- strcat (temp, "/");
- gcc_exec_prefix = temp;
- }
}
\f
/* Process a spec string, accumulating and running commands. */
if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
{
- int i;
for (i = 0; i < n_switches; i++)
if (!strcmp (switches[i].part1, "pipe"))
break;
that we search for startfiles. */
case 'D':
{
- struct prefix_list *pl = startfile_prefix.plist;
+ struct prefix_list *pl = startfile_prefixes.plist;
int bufsize = 100;
char *buffer = (char *) xmalloc (bufsize);
int idx;
/* Relative directories always come from -B,
and it is better not to use them for searching
at run time. In particular, stage1 loses */
- if (pl->prefix[0] != '/')
+ if (pl->prefix[0] != '/' && pl->prefix[0] != DIR_SEPARATOR)
continue;
#endif
+ /* Try subdirectory if there is one. */
+ if (multilib_dir != NULL)
+ {
+ if (machine_suffix)
+ {
+ if (strlen (pl->prefix) + strlen (machine_suffix)
+ >= bufsize)
+ bufsize = (strlen (pl->prefix)
+ + strlen (machine_suffix)) * 2 + 1;
+ buffer = (char *) xrealloc (buffer, bufsize);
+ strcpy (buffer, pl->prefix);
+ strcat (buffer, machine_suffix);
+ if (is_directory (buffer, multilib_dir, 1))
+ {
+ do_spec_1 ("-L", 0, NULL_PTR);
+#ifdef SPACE_AFTER_L_OPTION
+ do_spec_1 (" ", 0, NULL_PTR);
+#endif
+ do_spec_1 (buffer, 1, NULL_PTR);
+ do_spec_1 (multilib_dir, 1, NULL_PTR);
+ /* Make this a separate argument. */
+ do_spec_1 (" ", 0, NULL_PTR);
+ }
+ }
+ if (!pl->require_machine_suffix)
+ {
+ if (is_directory (pl->prefix, multilib_dir, 1))
+ {
+ do_spec_1 ("-L", 0, NULL_PTR);
+#ifdef SPACE_AFTER_L_OPTION
+ do_spec_1 (" ", 0, NULL_PTR);
+#endif
+ do_spec_1 (pl->prefix, 1, NULL_PTR);
+ do_spec_1 (multilib_dir, 1, NULL_PTR);
+ /* Make this a separate argument. */
+ do_spec_1 (" ", 0, NULL_PTR);
+ }
+ }
+ }
if (machine_suffix)
{
if (is_directory (pl->prefix, machine_suffix, 1))
buffer = (char *) xrealloc (buffer, bufsize);
strcpy (buffer, machine_suffix);
idx = strlen (buffer);
- if (buffer[idx - 1] == '/')
+ if (buffer[idx - 1] == '/'
+ || buffer[idx - 1] == DIR_SEPARATOR)
buffer[idx - 1] = 0;
do_spec_1 (buffer, 1, NULL_PTR);
/* Make this a separate argument. */
buffer = (char *) xrealloc (buffer, bufsize);
strcpy (buffer, pl->prefix);
idx = strlen (buffer);
- if (buffer[idx - 1] == '/')
+ if (buffer[idx - 1] == '/'
+ || buffer[idx - 1] == DIR_SEPARATOR)
buffer[idx - 1] = 0;
do_spec_1 (buffer, 1, NULL_PTR);
/* Make this a separate argument. */
case 'u':
case 'U':
if (save_temps_flag)
- obstack_grow (&obstack, input_basename, basename_length);
+ {
+ obstack_grow (&obstack, input_basename, basename_length);
+ delete_this_arg = 0;
+ }
else
{
#ifdef MKTEMP_EACH_FILE
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++;
/* See if we already have an association of %g/%u/%U and
t->length = p - suffix;
t->suffix = save_string (suffix, p - suffix);
t->unique = (c != 'g');
- choose_temp_base ();
+ temp_filename = choose_temp_base ();
+ temp_filename_length = strlen (temp_filename);
t->filename = temp_filename;
t->filename_length = temp_filename_length;
}
case 'I':
{
- struct prefix_list *pl = include_prefix.plist;
+ struct prefix_list *pl = include_prefixes.plist;
if (gcc_exec_prefix)
{
break;
case 'o':
- {
- register int f;
- for (f = 0; f < n_infiles; f++)
- store_arg (outfiles[f], 0, 0);
- }
+ for (i = 0; i < n_infiles; i++)
+ store_arg (outfiles[i], 0, 0);
+ break;
+
+ case 'O':
+ obstack_grow (&obstack, OBJECT_SUFFIX, strlen (OBJECT_SUFFIX));
+ arg_going = 1;
break;
case 's':
case 'W':
{
- int index = argbuf_index;
+ int cur_index = argbuf_index;
/* Handle the {...} following the %W. */
if (*p != '{')
abort ();
return -1;
/* If any args were output, mark the last one for deletion
on failure. */
- if (argbuf_index != index)
+ if (argbuf_index != cur_index)
record_temp_file (argbuf[argbuf_index - 1], 0, 1);
break;
}
}
break;
- /* Dump out the options accumulated previously using %x,
- -Xlinker and -Wl,. */
+ /* Dump out the options accumulated previously using %x. */
case 'X':
for (i = 0; i < n_linker_options; i++)
{
}
break;
+ /* Dump out the options accumulated previously using -Wp,. */
+ case 'Z':
+ for (i = 0; i < n_preprocessor_options; i++)
+ {
+ do_spec_1 (preprocessor_options[i], 1, NULL_PTR);
+ /* Make each accumulated option a separate argument. */
+ do_spec_1 (" ", 0, NULL_PTR);
+ }
+ break;
+
/* Here are digits and numbers that just process
a certain constant string as a spec. */
return value;
break;
+ case 'G':
+ value = do_spec_1 (libgcc_spec, 0, NULL_PTR);
+ if (value != 0)
+ return value;
+ break;
+
case 'p':
{
char *x = (char *) alloca (strlen (cpp_predefines) + 1);
*x++ = *y++;
*x++ = *y++;
- if (strncmp (y, "__", 2))
+ if (*y != '_'
+ || (*(y+1) != '_' && ! isupper (*(y+1))))
{
/* Stick __ at front of macro name. */
*x++ = '_';
{
y += 2;
- if (strncmp (y, "__", 2))
+ if (*y != '_'
+ || (*(y+1) != '_' && ! isupper (*(y+1))))
{
/* Stick -D__ at front of macro name. */
*x++ = '-';
int len;
/* The string after the S/P is the name of a spec that is to be
- processed. */
+ processed. */
while (*p && *p != ')' && *p != ']')
p++;
{
int c1 = *p++; /* Select first or second version number. */
char *v = compiler_version;
- char *q, *copy;
+ char *q;
+
+ /* The format of the version string is
+ ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)? */
+
+ /* Ignore leading non-digits. i.e. "foo-" in "foo-2.7.2". */
+ while (! isdigit (*v))
+ v++;
+ if (v > compiler_version && v[-1] != '-')
+ abort ();
+
/* If desired, advance to second version number. */
if (c1 == '2')
{
- /* Set P after the first period. */
- while (*v != 0 && *v != ' ' && *v != '.')
- v++;
- if (*v == '.')
+ /* Set V after the first period. */
+ while (isdigit (*v))
v++;
+ if (*v != '.')
+ abort ();
+ v++;
}
+
/* Set Q at the next period or at the end. */
q = v;
- while (*q != 0 && *q != ' ' && *q != '.')
+ while (isdigit (*q))
q++;
- /* Empty string means zero. */
- if (p == q)
- {
- v = "0";
- q = v + 1;
- }
+ if (*q != 0 && *q != ' ' && *q != '.' && *q != '-')
+ abort ();
+
/* Put that part into the command. */
obstack_grow (&obstack, v, q - v);
arg_going = 1;
{
register char *q;
char *filter;
- int pipe = 0;
+ int pipe_p = 0;
int negate = 0;
int suffix = 0;
/* A `|' after the open-brace means,
if the test fails, output a single minus sign rather than nothing.
This is used in %{|!pipe:...}. */
- pipe = 1, ++p;
+ pipe_p = 1, ++p;
if (*p == '!')
/* A `!' after the open-brace negates the condition:
if (*p == '.')
/* A `.' after the open-brace means test against the current suffix. */
{
- if (pipe)
+ if (pipe_p)
abort ();
suffix = 1;
return 0;
}
}
- else if (pipe)
+ else if (pipe_p)
{
/* Here if a %{|...} conditional fails: output a minus sign,
which means "standard output" or "standard input". */
case 'W': case 'f': case 'm':
if (! strncmp (name + 1, "no-", 3))
{
- /* We have Xno-YYY, search for XYYY. */
+ /* We have Xno-YYY, search for XYYY. */
for (i = switchnum + 1; i < n_switches; i++)
if (switches[i].part1[0] == name[0]
&& ! strcmp (&switches[i].part1[1], &name[4]))
{
char *newname;
- newname = find_a_file (&startfile_prefix, name, R_OK);
+ /* Try multilib_dir if it is defined. */
+ if (multilib_dir != NULL)
+ {
+ char *try;
+
+ try = (char *) alloca (strlen (multilib_dir) + strlen (name) + 2);
+ strcpy (try, multilib_dir);
+ strcat (try, dir_separator_str);
+ strcat (try, name);
+
+ newname = find_a_file (&startfile_prefixes, try, R_OK);
+
+ /* If we don't find it in the multi library dir, then fall
+ through and look for it in the normal places. */
+ if (newname != NULL)
+ return newname;
+ }
+
+ newname = find_a_file (&startfile_prefixes, name, R_OK);
return newname ? newname : name;
}
bcopy (path1, path, len1);
bcopy (path2, path + len1, len2);
cp = path + len1 + len2;
- if (cp[-1] != '/')
- *cp++ = '/';
+ if (cp[-1] != '/' && cp[-1] != DIR_SEPARATOR)
+ *cp++ = DIR_SEPARATOR;
*cp++ = '.';
*cp = '\0';
/* Exclude directories that the linker is known to search. */
if (linker
- && ((cp - path == 6 && strcmp (path, "/lib/.") == 0)
- || (cp - path == 10 && strcmp (path, "/usr/lib/.") == 0)))
+ && ((cp - path == 6
+ && strcmp (path, concat (dir_separator_str, "lib",
+ dir_separator_str, ".", NULL_PTR)) == 0)
+ || (cp - path == 10
+ && strcmp (path, concat (dir_separator_str, "usr",
+ dir_separator_str, "lib",
+ dir_separator_str, ".", NULL_PTR)) == 0)))
return 0;
return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
char *p;
p = argv[0] + strlen (argv[0]);
- while (p != argv[0] && p[-1] != '/') --p;
+ while (p != argv[0] && p[-1] != '/' && p[-1] != DIR_SEPARATOR) --p;
programname = p;
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
obstack_init (&obstack);
+ /* Build multilib_select, et. al from the separate lines that make up each
+ multilib selection. */
+ {
+ char **q = multilib_raw;
+ int need_space;
+
+ obstack_init (&multilib_obstack);
+ while ((p = *q++) != (char *) 0)
+ obstack_grow (&multilib_obstack, p, strlen (p));
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_select = obstack_finish (&multilib_obstack);
+
+ q = multilib_matches_raw;
+ while ((p = *q++) != (char *) 0)
+ obstack_grow (&multilib_obstack, p, strlen (p));
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_matches = obstack_finish (&multilib_obstack);
+
+ need_space = FALSE;
+ for (i = 0;
+ i < sizeof (multilib_defaults_raw) / sizeof (multilib_defaults_raw[0]);
+ i++)
+ {
+ if (need_space)
+ obstack_1grow (&multilib_obstack, ' ');
+ obstack_grow (&multilib_obstack,
+ multilib_defaults_raw[i],
+ strlen (multilib_defaults_raw[i]));
+ need_space = TRUE;
+ }
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_defaults = obstack_finish (&multilib_obstack);
+ }
+
/* Set up to remember the pathname of gcc and any options
needed for collect. We use argv[0] instead of programname because
we need the complete pathname. */
obstack_grow (&collect_obstack, argv[0], strlen (argv[0])+1);
putenv (obstack_finish (&collect_obstack));
+#ifdef INIT_ENVIRONMENT
+ /* Set up any other necessary machine specific environment variables. */
+ putenv (INIT_ENVIRONMENT);
+#endif
+
/* Choose directory for temp files. */
- choose_temp_base ();
+ temp_filename = choose_temp_base ();
+ temp_filename_length = strlen (temp_filename);
/* Make a table of what switches there are (switches, n_switches).
Make a table of specified input files (infiles, n_infiles).
This means one element containing 0s, as a terminator. */
compilers = (struct compiler *) xmalloc (sizeof default_compilers);
- bcopy (default_compilers, compilers, sizeof default_compilers);
+ bcopy ((char *) default_compilers, (char *) compilers,
+ sizeof default_compilers);
n_compilers = n_default_compilers;
/* Read specs from a file if there is one. */
- machine_suffix = concat (spec_machine, "/", concat (spec_version, "/", ""));
- just_machine_suffix = concat (spec_machine, "/", "");
+ machine_suffix = concat (spec_machine, dir_separator_str,
+ spec_version, dir_separator_str, NULL_PTR);
+ just_machine_suffix = concat (spec_machine, dir_separator_str, NULL_PTR);
- specs_file = find_a_file (&startfile_prefix, "specs", R_OK);
+ specs_file = find_a_file (&startfile_prefixes, "specs", R_OK);
/* Read the specs file unless it is a default one. */
if (specs_file != 0 && strcmp (specs_file, "specs"))
read_specs (specs_file);
+#ifdef EXTRA_SPECS
+ else
+ {
+ int k;
+ for (k = 0; k < sizeof (extra_specs) / sizeof (extra_specs[0]); k++)
+ set_spec (extra_specs[k].name, extra_specs[k].spec);
+ }
+#endif
+
/* If not cross-compiling, look for startfiles in the standard places. */
/* The fact that these are done here, after reading the specs file,
means that it cannot be found in these directories.
if (!cross_compile)
{
#ifdef MD_EXEC_PREFIX
- add_prefix (&exec_prefix, md_exec_prefix, 0, 0, NULL_PTR);
- add_prefix (&startfile_prefix, md_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, md_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_exec_prefix, 0, 0, NULL_PTR);
#endif
#ifdef MD_STARTFILE_PREFIX
- add_prefix (&startfile_prefix, md_startfile_prefix, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_startfile_prefix, 0, 0, NULL_PTR);
#endif
#ifdef MD_STARTFILE_PREFIX_1
- add_prefix (&startfile_prefix, md_startfile_prefix_1, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_startfile_prefix_1, 0, 0, NULL_PTR);
#endif
/* 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 (*standard_startfile_prefix == '/')
- add_prefix (&startfile_prefix, standard_startfile_prefix, 0, 0,
+ if (*standard_startfile_prefix == '/'
+ || *standard_startfile_prefix == DIR_SEPARATOR)
+ add_prefix (&startfile_prefixes, standard_startfile_prefix, 0, 0,
NULL_PTR);
else
{
if (gcc_exec_prefix)
- add_prefix (&startfile_prefix,
- concat (gcc_exec_prefix,
- standard_startfile_prefix,
- ""),
+ add_prefix (&startfile_prefixes,
+ concat (gcc_exec_prefix, machine_suffix,
+ standard_startfile_prefix, NULL_PTR),
0, 0, NULL_PTR);
- add_prefix (&startfile_prefix,
+ add_prefix (&startfile_prefixes,
concat (standard_exec_prefix,
machine_suffix,
- standard_startfile_prefix),
+ standard_startfile_prefix, NULL_PTR),
0, 0, NULL_PTR);
}
- add_prefix (&startfile_prefix, standard_startfile_prefix_1, 0, 0,
+ add_prefix (&startfile_prefixes, standard_startfile_prefix_1, 0, 0,
NULL_PTR);
- add_prefix (&startfile_prefix, standard_startfile_prefix_2, 0, 0,
+ add_prefix (&startfile_prefixes, standard_startfile_prefix_2, 0, 0,
NULL_PTR);
#if 0 /* Can cause surprises, and one can use -B./ instead. */
- add_prefix (&startfile_prefix, "./", 0, 1, NULL_PTR);
+ add_prefix (&startfile_prefixes, "./", 0, 1, NULL_PTR);
#endif
}
+ else
+ {
+ if (*standard_startfile_prefix != DIR_SEPARATOR && gcc_exec_prefix)
+ add_prefix (&startfile_prefixes,
+ concat (gcc_exec_prefix, machine_suffix,
+ standard_startfile_prefix, NULL_PTR),
+ 0, 0, NULL_PTR);
+ }
+
+ /* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake. */
+ if (gcc_exec_prefix)
+ {
+ char * temp = (char *) xmalloc (strlen (gcc_exec_prefix)
+ + strlen (spec_version)
+ + strlen (spec_machine) + 3);
+ strcpy (temp, gcc_exec_prefix);
+ strcat (temp, spec_machine);
+ strcat (temp, dir_separator_str);
+ strcat (temp, spec_version);
+ strcat (temp, dir_separator_str);
+ gcc_exec_prefix = temp;
+ }
/* Now we have the specs.
Set the `valid' bits for switches that match anything in any spec. */
validate_all_switches ();
+ /* Now that we have the switches and the specs, set
+ the subdirectory based on the options. */
+ set_multilib_dir ();
+
/* Warn about any switches that no pass was interested in. */
for (i = 0; i < n_switches; i++)
/* Obey some of the options. */
+ if (print_search_dirs)
+ {
+ printf ("install: %s%s\n", standard_exec_prefix, machine_suffix);
+ printf ("programs: %s\n", build_search_list (&exec_prefixes, "", 0));
+ printf ("libraries: %s\n", build_search_list (&startfile_prefixes, "", 0));
+ exit (0);
+ }
+
if (print_file_name)
{
printf ("%s\n", find_file (print_file_name));
if (print_prog_name)
{
- char *newname = find_a_file (&exec_prefix, print_prog_name, X_OK);
+ char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK);
printf ("%s\n", (newname ? newname : print_prog_name));
exit (0);
}
+ if (print_multi_lib)
+ {
+ print_multilib_info ();
+ exit (0);
+ }
+
+ if (print_multi_directory)
+ {
+ if (multilib_dir == NULL)
+ printf (".\n");
+ else
+ printf ("%s\n", multilib_dir);
+ exit (0);
+ }
+
if (verbose_flag)
{
- fprintf (stderr, "gcc version %s\n", version_string);
+ if (! strcmp (version_string, compiler_version))
+ fprintf (stderr, "gcc version %s\n", version_string);
+ else
+ fprintf (stderr, "gcc driver version %s executing gcc version %s\n",
+ version_string, compiler_version);
+
if (n_infiles == 0)
exit (0);
}
that correspond to the input files. */
outfiles = (char **) xmalloc (n_infiles * sizeof (char *));
- bzero (outfiles, n_infiles * sizeof (char *));
+ bzero ((char *) outfiles, n_infiles * sizeof (char *));
/* Record which files were specified explicitly as link input. */
register char *p;
int len;
+ if (cp->spec[0][0] == '#')
+ error ("%s: %s compiler not installed on this system",
+ input_filename, &cp->spec[0][1]);
+
input_basename = input_filename;
for (p = input_filename; *p; p++)
- if (*p == '/')
+ if (*p == '/' || *p == DIR_SEPARATOR)
input_basename = p + 1;
/* Find a suffix starting with the last period,
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
- putenv_from_prefixes (&exec_prefix, "COMPILER_PATH=");
- putenv_from_prefixes (&startfile_prefix, "LIBRARY_PATH=");
+ putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH=");
+ putenv_from_prefixes (&startfile_prefixes, "LIBRARY_PATH=");
/* Build COLLECT_GCC_OPTIONS to have all of the options specified to
the compiler. */
}
/* Warn if a -B option was specified but the prefix was never used. */
- unused_prefix_warnings (&exec_prefix);
- unused_prefix_warnings (&startfile_prefix);
+ unused_prefix_warnings (&exec_prefixes);
+ unused_prefix_warnings (&startfile_prefixes);
/* If options said don't run linker,
complain about input files to be given to the linker. */
||
(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)))))
+#else
&& !strcmp (cp->suffix,
name + length - strlen (cp->suffix))))
+#endif
{
if (cp->spec[0][0] == '@')
{
language = cp->spec[0] + 1;
new = (struct compiler *) xmalloc (sizeof (struct compiler));
new->suffix = cp->suffix;
- bcopy (lookup_compiler (NULL_PTR, 0, language)->spec,
- new->spec, sizeof new->spec);
+ bcopy ((char *) lookup_compiler (NULL_PTR, 0, language)->spec,
+ (char *) new->spec, sizeof new->spec);
return new;
}
/* A non-alias entry: return it. */
return value;
}
-/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
+/* This function is based on the one in libiberty. */
static char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
+concat VPROTO((char *first, ...))
{
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = xmalloc (len1 + len2 + len3 + 1);
+ register int length;
+ register char *newstr;
+ register char *end;
+ register char *arg;
+ va_list args;
+#ifndef __STDC__
+ char *first;
+#endif
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
+ /* First compute the size of the result and get sufficient memory. */
- return result;
+ VA_START (args, first);
+#ifndef __STDC__
+ first = va_arg (args, char *);
+#endif
+
+ arg = first;
+ length = 0;
+
+ while (arg != 0)
+ {
+ length += strlen (arg);
+ arg = va_arg (args, char *);
+ }
+
+ newstr = (char *) xmalloc (length + 1);
+ va_end (args);
+
+ /* Now copy the individual pieces to the result string. */
+
+ VA_START (args, first);
+#ifndef __STDC__
+ first = va_arg (args, char *);
+#endif
+
+ end = newstr;
+ arg = first;
+ while (arg != 0)
+ {
+ while (*arg)
+ *end++ = *arg++;
+ arg = va_arg (args, char *);
+ }
+ *end = '\000';
+ va_end (args);
+
+ return (newstr);
}
static char *
pfatal_with_name (name)
char *name;
{
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("%s: ", sys_errlist[errno], "");
- else
- s = "cannot open %s";
- fatal (s, name);
+ fatal ("%s: %s", name, my_strerror (errno));
}
static void
perror_with_name (name)
char *name;
{
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("%s: ", sys_errlist[errno], "");
- else
- s = "cannot open %s";
- error (s, name);
+ error ("%s: %s", name, my_strerror (errno));
}
static void
-perror_exec (name)
- char *name;
+pfatal_pexecute (errmsg_fmt, errmsg_arg)
+ char *errmsg_fmt;
+ char *errmsg_arg;
{
- char *s;
+ if (errmsg_arg)
+ {
+ /* Space for trailing '\0' is in %s. */
+ char *msg = xmalloc (strlen (errmsg_fmt) + strlen (errmsg_arg));
+ sprintf (msg, errmsg_fmt, errmsg_arg);
+ errmsg_fmt = msg;
+ }
- if (errno < sys_nerr)
- s = concat ("installation problem, cannot exec %s: ",
- sys_errlist[errno], "");
- else
- s = "installation problem, cannot exec %s";
- error (s, name);
+ fatal ("%s: %s", errmsg_fmt, my_strerror (errno));
}
/* More 'friendly' abort that prints the line and file.
VA_START (ap, format);
#ifndef __STDC__
- format = va_arg (ap, char*);
+ format = va_arg (ap, char *);
#endif
fprintf (stderr, "%s: ", programname);
VA_START (ap, format);
#ifndef __STDC__
- format = va_arg (ap, char*);
+ format = va_arg (ap, char *);
#endif
fprintf (stderr, "%s: ", programname);
/* We have a switch spec. */
validate_switches (p + 1);
+ p = libgcc_spec;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+
p = startfile_spec;
while (c = *p++)
if (c == '%' && *p == '{')
/* We have a switch spec. */
validate_switches (p + 1);
+
+#ifdef EXTRA_SPECS
+ {
+ int i;
+ for (i = 0; i < sizeof (extra_specs) / sizeof (extra_specs[0]); i++)
+ {
+ p = extra_specs[i].spec;
+ while (c = *p++)
+ if (c == '%' && *p == '{')
+ /* We have a switch spec. */
+ validate_switches (p + 1);
+ }
+ }
+#endif
+
}
/* Look at the switch-name that comes after START
}
}
}
+\f
+/* Check whether a particular argument was used. The first time we
+ canonialize the switches to keep only the ones we care about. */
+
+static int
+used_arg (p, len)
+ char *p;
+ int len;
+{
+ struct mswitchstr {
+ char *str;
+ char *replace;
+ int len;
+ int rep_len;
+ };
+
+ static struct mswitchstr *mswitches;
+ static int n_mswitches;
+ int i, j;
+
+ if (!mswitches)
+ {
+ struct mswitchstr *matches;
+ char *q;
+ int cnt = (*multilib_matches != '\0');
+
+ /* Break multilib_matches into the component strings of string and replacement
+ string */
+ for (p = multilib_matches; *p != '\0'; p++)
+ if (*p == ';')
+ cnt++;
+
+ matches = (struct mswitchstr *) alloca ((sizeof (struct mswitchstr)) * cnt);
+ i = 0;
+ q = multilib_matches;
+ while (*q != '\0')
+ {
+ matches[i].str = q;
+ while (*q != ' ')
+ {
+ if (*q == '\0')
+ abort ();
+ q++;
+ }
+ *q = '\0';
+ matches[i].len = q - matches[i].str;
+
+ matches[i].replace = ++q;
+ while (*q != ';' && *q != '\0')
+ {
+ if (*q == ' ')
+ abort ();
+ q++;
+ }
+ matches[i].rep_len = q - matches[i].replace;
+ i++;
+ if (*q == ';')
+ *q++ = '\0';
+ else
+ break;
+ }
+
+ /* Now build a list of the replacement string for switches that we care about */
+ mswitches = (struct mswitchstr *) xmalloc ((sizeof (struct mswitchstr)) * n_switches);
+ for (i = 0; i < n_switches; i++)
+ {
+ int xlen = strlen (switches[i].part1);
+ for (j = 0; j < cnt; j++)
+ if (xlen == matches[j].len && ! strcmp (switches[i].part1, matches[j].str))
+ {
+ mswitches[n_mswitches].str = matches[j].replace;
+ mswitches[n_mswitches].len = matches[j].rep_len;
+ mswitches[n_mswitches].replace = (char *)0;
+ mswitches[n_mswitches].rep_len = 0;
+ n_mswitches++;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < n_mswitches; i++)
+ if (len == mswitches[i].len && ! strncmp (p, mswitches[i].str, len))
+ return 1;
+
+ return 0;
+}
+
+static int
+default_arg (p, len)
+ char *p;
+ int len;
+{
+ char *start, *end;
+ int i;
+
+ for (start = multilib_defaults; *start != '\0'; start = end+1)
+ {
+ while (*start == ' ' || *start == '\t')
+ start++;
+
+ if (*start == '\0')
+ break;
+
+ for (end = start+1; *end != ' ' && *end != '\t' && *end != '\0'; end++)
+ ;
+
+ if ((end - start) == len && strncmp (p, start, len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Work out the subdirectory to use based on the
+ options. The format of multilib_select is a list of elements.
+ Each element is a subdirectory name followed by a list of options
+ followed by a semicolon. gcc will consider each line in turn. If
+ none of the options beginning with an exclamation point are
+ present, and all of the other options are present, that
+ subdirectory will be used. */
+
+static void
+set_multilib_dir ()
+{
+ char *p = multilib_select;
+ int this_path_len;
+ char *this_path, *this_arg;
+ int not_arg;
+ int ok;
+
+ while (*p != '\0')
+ {
+ /* Ignore newlines. */
+ if (*p == '\n')
+ {
+ ++p;
+ continue;
+ }
+
+ /* Get the initial path. */
+ this_path = p;
+ while (*p != ' ')
+ {
+ if (*p == '\0')
+ abort ();
+ ++p;
+ }
+ this_path_len = p - this_path;
+
+ /* Check the arguments. */
+ ok = 1;
+ ++p;
+ while (*p != ';')
+ {
+ if (*p == '\0')
+ abort ();
+
+ if (! ok)
+ {
+ ++p;
+ continue;
+ }
+
+ this_arg = p;
+ while (*p != ' ' && *p != ';')
+ {
+ if (*p == '\0')
+ abort ();
+ ++p;
+ }
+
+ if (*this_arg != '!')
+ not_arg = 0;
+ else
+ {
+ not_arg = 1;
+ ++this_arg;
+ }
+
+ /* If this is a default argument, we can just ignore it.
+ This is true even if this_arg begins with '!'. Beginning
+ with '!' does not mean that this argument is necessarily
+ inappropriate for this library: it merely means that
+ there is a more specific library which uses this
+ argument. If this argument is a default, we need not
+ consider that more specific library. */
+ if (! default_arg (this_arg, p - this_arg))
+ {
+ ok = used_arg (this_arg, p - this_arg);
+ if (not_arg)
+ ok = ! ok;
+ }
+
+ if (*p == ' ')
+ ++p;
+ }
+
+ if (ok)
+ {
+ if (this_path_len != 1
+ || this_path[0] != '.')
+ {
+ multilib_dir = xmalloc (this_path_len + 1);
+ strncpy (multilib_dir, this_path, this_path_len);
+ multilib_dir[this_path_len] = '\0';
+ }
+ break;
+ }
+
+ ++p;
+ }
+}
+
+/* Print out the multiple library subdirectory selection
+ information. This prints out a series of lines. Each line looks
+ like SUBDIRECTORY;@OPTION@OPTION, with as many options as is
+ required. Only the desired options are printed out, the negative
+ matches. The options are print without a leading dash. There are
+ no spaces to make it easy to use the information in the shell.
+ Each subdirectory is printed only once. This assumes the ordering
+ generated by the genmultilib script. */
+
+static void
+print_multilib_info ()
+{
+ char *p = multilib_select;
+ char *last_path = 0, *this_path;
+ int skip;
+ int last_path_len = 0;
+
+ while (*p != '\0')
+ {
+ /* Ignore newlines. */
+ if (*p == '\n')
+ {
+ ++p;
+ continue;
+ }
+
+ /* Get the initial path. */
+ this_path = p;
+ while (*p != ' ')
+ {
+ if (*p == '\0')
+ abort ();
+ ++p;
+ }
+
+ /* If this is a duplicate, skip it. */
+ skip = (last_path != 0 && p - this_path == last_path_len
+ && ! strncmp (last_path, this_path, last_path_len));
+
+ last_path = this_path;
+ last_path_len = p - this_path;
+
+ /* If this directory requires any default arguments, we can skip
+ it. We will already have printed a directory identical to
+ this one which does not require that default argument. */
+ if (! skip)
+ {
+ char *q;
+
+ q = p + 1;
+ while (*q != ';')
+ {
+ char *arg;
+
+ if (*q == '\0')
+ abort ();
+
+ if (*q == '!')
+ arg = NULL;
+ else
+ arg = q;
+
+ while (*q != ' ' && *q != ';')
+ {
+ if (*q == '\0')
+ abort ();
+ ++q;
+ }
+
+ if (arg != NULL
+ && default_arg (arg, q - arg))
+ {
+ skip = 1;
+ break;
+ }
+
+ if (*q == ' ')
+ ++q;
+ }
+ }
+
+ if (! skip)
+ {
+ char *p1;
+
+ for (p1 = last_path; p1 < p; p1++)
+ putchar (*p1);
+ putchar (';');
+ }
+
+ ++p;
+ while (*p != ';')
+ {
+ int use_arg;
+
+ if (*p == '\0')
+ abort ();
+
+ if (skip)
+ {
+ ++p;
+ continue;
+ }
+
+ use_arg = *p != '!';
+
+ if (use_arg)
+ putchar ('@');
+
+ while (*p != ' ' && *p != ';')
+ {
+ if (*p == '\0')
+ abort ();
+ if (use_arg)
+ putchar (*p);
+ ++p;
+ }
+
+ if (*p == ' ')
+ ++p;
+ }
+
+ if (! skip)
+ {
+ /* If there are extra options, print them now */
+ if (multilib_extra && *multilib_extra)
+ {
+ int print_at = TRUE;
+ char *q;
+
+ for (q = multilib_extra; *q != '\0'; q++)
+ {
+ if (*q == ' ')
+ print_at = TRUE;
+ else
+ {
+ if (print_at)
+ putchar ('@');
+ putchar (*q);
+ print_at = FALSE;
+ }
+ }
+ }
+ putchar ('\n');
+ }
+
+ ++p;
+ }
+}