/* Compiler driver program that can handle many languages.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ 2010
+ Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to 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!!!! */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This program is the user interface to the C compiler and possibly to
other compilers. It is used because compilation is a complicated procedure
4. If the argument takes an argument, e.g., `--baz argument1',
modify either DEFAULT_SWITCH_TAKES_ARG or
- DEFAULT_WORD_SWITCH_TAKES_ARG in this file. Omit the first `-'
+ DEFAULT_WORD_SWITCH_TAKES_ARG in gcc.h. Omit the first `-'
from `--baz'.
5. Document the option in this file's display_help(). If the
#if ! defined( SIGCHLD ) && defined( SIGCLD )
# define SIGCHLD SIGCLD
#endif
+#include "xregex.h"
#include "obstack.h"
#include "intl.h"
#include "prefix.h"
#include "gcc.h"
#include "flags.h"
+#include "opts.h"
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
+#ifdef HAVE_MMAP_FILE
+# include <sys/mman.h>
+# ifdef HAVE_MINCORE
+/* This is on Solaris. */
+# include <sys/types.h>
+# endif
#endif
-#if defined (HAVE_DECL_GETRUSAGE) && !HAVE_DECL_GETRUSAGE
-extern int getrusage (int, struct rusage *);
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void *)-1)
#endif
/* By default there is no special suffix for target executables. */
/* Flag set by cppspec.c to 1. */
int is_cpp_driver;
+/* Flag set to nonzero if an @file argument has been supplied to gcc. */
+static bool at_file_supplied;
+
/* Flag saying to pass the greatest exit code returned by a sub-process
to the calling program. */
static int pass_exit_codes;
static int print_multi_directory;
+static int print_sysroot;
+
/* Flag saying to print the relative path we'd use to
find OS libraries given the current compiler flags. */
static int print_help_list;
+/* Flag saying to print the version of gcc and its sub-processes. */
+
+static int print_version;
+
+/* Flag saying to print the sysroot suffix used for searching for
+ headers. */
+
+static int print_sysroot_headers_suffix;
+
/* Flag indicating whether we should print the command and arguments */
static int verbose_flag;
shell scripts to capture the driver-generated command line. */
static int verbose_only_flag;
-/* Flag indicating to print target specific command line options. */
+/* Flag indicating how to print command line options of sub-processes. */
-static int target_help_flag;
+static int print_subprocess_help;
/* Flag indicating whether we should report subprocess execution times
(if this is supported by the system - see pexecute.c). */
static int report_times;
+/* Whether we should report subprocess execution times to a file. */
+
+FILE *report_times_to_file = NULL;
+
/* Nonzero means place this string before uses of /, so that include
and library files can be found in an alternate location. */
/* Nonzero means write "temp" files in source directory
and use the source file's name in them, and don't delete them. */
-static int save_temps_flag;
+static enum save_temps {
+ SAVE_TEMPS_NONE, /* no -save-temps */
+ SAVE_TEMPS_CWD, /* -save-temps in current directory */
+ SAVE_TEMPS_OBJ /* -save-temps in object directory */
+} save_temps_flag;
+
+/* Output file to use to get the object directory for -save-temps=obj */
+static char *save_temps_prefix = 0;
+static size_t save_temps_length = 0;
+
+/* Nonzero means pass multiple source files to the compiler at one time. */
+
+static int combine_flag = 0;
/* Nonzero means use pipes to communicate between subprocesses.
Overridden by either of the above two flags. */
static const char *compiler_version;
-/* The target version specified with -V */
+/* The target version. */
static const char *const spec_version = DEFAULT_TARGET_VERSION;
-/* The target machine specified with -b. */
+/* The target machine. */
static const char *spec_machine = DEFAULT_TARGET_MACHINE;
/* Nonzero if cross-compiling.
When -b is used, the value comes from the `specs' file. */
-#ifdef CROSS_COMPILE
+#ifdef CROSS_DIRECTORY_STRUCTURE
static const char *cross_compile = "1";
#else
static const char *cross_compile = "0";
switch. The only case we support now is simply appending or deleting a
string to or from the end of the first part of the configuration name. */
+enum add_del {ADD, DELETE};
+
static const struct modify_target
{
const char *const sw;
- const enum add_del {ADD, DELETE} add_del;
+ const enum add_del add_del;
const char *const str;
}
modify_target[] = MODIFY_TARGET_NAME;
static struct obstack collect_obstack;
-/* These structs are used to collect resource usage information for
- subprocesses. */
-#ifdef HAVE_GETRUSAGE
-static struct rusage rus, prus;
-#endif
+/* This is a list of a wrapper program and its arguments.
+ e.g. wrapper_string of "strace,-c"
+ will cause all programs to run as
+ strace -c program arguments
+ instead of just
+ program arguments */
+static const char *wrapper_string;
/* Forward declaration for prototypes. */
struct path_prefix;
+struct prefix_list;
static void init_spec (void);
static void store_arg (const char *, int, int);
+static void insert_wrapper (const char *);
static char *load_specs (const char *);
static void read_specs (const char *, int);
static void set_spec (const char *, const char *);
static struct compiler *lookup_compiler (const char *, size_t, const char *);
-static char *build_search_list (struct path_prefix *, const char *, int);
-static void putenv_from_prefixes (struct path_prefix *, const char *);
+static char *build_search_list (const struct path_prefix *, const char *,
+ bool, bool);
+static void xputenv (const char *);
+static void putenv_from_prefixes (const struct path_prefix *, const char *,
+ bool);
static int access_check (const char *, int);
-static char *find_a_file (struct path_prefix *, const char *, int, int);
+static char *find_a_file (const struct path_prefix *, const char *, int, bool);
static void add_prefix (struct path_prefix *, const char *, const char *,
- int, int, int *, int);
+ int, int, int);
static void add_sysrooted_prefix (struct path_prefix *, const char *,
- const char *, int, int, int *, int);
+ const char *, int, int, int);
static void translate_options (int *, const char *const **);
static char *skip_whitespace (char *);
static void delete_if_ordinary (const char *);
static void do_option_spec (const char *, const char *);
static void do_self_spec (const char *);
static const char *find_file (const char *);
-static int is_directory (const char *, const char *, int);
+static int is_directory (const char *, bool);
static const char *validate_switches (const char *);
static void validate_all_switches (void);
static inline void validate_switches_from_spec (const char *);
static void set_multilib_dir (void);
static void print_multilib_info (void);
static void perror_with_name (const char *);
-static void pfatal_pexecute (const char *, const char *) ATTRIBUTE_NORETURN;
+static void fatal_ice (const char *, ...) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
static void notice (const char *, ...) ATTRIBUTE_PRINTF_1;
static void display_help (void);
static void add_preprocessor_option (const char *, int);
static void add_assembler_option (const char *, int);
static void add_linker_option (const char *, int);
-static void process_command (int, const char *const *);
+static void process_command (int, const char **);
static int execute (void);
static void alloc_args (void);
static void clear_args (void);
static void fatal_error (int);
-#ifdef ENABLE_SHARED_LIBGCC
+#if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC)
static void init_gcc_specs (struct obstack *, const char *, const char *,
const char *);
#endif
static const char *convert_filename (const char *, int, int);
#endif
+static const char *getenv_spec_function (int, const char **);
static const char *if_exists_spec_function (int, const char **);
static const char *if_exists_else_spec_function (int, const char **);
+static const char *replace_outfile_spec_function (int, const char **);
+static const char *version_compare_spec_function (int, const char **);
+static const char *include_spec_function (int, const char **);
+static const char *find_file_spec_function (int, const char **);
+static const char *print_asm_header_spec_function (int, const char **);
+static const char *compare_debug_dump_opt_spec_function (int, const char **);
+static const char *compare_debug_self_opt_spec_function (int, const char **);
+static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
\f
/* The Specs Language
%i substitute the name of the input file being processed.
%b substitute the basename of the input file being processed.
This is the substring up to (and not including) the last period
- and not including the directory.
+ and not including the directory unless -save-temps was specified
+ to put temporaries in a different location.
%B same as %b, but include the file suffix (text after the last period).
%gSUFFIX
substitute a file name that has suffix SUFFIX and is chosen
chosen in a way that is hard to predict even when previously
chosen file names are known. For example, `%g.s ... %g.o ... %g.s'
might turn into `ccUVUUAU.s ccXYAXZ12.o ccUVUUAU.s'. SUFFIX matches
- the regexp "[.A-Za-z]*%O"; "%O" is treated exactly as if it
+ the regexp "[.0-9A-Za-z]*%O"; "%O" is treated exactly as if it
had been pre-processed. Previously, %g was simply substituted
with a file name chosen once per compilation, without regard
to any appended suffix (which was therefore treated just like
it is subsequently output with %*. SUFFIX is terminated by the next
space or %.
%d marks the argument containing or following the %d as a
- temporary file name, so that that file will be deleted if CC exits
+ temporary file name, so that that file will be deleted if GCC exits
successfully. Unlike %g, this contributes no text to the argument.
%w marks the argument containing or following the %w as the
"output file" of this compilation. This puts the argument
SUFFIX characters following %O as they would following, for
example, `.o'.
%I Substitute any of -iprefix (made from GCC_EXEC_PREFIX), -isysroot
- (made from TARGET_SYSTEM_ROOT), and -isystem (made from COMPILER_PATH
- and -B options) as necessary.
+ (made from TARGET_SYSTEM_ROOT), -isystem (made from COMPILER_PATH
+ and -B options) and -imultilib as necessary.
%s current argument is the name of a library or startup file of some sort.
Search for that file in a standard list of directories
and substitute the full name found.
%l process LINK_SPEC as a spec.
%L process LIB_SPEC as a spec.
%G process LIBGCC_SPEC as a spec.
- %M output multilib_dir with directory separators replaced with "_";
- if multilib_dir is not set or is ".", output "".
+ %R Output the concatenation of target_system_root and
+ target_sysroot_suffix.
%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 CPP_SPEC as a spec.
argument vector in the usual fashion. The function returns
a string which is processed as if it had appeared literally
as part of the current spec.
- %{S} substitutes the -S switch, if that switch was given to CC.
+ %{S} substitutes the -S switch, if that switch was given to GCC.
If that switch was not specified, this substitutes nothing.
Here S is a metasyntactic variable.
- %{S*} substitutes all the switches specified to CC whose names start
+ %{S*} substitutes all the switches specified to GCC whose names start
with -S. This is used for -o, -I, etc; switches that take
- arguments. CC considers `-o foo' as being one switch whose
+ arguments. GCC considers `-o foo' as being one switch whose
name starts with `o'. %{o*} would substitute this text,
including the space; thus, two arguments would be generated.
%{S*&T*} likewise, but preserve order of S and T options (the order
of ampersand-separated variables; for each the wild card is
optional. Useful for CPP as %{D*&U*&A*}.
- %{S:X} substitutes X, if the -S switch was given to CC.
- %{!S:X} substitutes X, if the -S switch was NOT given to CC.
+ %{S:X} substitutes X, if the -S switch was given to GCC.
+ %{!S:X} substitutes X, if the -S switch was NOT given to GCC.
%{S*:X} substitutes X if one or more switches whose names start
- with -S was given to CC. Normally X is substituted only
+ with -S was given to GCC. Normally X is substituted only
once, no matter how many such switches appeared. However,
if %* appears somewhere in X, then X will be substituted
once for each matching switch, with the %* replaced by the
part of that switch that matched the '*'.
%{.S:X} substitutes X, if processing a file with suffix S.
%{!.S:X} substitutes X, if NOT processing a file with suffix S.
+ %{,S:X} substitutes X, if processing a file which will use spec S.
+ %{!,S:X} substitutes X, if NOT processing a file which will use spec S.
- %{S|T:X} substitutes X if either -S or -T was given to CC. This may be
- combined with !, ., and * as above binding stronger than the OR.
+ %{S|T:X} substitutes X if either -S or -T was given to GCC. This may be
+ combined with '!', '.', ',', and '*' as above binding stronger
+ than the OR.
If %* appears in X, all of the alternatives must be starred, and
only the first matching alternative is substituted.
- %{S:X; if S was given to CC, substitutes X;
- T:Y; else if T was given to CC, substitutes Y;
+ %{S:X; if S was given to GCC, substitutes X;
+ T:Y; else if T was given to GCC, substitutes Y;
:D} else substitutes D. There can be as many clauses as you need.
- This may be combined with ., !, |, and * as above.
+ This may be combined with '.', '!', ',', '|', and '*' as above.
%(Spec) processes a specification defined in a specs file as *Spec:
%[Spec] as above, but put __ around -D arguments
that a command should be piped to the following command, but only if -pipe
is specified.
-Note that it is built into CC which switches take arguments and which
+Note that it is built into GCC which switches take arguments and which
do not. You might think it would be useful to generalize this to
allow each compiler's spec to say which switches take arguments. But
-this cannot be done in a consistent fashion. CC cannot even decide
+this cannot be done in a consistent fashion. GCC cannot even decide
which input files have been specified without knowing which switches
take arguments, and it must know which input files to compile in order
to tell which compilers to run.
-CC also knows implicitly that arguments starting in `-l' are to be
+GCC also knows implicitly that arguments starting in `-l' are to be
treated as compiler output files, and passed to the linker in their
proper position among the other output files. */
\f
#define LIB_SPEC "%{!shared:%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}"
#endif
+/* mudflap specs */
+#ifndef MFWRAP_SPEC
+/* XXX: valid only for GNU ld */
+/* XXX: should exactly match hooks provided by libmudflap.a */
+#define MFWRAP_SPEC " %{static: %{fmudflap|fmudflapth: \
+ --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc\
+ --wrap=mmap --wrap=munmap --wrap=alloca\
+} %{fmudflapth: --wrap=pthread_create\
+}} %{fmudflap|fmudflapth: --wrap=main}"
+#endif
+#ifndef MFLIB_SPEC
+#define MFLIB_SPEC "%{fmudflap|fmudflapth: -export-dynamic}"
+#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)
+#if defined(REAL_LIBGCC_SPEC)
+#define LIBGCC_SPEC REAL_LIBGCC_SPEC
+#elif defined(LINK_LIBGCC_SPECIAL_1)
/* Have gcc do the search for libgcc.a. */
#define LIBGCC_SPEC "libgcc.a%s"
#else
#endif
/* config.h can define SWITCHES_NEED_SPACES to control which options
- require spaces between the option and the argument. */
+ require spaces between the option and the argument.
+
+ We define SWITCHES_NEED_SPACES to include "o" by default. This
+ causes "-ofoo.o" to be split into "-o foo.o" during the initial
+ processing of the command-line, before being seen by the specs
+ machinery. This makes sure we record "foo.o" as the temporary file
+ to be deleted in the case of error, rather than "-ofoo.o". */
#ifndef SWITCHES_NEED_SPACES
-#define SWITCHES_NEED_SPACES ""
+#define SWITCHES_NEED_SPACES "o"
#endif
/* config.h can define ENDFILE_SPEC to override the default crtn files. */
#define LINKER_NAME "collect2"
#endif
+#ifdef HAVE_AS_DEBUG_PREFIX_MAP
+#define ASM_MAP " %{fdebug-prefix-map=*:--debug-prefix-map %*}"
+#else
+#define ASM_MAP ""
+#endif
+
/* Define ASM_DEBUG_SPEC to be a spec suitable for translating '-g'
to the assembler. */
#ifndef ASM_DEBUG_SPEC
# if defined(DBX_DEBUGGING_INFO) && defined(DWARF2_DEBUGGING_INFO) \
&& defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
-# define ASM_DEBUG_SPEC \
- (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG \
- ? "%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}" \
- : "%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}")
+# define ASM_DEBUG_SPEC \
+ (PREFERRED_DEBUGGING_TYPE == DBX_DEBUG \
+ ? "%{!g0:%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}}" ASM_MAP \
+ : "%{!g0:%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}}" ASM_MAP)
# else
# if defined(DBX_DEBUGGING_INFO) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
-# define ASM_DEBUG_SPEC "%{g*:--gstabs}"
+# define ASM_DEBUG_SPEC "%{g*:%{!g0:--gstabs}}" ASM_MAP
# endif
# if defined(DWARF2_DEBUGGING_INFO) && defined(HAVE_AS_GDWARF2_DEBUG_FLAG)
-# define ASM_DEBUG_SPEC "%{g*:--gdwarf2}"
+# define ASM_DEBUG_SPEC "%{g*:%{!g0:--gdwarf2}}" ASM_MAP
# endif
# endif
#endif
#define LINK_GCC_C_SEQUENCE_SPEC "%G %L %G"
#endif
+#ifndef LINK_SSP_SPEC
+#ifdef TARGET_LIBC_PROVIDES_SSP
+#define LINK_SSP_SPEC "%{fstack-protector:}"
+#else
+#define LINK_SSP_SPEC "%{fstack-protector|fstack-protector-all:-lssp_nonshared -lssp}"
+#endif
+#endif
+
#ifndef LINK_PIE_SPEC
#ifdef HAVE_LD_PIE
#define LINK_PIE_SPEC "%{pie:-pie} "
#endif
#endif
+#ifndef LINK_BUILDID_SPEC
+# if defined(HAVE_LD_BUILDID) && defined(ENABLE_LD_BUILDID)
+# define LINK_BUILDID_SPEC "%{!r:--build-id} "
+# endif
+#endif
+
+
/* -u* was put back because both BSD and SysV seem to support it. */
/* %{static:} simply prevents an error message if the target machine
doesn't handle -static. */
/* 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. */
+/* We pass any -flto and -fwhopr flags on to the linker, which is expected
+ to understand them. In practice, this means it had better be collect2. */
#ifndef LINK_COMMAND_SPEC
#define LINK_COMMAND_SPEC "\
%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
- %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
+ %(linker) \
+ %{fuse-linker-plugin: \
+ -plugin %(linker_plugin_file) \
+ -plugin-opt=%(lto_wrapper) \
+ -plugin-opt=-fresolution=%u.res \
+ %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)} \
+ %{static:-plugin-opt=-pass-through=-lc} \
+ } \
+ %{flto} %{fwhopr*} %l " LINK_PIE_SPEC \
+ "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
%{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
- %{static:} %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate:-lgcov}\
- %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}}\
+ %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
+ %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
+ %{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
+ %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
%{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
#endif
#ifndef LINK_LIBGCC_SPEC
-# ifdef LINK_LIBGCC_SPECIAL
-/* Don't generate -L options for startfile prefix list. */
-# define LINK_LIBGCC_SPEC ""
-# else
-/* Do generate them. */
-# define LINK_LIBGCC_SPEC "%D"
-# endif
+/* Generate -L options for startfile prefix list. */
+# define LINK_LIBGCC_SPEC "%D"
#endif
#ifndef STARTFILE_PREFIX_SPEC
# define STARTFILE_PREFIX_SPEC ""
#endif
+#ifndef SYSROOT_SPEC
+# define SYSROOT_SPEC "--sysroot=%R"
+#endif
+
#ifndef SYSROOT_SUFFIX_SPEC
# define SYSROOT_SUFFIX_SPEC ""
#endif
static const char *cc1_spec = CC1_SPEC;
static const char *cc1plus_spec = CC1PLUS_SPEC;
static const char *link_gcc_c_sequence_spec = LINK_GCC_C_SEQUENCE_SPEC;
+static const char *link_ssp_spec = LINK_SSP_SPEC;
static const char *asm_spec = ASM_SPEC;
static const char *asm_final_spec = ASM_FINAL_SPEC;
static const char *link_spec = LINK_SPEC;
static const char *lib_spec = LIB_SPEC;
+static const char *mfwrap_spec = MFWRAP_SPEC;
+static const char *mflib_spec = MFLIB_SPEC;
+static const char *link_gomp_spec = "";
static const char *libgcc_spec = LIBGCC_SPEC;
static const char *endfile_spec = ENDFILE_SPEC;
static const char *startfile_spec = STARTFILE_SPEC;
static const char *switches_need_spaces = SWITCHES_NEED_SPACES;
static const char *linker_name_spec = LINKER_NAME;
+static const char *linker_plugin_file_spec = "";
+static const char *lto_wrapper_spec = "";
+static const char *lto_gcc_spec = "";
+static const char *lto_libgcc_spec = "";
static const char *link_command_spec = LINK_COMMAND_SPEC;
static const char *link_libgcc_spec = LINK_LIBGCC_SPEC;
static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC;
+static const char *sysroot_spec = SYSROOT_SPEC;
static const char *sysroot_suffix_spec = SYSROOT_SUFFIX_SPEC;
static const char *sysroot_hdrs_suffix_spec = SYSROOT_HEADERS_SUFFIX_SPEC;
file that happens to exist is up-to-date. */
static const char *cpp_unique_options =
"%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}}\
- %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %I\
+ %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I\
%{MD:-MD %{!o:%b.d}%{o*:%.d%*}}\
%{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}}\
%{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
- %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}}\
- %{trigraphs} %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\
+ %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}}\
+ %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD}\
+ %{!iplugindir*:%{fplugin*:-iplugindir=%:find-file(plugin)}}\
+ %{H} %C %{D*&U*&A*} %{i*} %Z %i\
+ %{fmudflap:-D_MUDFLAP -include mf-runtime.h}\
+ %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h}\
%{E|M|MM:%W{o*}}";
/* This contains cpp options which are common with cc1_options and are passed
options used to set target flags. Those special target flags settings may
in turn cause preprocessor symbols to be defined specially. */
static const char *cpp_options =
-"%(cpp_unique_options) %1 %{m*} %{std*} %{ansi} %{W*&pedantic*} %{w} %{f*}\
- %{g*:%{!g0:%{!fno-working-directory:-fworking-directory}}} %{O*} %{undef}";
+"%(cpp_unique_options) %1 %{m*} %{std*&ansi&trigraphs} %{W*&pedantic*} %{w}\
+ %{f*} %{g*:%{!g0:%{g*} %{!fno-working-directory:-fworking-directory}}} %{O*}\
+ %{undef} %{save-temps*:-fpch-preprocess}";
/* This contains cpp options which are not passed when the preprocessor
output will be used by another program. */
static const char *cpp_debug_options = "%{d*}";
-/* NB: This is shared amongst all front-ends. */
+/* NB: This is shared amongst all front-ends, except for Ada. */
static const char *cc1_options =
"%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
- %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\
- -auxbase%{c|S:%{o*:-strip %*}%{!o*: %b}}%{!c:%{!S: %b}}\
- %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi}\
+ %{!iplugindir*:%{fplugin*:-iplugindir=%:find-file(plugin)}}\
+ %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{a*}\
+ %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
+ %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
+ %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
%{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
%{Qn:-fno-ident} %{--help:--help}\
%{--target-help:--target-help}\
+ %{--help=*:--help=%(VALUE)}\
%{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
- %{fsyntax-only:-o %j} %{-param*}";
+ %{fsyntax-only:-o %j} %{-param*}\
+ %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants}\
+ %{coverage:-fprofile-arcs -ftest-coverage}";
static const char *asm_options =
+"%{--target-help:%:print-asm-header()} "
+#if HAVE_GNU_AS
+/* If GNU AS is used, then convert -w (no warnings), -I, and -v
+ to the assembler equivalents. */
+"%{v} %{w:-W} %{I*} "
+#endif
"%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}";
static const char *invoke_as =
#ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
-"%{!S:-o %|.s |\n as %(asm_options) %|.s %A }";
+"%{!fwpa:\
+ %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
+ %{!S:-o %|.s |\n as %(asm_options) %|.s %A }\
+ }";
#else
-"%{!S:-o %|.s |\n as %(asm_options) %m.s %A }";
+"%{!fwpa:\
+ %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\
+ %{!S:-o %|.s |\n as %(asm_options) %m.s %A }\
+ }";
#endif
/* Some compilers have limits on line lengths, and the multilib_select
#define DRIVER_SELF_SPECS ""
#endif
-static const char *const driver_self_specs[] = { DRIVER_SELF_SPECS };
+/* Adding -fopenmp should imply pthreads. This is particularly important
+ for targets that use different start files and suchlike. */
+#ifndef GOMP_SELF_SPECS
+#define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: -pthread}"
+#endif
+
+static const char *const driver_self_specs[] = {
+ "%{fdump-final-insns:-fdump-final-insns=.} %<fdump-final-insns",
+ DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS
+};
#ifndef OPTION_DEFAULT_SPECS
#define OPTION_DEFAULT_SPECS { "", "" }
#ifdef HAVE_TARGET_EXECUTABLE_SUFFIX
/* This defines which switches stop a full compilation. */
#define DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR) \
- ((CHAR) == 'c' || (CHAR) == 'S')
+ ((CHAR) == 'c' || (CHAR) == 'S' || (CHAR) == 'E')
#ifndef SWITCH_CURTAILS_COMPILATION
#define SWITCH_CURTAILS_COMPILATION(CHAR) \
const char *cpp_spec; /* If non-NULL, substitute this spec
for `%C', rather than the usual
cpp_spec. */
+ const int combinable; /* If nonzero, compiler can deal with
+ multiple source files at once (IMA). */
+ const int needs_preprocessing; /* If nonzero, source files need to
+ be run through a preprocessor. */
};
/* Pointer to a vector of `struct compiler' that gives the spec for
were not present when we built the driver, we will hit these copies
and be given a more meaningful error than "file not used since
linking is not done". */
- {".m", "#Objective-C", 0}, {".mi", "#Objective-C", 0},
- {".cc", "#C++", 0}, {".cxx", "#C++", 0}, {".cpp", "#C++", 0},
- {".cp", "#C++", 0}, {".c++", "#C++", 0}, {".C", "#C++", 0},
- {".CPP", "#C++", 0}, {".ii", "#C++", 0},
- {".ads", "#Ada", 0}, {".adb", "#Ada", 0},
- {".f", "#Fortran", 0}, {".for", "#Fortran", 0}, {".fpp", "#Fortran", 0},
- {".F", "#Fortran", 0}, {".FOR", "#Fortran", 0}, {".FPP", "#Fortran", 0},
- {".r", "#Ratfor", 0},
- {".p", "#Pascal", 0}, {".pas", "#Pascal", 0},
- {".java", "#Java", 0}, {".class", "#Java", 0},
- {".zip", "#Java", 0}, {".jar", "#Java", 0},
+ {".m", "#Objective-C", 0, 0, 0}, {".mi", "#Objective-C", 0, 0, 0},
+ {".mm", "#Objective-C++", 0, 0, 0}, {".M", "#Objective-C++", 0, 0, 0},
+ {".mii", "#Objective-C++", 0, 0, 0},
+ {".cc", "#C++", 0, 0, 0}, {".cxx", "#C++", 0, 0, 0},
+ {".cpp", "#C++", 0, 0, 0}, {".cp", "#C++", 0, 0, 0},
+ {".c++", "#C++", 0, 0, 0}, {".C", "#C++", 0, 0, 0},
+ {".CPP", "#C++", 0, 0, 0}, {".ii", "#C++", 0, 0, 0},
+ {".ads", "#Ada", 0, 0, 0}, {".adb", "#Ada", 0, 0, 0},
+ {".f", "#Fortran", 0, 0, 0}, {".F", "#Fortran", 0, 0, 0},
+ {".for", "#Fortran", 0, 0, 0}, {".FOR", "#Fortran", 0, 0, 0},
+ {".ftn", "#Fortran", 0, 0, 0}, {".FTN", "#Fortran", 0, 0, 0},
+ {".fpp", "#Fortran", 0, 0, 0}, {".FPP", "#Fortran", 0, 0, 0},
+ {".f90", "#Fortran", 0, 0, 0}, {".F90", "#Fortran", 0, 0, 0},
+ {".f95", "#Fortran", 0, 0, 0}, {".F95", "#Fortran", 0, 0, 0},
+ {".f03", "#Fortran", 0, 0, 0}, {".F03", "#Fortran", 0, 0, 0},
+ {".f08", "#Fortran", 0, 0, 0}, {".F08", "#Fortran", 0, 0, 0},
+ {".r", "#Ratfor", 0, 0, 0},
+ {".p", "#Pascal", 0, 0, 0}, {".pas", "#Pascal", 0, 0, 0},
+ {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
+ {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
/* Next come the entries for C. */
- {".c", "@c", 0},
+ {".c", "@c", 0, 1, 1},
{"@c",
/* cc1 has an integrated ISO C preprocessor. We should invoke the
external preprocessor if -save-temps is given. */
%{!E:%{!M:%{!MM:\
%{traditional|ftraditional:\
%eGNU C no longer supports -traditional without -E}\
- %{save-temps|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
- %(cpp_options) -o %{save-temps:%b.i} %{!save-temps:%g.i} \n\
- cc1 -fpreprocessed %{save-temps:%b.i} %{!save-temps:%g.i} \
+ %{!combine:\
+ %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
+ %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
+ cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
%(cc1_options)}\
- %{!save-temps:%{!traditional-cpp:%{!no-integrated-cpp:\
+ %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
cc1 %(cpp_unique_options) %(cc1_options)}}}\
- %{!fsyntax-only:%(invoke_as)}}}}", 0},
+ %{!fsyntax-only:%(invoke_as)}} \
+ %{combine:\
+ %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
+ %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i}}\
+ %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
+ cc1 %(cpp_unique_options) %(cc1_options)}}\
+ %{!fsyntax-only:%(invoke_as)}}}}}}", 0, 1, 1},
{"-",
- "%{!E:%e-E required when input is from standard input}\
- %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0},
- {".h", "@c-header", 0},
+ "%{!E:%e-E or -x required when input is from standard input}\
+ %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0, 0, 0},
+ {".h", "@c-header", 0, 0, 0},
{"@c-header",
/* cc1 has an integrated ISO C preprocessor. We should invoke the
external preprocessor if -save-temps is given. */
"%{E|M|MM:%(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)}\
%{!E:%{!M:%{!MM:\
- %{save-temps|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
- %(cpp_options) -o %{save-temps:%b.i} %{!save-temps:%g.i} \n\
- cc1 -fpreprocessed %{save-temps:%b.i} %{!save-temps:%g.i} \
+ %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
+ %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
+ cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
%(cc1_options)\
-o %g.s %{!o*:--output-pch=%i.gch}\
%W{o*:--output-pch=%*}%V}\
- %{!save-temps:%{!traditional-cpp:%{!no-integrated-cpp:\
+ %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
cc1 %(cpp_unique_options) %(cc1_options)\
-o %g.s %{!o*:--output-pch=%i.gch}\
- %W{o*:--output-pch=%*}%V}}}}}}", 0},
- {".i", "@cpp-output", 0},
+ %W{o*:--output-pch=%*}%V}}}}}}", 0, 0, 0},
+ {".i", "@cpp-output", 0, 1, 0},
{"@cpp-output",
- "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0},
- {".s", "@assembler", 0},
+ "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 1, 0},
+ {".s", "@assembler", 0, 1, 0},
{"@assembler",
- "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0},
- {".S", "@assembler-with-cpp", 0},
+ "%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0, 1, 0},
+ {".sx", "@assembler-with-cpp", 0, 1, 0},
+ {".S", "@assembler-with-cpp", 0, 1, 0},
{"@assembler-with-cpp",
#ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
- "%(trad_capable_cpp) -lang-asm %(cpp_options)\
+ "%(trad_capable_cpp) -lang-asm %(cpp_options) -fno-directives-only\
%{E|M|MM:%(cpp_debug_options)}\
%{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\
as %(asm_debug) %(asm_options) %|.s %A }}}}"
#else
- "%(trad_capable_cpp) -lang-asm %(cpp_options)\
+ "%(trad_capable_cpp) -lang-asm %(cpp_options) -fno-directives-only\
%{E|M|MM:%(cpp_debug_options)}\
%{!M:%{!MM:%{!E:%{!S:-o %|.s |\n\
as %(asm_debug) %(asm_options) %m.s %A }}}}"
#endif
- , 0},
+ , 0, 1, 0},
#include "specs.h"
/* Mark end of table. */
- {0, 0, 0}
+ {0, 0, 0, 0, 0}
};
/* Number of elements in default_compilers, not counting the terminator. */
{"--classpath", "-fclasspath=", "aj"},
{"--bootclasspath", "-fbootclasspath=", "aj"},
{"--CLASSPATH", "-fclasspath=", "aj"},
+ {"--combine", "-combine", 0},
{"--comments", "-C", 0},
{"--comments-in-macros", "-CC", 0},
{"--compile", "-c", 0},
{"--dependencies", "-M", 0},
{"--dump", "-d", "a"},
{"--dumpbase", "-dumpbase", "a"},
+ {"--dumpdir", "-dumpdir", "a"},
+ {"--encoding", "-fencoding=", "aj"},
{"--entry", "-e", 0},
{"--extra-warnings", "-W", 0},
+ {"--extdirs", "-fextdirs=", "aj"},
{"--for-assembler", "-Wa", "a"},
{"--for-linker", "-Xlinker", "a"},
{"--force-link", "-u", "a"},
+ {"--coverage", "-coverage", 0},
{"--imacros", "-imacros", "a"},
{"--include", "-include", "a"},
{"--include-barrier", "-I-", 0},
{"--library-directory", "-L", "a"},
{"--machine", "-m", "aj"},
{"--machine-", "-m", "*j"},
+ {"--no-canonical-prefixes", "-no-canonical-prefixes", 0},
{"--no-integrated-cpp", "-no-integrated-cpp", 0},
{"--no-line-commands", "-P", 0},
{"--no-precompiled-includes", "-noprecomp", 0},
{"--output", "-o", "a"},
{"--output-class-directory", "-foutput-class-dir=", "ja"},
{"--param", "--param", "a"},
+ {"--pass-exit-codes", "-pass-exit-codes", 0},
{"--pedantic", "-pedantic", 0},
{"--pedantic-errors", "-pedantic-errors", 0},
{"--pie", "-pie", 0},
{"--print-multi-directory", "-print-multi-directory", 0},
{"--print-multi-os-directory", "-print-multi-os-directory", 0},
{"--print-prog-name", "-print-prog-name=", "aj"},
+ {"--print-sysroot", "-print-sysroot", 0},
+ {"--print-sysroot-headers-suffix", "-print-sysroot-headers-suffix", 0},
{"--profile", "-p", 0},
{"--profile-blocks", "-a", 0},
{"--quiet", "-q", 0},
{"--static", "-static", 0},
{"--std", "-std=", "aj"},
{"--symbolic", "-symbolic", 0},
+ {"--sysroot", "--sysroot=", "aj"},
{"--time", "-time", 0},
{"--trace-includes", "-H", 0},
{"--traditional", "-traditional", 0},
/* Translate the options described by *ARGCP and *ARGVP.
Make a new vector and store it back in *ARGVP,
- and store its length in *ARGVC. */
+ and store its length in *ARGCP. */
static void
translate_options (int *argcp, const char *const **argvp)
int argc = *argcp;
const char *const *argv = *argvp;
int newvsize = (argc + 2) * 2 * sizeof (const char *);
- const char **newv = xmalloc (newvsize);
+ const char **newv = XNEWVAR (const char *, newvsize);
int newindex = 0;
i = 0;
}
newvsize += spaces * sizeof (const char *);
- newv = xrealloc (newv, newvsize);
+ newv = XRESIZEVAR (const char *, newv, newvsize);
sp = target_option_translations[tott_idx].replacements;
np = xstrdup (sp);
else if (strchr (arginfo, '*') != 0)
{
- error ("incomplete `%s' option", option_map[j].name);
+ error ("incomplete '%s' option", option_map[j].name);
break;
}
{
if (i + 1 == argc)
{
- error ("missing argument to `%s' option",
+ error ("missing argument to '%s' option",
option_map[j].name);
break;
}
else if (strchr (arginfo, 'o') == 0)
{
if (arg != 0)
- error ("extraneous argument to `%s' option",
+ error ("extraneous argument to '%s' option",
option_map[j].name);
arg = 0;
}
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. */
int priority; /* Sort key - priority within list. */
int os_multilib; /* 1 if OS multilib scheme should be used,
0 for GCC multilib scheme. */
/* Default prefixes to attach to command names. */
-#ifdef CROSS_COMPILE /* Don't use these prefixes for a cross compiler. */
+#ifndef STANDARD_STARTFILE_PREFIX_1
+#define STANDARD_STARTFILE_PREFIX_1 "/lib/"
+#endif
+#ifndef STANDARD_STARTFILE_PREFIX_2
+#define STANDARD_STARTFILE_PREFIX_2 "/usr/lib/"
+#endif
+
+#ifdef CROSS_DIRECTORY_STRUCTURE /* Don't use these prefixes for a cross compiler. */
#undef MD_EXEC_PREFIX
#undef MD_STARTFILE_PREFIX
#undef MD_STARTFILE_PREFIX_1
#define MD_STARTFILE_PREFIX_1 ""
#endif
+/* These directories are locations set at configure-time based on the
+ --prefix option provided to configure. Their initializers are
+ defined in Makefile.in. These paths are not *directly* used when
+ gcc_exec_prefix is set because, in that case, we know where the
+ compiler has been installed, and use paths relative to that
+ location instead. */
static const char *const standard_exec_prefix = STANDARD_EXEC_PREFIX;
-static const char *const standard_exec_prefix_1 = "/usr/libexec/gcc/";
-static const char *const standard_exec_prefix_2 = "/usr/lib/gcc/";
-static const char *md_exec_prefix = MD_EXEC_PREFIX;
+static const char *const standard_libexec_prefix = STANDARD_LIBEXEC_PREFIX;
+static const char *const standard_bindir_prefix = STANDARD_BINDIR_PREFIX;
+static const char *const standard_startfile_prefix = STANDARD_STARTFILE_PREFIX;
+/* For native compilers, these are well-known paths containing
+ components that may be provided by the system. For cross
+ compilers, these paths are not used. */
+static const char *md_exec_prefix = MD_EXEC_PREFIX;
static const char *md_startfile_prefix = MD_STARTFILE_PREFIX;
static const char *md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1;
-static const char *const standard_startfile_prefix = STANDARD_STARTFILE_PREFIX;
-static const char *const standard_startfile_prefix_1 = "/lib/";
-static const char *const standard_startfile_prefix_2 = "/usr/lib/";
+static const char *const standard_startfile_prefix_1
+ = STANDARD_STARTFILE_PREFIX_1;
+static const char *const standard_startfile_prefix_2
+ = STANDARD_STARTFILE_PREFIX_2;
+/* A relative path to be used in finding the location of tools
+ relative to the driver. */
static const char *const tooldir_base_prefix = TOOLDIR_BASE_PREFIX;
-static const char *tooldir_prefix;
-
-static const char *const standard_bindir_prefix = STANDARD_BINDIR_PREFIX;
-
-static const char *standard_libexec_prefix = STANDARD_LIBEXEC_PREFIX;
/* Subdirectory to use for locating libraries. Set by
set_multilib_dir based on the compilation options. */
INIT_STATIC_SPEC ("cc1_options", &cc1_options),
INIT_STATIC_SPEC ("cc1plus", &cc1plus_spec),
INIT_STATIC_SPEC ("link_gcc_c_sequence", &link_gcc_c_sequence_spec),
+ INIT_STATIC_SPEC ("link_ssp", &link_ssp_spec),
INIT_STATIC_SPEC ("endfile", &endfile_spec),
INIT_STATIC_SPEC ("link", &link_spec),
INIT_STATIC_SPEC ("lib", &lib_spec),
+ INIT_STATIC_SPEC ("mfwrap", &mfwrap_spec),
+ INIT_STATIC_SPEC ("mflib", &mflib_spec),
+ INIT_STATIC_SPEC ("link_gomp", &link_gomp_spec),
INIT_STATIC_SPEC ("libgcc", &libgcc_spec),
INIT_STATIC_SPEC ("startfile", &startfile_spec),
INIT_STATIC_SPEC ("switches_need_spaces", &switches_need_spaces),
INIT_STATIC_SPEC ("multilib_exclusions", &multilib_exclusions),
INIT_STATIC_SPEC ("multilib_options", &multilib_options),
INIT_STATIC_SPEC ("linker", &linker_name_spec),
+ INIT_STATIC_SPEC ("linker_plugin_file", &linker_plugin_file_spec),
+ INIT_STATIC_SPEC ("lto_wrapper", <o_wrapper_spec),
+ INIT_STATIC_SPEC ("lto_gcc", <o_gcc_spec),
+ INIT_STATIC_SPEC ("lto_libgcc", <o_libgcc_spec),
INIT_STATIC_SPEC ("link_libgcc", &link_libgcc_spec),
INIT_STATIC_SPEC ("md_exec_prefix", &md_exec_prefix),
INIT_STATIC_SPEC ("md_startfile_prefix", &md_startfile_prefix),
INIT_STATIC_SPEC ("md_startfile_prefix_1", &md_startfile_prefix_1),
INIT_STATIC_SPEC ("startfile_prefix_spec", &startfile_prefix_spec),
+ INIT_STATIC_SPEC ("sysroot_spec", &sysroot_spec),
INIT_STATIC_SPEC ("sysroot_suffix_spec", &sysroot_suffix_spec),
INIT_STATIC_SPEC ("sysroot_hdrs_suffix_spec", &sysroot_hdrs_suffix_spec),
};
static const struct spec_function static_spec_functions[] =
{
+ { "getenv", getenv_spec_function },
{ "if-exists", if_exists_spec_function },
{ "if-exists-else", if_exists_else_spec_function },
+ { "replace-outfile", replace_outfile_spec_function },
+ { "version-compare", version_compare_spec_function },
+ { "include", include_spec_function },
+ { "find-file", find_file_spec_function },
+ { "print-asm-header", print_asm_header_spec_function },
+ { "compare-debug-dump-opt", compare_debug_dump_opt_spec_function },
+ { "compare-debug-self-opt", compare_debug_self_opt_spec_function },
+ { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
+#ifdef EXTRA_SPEC_FUNCTIONS
+ EXTRA_SPEC_FUNCTIONS
+#endif
{ 0, 0 }
};
/* Add appropriate libgcc specs to OBSTACK, taking into account
various permutations of -shared-libgcc, -shared, and such. */
-#ifdef ENABLE_SHARED_LIBGCC
+#if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC)
+
+#ifndef USE_LD_AS_NEEDED
+#define USE_LD_AS_NEEDED 0
+#endif
+
static void
init_gcc_specs (struct obstack *obstack, const char *shared_name,
const char *static_name, const char *eh_name)
{
char *buf;
- buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name,
- "}%{!static:%{!static-libgcc:",
- "%{!shared:%{!shared-libgcc:", static_name, " ",
- eh_name, "}%{shared-libgcc:", shared_name, " ",
- static_name, "}}%{shared:",
+ buf = concat ("%{static|static-libgcc:", static_name, " ", eh_name, "}"
+ "%{!static:%{!static-libgcc:"
+#if USE_LD_AS_NEEDED
+ "%{!shared-libgcc:",
+ static_name, " --as-needed ", shared_name, " --no-as-needed"
+ "}"
+ "%{shared-libgcc:",
+ shared_name, "%{!shared: ", static_name, "}"
+ "}"
+#else
+ "%{!shared:"
+ "%{!shared-libgcc:", static_name, " ", eh_name, "}"
+ "%{shared-libgcc:", shared_name, " ", static_name, "}"
+ "}"
#ifdef LINK_EH_SPEC
- "%{shared-libgcc:", shared_name,
- "}%{!shared-libgcc:", static_name, "}",
+ "%{shared:"
+ "%{shared-libgcc:", shared_name, "}"
+ "%{!shared-libgcc:", static_name, "}"
+ "}"
#else
- shared_name,
+ "%{shared:", shared_name, "}"
+#endif
#endif
- "}}}", NULL);
+ "}}", NULL);
obstack_grow (obstack, buf, strlen (buf));
free (buf);
notice ("Using built-in specs.\n");
#ifdef EXTRA_SPECS
- extra_specs = xcalloc (sizeof (struct spec_list),
- ARRAY_SIZE (extra_specs_1));
+ extra_specs = XCNEWVEC (struct spec_list, ARRAY_SIZE (extra_specs_1));
for (i = ARRAY_SIZE (extra_specs_1) - 1; i >= 0; i--)
{
}
#endif
- /* Initialize here, not in definition. The IRIX 6 O32 cc sometimes chokes
- on ?: in file-scope variable initializations. */
- asm_debug = ASM_DEBUG_SPEC;
-
for (i = ARRAY_SIZE (static_specs) - 1; i >= 0; i--)
{
sl = &static_specs[i];
next = sl;
}
-#ifdef ENABLE_SHARED_LIBGCC
+#if defined(ENABLE_SHARED_LIBGCC) && !defined(REAL_LIBGCC_SPEC)
/* ??? If neither -shared-libgcc nor --static-libgcc was
seen, then we should be making an educated guess. Some proposed
heuristics for ELF include:
if (in_sep && *p == '-' && strncmp (p, "-lgcc", 5) == 0)
{
init_gcc_specs (&obstack,
-#ifdef NO_SHARED_LIBGCC_MULTILIB
"-lgcc_s"
-#else
- "-lgcc_s%M"
+#ifdef USE_LIBUNWIND_EXCEPTIONS
+ " -lunwind"
#endif
,
"-lgcc",
"-lgcc_eh"
#ifdef USE_LIBUNWIND_EXCEPTIONS
+# ifdef HAVE_LD_STATIC_DYNAMIC
+ " %{!static:-Bstatic} -lunwind %{!static:-Bdynamic}"
+# else
" -lunwind"
+# endif
#endif
);
/* Ug. We don't know shared library extensions. Hope that
systems that use this form don't do shared libraries. */
init_gcc_specs (&obstack,
-#ifdef NO_SHARED_LIBGCC_MULTILIB
- "-lgcc_s"
-#else
- "-lgcc_s%M"
-#endif
- ,
+ "-lgcc_s",
"libgcc.a%s",
"libgcc_eh.a%s"
#ifdef USE_LIBUNWIND_EXCEPTIONS
}
obstack_1grow (&obstack, '\0');
- libgcc_spec = obstack_finish (&obstack);
+ libgcc_spec = XOBFINISH (&obstack, const char *);
}
#endif
#ifdef USE_AS_TRADITIONAL_FORMAT
static const char tf[] = "--traditional-format ";
obstack_grow (&obstack, tf, sizeof(tf) - 1);
obstack_grow0 (&obstack, asm_spec, strlen (asm_spec));
- asm_spec = obstack_finish (&obstack);
+ asm_spec = XOBFINISH (&obstack, const char *);
}
#endif
-#ifdef LINK_EH_SPEC
+
+#if defined LINK_EH_SPEC || defined LINK_BUILDID_SPEC
+# ifdef LINK_BUILDID_SPEC
+ /* Prepend LINK_BUILDID_SPEC to whatever link_spec we had before. */
+ obstack_grow (&obstack, LINK_BUILDID_SPEC, sizeof(LINK_BUILDID_SPEC) - 1);
+# endif
+# ifdef LINK_EH_SPEC
/* Prepend LINK_EH_SPEC to whatever link_spec we had before. */
obstack_grow (&obstack, LINK_EH_SPEC, sizeof(LINK_EH_SPEC) - 1);
+# endif
obstack_grow0 (&obstack, link_spec, strlen (link_spec));
- link_spec = obstack_finish (&obstack);
+ link_spec = XOBFINISH (&obstack, const char *);
#endif
specs = sl;
if (!sl)
{
/* Not found - make it. */
- sl = xmalloc (sizeof (struct spec_list));
+ sl = XNEW (struct spec_list);
sl->name = xstrdup (name);
sl->name_len = name_len;
sl->ptr_spec = &sl->ptr;
/* Free the old spec. */
if (old_spec && sl->alloc_p)
- free ((void *) old_spec);
+ free (CONST_CAST(char *, old_spec));
sl->alloc_p = 1;
}
static int argbuf_index;
+/* Position in the argbuf array containing the name of the output file
+ (the value associated with the "-o" flag). */
+
+static int have_o_argbuf_index = 0;
+
+/* Were the options -c, -S or -E passed. */
+static int have_c = 0;
+
+/* Was the option -o passed. */
+static int have_o = 0;
+
/* This is the list of suffixes and codes (%g/%u/%U/%j) and the associated
temp file. If the HOST_BIT_BUCKET is used for %j, no entry is made for
it here. */
alloc_args (void)
{
argbuf_length = 10;
- argbuf = xmalloc (argbuf_length * sizeof (const char *));
+ argbuf = XNEWVEC (const char *, argbuf_length);
}
/* Clear out the vector of arguments (after a command is executed). */
store_arg (const char *arg, int delete_always, int delete_failure)
{
if (argbuf_index + 1 == argbuf_length)
- argbuf = xrealloc (argbuf, (argbuf_length *= 2) * sizeof (const char *));
+ argbuf = XRESIZEVEC (const char *, argbuf, (argbuf_length *= 2));
argbuf[argbuf_index++] = arg;
argbuf[argbuf_index] = 0;
+ if (strcmp (arg, "-o") == 0)
+ have_o_argbuf_index = argbuf_index;
if (delete_always || delete_failure)
- record_temp_file (arg, delete_always, delete_failure);
+ {
+ const char *p;
+ /* If the temporary file we should delete is specified as
+ part of a joined argument extract the filename. */
+ if (arg[0] == '-'
+ && (p = strrchr (arg, '=')))
+ arg = p + 1;
+ record_temp_file (arg, delete_always, delete_failure);
+ }
}
\f
/* Load specs from a file name named FILENAME, replacing occurrences of
pfatal_with_name (filename);
/* Read contents of file into BUFFER. */
- buffer = xmalloc ((unsigned) statbuf.st_size + 1);
+ buffer = XNEWVEC (char, statbuf.st_size + 1);
readlen = read (desc, buffer, (unsigned) statbuf.st_size);
if (readlen < 0)
pfatal_with_name (filename);
buffer[readlen] = 0;
close (desc);
- specs = xmalloc (readlen + 1);
+ specs = XNEWVEC (char, readlen + 1);
specs_p = specs;
for (buffer_p = buffer; buffer_p && *buffer_p; buffer_p++)
{
(long) (p1 - buffer + 1));
p[-2] = '\0';
- new_filename = find_a_file (&startfile_prefixes, p1, R_OK, 0);
+ new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
read_specs (new_filename ? new_filename : p1, FALSE);
continue;
}
(long) (p1 - buffer + 1));
p[-2] = '\0';
- new_filename = find_a_file (&startfile_prefixes, p1, R_OK, 0);
+ new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
if (new_filename)
read_specs (new_filename, FALSE);
else if (verbose_flag)
set_spec (p2, *(sl->ptr_spec));
if (sl->alloc_p)
- free ((void *) *(sl->ptr_spec));
+ free (CONST_CAST (char *, *(sl->ptr_spec)));
*(sl->ptr_spec) = "";
sl->alloc_p = 0;
{
/* Add this pair to the vector. */
compilers
- = xrealloc (compilers,
- (n_compilers + 2) * sizeof (struct compiler));
+ = XRESIZEVEC (struct compiler, compilers, n_compilers + 2);
compilers[n_compilers].suffix = suffix;
compilers[n_compilers].spec = spec;
if (! strcmp (name, temp->name))
goto already1;
- temp = xmalloc (sizeof (struct temp_file));
+ temp = XNEW (struct temp_file);
temp->next = always_delete_queue;
temp->name = name;
always_delete_queue = temp;
if (! strcmp (name, temp->name))
goto already2;
- temp = xmalloc (sizeof (struct temp_file));
+ temp = XNEW (struct temp_file);
temp->next = failure_delete_queue;
temp->name = name;
failure_delete_queue = temp;
/* Delete all the temporary files whose names we previously recorded. */
+#ifndef DELETE_IF_ORDINARY
+#define DELETE_IF_ORDINARY(NAME,ST,VERBOSE_FLAG) \
+do \
+ { \
+ if (stat (NAME, &ST) >= 0 && S_ISREG (ST.st_mode)) \
+ if (unlink (NAME) < 0) \
+ if (VERBOSE_FLAG) \
+ perror_with_name (NAME); \
+ } while (0)
+#endif
+
static void
delete_if_ordinary (const char *name)
{
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);
+ DELETE_IF_ORDINARY (name, st, verbose_flag);
}
static void
failure_delete_queue = 0;
}
\f
-/* Build a list of search directories from PATHS.
- PREFIX is a string to prepend to the list.
- If CHECK_DIR_P is nonzero 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 char *
-build_search_list (struct path_prefix *paths, const char *prefix,
- int check_dir_p)
+/* Call CALLBACK for each path in PATHS, breaking out early if CALLBACK
+ returns non-NULL.
+ If DO_MULTI is true iterate over the paths twice, first with multilib
+ suffix then without, otherwise iterate over the paths once without
+ adding a multilib suffix. When DO_MULTI is true, some attempt is made
+ to avoid visiting the same path twice, but we could do better. For
+ instance, /usr/lib/../lib is considered different from /usr/lib.
+ At least EXTRA_SPACE chars past the end of the path passed to
+ CALLBACK are available for use by the callback.
+ CALLBACK_INFO allows extra parameters to be passed to CALLBACK.
+
+ Returns the value returned by CALLBACK. */
+
+static void *
+for_each_path (const struct path_prefix *paths,
+ bool do_multi,
+ size_t extra_space,
+ void *(*callback) (char *, void *),
+ void *callback_info)
{
- int suffix_len = (machine_suffix) ? strlen (machine_suffix) : 0;
- int just_suffix_len
- = (just_machine_suffix) ? strlen (just_machine_suffix) : 0;
- int first_time = TRUE;
- struct prefix_list *pprefix;
-
- obstack_grow (&collect_obstack, prefix, strlen (prefix));
- obstack_1grow (&collect_obstack, '=');
-
- for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next)
+ struct prefix_list *pl;
+ const char *multi_dir = NULL;
+ const char *multi_os_dir = NULL;
+ const char *multi_suffix;
+ const char *just_multi_suffix;
+ char *path = NULL;
+ void *ret = NULL;
+ bool skip_multi_dir = false;
+ bool skip_multi_os_dir = false;
+
+ multi_suffix = machine_suffix;
+ just_multi_suffix = just_machine_suffix;
+ if (do_multi && multilib_dir && strcmp (multilib_dir, ".") != 0)
{
- int len = strlen (pprefix->prefix);
+ multi_dir = concat (multilib_dir, dir_separator_str, NULL);
+ multi_suffix = concat (multi_suffix, multi_dir, NULL);
+ just_multi_suffix = concat (just_multi_suffix, multi_dir, NULL);
+ }
+ if (do_multi && multilib_os_dir && strcmp (multilib_os_dir, ".") != 0)
+ multi_os_dir = concat (multilib_os_dir, dir_separator_str, NULL);
- if (machine_suffix
- && (! check_dir_p
- || is_directory (pprefix->prefix, machine_suffix, 0)))
+ while (1)
+ {
+ size_t multi_dir_len = 0;
+ size_t multi_os_dir_len = 0;
+ size_t suffix_len;
+ size_t just_suffix_len;
+ size_t len;
+
+ if (multi_dir)
+ multi_dir_len = strlen (multi_dir);
+ if (multi_os_dir)
+ multi_os_dir_len = strlen (multi_os_dir);
+ suffix_len = strlen (multi_suffix);
+ just_suffix_len = strlen (just_multi_suffix);
+
+ if (path == NULL)
{
- if (!first_time)
- obstack_1grow (&collect_obstack, PATH_SEPARATOR);
-
- first_time = FALSE;
- obstack_grow (&collect_obstack, pprefix->prefix, len);
- obstack_grow (&collect_obstack, machine_suffix, suffix_len);
+ len = paths->max_len + extra_space + 1;
+ if (suffix_len > multi_os_dir_len)
+ len += suffix_len;
+ else
+ len += multi_os_dir_len;
+ path = XNEWVEC (char, len);
}
- if (just_machine_suffix
- && pprefix->require_machine_suffix == 2
- && (! check_dir_p
- || is_directory (pprefix->prefix, just_machine_suffix, 0)))
+ for (pl = paths->plist; pl != 0; pl = pl->next)
{
- if (! first_time)
- obstack_1grow (&collect_obstack, PATH_SEPARATOR);
+ len = strlen (pl->prefix);
+ memcpy (path, pl->prefix, len);
+
+ /* Look first in MACHINE/VERSION subdirectory. */
+ if (!skip_multi_dir)
+ {
+ memcpy (path + len, multi_suffix, suffix_len + 1);
+ ret = callback (path, callback_info);
+ if (ret)
+ break;
+ }
+
+ /* Some paths are tried with just the machine (ie. target)
+ subdir. This is used for finding as, ld, etc. */
+ if (!skip_multi_dir
+ && pl->require_machine_suffix == 2)
+ {
+ memcpy (path + len, just_multi_suffix, just_suffix_len + 1);
+ ret = callback (path, callback_info);
+ if (ret)
+ break;
+ }
+
+ /* Now try the base path. */
+ if (!pl->require_machine_suffix
+ && !(pl->os_multilib ? skip_multi_os_dir : skip_multi_dir))
+ {
+ const char *this_multi;
+ size_t this_multi_len;
+
+ if (pl->os_multilib)
+ {
+ this_multi = multi_os_dir;
+ this_multi_len = multi_os_dir_len;
+ }
+ else
+ {
+ this_multi = multi_dir;
+ this_multi_len = multi_dir_len;
+ }
+
+ if (this_multi_len)
+ memcpy (path + len, this_multi, this_multi_len + 1);
+ else
+ path[len] = '\0';
- first_time = FALSE;
- obstack_grow (&collect_obstack, pprefix->prefix, len);
- obstack_grow (&collect_obstack, just_machine_suffix,
- just_suffix_len);
+ ret = callback (path, callback_info);
+ if (ret)
+ break;
+ }
}
+ if (pl)
+ break;
- if (! pprefix->require_machine_suffix)
- {
- if (! first_time)
- obstack_1grow (&collect_obstack, PATH_SEPARATOR);
+ if (multi_dir == NULL && multi_os_dir == NULL)
+ break;
- first_time = FALSE;
- obstack_grow (&collect_obstack, pprefix->prefix, len);
+ /* Run through the paths again, this time without multilibs.
+ Don't repeat any we have already seen. */
+ if (multi_dir)
+ {
+ free (CONST_CAST (char *, multi_dir));
+ multi_dir = NULL;
+ free (CONST_CAST (char *, multi_suffix));
+ multi_suffix = machine_suffix;
+ free (CONST_CAST (char *, just_multi_suffix));
+ just_multi_suffix = just_machine_suffix;
+ }
+ else
+ skip_multi_dir = true;
+ if (multi_os_dir)
+ {
+ free (CONST_CAST (char *, multi_os_dir));
+ multi_os_dir = NULL;
}
+ else
+ skip_multi_os_dir = true;
+ }
+
+ if (multi_dir)
+ {
+ free (CONST_CAST (char *, multi_dir));
+ free (CONST_CAST (char *, multi_suffix));
+ free (CONST_CAST (char *, just_multi_suffix));
}
+ if (multi_os_dir)
+ free (CONST_CAST (char *, multi_os_dir));
+ if (ret != path)
+ free (path);
+ return ret;
+}
+
+/* Callback for build_search_list. Adds path to obstack being built. */
+
+struct add_to_obstack_info {
+ struct obstack *ob;
+ bool check_dir;
+ bool first_time;
+};
+
+static void *
+add_to_obstack (char *path, void *data)
+{
+ struct add_to_obstack_info *info = (struct add_to_obstack_info *) data;
+
+ if (info->check_dir && !is_directory (path, false))
+ return NULL;
+
+ if (!info->first_time)
+ obstack_1grow (info->ob, PATH_SEPARATOR);
+
+ obstack_grow (info->ob, path, strlen (path));
+
+ info->first_time = false;
+ return NULL;
+}
+
+/* Add or change the value of an environment variable, outputting the
+ change to standard error if in verbose mode. */
+static void
+xputenv (const char *string)
+{
+ if (verbose_flag)
+ notice ("%s\n", string);
+ putenv (CONST_CAST (char *, string));
+}
+
+/* Build a list of search directories from PATHS.
+ PREFIX is a string to prepend to the list.
+ If CHECK_DIR_P is true we ensure the directory exists.
+ If DO_MULTI is true, multilib paths are output first, then
+ non-multilib paths.
+ This is used mostly by putenv_from_prefixes so we use `collect_obstack'.
+ It is also used by the --print-search-dirs flag. */
+
+static char *
+build_search_list (const struct path_prefix *paths, const char *prefix,
+ bool check_dir, bool do_multi)
+{
+ struct add_to_obstack_info info;
+
+ info.ob = &collect_obstack;
+ info.check_dir = check_dir;
+ info.first_time = true;
+
+ obstack_grow (&collect_obstack, prefix, strlen (prefix));
+ obstack_1grow (&collect_obstack, '=');
+
+ for_each_path (paths, do_multi, 0, add_to_obstack, &info);
obstack_1grow (&collect_obstack, '\0');
- return obstack_finish (&collect_obstack);
+ return XOBFINISH (&collect_obstack, char *);
}
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
static void
-putenv_from_prefixes (struct path_prefix *paths, const char *env_var)
+putenv_from_prefixes (const struct path_prefix *paths, const char *env_var,
+ bool do_multi)
{
- putenv (build_search_list (paths, env_var, 1));
+ xputenv (build_search_list (paths, env_var, true, do_multi));
}
\f
/* Check whether NAME can be accessed in MODE. This is like access,
return access (name, mode);
}
+/* Callback for find_a_file. Appends the file name to the directory
+ path. If the resulting file exists in the right mode, return the
+ full pathname to the file. */
+
+struct file_at_path_info {
+ const char *name;
+ const char *suffix;
+ int name_len;
+ int suffix_len;
+ int mode;
+};
+
+static void *
+file_at_path (char *path, void *data)
+{
+ struct file_at_path_info *info = (struct file_at_path_info *) data;
+ size_t len = strlen (path);
+
+ memcpy (path + len, info->name, info->name_len);
+ len += info->name_len;
+
+ /* Some systems have a suffix for executable files.
+ So try appending that first. */
+ if (info->suffix_len)
+ {
+ memcpy (path + len, info->suffix, info->suffix_len + 1);
+ if (access_check (path, info->mode) == 0)
+ return path;
+ }
+
+ path[len] = '\0';
+ if (access_check (path, info->mode) == 0)
+ return path;
+
+ return NULL;
+}
+
/* Search for NAME using the prefix list PREFIXES. MODE is passed to
- access to check permissions.
+ access to check permissions. If DO_MULTI is true, search multilib
+ paths then non-multilib paths, otherwise do not search multilib paths.
Return 0 if not found, otherwise return its name, allocated with malloc. */
static char *
-find_a_file (struct path_prefix *pprefix, const char *name, int mode,
- int multilib)
+find_a_file (const struct path_prefix *pprefix, const char *name, int mode,
+ bool do_multi)
{
- char *temp;
- const char *const file_suffix =
- ((mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "");
- struct prefix_list *pl;
- int len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1;
- const char *multilib_name, *multilib_os_name;
+ struct file_at_path_info info;
#ifdef DEFAULT_ASSEMBLER
if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
return xstrdup (DEFAULT_LINKER);
#endif
- if (machine_suffix)
- len += strlen (machine_suffix);
-
- multilib_name = name;
- multilib_os_name = name;
- if (multilib && multilib_os_dir)
- {
- int len1 = multilib_dir ? strlen (multilib_dir) + 1 : 0;
- int len2 = strlen (multilib_os_dir) + 1;
-
- len += len1 > len2 ? len1 : len2;
- if (multilib_dir)
- multilib_name = ACONCAT ((multilib_dir, dir_separator_str, name,
- NULL));
- if (strcmp (multilib_os_dir, ".") != 0)
- multilib_os_name = ACONCAT ((multilib_os_dir, dir_separator_str, name,
- NULL));
- }
-
- temp = xmalloc (len);
-
/* Determine the filename to execute (special case for absolute paths). */
if (IS_ABSOLUTE_PATH (name))
{
if (access (name, mode) == 0)
- {
- strcpy (temp, name);
- return temp;
- }
- }
- else
- for (pl = pprefix->plist; pl; pl = pl->next)
- {
- const char *this_name
- = pl->os_multilib ? multilib_os_name : multilib_name;
-
- if (machine_suffix)
- {
- /* Some systems have a suffix for executable files.
- So try appending that first. */
- if (file_suffix[0] != 0)
- {
- strcpy (temp, pl->prefix);
- strcat (temp, machine_suffix);
- strcat (temp, multilib_name);
- strcat (temp, file_suffix);
- if (access_check (temp, mode) == 0)
- {
- if (pl->used_flag_ptr != 0)
- *pl->used_flag_ptr = 1;
- return temp;
- }
- }
-
- /* Now try just the multilib_name. */
- strcpy (temp, pl->prefix);
- strcat (temp, machine_suffix);
- strcat (temp, multilib_name);
- if (access_check (temp, mode) == 0)
- {
- if (pl->used_flag_ptr != 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 first. */
- if (file_suffix[0] != 0)
- {
- strcpy (temp, pl->prefix);
- strcat (temp, just_machine_suffix);
- strcat (temp, multilib_name);
- strcat (temp, file_suffix);
- if (access_check (temp, mode) == 0)
- {
- if (pl->used_flag_ptr != 0)
- *pl->used_flag_ptr = 1;
- return temp;
- }
- }
+ return xstrdup (name);
- strcpy (temp, pl->prefix);
- strcat (temp, just_machine_suffix);
- strcat (temp, multilib_name);
- if (access_check (temp, mode) == 0)
- {
- if (pl->used_flag_ptr != 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 first. */
- if (file_suffix[0] != 0)
- {
- strcpy (temp, pl->prefix);
- strcat (temp, this_name);
- strcat (temp, file_suffix);
- if (access_check (temp, mode) == 0)
- {
- if (pl->used_flag_ptr != 0)
- *pl->used_flag_ptr = 1;
- return temp;
- }
- }
+ return NULL;
+ }
- strcpy (temp, pl->prefix);
- strcat (temp, this_name);
- if (access_check (temp, mode) == 0)
- {
- if (pl->used_flag_ptr != 0)
- *pl->used_flag_ptr = 1;
- return temp;
- }
- }
- }
+ info.name = name;
+ info.suffix = (mode & X_OK) != 0 ? HOST_EXECUTABLE_SUFFIX : "";
+ info.name_len = strlen (info.name);
+ info.suffix_len = strlen (info.suffix);
+ info.mode = mode;
- free (temp);
- return 0;
+ return (char*) for_each_path (pprefix, do_multi,
+ info.name_len + info.suffix_len,
+ file_at_path, &info);
}
/* Ranking of prefixes in the sort list. -B prefixes are put before
static void
add_prefix (struct path_prefix *pprefix, const char *prefix,
const char *component, /* enum prefix_priority */ int priority,
- int require_machine_suffix, int *warn, int os_multilib)
+ int require_machine_suffix, int os_multilib)
{
struct prefix_list *pl, **prev;
int len;
if (len > pprefix->max_len)
pprefix->max_len = len;
- pl = xmalloc (sizeof (struct prefix_list));
+ pl = XNEW (struct prefix_list);
pl->prefix = prefix;
pl->require_machine_suffix = require_machine_suffix;
- pl->used_flag_ptr = warn;
pl->priority = priority;
pl->os_multilib = os_multilib;
- if (warn)
- *warn = 0;
/* Insert after PREV. */
pl->next = (*prev);
}
/* Same as add_prefix, but prepending target_system_root to prefix. */
+/* The target_system_root prefix has been relocated by gcc_exec_prefix. */
static void
add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix,
const char *component,
/* enum prefix_priority */ int priority,
- int require_machine_suffix, int *warn, int os_multilib)
+ int require_machine_suffix, int os_multilib)
{
if (!IS_ABSOLUTE_PATH (prefix))
- abort ();
+ fatal ("system path '%s' is not absolute", prefix);
if (target_system_root)
{
}
add_prefix (pprefix, prefix, component, priority,
- require_machine_suffix, warn, os_multilib);
+ require_machine_suffix, os_multilib);
}
\f
/* Execute the command specified by the arguments on the current line of spec.
int i;
int n_commands; /* # of command. */
char *string;
+ struct pex_obj *pex;
struct command
{
const char *prog; /* program name. */
const char **argv; /* vector of args. */
- int pid; /* pid of process for this command. */
};
struct command *commands; /* each command buffer with above info. */
- if (processing_spec_function)
- abort ();
+ gcc_assert (!processing_spec_function);
+
+ if (wrapper_string)
+ {
+ string = find_a_file (&exec_prefixes, argbuf[0], X_OK, false);
+ argbuf[0] = (string) ? string : argbuf[0];
+ insert_wrapper (wrapper_string);
+ }
/* Count # of piped commands. */
for (n_commands = 1, i = 0; i < argbuf_index; i++)
n_commands++;
/* Get storage for each command. */
- commands = alloca (n_commands * sizeof (struct command));
+ commands = (struct command *) alloca (n_commands * sizeof (struct command));
/* Split argbuf into its separate piped processes,
and record info about each one.
commands[0].prog = argbuf[0]; /* first command. */
commands[0].argv = &argbuf[0];
- string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, 0);
- if (string)
- commands[0].argv[0] = string;
+ if (!wrapper_string)
+ {
+ string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false);
+ commands[0].argv[0] = (string) ? string : commands[0].argv[0];
+ }
for (n_commands = 1, i = 0; i < argbuf_index; i++)
if (strcmp (argbuf[i], "|") == 0)
commands[n_commands].prog = argbuf[i + 1];
commands[n_commands].argv = &argbuf[i + 1];
string = find_a_file (&exec_prefixes, commands[n_commands].prog,
- X_OK, 0);
+ X_OK, false);
if (string)
commands[n_commands].argv[0] = string;
n_commands++;
for (j = commands[i].argv; *j; j++)
{
const char *p;
- fprintf (stderr, " \"");
for (p = *j; *p; ++p)
+ if (!ISALNUM ((unsigned char) *p)
+ && *p != '_' && *p != '/' && *p != '-' && *p != '.')
+ break;
+ if (*p || !*j)
{
- if (*p == '"' || *p == '\\' || *p == '$')
- fputc ('\\', stderr);
- fputc (*p, stderr);
+ fprintf (stderr, " \"");
+ for (p = *j; *p; ++p)
+ {
+ if (*p == '"' || *p == '\\' || *p == '$')
+ fputc ('\\', stderr);
+ fputc (*p, stderr);
+ }
+ fputc ('"', stderr);
}
- fputc ('"', stderr);
+ else
+ fprintf (stderr, " %s", *j);
}
}
else
for (argc = 0; commands[i].argv[argc] != NULL; argc++)
;
- argv = alloca ((argc + 3) * sizeof (char *));
+ argv = XALLOCAVEC (const char *, argc + 3);
argv[0] = VALGRIND_PATH;
argv[1] = "-q";
/* Run each piped subprocess. */
+ pex = pex_init (PEX_USE_PIPES | ((report_times || report_times_to_file)
+ ? PEX_RECORD_TIMES : 0),
+ programname, temp_filename);
+ if (pex == NULL)
+ pfatal_with_name (_("pex_init failed"));
+
for (i = 0; i < n_commands; i++)
{
- char *errmsg_fmt, *errmsg_arg;
+ const char *errmsg;
+ int err;
const char *string = commands[i].argv[0];
- /* For some bizarre reason, the second argument of execvp() is
- char *const *, not const char *const *. */
- commands[i].pid = pexecute (string, (char *const *) 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);
+ errmsg = pex_run (pex,
+ ((i + 1 == n_commands ? PEX_LAST : 0)
+ | (string == commands[i].prog ? PEX_SEARCH : 0)),
+ string, CONST_CAST (char **, commands[i].argv),
+ NULL, NULL, &err);
+ if (errmsg != NULL)
+ {
+ if (err == 0)
+ fatal (errmsg);
+ else
+ {
+ errno = err;
+ pfatal_with_name (errmsg);
+ }
+ }
if (string != commands[i].prog)
- free ((void *) string);
+ free (CONST_CAST (char *, string));
}
execution_count++;
- /* 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.
- Ignore subprocesses that we don't know about,
- since they can be spawned by the process that exec'ed us. */
+ /* Wait for all the subprocesses to finish. */
{
+ int *statuses;
+ struct pex_time *times = NULL;
int ret_code = 0;
-#ifdef HAVE_GETRUSAGE
- struct timeval d;
- double ut = 0.0, st = 0.0;
-#endif
- for (i = 0; i < n_commands;)
+ statuses = (int *) alloca (n_commands * sizeof (int));
+ if (!pex_get_status (pex, n_commands, statuses))
+ pfatal_with_name (_("failed to get exit status"));
+
+ if (report_times || report_times_to_file)
{
- int j;
- int status;
- int pid;
+ times = (struct pex_time *) alloca (n_commands * sizeof (struct pex_time));
+ if (!pex_get_times (pex, n_commands, times))
+ pfatal_with_name (_("failed to get process times"));
+ }
- pid = pwait (commands[i].pid, &status, 0);
- if (pid < 0)
- abort ();
+ pex_free (pex);
-#ifdef HAVE_GETRUSAGE
- if (report_times)
- {
- /* getrusage returns the total resource usage of all children
- up to now. Copy the previous values into prus, get the
- current statistics, then take the difference. */
-
- prus = rus;
- getrusage (RUSAGE_CHILDREN, &rus);
- d.tv_sec = rus.ru_utime.tv_sec - prus.ru_utime.tv_sec;
- d.tv_usec = rus.ru_utime.tv_usec - prus.ru_utime.tv_usec;
- ut = (double) d.tv_sec + (double) d.tv_usec / 1.0e6;
-
- d.tv_sec = rus.ru_stime.tv_sec - prus.ru_stime.tv_sec;
- d.tv_usec = rus.ru_stime.tv_usec - prus.ru_stime.tv_usec;
- st = (double) d.tv_sec + (double) d.tv_usec / 1.0e6;
- }
-#endif
+ for (i = 0; i < n_commands; ++i)
+ {
+ int status = statuses[i];
- for (j = 0; j < n_commands; j++)
- if (commands[j].pid == pid)
- {
- i++;
- if (WIFSIGNALED (status))
- {
+ if (WIFSIGNALED (status))
+ {
#ifdef SIGPIPE
- /* SIGPIPE is a special case. It happens in -pipe mode
- when the compiler dies before the preprocessor is
- done, or the assembler dies before the compiler is
- done. There's generally been an error already, and
- this is just fallout. So don't generate another error
- unless we would otherwise have succeeded. */
- if (WTERMSIG (status) == SIGPIPE
- && (signal_count || greatest_status >= MIN_FATAL_STATUS))
- ;
- else
+ /* SIGPIPE is a special case. It happens in -pipe mode
+ when the compiler dies before the preprocessor is done,
+ or the assembler dies before the compiler is done.
+ There's generally been an error already, and this is
+ just fallout. So don't generate another error unless
+ we would otherwise have succeeded. */
+ if (WTERMSIG (status) == SIGPIPE
+ && (signal_count || greatest_status >= MIN_FATAL_STATUS))
+ {
+ signal_count++;
+ ret_code = -1;
+ }
+ else
#endif
- fatal ("\
+ fatal_ice ("\
Internal error: %s (program %s)\n\
Please submit a full bug report.\n\
See %s for instructions.",
- strsignal (WTERMSIG (status)), commands[j].prog,
- bug_report_url);
- signal_count++;
- ret_code = -1;
- }
- else if (WIFEXITED (status)
- && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
- {
- if (WEXITSTATUS (status) > greatest_status)
- greatest_status = WEXITSTATUS (status);
- ret_code = -1;
- }
-#ifdef HAVE_GETRUSAGE
- if (report_times && ut + st != 0)
- notice ("# %s %.2f %.2f\n", commands[j].prog, ut, st);
-#endif
- break;
- }
- }
+ strsignal (WTERMSIG (status)), commands[i].prog,
+ bug_report_url);
+ }
+ else if (WIFEXITED (status)
+ && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
+ {
+ if (WEXITSTATUS (status) > greatest_status)
+ greatest_status = WEXITSTATUS (status);
+ ret_code = -1;
+ }
+
+ if (report_times || report_times_to_file)
+ {
+ struct pex_time *pt = ×[i];
+ double ut, st;
+
+ ut = ((double) pt->user_seconds
+ + (double) pt->user_microseconds / 1.0e6);
+ st = ((double) pt->system_seconds
+ + (double) pt->system_microseconds / 1.0e6);
+
+ if (ut + st != 0)
+ {
+ if (report_times)
+ notice ("# %s %.2f %.2f\n", commands[i].prog, ut, st);
+
+ if (report_times_to_file)
+ {
+ int c = 0;
+ const char *const *j;
+
+ fprintf (report_times_to_file, "%g %g", ut, st);
+
+ for (j = &commands[i].prog; *j; j = &commands[i].argv[++c])
+ {
+ const char *p;
+ for (p = *j; *p; ++p)
+ if (*p == '"' || *p == '\\' || *p == '$'
+ || ISSPACE (*p))
+ break;
+
+ if (*p)
+ {
+ fprintf (report_times_to_file, " \"");
+ for (p = *j; *p; ++p)
+ {
+ if (*p == '"' || *p == '\\' || *p == '$')
+ fputc ('\\', report_times_to_file);
+ fputc (*p, report_times_to_file);
+ }
+ fputc ('"', report_times_to_file);
+ }
+ else
+ fprintf (report_times_to_file, " %s", *j);
+ }
+
+ fputc ('\n', report_times_to_file);
+ }
+ }
+ }
+ }
+
return ret_code;
}
}
If a switch uses following arguments, then the `part1' field
is the switch itself and the `args' field
is a null-terminated vector containing the following arguments.
- The `live_cond' field is:
- 0 when initialized
- 1 if the switch is true in a conditional spec,
- -1 if false (overridden by a later switch)
- -2 if this switch should be ignored (used in %<S)
+ Bits in the `live_cond' field are:
+ SWITCH_LIVE to indicate this switch is true in a conditional spec.
+ SWITCH_FALSE to indicate this switch is overridden by a later switch.
+ SWITCH_IGNORE to indicate this switch should be ignored (used in %<S).
+ SWITCH_IGNORE_PERMANENTLY to indicate this switch should be ignored
+ in all do_spec calls afterwards. Used for %<S from self specs.
The `validated' field is nonzero if any spec has looked at this switch;
if it remains zero at the end of the run, it must be meaningless. */
-#define SWITCH_OK 0
-#define SWITCH_FALSE -1
-#define SWITCH_IGNORE -2
-#define SWITCH_LIVE 1
+#define SWITCH_LIVE 0x1
+#define SWITCH_FALSE 0x2
+#define SWITCH_IGNORE 0x4
+#define SWITCH_IGNORE_PERMANENTLY 0x8
struct switchstr
{
const char *part1;
const char **args;
- int live_cond;
+ unsigned int live_cond;
unsigned char validated;
unsigned char ordering;
};
static int n_switches;
+/* Set to zero if -fcompare-debug is disabled, positive if it's
+ enabled and we're running the first compilation, negative if it's
+ enabled and we're running the second compilation. For most of the
+ time, it's in the range -1..1, but it can be temporarily set to 2
+ or 3 to indicate that the -fcompare-debug flags didn't come from
+ the command-line, but rather from the GCC_COMPARE_DEBUG environment
+ variable, until a synthesized -fcompare-debug flag is added to the
+ command line. */
+int compare_debug;
+
+/* Set to nonzero if we've seen the -fcompare-debug-second flag. */
+int compare_debug_second;
+
+/* Set to the flags that should be passed to the second compilation in
+ a -fcompare-debug compilation. */
+const char *compare_debug_opt;
+
+static struct switchstr *switches_debug_check[2];
+
+static int n_switches_debug_check[2];
+
+static char *debug_check_temp_file[2];
+
+/* Language is one of three things:
+
+ 1) The name of a real programming language.
+ 2) NULL, indicating that no one has figured out
+ what it is yet.
+ 3) '*', indicating that the file should be passed
+ to the linker. */
struct infile
{
const char *name;
const char *language;
+ struct compiler *incompiler;
+ bool compiled;
+ bool preprocessed;
};
/* Also a vector of input files specified. */
/* And a vector of corresponding output files is made up later. */
const char **outfiles;
-
-/* Used to track if none of the -B paths are used. */
-static int warn_B;
-
-/* Gives value to pass as "warn" to add_prefix for standard prefixes. */
-static int *warn_std_ptr = 0;
\f
#if defined(HAVE_TARGET_OBJECT_SUFFIX) || defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
{
obstack_grow (&obstack, name, len - 2);
obstack_grow0 (&obstack, TARGET_OBJECT_SUFFIX, strlen (TARGET_OBJECT_SUFFIX));
- name = obstack_finish (&obstack);
+ name = XOBFINISH (&obstack, const char *);
}
#endif
obstack_grow (&obstack, name, len);
obstack_grow0 (&obstack, TARGET_EXECUTABLE_SUFFIX,
strlen (TARGET_EXECUTABLE_SUFFIX));
- name = obstack_finish (&obstack);
+ name = XOBFINISH (&obstack, const char *);
#endif
return name;
fputs (_(" -pass-exit-codes Exit with highest error code from a phase\n"), stdout);
fputs (_(" --help Display this information\n"), stdout);
fputs (_(" --target-help Display target specific command line options\n"), stdout);
+ fputs (_(" --help={target|optimizers|warnings|params|[^]{joined|separate|undocumented}}[,...]\n"), stdout);
+ fputs (_(" Display specific types of command line options\n"), stdout);
if (! verbose_flag)
fputs (_(" (Use '-v --help' to display command line options of sub-processes)\n"), stdout);
+ fputs (_(" --version Display compiler version information\n"), stdout);
fputs (_(" -dumpspecs Display all of the built in spec strings\n"), stdout);
fputs (_(" -dumpversion Display the version of the compiler\n"), stdout);
fputs (_(" -dumpmachine Display the compiler's target processor\n"), stdout);
-print-multi-lib Display the mapping between command line options and\n\
multiple library search directories\n"), stdout);
fputs (_(" -print-multi-os-directory Display the relative path to OS libraries\n"), stdout);
+ fputs (_(" -print-sysroot Display the target libraries directory\n"), stdout);
+ fputs (_(" -print-sysroot-headers-suffix Display the sysroot suffix used to find headers\n"), stdout);
fputs (_(" -Wa,<options> Pass comma-separated <options> on to the assembler\n"), stdout);
fputs (_(" -Wp,<options> Pass comma-separated <options> on to the preprocessor\n"), stdout);
fputs (_(" -Wl,<options> Pass comma-separated <options> on to the linker\n"), stdout);
fputs (_(" -Xassembler <arg> Pass <arg> on to the assembler\n"), stdout);
fputs (_(" -Xpreprocessor <arg> Pass <arg> on to the preprocessor\n"), stdout);
fputs (_(" -Xlinker <arg> Pass <arg> on to the linker\n"), stdout);
+ fputs (_(" -combine Pass multiple source files to compiler at once\n"), stdout);
fputs (_(" -save-temps Do not delete intermediate files\n"), stdout);
+ fputs (_(" -save-temps=<arg> Do not delete intermediate files\n"), stdout);
+ fputs (_("\
+ -no-canonical-prefixes Do not canonicalize paths when building relative\n\
+ prefixes to other gcc components\n"), stdout);
fputs (_(" -pipe Use pipes rather than intermediate files\n"), stdout);
fputs (_(" -time Time the execution of each subprocess\n"), stdout);
fputs (_(" -specs=<file> Override built-in specs with the contents of <file>\n"), stdout);
fputs (_(" -std=<standard> Assume that the input sources are for <standard>\n"), stdout);
+ fputs (_("\
+ --sysroot=<directory> Use <directory> as the root directory for headers\n\
+ and libraries\n"), stdout);
fputs (_(" -B <directory> Add <directory> to the compiler's search paths\n"), stdout);
- fputs (_(" -b <machine> Run gcc for target <machine>, if installed\n"), stdout);
- fputs (_(" -V <version> Run gcc version number <version>, if installed\n"), stdout);
fputs (_(" -v Display the programs invoked by the compiler\n"), stdout);
fputs (_(" -### Like -v but options quoted and commands not executed\n"), stdout);
fputs (_(" -E Preprocess only; do not compile, assemble or link\n"), stdout);
n_preprocessor_options++;
if (! preprocessor_options)
- preprocessor_options = xmalloc (n_preprocessor_options * sizeof (char *));
+ preprocessor_options = XNEWVEC (char *, n_preprocessor_options);
else
- preprocessor_options = xrealloc (preprocessor_options,
- n_preprocessor_options * sizeof (char *));
+ preprocessor_options = XRESIZEVEC (char *, preprocessor_options,
+ n_preprocessor_options);
preprocessor_options [n_preprocessor_options - 1] =
save_string (option, len);
n_assembler_options++;
if (! assembler_options)
- assembler_options = xmalloc (n_assembler_options * sizeof (char *));
+ assembler_options = XNEWVEC (char *, n_assembler_options);
else
- assembler_options = xrealloc (assembler_options,
- n_assembler_options * sizeof (char *));
+ assembler_options = XRESIZEVEC (char *, assembler_options,
+ n_assembler_options);
assembler_options [n_assembler_options - 1] = save_string (option, len);
}
n_linker_options++;
if (! linker_options)
- linker_options = xmalloc (n_linker_options * sizeof (char *));
+ linker_options = XNEWVEC (char *, n_linker_options);
else
- linker_options = xrealloc (linker_options,
- n_linker_options * sizeof (char *));
+ linker_options = XRESIZEVEC (char *, linker_options, n_linker_options);
linker_options [n_linker_options - 1] = save_string (option, len);
}
Store its length in `n_switches'. */
static void
-process_command (int argc, const char *const *argv)
+process_command (int argc, const char **argv)
{
int i;
const char *temp;
char *temp1;
const char *spec_lang = 0;
int last_language_n_infiles;
- int have_c = 0;
- int have_o = 0;
int lang_n_infiles = 0;
#ifdef MODIFY_TARGET_NAME
int is_modify_target_name;
- int j;
+ unsigned int j;
#endif
+ const char *tooldir_prefix;
+ char *(*get_relative_prefix) (const char *, const char *,
+ const char *) = NULL;
GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX");
}
}
- /* If there is a -V or -b option (or both), process it now, before
- trying to interpret the rest of the command line. */
- if (argc > 1 && argv[1][0] == '-'
- && (argv[1][1] == 'V' || argv[1][1] == 'b'))
+ /* Convert new-style -- options to old-style. */
+ translate_options (&argc,
+ CONST_CAST2 (const char *const **, const char ***,
+ &argv));
+
+ /* Handle any -no-canonical-prefixes flag early, to assign the function
+ that builds relative prefixes. This function creates default search
+ paths that are needed later in normal option handling. */
+
+ for (i = 1; i < argc; i++)
{
- const char *new_version = DEFAULT_TARGET_VERSION;
- const char *new_machine = DEFAULT_TARGET_MACHINE;
- const char *progname = argv[0];
- char **new_argv;
- char *new_argv0;
- int baselen;
-
- while (argc > 1 && argv[1][0] == '-'
- && (argv[1][1] == 'V' || argv[1][1] == 'b'))
+ if (! strcmp (argv[i], "-no-canonical-prefixes"))
{
- char opt = argv[1][1];
- const char *arg;
- if (argv[1][2] != '\0')
- {
- arg = argv[1] + 2;
- argc -= 1;
- argv += 1;
- }
- else if (argc > 2)
- {
- arg = argv[2];
- argc -= 2;
- argv += 2;
- }
- else
- fatal ("`-%c' option must have argument", opt);
- if (opt == 'V')
- new_version = arg;
- else
- new_machine = arg;
- }
-
- for (baselen = strlen (progname); baselen > 0; baselen--)
- if (IS_DIR_SEPARATOR (progname[baselen-1]))
+ get_relative_prefix = make_relative_prefix_ignore_links;
break;
- new_argv0 = xmemdup (progname, baselen,
- baselen + concat_length (new_version, new_machine,
- "-gcc-", NULL) + 1);
- strcpy (new_argv0 + baselen, new_machine);
- strcat (new_argv0, "-gcc-");
- strcat (new_argv0, new_version);
-
- new_argv = xmemdup (argv, (argc + 1) * sizeof (argv[0]),
- (argc + 1) * sizeof (argv[0]));
- new_argv[0] = new_argv0;
-
- execvp (new_argv0, new_argv);
- fatal ("couldn't run `%s': %s", new_argv0, xstrerror (errno));
+ }
}
+ if (! get_relative_prefix)
+ get_relative_prefix = make_relative_prefix;
/* Set up the default search paths. If there is no GCC_EXEC_PREFIX,
see if we can create it from the pathname specified in argv[0]. */
/* FIXME: make_relative_prefix doesn't yet work for VMS. */
if (!gcc_exec_prefix)
{
- gcc_exec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix,
- standard_exec_prefix);
- gcc_libexec_prefix = make_relative_prefix (argv[0],
- standard_bindir_prefix,
- standard_libexec_prefix);
+ gcc_exec_prefix = get_relative_prefix (argv[0],
+ standard_bindir_prefix,
+ standard_exec_prefix);
+ gcc_libexec_prefix = get_relative_prefix (argv[0],
+ standard_bindir_prefix,
+ standard_libexec_prefix);
if (gcc_exec_prefix)
- putenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL));
+ xputenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL));
}
else
- gcc_libexec_prefix = make_relative_prefix (gcc_exec_prefix,
- standard_exec_prefix,
- standard_libexec_prefix);
+ {
+ /* make_relative_prefix requires a program name, but
+ GCC_EXEC_PREFIX is typically a directory name with a trailing
+ / (which is ignored by make_relative_prefix), so append a
+ program name. */
+ char *tmp_prefix = concat (gcc_exec_prefix, "gcc", NULL);
+ gcc_libexec_prefix = get_relative_prefix (tmp_prefix,
+ standard_exec_prefix,
+ standard_libexec_prefix);
+
+ /* The path is unrelocated, so fallback to the original setting. */
+ if (!gcc_libexec_prefix)
+ gcc_libexec_prefix = standard_libexec_prefix;
+
+ free (tmp_prefix);
+ }
#else
#endif
+ /* From this point onward, gcc_exec_prefix is non-null if the toolchain
+ is relocated. The toolchain was either relocated using GCC_EXEC_PREFIX
+ or an automatically created GCC_EXEC_PREFIX from argv[0]. */
+
+ /* Do language-specific adjustment/addition of flags. */
+ lang_specific_driver (&argc,
+ CONST_CAST2 (const char *const **, const char ***,
+ &argv),
+ &added_libraries);
if (gcc_exec_prefix)
{
set_std_prefix (gcc_exec_prefix, len);
add_prefix (&exec_prefixes, gcc_libexec_prefix, "GCC",
- PREFIX_PRIORITY_LAST, 0, NULL, 0);
+ PREFIX_PRIORITY_LAST, 0, 0);
add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC",
- PREFIX_PRIORITY_LAST, 0, NULL, 0);
+ PREFIX_PRIORITY_LAST, 0, 0);
}
/* COMPILER_PATH and LIBRARY_PATH have values
if (temp)
{
const char *startp, *endp;
- char *nstore = alloca (strlen (temp) + 3);
+ char *nstore = (char *) alloca (strlen (temp) + 3);
startp = endp = temp;
while (1)
else
nstore[endp - startp] = 0;
add_prefix (&exec_prefixes, nstore, 0,
- PREFIX_PRIORITY_LAST, 0, NULL, 0);
- add_prefix (&include_prefixes,
- concat (nstore, "include", NULL),
- 0, PREFIX_PRIORITY_LAST, 0, NULL, 0);
+ PREFIX_PRIORITY_LAST, 0, 0);
+ add_prefix (&include_prefixes, nstore, 0,
+ PREFIX_PRIORITY_LAST, 0, 0);
if (*endp == 0)
break;
endp = startp = endp + 1;
if (temp && *cross_compile == '0')
{
const char *startp, *endp;
- char *nstore = alloca (strlen (temp) + 3);
+ char *nstore = (char *) alloca (strlen (temp) + 3);
startp = endp = temp;
while (1)
else
nstore[endp - startp] = 0;
add_prefix (&startfile_prefixes, nstore, NULL,
- PREFIX_PRIORITY_LAST, 0, NULL, 1);
+ PREFIX_PRIORITY_LAST, 0, 1);
if (*endp == 0)
break;
endp = startp = endp + 1;
if (temp && *cross_compile == '0')
{
const char *startp, *endp;
- char *nstore = alloca (strlen (temp) + 3);
+ char *nstore = (char *) alloca (strlen (temp) + 3);
startp = endp = temp;
while (1)
else
nstore[endp - startp] = 0;
add_prefix (&startfile_prefixes, nstore, NULL,
- PREFIX_PRIORITY_LAST, 0, NULL, 1);
+ PREFIX_PRIORITY_LAST, 0, 1);
if (*endp == 0)
break;
endp = startp = endp + 1;
}
}
- /* Convert new-style -- options to old-style. */
- translate_options (&argc, &argv);
-
- /* Do language-specific adjustment/addition of flags. */
- lang_specific_driver (&argc, &argv, &added_libraries);
-
/* Scan argv twice. Here, the first time, just count how many switches
there will be in their vector, and how many input files in theirs.
Here we also parse the switches that cc itself uses (e.g. -v). */
else if (strcmp (argv[i], "-fversion") == 0)
{
/* translate_options () has turned --version into -fversion. */
- printf (_("%s (GCC) %s\n"), programname, version_string);
- fputs (_("Copyright (C) 2003 Free Software Foundation, Inc.\n"),
- stdout);
- fputs (_("This is free software; see the source for copying conditions. There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"),
- stdout);
- exit (0);
+ print_version = 1;
+
+ /* We will be passing a dummy file on to the sub-processes. */
+ n_infiles++;
+ n_switches++;
+
+ /* CPP driver cannot obtain switch from cc1_options. */
+ if (is_cpp_driver)
+ add_preprocessor_option ("--version", strlen ("--version"));
+ add_assembler_option ("--version", strlen ("--version"));
+ add_linker_option ("--version", strlen ("--version"));
}
else if (strcmp (argv[i], "-fhelp") == 0)
{
add_assembler_option ("--help", 6);
add_linker_option ("--help", 6);
}
+ else if (strncmp (argv[i], "-fhelp=", 7) == 0)
+ {
+ /* translate_options () has turned --help into -fhelp. */
+ print_subprocess_help = 2;
+
+ /* We will be passing a dummy file on to the sub-processes. */
+ n_infiles++;
+ n_switches++;
+ }
else if (strcmp (argv[i], "-ftarget-help") == 0)
{
/* translate_options() has turned --target-help into -ftarget-help. */
- target_help_flag = 1;
+ print_subprocess_help = 1;
/* We will be passing a dummy file on to the sub-processes. */
n_infiles++;
print_multi_lib = 1;
else if (! strcmp (argv[i], "-print-multi-directory"))
print_multi_directory = 1;
+ else if (! strcmp (argv[i], "-print-sysroot"))
+ print_sysroot = 1;
else if (! strcmp (argv[i], "-print-multi-os-directory"))
print_multi_os_directory = 1;
+ else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
+ print_sysroot_headers_suffix = 1;
+ else if (! strcmp (argv[i], "-fcompare-debug-second"))
+ {
+ compare_debug_second = 1;
+ n_switches++;
+ }
+ else if (! strcmp (argv[i], "-fno-compare-debug"))
+ {
+ argv[i] = "-fcompare-debug=";
+ goto compare_debug_with_arg;
+ }
+ else if (! strcmp (argv[i], "-fcompare-debug"))
+ {
+ argv[i] = "-fcompare-debug=-gtoggle";
+ goto compare_debug_with_arg;
+ }
+#define OPT "-fcompare-debug="
+ else if (! strncmp (argv[i], OPT, sizeof (OPT) - 1))
+ {
+ const char *opt;
+ compare_debug_with_arg:
+ opt = argv[i] + sizeof (OPT) - 1;
+#undef OPT
+ if (*opt)
+ compare_debug = 1;
+ else
+ compare_debug = -1;
+ if (compare_debug < 0)
+ compare_debug_opt = NULL;
+ else
+ compare_debug_opt = opt;
+ n_switches++;
+ }
else if (! strncmp (argv[i], "-Wa,", 4))
{
int prev, j;
else if (strcmp (argv[i], "-Xlinker") == 0)
{
if (i + 1 == argc)
- fatal ("argument to `-Xlinker' is missing");
+ fatal ("argument to '-Xlinker' is missing");
n_infiles++;
i++;
else if (strcmp (argv[i], "-Xpreprocessor") == 0)
{
if (i + 1 == argc)
- fatal ("argument to `-Xpreprocessor' is missing");
+ fatal ("argument to '-Xpreprocessor' is missing");
add_preprocessor_option (argv[i+1], strlen (argv[i+1]));
}
else if (strcmp (argv[i], "-Xassembler") == 0)
{
if (i + 1 == argc)
- fatal ("argument to `-Xassembler' is missing");
+ fatal ("argument to '-Xassembler' is missing");
add_assembler_option (argv[i+1], strlen (argv[i+1]));
}
else if (strcmp (argv[i], "-l") == 0)
{
if (i + 1 == argc)
- fatal ("argument to `-l' is missing");
+ fatal ("argument to '-l' is missing");
n_infiles++;
i++;
n_infiles++;
else if (strcmp (argv[i], "-save-temps") == 0)
{
- save_temps_flag = 1;
+ save_temps_flag = SAVE_TEMPS_CWD;
+ n_switches++;
+ }
+ else if (strncmp (argv[i], "-save-temps=", 12) == 0)
+ {
+ n_switches++;
+ if (strcmp (argv[i]+12, "cwd") == 0)
+ save_temps_flag = SAVE_TEMPS_CWD;
+ else if (strcmp (argv[i]+12, "obj") == 0
+ || strcmp (argv[i]+12, "object") == 0)
+ save_temps_flag = SAVE_TEMPS_OBJ;
+ else
+ fatal ("'%s' is an unknown -save-temps option", argv[i]);
+ }
+ else if (strcmp (argv[i], "-no-canonical-prefixes") == 0)
+ /* Already handled as a special case, so ignored here. */
+ ;
+ else if (strcmp (argv[i], "-combine") == 0)
+ {
+ combine_flag = 1;
n_switches++;
}
else if (strcmp (argv[i], "-specs") == 0)
{
- struct user_specs *user = xmalloc (sizeof (struct user_specs));
+ struct user_specs *user = XNEW (struct user_specs);
if (++i >= argc)
- fatal ("argument to `-specs' is missing");
+ fatal ("argument to '-specs' is missing");
user->next = (struct user_specs *) 0;
user->filename = argv[i];
}
else if (strncmp (argv[i], "-specs=", 7) == 0)
{
- struct user_specs *user = xmalloc (sizeof (struct user_specs));
+ struct user_specs *user = XNEW (struct user_specs);
if (strlen (argv[i]) == 7)
- fatal ("argument to `-specs=' is missing");
+ fatal ("argument to '-specs=' is missing");
user->next = (struct user_specs *) 0;
user->filename = argv[i] + 7;
}
else if (strcmp (argv[i], "-time") == 0)
report_times = 1;
+ else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
+ {
+ if (report_times_to_file)
+ fclose (report_times_to_file);
+ report_times_to_file = fopen (argv[i] + sizeof ("-time=") - 1, "a");
+ }
else if (strcmp (argv[i], "-pipe") == 0)
{
/* -pipe has to go into the switches array as well as
use_pipes = 1;
n_switches++;
}
+ else if (strcmp (argv[i], "-wrapper") == 0)
+ {
+ if (++i >= argc)
+ fatal ("argument to '-wrapper' is missing");
+
+ wrapper_string = argv[i];
+ n_switches++;
+ n_switches++;
+ }
else if (strcmp (argv[i], "-###") == 0)
{
/* This is similar to -v except that there is no execution
switch (c)
{
- case 'b':
- case 'V':
- fatal ("`-%c' must come at the start of the command line", c);
- break;
-
case 'B':
{
const char *value;
int len;
if (p[1] == 0 && i + 1 == argc)
- fatal ("argument to `-B' is missing");
+ fatal ("argument to '-B' is missing");
if (p[1] == 0)
value = argv[++i];
else
if appending a directory separator actually makes a
valid directory name. */
if (! IS_DIR_SEPARATOR (value [len - 1])
- && is_directory (value, "", 0))
+ && is_directory (value, false))
{
- char *tmp = xmalloc (len + 2);
+ char *tmp = XNEWVEC (char, len + 2);
strcpy (tmp, value);
tmp[len] = DIR_SEPARATOR;
tmp[++ len] = 0;
value = tmp;
}
- /* As a kludge, if the arg is "[foo/]stageN/", just
- add "[foo/]include" to the include prefix. */
- if ((len == 7
- || (len > 7
- && (IS_DIR_SEPARATOR (value[len - 8]))))
- && strncmp (value + len - 7, "stage", 5) == 0
- && ISDIGIT (value[len - 2])
- && (IS_DIR_SEPARATOR (value[len - 1])))
- {
- if (len == 7)
- add_prefix (&include_prefixes, "include", NULL,
- PREFIX_PRIORITY_B_OPT, 0, NULL, 0);
- else
- {
- char * string = xmalloc (len + 1);
-
- strncpy (string, value, len - 7);
- strcpy (string + len - 7, "include");
- add_prefix (&include_prefixes, string, NULL,
- PREFIX_PRIORITY_B_OPT, 0, NULL, 0);
- }
- }
-
add_prefix (&exec_prefixes, value, NULL,
- PREFIX_PRIORITY_B_OPT, 0, &warn_B, 0);
+ PREFIX_PRIORITY_B_OPT, 0, 0);
add_prefix (&startfile_prefixes, value, NULL,
- PREFIX_PRIORITY_B_OPT, 0, &warn_B, 0);
- add_prefix (&include_prefixes, concat (value, "include", NULL),
- NULL, PREFIX_PRIORITY_B_OPT, 0, NULL, 0);
+ PREFIX_PRIORITY_B_OPT, 0, 0);
+ add_prefix (&include_prefixes, value, NULL,
+ PREFIX_PRIORITY_B_OPT, 0, 0);
n_switches++;
}
break;
case 'S':
case 'c':
+ case 'E':
if (p[1] == 0)
{
have_c = 1;
{
int skip;
- /* Forward scan, just in case -S or -c is specified
+ /* Forward scan, just in case -S, -E or -c is specified
after -o. */
int j = i + 1;
if (p[1] == 0)
else
argv[i] = convert_filename (argv[i], ! have_c, 0);
#endif
+ /* Save the output name in case -save-temps=obj was used. */
+ if ((p[1] == 0) && argv[i + 1])
+ save_temps_prefix = xstrdup(argv[i + 1]);
+ else
+ save_temps_prefix = xstrdup(argv[i] + 1);
goto normal_switch;
default:
for (j = 0; j < ARRAY_SIZE (modify_target); j++)
if (! strcmp (argv[i], modify_target[j].sw))
{
- char *new_name = xmalloc (strlen (modify_target[j].str)
+ char *new_name = XNEWVEC (char, strlen (modify_target[j].str)
+ strlen (spec_machine));
const char *p, *r;
char *q;
}
}
- combine_inputs = (have_c && have_o && lang_n_infiles > 1);
+ /* If -save-temps=obj and -o name, create the prefix to use for %b.
+ Otherwise just make -save-temps=obj the same as -save-temps=cwd. */
+ if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL)
+ {
+ save_temps_length = strlen (save_temps_prefix);
+ temp = strrchr (lbasename (save_temps_prefix), '.');
+ if (temp)
+ {
+ save_temps_length -= strlen (temp);
+ save_temps_prefix[save_temps_length] = '\0';
+ }
+
+ }
+ else if (save_temps_prefix != NULL)
+ {
+ free (save_temps_prefix);
+ save_temps_prefix = NULL;
+ }
- if ((save_temps_flag || report_times) && use_pipes)
+ if (save_temps_flag && use_pipes)
{
/* -save-temps overrides -pipe, so that temp files are produced */
if (save_temps_flag)
error ("warning: -pipe ignored because -save-temps specified");
- /* -time overrides -pipe because we can't get correct stats when
- multiple children are running at once. */
- else if (report_times)
- error ("warning: -pipe ignored because -time specified");
-
use_pipes = 0;
}
- /* Set up the search paths before we go looking for config files. */
+ if (!compare_debug)
+ {
+ const char *gcd = getenv ("GCC_COMPARE_DEBUG");
+
+ if (gcd && gcd[0] == '-')
+ {
+ compare_debug = 2;
+ compare_debug_opt = gcd;
+ n_switches++;
+ }
+ else if (gcd && *gcd && strcmp (gcd, "0"))
+ {
+ compare_debug = 3;
+ compare_debug_opt = "-gtoggle";
+ n_switches++;
+ }
+ }
+ else if (compare_debug < 0)
+ {
+ compare_debug = 0;
+ gcc_assert (!compare_debug_opt);
+ }
+
+ /* Set up the search paths. We add directories that we expect to
+ contain GNU Toolchain components before directories specified by
+ the machine description so that we will find GNU components (like
+ the GNU assembler) before those of the host system. */
- /* 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. */
+ /* If we don't know where the toolchain has been installed, use the
+ configured-in locations. */
+ if (!gcc_exec_prefix)
+ {
#ifndef OS2
- add_prefix (&exec_prefixes, standard_libexec_prefix, "GCC",
- PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0);
- add_prefix (&exec_prefixes, standard_libexec_prefix, "BINUTILS",
- PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0);
- add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS",
- PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0);
- add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS",
- PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0);
- add_prefix (&exec_prefixes, standard_exec_prefix_2, "BINUTILS",
- PREFIX_PRIORITY_LAST, 2, warn_std_ptr, 0);
+ add_prefix (&exec_prefixes, standard_libexec_prefix, "GCC",
+ PREFIX_PRIORITY_LAST, 1, 0);
+ add_prefix (&exec_prefixes, standard_libexec_prefix, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 2, 0);
+ add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 2, 0);
#endif
+ add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 1, 0);
+ }
- add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS",
- PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0);
- add_prefix (&startfile_prefixes, standard_exec_prefix_2, "BINUTILS",
- PREFIX_PRIORITY_LAST, 1, warn_std_ptr, 0);
-
+ gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix));
tooldir_prefix = concat (tooldir_base_prefix, spec_machine,
dir_separator_str, NULL);
- /* 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 (!IS_ABSOLUTE_PATH (tooldir_prefix))
- {
- if (gcc_exec_prefix)
- {
- char *gcc_exec_tooldir_prefix
- = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
- spec_version, dir_separator_str, tooldir_prefix, NULL);
-
- add_prefix (&exec_prefixes,
- concat (gcc_exec_tooldir_prefix, "bin",
- dir_separator_str, NULL),
- NULL, PREFIX_PRIORITY_LAST, 0, NULL, 0);
- add_prefix (&startfile_prefixes,
- concat (gcc_exec_tooldir_prefix, "lib",
- dir_separator_str, NULL),
- NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1);
- }
-
- tooldir_prefix = concat (standard_exec_prefix, spec_machine,
- dir_separator_str, spec_version,
- dir_separator_str, tooldir_prefix, NULL);
- }
+ /* Look for tools relative to the location from which the driver is
+ running, or, if that is not available, the configured prefix. */
+ tooldir_prefix
+ = concat (gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix,
+ spec_machine, dir_separator_str,
+ spec_version, dir_separator_str, tooldir_prefix, NULL);
add_prefix (&exec_prefixes,
concat (tooldir_prefix, "bin", dir_separator_str, NULL),
- "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 0);
+ "BINUTILS", PREFIX_PRIORITY_LAST, 0, 0);
add_prefix (&startfile_prefixes,
concat (tooldir_prefix, "lib", dir_separator_str, NULL),
- "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1);
+ "BINUTILS", PREFIX_PRIORITY_LAST, 0, 1);
#if defined(TARGET_SYSTEM_ROOT_RELOCATABLE) && !defined(VMS)
/* If the normal TARGET_SYSTEM_ROOT is inside of $exec_prefix,
``make_relative_prefix'' is not compiled for VMS, so don't call it. */
if (target_system_root && gcc_exec_prefix)
{
- char *tmp_prefix = make_relative_prefix (argv[0],
- standard_bindir_prefix,
- target_system_root);
+ char *tmp_prefix = get_relative_prefix (argv[0],
+ standard_bindir_prefix,
+ target_system_root);
if (tmp_prefix && access_check (tmp_prefix, F_OK) == 0)
{
target_system_root = tmp_prefix;
/* Then create the space for the vectors and scan again. */
- switches = xmalloc ((n_switches + 1) * sizeof (struct switchstr));
- infiles = xmalloc ((n_infiles + 1) * sizeof (struct infile));
+ switches = XNEWVEC (struct switchstr, n_switches + 1);
+ infiles = XNEWVEC (struct infile, n_infiles + 1);
n_switches = 0;
n_infiles = 0;
last_language_n_infiles = -1;
;
else if (! strncmp (argv[i], "-Wp,", 4))
;
+ else if (! strcmp (argv[i], "-no-canonical-prefixes"))
+ ;
else if (! strcmp (argv[i], "-pass-exit-codes"))
;
else if (! strcmp (argv[i], "-print-search-dirs"))
;
else if (! strcmp (argv[i], "-print-multi-directory"))
;
- else if (! strcmp (argv[i], "-print-multi-os-directory"))
+ else if (! strcmp (argv[i], "-print-sysroot"))
;
- else if (! strcmp (argv[i], "-ftarget-help"))
+ else if (! strcmp (argv[i], "-print-multi-os-directory"))
;
- else if (! strcmp (argv[i], "-fhelp"))
+ else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
;
+ else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot=")))
+ {
+ target_system_root = argv[i] + strlen ("--sysroot=");
+ target_system_root_changed = 1;
+ }
else if (argv[i][0] == '+' && argv[i][1] == 'e')
{
/* Compensate for the +e options to the C++ front-end;
-e0 or -e1 down into the linker. */
switches[n_switches].part1 = &argv[i][0];
switches[n_switches].args = 0;
- switches[n_switches].live_cond = SWITCH_OK;
+ switches[n_switches].live_cond = 0;
switches[n_switches].validated = 0;
n_switches++;
}
infiles[n_infiles].language = "*";
infiles[n_infiles++].name = argv[++i];
}
+ /* Xassembler and Xpreprocessor were already handled in the first argv
+ scan, so all we need to do here is ignore them and their argument. */
else if (strcmp (argv[i], "-Xassembler") == 0)
- {
- infiles[n_infiles].language = "*";
- infiles[n_infiles++].name = argv[++i];
- }
+ i++;
else if (strcmp (argv[i], "-Xpreprocessor") == 0)
- {
- infiles[n_infiles].language = "*";
- infiles[n_infiles++].name = argv[++i];
- }
+ i++;
else if (strcmp (argv[i], "-l") == 0)
{ /* POSIX allows separation of -l and the lib arg;
canonicalize by concatenating -l with its arg */
infiles[n_infiles].language = "*";
infiles[n_infiles++].name = argv[i];
}
+ else if (strcmp (argv[i], "-wrapper") == 0)
+ i++;
else if (strcmp (argv[i], "-specs") == 0)
i++;
else if (strncmp (argv[i], "-specs=", 7) == 0)
;
else if (strcmp (argv[i], "-time") == 0)
;
+ else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
+ ;
else if (strcmp (argv[i], "-###") == 0)
;
else if (argv[i][0] == '-' && argv[i][1] != 0)
if (c == 'x')
{
if (p[1] == 0 && i + 1 == argc)
- fatal ("argument to `-x' is missing");
+ fatal ("argument to '-x' is missing");
if (p[1] == 0)
spec_lang = argv[++i];
else
n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
}
if (i + n_args >= argc)
- fatal ("argument to `-%s' is missing", p);
+ fatal ("argument to '-%s' is missing", p);
switches[n_switches].args
- = xmalloc ((n_args + 1) * sizeof(const char *));
+ = XNEWVEC (const char *, n_args + 1);
while (j < n_args)
switches[n_switches].args[j++] = argv[++i];
/* Null-terminate the vector. */
{
/* On some systems, ld cannot handle some options without
a space. So split the option from its argument. */
- char *part1 = xmalloc (2);
+ char *part1 = XNEWVEC (char, 2);
part1[0] = c;
part1[1] = '\0';
switches[n_switches].part1 = part1;
- switches[n_switches].args = xmalloc (2 * sizeof (const char *));
+ switches[n_switches].args = XNEWVEC (const char *, 2);
switches[n_switches].args[0] = xstrdup (p+1);
switches[n_switches].args[1] = 0;
}
else
switches[n_switches].args = 0;
- switches[n_switches].live_cond = SWITCH_OK;
+ switches[n_switches].live_cond = 0;
switches[n_switches].validated = 0;
switches[n_switches].ordering = 0;
- /* These are always valid, since gcc.c itself understands them. */
+ /* These are always valid, since gcc.c itself understands the
+ first four, gfortranspec.c understands -static-libgfortran
+ and g++spec.c understands -static-libstdc++ */
if (!strcmp (p, "save-temps")
|| !strcmp (p, "static-libgcc")
|| !strcmp (p, "shared-libgcc")
- || !strcmp (p, "pipe"))
+ || !strcmp (p, "pipe")
+ || !strcmp (p, "static-libgfortran")
+ || !strcmp (p, "static-libstdc++"))
switches[n_switches].validated = 1;
else
{
}
else
{
+ const char *p = strrchr (argv[i], '@');
+ char *fname;
+ long offset;
+ int consumed;
#ifdef HAVE_TARGET_OBJECT_SUFFIX
argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
#endif
-
- if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0)
+ /* For LTO static archive support we handle input file
+ specifications that are composed of a filename and
+ an offset like FNAME@OFFSET. */
+ if (p
+ && p != argv[i]
+ && sscanf (p, "@%li%n", &offset, &consumed) >= 1
+ && strlen (p) == (unsigned int)consumed)
{
- perror_with_name (argv[i]);
- error_count++;
+ fname = (char *)xmalloc (p - argv[i] + 1);
+ memcpy (fname, argv[i], p - argv[i]);
+ fname[p - argv[i]] = '\0';
+ /* Only accept non-stdin and existing FNAME parts, otherwise
+ try with the full name. */
+ if (strcmp (fname, "-") == 0 || access (fname, F_OK) < 0)
+ {
+ free (fname);
+ fname = xstrdup (argv[i]);
+ }
}
else
- {
- infiles[n_infiles].language = spec_lang;
- infiles[n_infiles++].name = argv[i];
- }
+ fname = xstrdup (argv[i]);
+
+ if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
+ {
+ perror_with_name (fname);
+ error_count++;
+ }
+ else
+ {
+ infiles[n_infiles].language = spec_lang;
+ infiles[n_infiles++].name = argv[i];
+ }
+
+ free (fname);
}
}
if (n_infiles == last_language_n_infiles && spec_lang != 0)
- error ("warning: `-x %s' after last input file has no effect", spec_lang);
+ error ("warning: '-x %s' after last input file has no effect", spec_lang);
+
+ if (compare_debug == 2 || compare_debug == 3)
+ {
+ switches[n_switches].part1 = concat ("fcompare-debug=",
+ compare_debug_opt,
+ NULL);
+ switches[n_switches].args = 0;
+ switches[n_switches].live_cond = 0;
+ switches[n_switches].validated = 0;
+ switches[n_switches].ordering = 0;
+ n_switches++;
+ compare_debug = 1;
+ }
/* Ensure we only invoke each subprocess once. */
- if (target_help_flag || print_help_list)
+ if (print_subprocess_help || print_help_list || print_version)
{
n_infiles = 1;
- /* Create a dummy input file, so that we can pass --target-help on to
- the various sub-processes. */
+ /* Create a dummy input file, so that we can pass
+ the help option on to the various sub-processes. */
infiles[0].language = "c";
infiles[0].name = "help-dummy";
-
- if (target_help_flag)
- {
- switches[n_switches].part1 = "--target-help";
- switches[n_switches].args = 0;
- switches[n_switches].live_cond = SWITCH_OK;
- switches[n_switches].validated = 0;
-
- n_switches++;
- }
-
- if (print_help_list)
- {
- switches[n_switches].part1 = "--help";
- switches[n_switches].args = 0;
- switches[n_switches].live_cond = SWITCH_OK;
- switches[n_switches].validated = 0;
-
- n_switches++;
- }
}
switches[n_switches].part1 = 0;
first_time = FALSE;
/* Ignore elided switches. */
- if (switches[i].live_cond == SWITCH_IGNORE)
+ if ((switches[i].live_cond & SWITCH_IGNORE) != 0)
continue;
obstack_grow (&collect_obstack, "'-", 2);
}
}
obstack_grow (&collect_obstack, "\0", 1);
- putenv (obstack_finish (&collect_obstack));
+ xputenv (XOBFINISH (&collect_obstack, char *));
}
\f
/* Process a spec string, accumulating and running commands. */
static int suffixed_basename_length;
static const char *input_basename;
static const char *input_suffix;
+#ifndef HOST_LACKS_INODE_NUMBERS
static struct stat input_stat;
+#endif
static int input_stat_set;
/* The compiler used to process the current input file. */
search dirs for it. */
static int this_is_library_file;
+/* Nonzero means %T has been seen; the next arg to be terminated
+ is the name of a linker script and we should try all of the
+ standard search dirs for it. If it is found insert a --script
+ command line switch and then substitute the full path in place,
+ otherwise generate an error message. */
+static int this_is_linker_script;
+
/* Nonzero means that the input of this command is coming from a pipe. */
static int input_from_pipe;
arguments. */
static const char *suffix_subst;
+/* If there is an argument being accumulated, terminate it and store it. */
+
+static void
+end_going_arg (void)
+{
+ if (arg_going)
+ {
+ const char *string;
+
+ obstack_1grow (&obstack, 0);
+ string = XOBFINISH (&obstack, const char *);
+ if (this_is_library_file)
+ string = find_file (string);
+ if (this_is_linker_script)
+ {
+ char * full_script_path = find_a_file (&startfile_prefixes, string, R_OK, true);
+
+ if (full_script_path == NULL)
+ {
+ error (_("unable to locate default linker script '%s' in the library search paths"), string);
+ /* Script was not found on search path. */
+ return;
+ }
+ store_arg ("--script", false, false);
+ string = full_script_path;
+ }
+ store_arg (string, delete_this_arg, this_is_output_file);
+ if (this_is_output_file)
+ outfiles[input_file_number] = string;
+ arg_going = 0;
+ }
+}
+
+
+/* Parse the WRAPPER string which is a comma separated list of the command line
+ and insert them into the beginning of argbuf. */
+
+static void
+insert_wrapper (const char *wrapper)
+{
+ int n = 0;
+ int i;
+ char *buf = xstrdup (wrapper);
+ char *p = buf;
+
+ do
+ {
+ n++;
+ while (*p == ',')
+ p++;
+ }
+ while ((p = strchr (p, ',')) != NULL);
+
+ if (argbuf_index + n >= argbuf_length)
+ {
+ argbuf_length = argbuf_length * 2;
+ while (argbuf_length < argbuf_index + n)
+ argbuf_length *= 2;
+ argbuf = XRESIZEVEC (const char *, argbuf, argbuf_length);
+ }
+ for (i = argbuf_index - 1; i >= 0; i--)
+ argbuf[i + n] = argbuf[i];
+
+ i = 0;
+ p = buf;
+ do
+ {
+ while (*p == ',')
+ {
+ *p = 0;
+ p++;
+ }
+ argbuf[i++] = p;
+ }
+ while ((p = strchr (p, ',')) != NULL);
+ gcc_assert (i == n);
+ argbuf_index += n;
+}
+
/* Process the spec SPEC and run the commands specified therein.
Returns 0 if the spec is successfully processed; -1 if failed. */
static int
do_spec_2 (const char *spec)
{
- const char *string;
int result;
clear_args ();
delete_this_arg = 0;
this_is_output_file = 0;
this_is_library_file = 0;
+ this_is_linker_script = 0;
input_from_pipe = 0;
suffix_subst = NULL;
result = do_spec_1 (spec, 0, NULL);
- /* End any pending argument. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = obstack_finish (&obstack);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- arg_going = 0;
- }
+ end_going_arg ();
return result;
}
}
/* Replace each %(VALUE) by the specified value. */
- tmp_spec = alloca (strlen (spec) + 1
+ tmp_spec = (char *) alloca (strlen (spec) + 1
+ value_count * (value_len - strlen ("%(VALUE)")));
tmp_spec_p = tmp_spec;
q = spec;
static void
do_self_spec (const char *spec)
{
+ int i;
+
do_spec_2 (spec);
do_spec_1 (" ", 0, NULL);
+ /* Mark %<S switches processed by do_self_spec to be ignored permanently.
+ do_self_specs adds the replacements to switches array, so it shouldn't
+ be processed afterwards. */
+ for (i = 0; i < n_switches; i++)
+ if ((switches[i].live_cond & SWITCH_IGNORE))
+ switches[i].live_cond |= SWITCH_IGNORE_PERMANENTLY;
+
if (argbuf_index > 0)
{
- int i, first;
-
- first = n_switches;
- n_switches += argbuf_index;
- switches = xrealloc (switches,
- sizeof (struct switchstr) * (n_switches + 1));
+ switches = XRESIZEVEC (struct switchstr, switches,
+ n_switches + argbuf_index + 1);
- switches[n_switches] = switches[first];
for (i = 0; i < argbuf_index; i++)
{
struct switchstr *sw;
+ const char *p = argbuf[i];
+ int c = *p;
/* Each switch should start with '-'. */
- if (argbuf[i][0] != '-')
- abort ();
+ if (c != '-')
+ fatal ("switch '%s' does not start with '-'", argbuf[i]);
+
+ p++;
+ c = *p;
- sw = &switches[i + first];
- sw->part1 = &argbuf[i][1];
- sw->args = 0;
- sw->live_cond = SWITCH_OK;
+ sw = &switches[n_switches++];
+ sw->part1 = p;
+ sw->live_cond = 0;
sw->validated = 0;
sw->ordering = 0;
- }
- }
-}
-/* Process the sub-spec SPEC as a portion of a larger spec.
- This is like processing a whole spec except that we do
- not initialize at the beginning and we do not supply a
- newline by default at the end.
- INSWITCH nonzero means don't process %-sequences in SPEC;
- in this case, % is treated as an ordinary character.
- This is used while substituting switches.
- INSWITCH nonzero also causes SPC not to terminate an argument.
+ /* Deal with option arguments in separate argv elements. */
+ if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
+ || WORD_SWITCH_TAKES_ARG (p))
+ {
+ int j = 0;
+ int n_args = WORD_SWITCH_TAKES_ARG (p);
+
+ if (n_args == 0)
+ {
+ /* Count only the option arguments in separate argv elements. */
+ n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
+ }
+ if (i + n_args >= argbuf_index)
+ fatal ("argument to '-%s' is missing", p);
+ sw->args
+ = XNEWVEC (const char *, n_args + 1);
+ while (j < n_args)
+ sw->args[j++] = argbuf[++i];
+ /* Null-terminate the vector. */
+ sw->args[j] = 0;
+ }
+ else if (strchr (switches_need_spaces, c))
+ {
+ /* On some systems, ld cannot handle some options without
+ a space. So split the option from its argument. */
+ char *part1 = XNEWVEC (char, 2);
+ part1[0] = c;
+ part1[1] = '\0';
+
+ sw->part1 = part1;
+ sw->args = XNEWVEC (const char *, 2);
+ sw->args[0] = xstrdup (p+1);
+ sw->args[1] = 0;
+ }
+ else
+ sw->args = 0;
+ }
+
+ switches[n_switches].part1 = 0;
+ }
+}
+
+/* Callback for processing %D and %I specs. */
+
+struct spec_path_info {
+ const char *option;
+ const char *append;
+ size_t append_len;
+ bool omit_relative;
+ bool separate_options;
+};
+
+static void *
+spec_path (char *path, void *data)
+{
+ struct spec_path_info *info = (struct spec_path_info *) data;
+ size_t len = 0;
+ char save = 0;
+
+ if (info->omit_relative && !IS_ABSOLUTE_PATH (path))
+ return NULL;
+
+ if (info->append_len != 0)
+ {
+ len = strlen (path);
+ memcpy (path + len, info->append, info->append_len + 1);
+ }
+
+ if (!is_directory (path, true))
+ return NULL;
+
+ do_spec_1 (info->option, 1, NULL);
+ if (info->separate_options)
+ do_spec_1 (" ", 0, NULL);
+
+ if (info->append_len == 0)
+ {
+ len = strlen (path);
+ save = path[len - 1];
+ if (IS_DIR_SEPARATOR (path[len - 1]))
+ path[len - 1] = '\0';
+ }
+
+ do_spec_1 (path, 1, NULL);
+ do_spec_1 (" ", 0, NULL);
+
+ /* Must not damage the original path. */
+ if (info->append_len == 0)
+ path[len - 1] = save;
+
+ return NULL;
+}
+
+/* Create a temporary FILE with the contents of ARGV. Add @FILE to the
+ argument list. */
+
+static void
+create_at_file (char **argv)
+{
+ char *temp_file = make_temp_file ("");
+ char *at_argument = concat ("@", temp_file, NULL);
+ FILE *f = fopen (temp_file, "w");
+ int status;
+
+ if (f == NULL)
+ fatal ("could not open temporary response file %s",
+ temp_file);
+
+ status = writeargv (argv, f);
+
+ if (status)
+ fatal ("could not write to temporary response file %s",
+ temp_file);
+
+ status = fclose (f);
+
+ if (EOF == status)
+ fatal ("could not close temporary response file %s",
+ temp_file);
+
+ store_arg (at_argument, 0, 0);
+
+ record_temp_file (temp_file, !save_temps_flag, !save_temps_flag);
+}
+
+/* True if we should compile INFILE. */
+
+static bool
+compile_input_file_p (struct infile *infile)
+{
+ if ((!infile->language) || (infile->language[0] != '*'))
+ if (infile->incompiler == input_file_compiler)
+ return true;
+ return false;
+}
+
+/* Process the sub-spec SPEC as a portion of a larger spec.
+ This is like processing a whole spec except that we do
+ not initialize at the beginning and we do not supply a
+ newline by default at the end.
+ INSWITCH nonzero means don't process %-sequences in SPEC;
+ in this case, % is treated as an ordinary character.
+ This is used while substituting switches.
+ INSWITCH nonzero also causes SPC not to terminate an argument.
Value is zero unless a line was finished
and the command on that line reported an error. */
const char *p = spec;
int c;
int i;
- const char *string;
int value;
while ((c = *p++))
switch (inswitch ? 'a' : c)
{
case '\n':
- /* End of line: finish any pending argument,
- then run the pending command if one has been started. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = obstack_finish (&obstack);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- }
- arg_going = 0;
+ end_going_arg ();
if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
{
delete_this_arg = 0;
this_is_output_file = 0;
this_is_library_file = 0;
+ this_is_linker_script = 0;
input_from_pipe = 0;
break;
case '|':
- /* End any pending argument. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = obstack_finish (&obstack);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- }
+ end_going_arg ();
/* Use pipe */
obstack_1grow (&obstack, c);
case '\t':
case ' ':
- /* Space or tab ends an argument if one is pending. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = obstack_finish (&obstack);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- }
+ end_going_arg ();
+
/* Reinitialize for a new argument. */
- arg_going = 0;
delete_this_arg = 0;
this_is_output_file = 0;
this_is_library_file = 0;
+ this_is_linker_script = 0;
break;
case '%':
switch (c = *p++)
{
case 0:
- fatal ("invalid specification! Bug in cc");
+ fatal ("spec '%s' invalid", spec);
case 'b':
- obstack_grow (&obstack, input_basename, basename_length);
+ if (save_temps_length)
+ obstack_grow (&obstack, save_temps_prefix, save_temps_length);
+ else
+ obstack_grow (&obstack, input_basename, basename_length);
+ if (compare_debug < 0)
+ obstack_grow (&obstack, ".gk", 3);
arg_going = 1;
break;
case 'B':
- obstack_grow (&obstack, input_basename, suffixed_basename_length);
+ if (save_temps_length)
+ obstack_grow (&obstack, save_temps_prefix, save_temps_length);
+ else
+ obstack_grow (&obstack, input_basename, suffixed_basename_length);
+ if (compare_debug < 0)
+ obstack_grow (&obstack, ".gk", 3);
arg_going = 1;
break;
that we search for startfiles. */
case 'D':
{
- struct prefix_list *pl = startfile_prefixes.plist;
- size_t bufsize = 100;
- char *buffer = xmalloc (bufsize);
- int idx;
+ struct spec_path_info info;
- for (; pl; pl = pl->next)
- {
+ info.option = "-L";
+ info.append_len = 0;
#ifdef RELATIVE_PREFIX_NOT_LINKDIR
- /* Used on systems which record the specified -L dirs
- and use them to search for dynamic linking. */
- /* Relative directories always come from -B,
- and it is better not to use them for searching
- at run time. In particular, stage1 loses. */
- if (!IS_ABSOLUTE_PATH (pl->prefix))
- continue;
+ /* Used on systems which record the specified -L dirs
+ and use them to search for dynamic linking.
+ Relative directories always come from -B,
+ and it is better not to use them for searching
+ at run time. In particular, stage1 loses. */
+ info.omit_relative = true;
+#else
+ info.omit_relative = false;
#endif
- /* Try subdirectory if there is one. */
- if (multilib_dir != NULL
- || (pl->os_multilib && multilib_os_dir != NULL))
- {
- const char *multi_dir;
+ info.separate_options = false;
- multi_dir = pl->os_multilib ? multilib_os_dir
- : multilib_dir;
- if (machine_suffix && multilib_dir)
- {
- if (strlen (pl->prefix) + strlen (machine_suffix)
- >= bufsize)
- bufsize = (strlen (pl->prefix)
- + strlen (machine_suffix)) * 2 + 1;
- buffer = xrealloc (buffer, bufsize);
- strcpy (buffer, pl->prefix);
- strcat (buffer, machine_suffix);
- if (is_directory (buffer, multilib_dir, 1))
- {
- do_spec_1 ("-L", 0, NULL);
-#ifdef SPACE_AFTER_L_OPTION
- do_spec_1 (" ", 0, NULL);
-#endif
- do_spec_1 (buffer, 1, NULL);
- do_spec_1 (multilib_dir, 1, NULL);
- /* Make this a separate argument. */
- do_spec_1 (" ", 0, NULL);
- }
- }
- if (!pl->require_machine_suffix)
- {
- if (is_directory (pl->prefix, multi_dir, 1))
- {
- do_spec_1 ("-L", 0, NULL);
-#ifdef SPACE_AFTER_L_OPTION
- do_spec_1 (" ", 0, NULL);
-#endif
- do_spec_1 (pl->prefix, 1, NULL);
- do_spec_1 (multi_dir, 1, NULL);
- /* Make this a separate argument. */
- do_spec_1 (" ", 0, NULL);
- }
- }
- }
- if (machine_suffix)
- {
- if (is_directory (pl->prefix, machine_suffix, 1))
- {
- do_spec_1 ("-L", 0, NULL);
-#ifdef SPACE_AFTER_L_OPTION
- do_spec_1 (" ", 0, NULL);
-#endif
- do_spec_1 (pl->prefix, 1, NULL);
- /* Remove slash from machine_suffix. */
- if (strlen (machine_suffix) >= bufsize)
- bufsize = strlen (machine_suffix) * 2 + 1;
- buffer = xrealloc (buffer, bufsize);
- strcpy (buffer, machine_suffix);
- idx = strlen (buffer);
- if (IS_DIR_SEPARATOR (buffer[idx - 1]))
- buffer[idx - 1] = 0;
- do_spec_1 (buffer, 1, NULL);
- /* Make this a separate argument. */
- do_spec_1 (" ", 0, NULL);
- }
- }
- if (!pl->require_machine_suffix)
- {
- if (is_directory (pl->prefix, "", 1))
- {
- do_spec_1 ("-L", 0, NULL);
-#ifdef SPACE_AFTER_L_OPTION
- do_spec_1 (" ", 0, NULL);
-#endif
- /* Remove slash from pl->prefix. */
- if (strlen (pl->prefix) >= bufsize)
- bufsize = strlen (pl->prefix) * 2 + 1;
- buffer = xrealloc (buffer, bufsize);
- strcpy (buffer, pl->prefix);
- idx = strlen (buffer);
- if (IS_DIR_SEPARATOR (buffer[idx - 1]))
- buffer[idx - 1] = 0;
- do_spec_1 (buffer, 1, NULL);
- /* Make this a separate argument. */
- do_spec_1 (" ", 0, NULL);
- }
- }
- }
- free (buffer);
+ for_each_path (&startfile_prefixes, true, 0, spec_path, &info);
}
break;
char *buf;
while (*p != 0 && *p != '\n')
p++;
- buf = alloca (p - q + 1);
+ buf = (char *) alloca (p - q + 1);
strncpy (buf, q, p - q);
buf[p - q] = 0;
- error ("%s", buf);
+ error ("%s", _(buf));
return -1;
}
break;
char *buf;
while (*p != 0 && *p != '\n')
p++;
- buf = alloca (p - q + 1);
+ buf = (char *) alloca (p - q + 1);
strncpy (buf, q, p - q);
buf[p - q] = 0;
- notice ("%s\n", buf);
+ notice ("%s\n", _(buf));
if (*p)
p++;
}
arg_going = 1;
/* consume suffix */
- while (*p == '.' || ISALPHA ((unsigned char) *p))
+ while (*p == '.' || ISALNUM ((unsigned char) *p))
p++;
if (p[0] == '%' && p[1] == 'O')
p += 2;
if (use_pipes)
{
/* consume suffix */
- while (*p == '.' || ISALPHA ((unsigned char) *p))
+ while (*p == '.' || ISALNUM ((unsigned char) *p))
p++;
if (p[0] == '%' && p[1] == 'O')
p += 2;
const char *suffix = p;
char *saved_suffix = NULL;
- while (*p == '.' || ISALPHA ((unsigned char) *p))
+ while (*p == '.' || ISALNUM ((unsigned char) *p))
p++;
suffix_length = p - suffix;
if (p[0] == '%' && p[1] == 'O')
{
p += 2;
/* We don't support extra suffix characters after %O. */
- if (*p == '.' || ISALPHA ((unsigned char) *p))
- abort ();
+ if (*p == '.' || ISALNUM ((unsigned char) *p))
+ fatal ("spec '%s' has invalid '%%0%c'", spec, *p);
if (suffix_length == 0)
suffix = TARGET_OBJECT_SUFFIX;
else
{
saved_suffix
- = xmalloc (suffix_length
+ = XNEWVEC (char, suffix_length
+ strlen (TARGET_OBJECT_SUFFIX));
strncpy (saved_suffix, suffix, suffix_length);
strcpy (saved_suffix + suffix_length,
suffix_length += strlen (TARGET_OBJECT_SUFFIX);
}
+ if (compare_debug < 0)
+ {
+ suffix = concat (".gk", suffix, NULL);
+ suffix_length += 3;
+ }
+
+ /* If -save-temps=obj and -o were specified, use that for the
+ temp file. */
+ if (save_temps_length)
+ {
+ char *tmp;
+ temp_filename_length
+ = save_temps_length + suffix_length + 1;
+ tmp = (char *) alloca (temp_filename_length);
+ memcpy (tmp, save_temps_prefix, save_temps_length);
+ memcpy (tmp + save_temps_length, suffix, suffix_length);
+ tmp[save_temps_length + suffix_length] = '\0';
+ temp_filename = save_string (tmp,
+ temp_filename_length + 1);
+ obstack_grow (&obstack, temp_filename,
+ temp_filename_length);
+ arg_going = 1;
+ delete_this_arg = 0;
+ break;
+ }
+
/* If the input_filename has the same suffix specified
for the %g, %u, or %U, and -save-temps is specified,
we could end up using that file as an intermediate
if (save_temps_flag)
{
- temp_filename_length = basename_length + suffix_length;
- temp_filename = alloca (temp_filename_length + 1);
- strncpy ((char *) temp_filename, input_basename, basename_length);
- strncpy ((char *) temp_filename + basename_length, suffix,
- suffix_length);
- *((char *) temp_filename + temp_filename_length) = '\0';
+ char *tmp;
+ temp_filename_length = basename_length + suffix_length + 1;
+ tmp = (char *) alloca (temp_filename_length);
+ memcpy (tmp, input_basename, basename_length);
+ memcpy (tmp + basename_length, suffix, suffix_length);
+ tmp[basename_length + suffix_length] = '\0';
+ temp_filename = tmp;
+
if (strcmp (temp_filename, input_filename) != 0)
{
+#ifndef HOST_LACKS_INODE_NUMBERS
struct stat st_temp;
/* Note, set_input() resets input_stat_set to 0. */
and we can do the stat for the temp_filename
then the they could still refer to the same
file if st_dev/st_ino's are the same. */
-
if (input_stat_set != 1
|| stat (temp_filename, &st_temp) < 0
|| input_stat.st_dev != st_temp.st_dev
|| input_stat.st_ino != st_temp.st_ino)
+#else
+ /* Just compare canonical pathnames. */
+ char* input_realname = lrealpath (input_filename);
+ char* temp_realname = lrealpath (temp_filename);
+ bool files_differ = strcmp (input_realname, temp_realname);
+ free (input_realname);
+ free (temp_realname);
+ if (files_differ)
+#endif
{
temp_filename = save_string (temp_filename,
temp_filename_length + 1);
{
if (t == 0)
{
- t = xmalloc (sizeof (struct temp_name));
+ t = XNEW (struct temp_name);
t->next = temp_names;
temp_names = t;
}
case 'i':
if (combine_inputs)
{
- for (i = 0; (int) i < n_infiles; i++)
- store_arg (infiles[i].name, 0, 0);
+ if (at_file_supplied)
+ {
+ /* We are going to expand `%i' to `@FILE', where FILE
+ is a newly-created temporary filename. The filenames
+ that would usually be expanded in place of %o will be
+ written to the temporary file. */
+ char **argv;
+ int n_files = 0;
+ int j;
+
+ for (i = 0; i < n_infiles; i++)
+ if (compile_input_file_p (&infiles[i]))
+ n_files++;
+
+ argv = (char **) alloca (sizeof (char *) * (n_files + 1));
+
+ /* Copy the strings over. */
+ for (i = 0, j = 0; i < n_infiles; i++)
+ if (compile_input_file_p (&infiles[i]))
+ {
+ argv[j] = CONST_CAST (char *, infiles[i].name);
+ infiles[i].compiled = true;
+ j++;
+ }
+ argv[j] = NULL;
+
+ create_at_file (argv);
+ }
+ else
+ for (i = 0; (int) i < n_infiles; i++)
+ if (compile_input_file_p (&infiles[i]))
+ {
+ store_arg (infiles[i].name, 0, 0);
+ infiles[i].compiled = true;
+ }
}
else
{
case 'I':
{
- struct prefix_list *pl = include_prefixes.plist;
+ struct spec_path_info info;
+
+ if (multilib_dir)
+ {
+ do_spec_1 ("-imultilib", 1, NULL);
+ /* Make this a separate argument. */
+ do_spec_1 (" ", 0, NULL);
+ do_spec_1 (multilib_dir, 1, NULL);
+ do_spec_1 (" ", 0, NULL);
+ }
if (gcc_exec_prefix)
{
do_spec_1 (" ", 0, NULL);
}
- for (; pl; pl = pl->next)
- {
- do_spec_1 ("-isystem", 1, NULL);
- /* Make this a separate argument. */
- do_spec_1 (" ", 0, NULL);
- do_spec_1 (pl->prefix, 1, NULL);
- do_spec_1 (" ", 0, NULL);
- }
+ info.option = "-isystem";
+ info.append = "include";
+ info.append_len = strlen (info.append);
+ info.omit_relative = false;
+ info.separate_options = true;
+
+ for_each_path (&include_prefixes, false, info.append_len,
+ spec_path, &info);
+
+ info.append = "include-fixed";
+ if (*sysroot_hdrs_suffix_spec)
+ info.append = concat (info.append, dir_separator_str,
+ multilib_dir, NULL);
+ info.append_len = strlen (info.append);
+ for_each_path (&include_prefixes, false, info.append_len,
+ spec_path, &info);
}
break;
int max = n_infiles;
max += lang_specific_extra_outfiles;
- for (i = 0; i < max; i++)
- if (outfiles[i])
- store_arg (outfiles[i], 0, 0);
+ if (HAVE_GNU_LD && at_file_supplied)
+ {
+ /* We are going to expand `%o' to `@FILE', where FILE
+ is a newly-created temporary filename. The filenames
+ that would usually be expanded in place of %o will be
+ written to the temporary file. */
+
+ char **argv;
+ int n_files, j;
+
+ /* Convert OUTFILES into a form suitable for writeargv. */
+
+ /* Determine how many are non-NULL. */
+ for (n_files = 0, i = 0; i < max; i++)
+ n_files += outfiles[i] != NULL;
+
+ argv = (char **) alloca (sizeof (char *) * (n_files + 1));
+
+ /* Copy the strings over. */
+ for (i = 0, j = 0; i < max; i++)
+ if (outfiles[i])
+ {
+ argv[j] = CONST_CAST (char *, outfiles[i]);
+ j++;
+ }
+ argv[j] = NULL;
+
+ create_at_file (argv);
+ }
+ else
+ for (i = 0; i < max; i++)
+ if (outfiles[i])
+ store_arg (outfiles[i], 0, 0);
break;
}
this_is_library_file = 1;
break;
+ case 'T':
+ this_is_linker_script = 1;
+ break;
+
case 'V':
outfiles[input_file_number] = NULL;
break;
int cur_index = argbuf_index;
/* Handle the {...} following the %W. */
if (*p != '{')
- abort ();
+ fatal ("spec '%s' has invalid '%%W%c", spec, *p);
p = handle_braces (p + 1);
if (p == 0)
return -1;
- /* End any pending argument. */
- if (arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = obstack_finish (&obstack);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- arg_going = 0;
- }
+ end_going_arg ();
/* If any args were output, mark the last one for deletion
on failure. */
if (argbuf_index != cur_index)
/* Skip past the option value and make a copy. */
if (*p != '{')
- abort ();
+ fatal ("spec '%s' has invalid '%%x%c'", spec, *p);
while (*p++ != '}')
;
string = save_string (p1 + 1, p - p1 - 2);
return value;
break;
- case 'M':
- if (multilib_dir && strcmp (multilib_dir, ".") != 0)
- {
- char *p;
- const char *q;
- size_t len;
-
- len = strlen (multilib_dir);
- obstack_blank (&obstack, len + 1);
- p = obstack_next_free (&obstack) - (len + 1);
-
- *p++ = '_';
- for (q = multilib_dir; *q ; ++q, ++p)
- *p = (IS_DIR_SEPARATOR (*q) ? '_' : *q);
- }
- break;
-
case 'R':
/* We assume there is a directory
separator at the end of this string. */
if (!strncmp (switches[i].part1, p, len - have_wildcard)
&& (have_wildcard || switches[i].part1[len] == '\0'))
{
- switches[i].live_cond = SWITCH_IGNORE;
+ switches[i].live_cond |= SWITCH_IGNORE;
switches[i].validated = 1;
}
}
else
/* Catch the case where a spec string contains something like
- '%{foo:%*}'. ie there is no * in the pattern on the left
+ '%{foo:%*}'. i.e. there is no * in the pattern on the left
hand side of the :. */
error ("spec failure: '%%*' has not been initialized by pattern match");
break;
}
else
{
- char *x = alloca (strlen (name) * 2 + 1);
+ char *x = (char *) alloca (strlen (name) * 2 + 1);
char *buf = x;
const char *y = name;
int flag = 0;
/* End of string. If we are processing a spec function, we need to
end any pending argument. */
- if (processing_spec_function && arg_going)
- {
- obstack_1grow (&obstack, 0);
- string = obstack_finish (&obstack);
- if (this_is_library_file)
- string = find_file (string);
- store_arg (string, delete_this_arg, this_is_output_file);
- if (this_is_output_file)
- outfiles[input_file_number] = string;
- arg_going = 0;
- }
+ if (processing_spec_function)
+ end_going_arg ();
return 0;
}
static const struct spec_function *
lookup_spec_function (const char *name)
{
- static const struct spec_function * const spec_function_tables[] =
- {
- static_spec_functions,
- lang_specific_spec_functions,
- };
const struct spec_function *sf;
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE (spec_function_tables); i++)
- {
- for (sf = spec_function_tables[i]; sf->name != NULL; sf++)
- if (strcmp (sf->name, name) == 0)
- return sf;
- }
+ for (sf = static_spec_functions; sf->name != NULL; sf++)
+ if (strcmp (sf->name, name) == 0)
+ return sf;
return NULL;
}
int save_this_is_output_file;
int save_this_is_library_file;
int save_input_from_pipe;
+ int save_this_is_linker_script;
const char *save_suffix_subst;
sf = lookup_spec_function (func);
if (sf == NULL)
- fatal ("unknown spec function `%s'", func);
+ fatal ("unknown spec function '%s'", func);
/* Push the spec processing context. */
save_argbuf_index = argbuf_index;
save_delete_this_arg = delete_this_arg;
save_this_is_output_file = this_is_output_file;
save_this_is_library_file = this_is_library_file;
+ save_this_is_linker_script = this_is_linker_script;
save_input_from_pipe = input_from_pipe;
save_suffix_subst = suffix_subst;
alloc_args ();
if (do_spec_2 (args) < 0)
- fatal ("error in args to spec function `%s'", func);
+ fatal ("error in args to spec function '%s'", func);
/* argbuf_index is an index for the next argument to be inserted, and
so contains the count of the args already inserted. */
delete_this_arg = save_delete_this_arg;
this_is_output_file = save_this_is_output_file;
this_is_library_file = save_this_is_library_file;
+ this_is_linker_script = save_this_is_linker_script;
input_from_pipe = save_input_from_pipe;
suffix_subst = save_suffix_subst;
&& input_suffix[end_atom - atom] == '\0');
}
-/* Inline subroutine of handle_braces. Returns true if a switch
+/* Subroutine of handle_braces. Returns true if the current
+ input file's spec name matches the atom bracketed by ATOM and END_ATOM. */
+static bool
+input_spec_matches (const char *atom, const char *end_atom)
+{
+ return (input_file_compiler
+ && input_file_compiler->suffix
+ && input_file_compiler->suffix[0] != '\0'
+ && !strncmp (input_file_compiler->suffix + 1, atom,
+ end_atom - atom)
+ && input_file_compiler->suffix[end_atom - atom + 1] == '\0');
+}
+
+/* Subroutine of handle_braces. Returns true if a switch
matching the atom bracketed by ATOM and END_ATOM appeared on the
command line. */
-static inline bool
+static bool
switch_matches (const char *atom, const char *end_atom, int starred)
{
int i;
{
const char *atom, *end_atom;
const char *d_atom = NULL, *d_end_atom = NULL;
+ const char *orig = p;
bool a_is_suffix;
+ bool a_is_spectype;
bool a_is_starred;
bool a_is_negated;
bool a_matched;
do
{
if (a_must_be_last)
- abort ();
+ goto invalid;
/* Scan one "atom" (S in the description above of %{}, possibly
- with !, ., or * modifiers). */
- a_matched = a_is_suffix = a_is_starred = a_is_negated = false;
+ with '!', '.', '@', ',', or '*' modifiers). */
+ a_matched = false;
+ a_is_suffix = false;
+ a_is_starred = false;
+ a_is_negated = false;
+ a_is_spectype = false;
SKIP_WHITE();
if (*p == '!')
SKIP_WHITE();
if (*p == '.')
p++, a_is_suffix = true;
+ else if (*p == ',')
+ p++, a_is_spectype = true;
atom = p;
while (ISIDNUM(*p) || *p == '-' || *p == '+' || *p == '='
p++, a_is_starred = 1;
SKIP_WHITE();
- if (*p == '&' || *p == '}')
+ switch (*p)
{
+ case '&': case '}':
/* Substitute the switch(es) indicated by the current atom. */
ordered_set = true;
if (disjunct_set || n_way_choice || a_is_negated || a_is_suffix
- || atom == end_atom)
- abort ();
+ || a_is_spectype || atom == end_atom)
+ goto invalid;
mark_matching_switches (atom, end_atom, a_is_starred);
if (*p == '}')
process_marked_switches ();
- }
- else if (*p == '|' || *p == ':')
- {
+ break;
+
+ case '|': case ':':
/* Substitute some text if the current atom appears as a switch
or suffix. */
disjunct_set = true;
if (ordered_set)
- abort ();
+ goto invalid;
if (atom == end_atom)
{
if (!n_way_choice || disj_matched || *p == '|'
- || a_is_negated || a_is_suffix || a_is_starred)
- abort ();
+ || a_is_negated || a_is_suffix || a_is_spectype
+ || a_is_starred)
+ goto invalid;
/* An empty term may appear as the last choice of an
N-way choice set; it means "otherwise". */
}
else
{
- if (a_is_suffix && a_is_starred)
- abort ();
-
- if (!a_is_starred)
- disj_starred = false;
-
- /* Don't bother testing this atom if we already have a
- match. */
- if (!disj_matched && !n_way_matched)
- {
- if (a_is_suffix)
- a_matched = input_suffix_matches (atom, end_atom);
- else
- a_matched = switch_matches (atom, end_atom, a_is_starred);
-
- if (a_matched != a_is_negated)
- {
- disj_matched = true;
- d_atom = atom;
- d_end_atom = end_atom;
- }
- }
+ if ((a_is_suffix || a_is_spectype) && a_is_starred)
+ goto invalid;
+
+ if (!a_is_starred)
+ disj_starred = false;
+
+ /* Don't bother testing this atom if we already have a
+ match. */
+ if (!disj_matched && !n_way_matched)
+ {
+ if (a_is_suffix)
+ a_matched = input_suffix_matches (atom, end_atom);
+ else if (a_is_spectype)
+ a_matched = input_spec_matches (atom, end_atom);
+ else
+ a_matched = switch_matches (atom, end_atom, a_is_starred);
+
+ if (a_matched != a_is_negated)
+ {
+ disj_matched = true;
+ d_atom = atom;
+ d_end_atom = end_atom;
+ }
+ }
}
if (*p == ':')
d_atom = d_end_atom = NULL;
}
}
+ break;
+
+ default:
+ goto invalid;
}
- else
- abort ();
}
while (*p++ != '}');
return p;
+ invalid:
+ fatal ("braced spec '%s' is invalid at '%c'", orig, *p);
+
#undef SKIP_WHITE
}
else if (*p == '%' && p[1] == '*' && nesting_level == 1)
have_subst = true;
else if (*p == '\0')
- abort ();
+ goto invalid;
p++;
}
end_body--;
if (have_subst && !starred)
- abort ();
+ goto invalid;
if (matched)
{
}
return p;
+
+ invalid:
+ fatal ("braced spec body '%s' is invalid", body);
}
\f
/* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
const char *name = switches[switchnum].part1;
int i;
+ /* If we already processed this switch and determined if it was
+ live or not, return our past determination. */
+ if (switches[switchnum].live_cond != 0)
+ return ((switches[switchnum].live_cond & SWITCH_LIVE) != 0
+ && (switches[switchnum].live_cond & SWITCH_FALSE) == 0
+ && (switches[switchnum].live_cond & SWITCH_IGNORE_PERMANENTLY)
+ == 0);
+
/* In the common case of {<at-most-one-letter>*}, a negating
switch would always match, so ignore that case. We will just
send the conflicting switches to the compiler phase. */
if (prefix_length >= 0 && prefix_length <= 1)
return 1;
- /* If we already processed this switch and determined if it was
- live or not, return our past determination. */
- if (switches[switchnum].live_cond != 0)
- return switches[switchnum].live_cond > 0;
-
/* Now search for duplicate in a manner that depends on the name. */
switch (*name)
{
}
/* Otherwise the switch is live. */
- switches[switchnum].live_cond = SWITCH_LIVE;
+ switches[switchnum].live_cond |= SWITCH_LIVE;
return 1;
}
\f
static void
give_switch (int switchnum, int omit_first_word)
{
- if (switches[switchnum].live_cond == SWITCH_IGNORE)
+ if ((switches[switchnum].live_cond & SWITCH_IGNORE) != 0)
return;
if (!omit_first_word)
while (length-- && !IS_DIR_SEPARATOR (arg[length]))
if (arg[length] == '.')
{
- ((char *)arg)[length] = 0;
+ (CONST_CAST(char *, arg))[length] = 0;
dot = 1;
break;
}
do_spec_1 (arg, 1, NULL);
if (dot)
- ((char *)arg)[length] = '.';
+ (CONST_CAST(char *, arg))[length] = '.';
do_spec_1 (suffix_subst, 1, NULL);
}
else
static const char *
find_file (const char *name)
{
- char *newname;
-
- /* Try multilib_dir if it is defined. */
- if (multilib_os_dir != NULL)
- {
- newname = find_a_file (&startfile_prefixes, name, R_OK, 1);
-
- /* 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, 0);
+ char *newname = find_a_file (&startfile_prefixes, name, R_OK, true);
return newname ? newname : name;
}
/* Determine whether a directory exists. If LINKER, return 0 for
- certain fixed names not needed by the linker. If not LINKER, it is
- only important to return 0 if the host machine has a small ARG_MAX
- limit. */
+ certain fixed names not needed by the linker. */
static int
-is_directory (const char *path1, const char *path2, int linker)
+is_directory (const char *path1, bool linker)
{
- int len1 = strlen (path1);
- int len2 = strlen (path2);
- char *path = alloca (3 + len1 + len2);
+ int len1;
+ char *path;
char *cp;
struct stat st;
-#ifndef SMALL_ARG_MAX
- if (! linker)
- return 1;
-#endif
-
- /* Construct the path from the two parts. Ensure the string ends with "/.".
- The resulting path will be a directory even if the given path is a
- symbolic link. */
+ /* Ensure the string ends with "/.". The resulting path will be a
+ directory even if the given path is a symbolic link. */
+ len1 = strlen (path1);
+ path = (char *) alloca (3 + len1);
memcpy (path, path1, len1);
- memcpy (path + len1, path2, len2);
- cp = path + len1 + len2;
+ cp = path + len1;
if (!IS_DIR_SEPARATOR (cp[-1]))
*cp++ = DIR_SEPARATOR;
*cp++ = '.';
/* Exclude directories that the linker is known to search. */
if (linker
+ && IS_DIR_SEPARATOR (path[0])
&& ((cp - path == 6
- && strcmp (path, concat (dir_separator_str, "lib",
- dir_separator_str, ".", NULL)) == 0)
+ && strncmp (path + 1, "lib", 3) == 0)
|| (cp - path == 10
- && strcmp (path, concat (dir_separator_str, "usr",
- dir_separator_str, "lib",
- dir_separator_str, ".", NULL)) == 0)))
+ && strncmp (path + 1, "usr", 3) == 0
+ && IS_DIR_SEPARATOR (path[4])
+ && strncmp (path + 5, "lib", 3) == 0)))
return 0;
return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
input_filename = filename;
input_filename_length = strlen (input_filename);
-
- input_basename = input_filename;
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
- /* Skip drive name so 'x:foo' is handled properly. */
- if (input_basename[1] == ':')
- input_basename += 2;
-#endif
- for (p = input_basename; *p; p++)
- if (IS_DIR_SEPARATOR (*p))
- input_basename = p + 1;
+ input_basename = lbasename (input_filename);
/* Find a suffix starting with the last period,
and set basename_length to exclude that suffix. */
kill (getpid (), signum);
}
-extern int main (int, const char *const *);
+/* Compare the contents of the two files named CMPFILE[0] and
+ CMPFILE[1]. Return zero if they're identical, nonzero
+ otherwise. */
-int
-main (int argc, const char *const *argv)
+static int
+compare_files (char *cmpfile[])
{
- size_t i;
- int value;
- int linker_was_run = 0;
- int num_linker_inputs = 0;
- char *explicit_link_files;
- char *specs_file;
- const char *p;
- struct user_specs *uptr;
-
- p = argv[0] + strlen (argv[0]);
- while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
- --p;
- programname = p;
+ int ret = 0;
+ FILE *temp[2] = { NULL, NULL };
+ int i;
- xmalloc_set_program_name (programname);
+#if HAVE_MMAP_FILE
+ {
+ size_t length[2];
+ void *map[2] = { NULL, NULL };
-#ifdef GCC_DRIVER_HOST_INITIALIZATION
- /* Perform host dependent initialization when needed. */
- GCC_DRIVER_HOST_INITIALIZATION;
-#endif
+ for (i = 0; i < 2; i++)
+ {
+ struct stat st;
- gcc_init_libintl ();
+ if (stat (cmpfile[i], &st) < 0 || !S_ISREG (st.st_mode))
+ {
+ error ("%s: could not determine length of compare-debug file %s",
+ input_filename, cmpfile[i]);
+ ret = 1;
+ break;
+ }
- if (signal (SIGINT, SIG_IGN) != SIG_IGN)
- signal (SIGINT, fatal_error);
-#ifdef SIGHUP
- if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
- signal (SIGHUP, fatal_error);
-#endif
- if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
- signal (SIGTERM, fatal_error);
-#ifdef SIGPIPE
- if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
- signal (SIGPIPE, fatal_error);
-#endif
-#ifdef SIGCHLD
- /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
- receive the signal. A different setting is inheritable */
- signal (SIGCHLD, SIG_DFL);
-#endif
+ length[i] = st.st_size;
+ }
- /* Allocate the argument vector. */
- alloc_args ();
+ if (!ret && length[0] != length[1])
+ {
+ error ("%s: -fcompare-debug failure (length)", input_filename);
+ ret = 1;
+ }
+
+ if (!ret)
+ for (i = 0; i < 2; i++)
+ {
+ int fd = open (cmpfile[i], O_RDONLY);
+ if (fd < 0)
+ {
+ error ("%s: could not open compare-debug file %s",
+ input_filename, cmpfile[i]);
+ ret = 1;
+ break;
+ }
+
+ map[i] = mmap (NULL, length[i], PROT_READ, MAP_PRIVATE, fd, 0);
+ close (fd);
+
+ if (map[i] == (void *) MAP_FAILED)
+ {
+ ret = -1;
+ break;
+ }
+ }
+
+ if (!ret)
+ {
+ if (memcmp (map[0], map[1], length[0]) != 0)
+ {
+ error ("%s: -fcompare-debug failure", input_filename);
+ ret = 1;
+ }
+ }
+
+ for (i = 0; i < 2; i++)
+ if (map[i])
+ munmap ((caddr_t) map[i], length[i]);
+
+ if (ret >= 0)
+ return ret;
+
+ ret = 0;
+ }
+#endif
+
+ for (i = 0; i < 2; i++)
+ {
+ temp[i] = fopen (cmpfile[i], "r");
+ if (!temp[i])
+ {
+ error ("%s: could not open compare-debug file %s",
+ input_filename, cmpfile[i]);
+ ret = 1;
+ break;
+ }
+ }
+
+ if (!ret && temp[0] && temp[1])
+ for (;;)
+ {
+ int c0, c1;
+ c0 = fgetc (temp[0]);
+ c1 = fgetc (temp[1]);
+
+ if (c0 != c1)
+ {
+ error ("%s: -fcompare-debug failure",
+ input_filename);
+ ret = 1;
+ break;
+ }
+
+ if (c0 == EOF)
+ break;
+ }
+
+ for (i = 1; i >= 0; i--)
+ {
+ if (temp[i])
+ fclose (temp[i]);
+ }
+
+ return ret;
+}
+
+extern int main (int, char **);
+
+int
+main (int argc, char **argv)
+{
+ size_t i;
+ int value;
+ int linker_was_run = 0;
+ int lang_n_infiles = 0;
+ int num_linker_inputs = 0;
+ char *explicit_link_files;
+ char *specs_file;
+ const char *p;
+ struct user_specs *uptr;
+ char **old_argv = argv;
+
+ /* Initialize here, not in definition. The IRIX 6 O32 cc sometimes chokes
+ on ?: in file-scope variable initializations. */
+ asm_debug = ASM_DEBUG_SPEC;
+
+ p = argv[0] + strlen (argv[0]);
+ while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
+ --p;
+ programname = p;
+
+ xmalloc_set_program_name (programname);
+
+ expandargv (&argc, &argv);
+
+ /* Determine if any expansions were made. */
+ if (argv != old_argv)
+ at_file_supplied = true;
+
+ prune_options (&argc, &argv);
+
+#ifdef GCC_DRIVER_HOST_INITIALIZATION
+ /* Perform host dependent initialization when needed. */
+ GCC_DRIVER_HOST_INITIALIZATION;
+#endif
+
+ /* Unlock the stdio streams. */
+ unlock_std_streams ();
+
+ gcc_init_libintl ();
+
+ if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+ signal (SIGINT, fatal_error);
+#ifdef SIGHUP
+ if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+ signal (SIGHUP, fatal_error);
+#endif
+ if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
+ signal (SIGTERM, fatal_error);
+#ifdef SIGPIPE
+ if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
+ signal (SIGPIPE, fatal_error);
+#endif
+#ifdef SIGCHLD
+ /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
+ receive the signal. A different setting is inheritable */
+ signal (SIGCHLD, SIG_DFL);
+#endif
+
+ /* Allocate the argument vector. */
+ alloc_args ();
obstack_init (&obstack);
obstack_grow (&multilib_obstack, p, strlen (p));
obstack_1grow (&multilib_obstack, 0);
- multilib_select = obstack_finish (&multilib_obstack);
+ multilib_select = XOBFINISH (&multilib_obstack, const char *);
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);
+ multilib_matches = XOBFINISH (&multilib_obstack, const char *);
q = multilib_exclusions_raw;
while ((p = *q++) != (char *) 0)
obstack_grow (&multilib_obstack, p, strlen (p));
obstack_1grow (&multilib_obstack, 0);
- multilib_exclusions = obstack_finish (&multilib_obstack);
+ multilib_exclusions = XOBFINISH (&multilib_obstack, const char *);
need_space = FALSE;
for (i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
}
obstack_1grow (&multilib_obstack, 0);
- multilib_defaults = obstack_finish (&multilib_obstack);
+ multilib_defaults = XOBFINISH (&multilib_obstack, const char *);
}
- /* 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_init (&collect_obstack);
- obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
- 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);
+ xputenv (INIT_ENVIRONMENT);
#endif
/* Make a table of what switches there are (switches, n_switches).
Make a table of specified input files (infiles, n_infiles).
Decode switches that are handled locally. */
- process_command (argc, argv);
+ process_command (argc, CONST_CAST2 (const char **, char **, argv));
/* Initialize the vector of specs to just the default.
This means one element containing 0s, as a terminator. */
- compilers = xmalloc (sizeof default_compilers);
+ compilers = XNEWVAR (struct compiler, sizeof default_compilers);
memcpy (compilers, default_compilers, sizeof default_compilers);
n_compilers = n_default_compilers;
spec_version, dir_separator_str, NULL);
just_machine_suffix = concat (spec_machine, dir_separator_str, NULL);
- specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, 0);
+ specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true);
/* Read the specs file unless it is a default one. */
if (specs_file != 0 && strcmp (specs_file, "specs"))
read_specs (specs_file, TRUE);
/* We need to check standard_exec_prefix/just_machine_suffix/specs
for any override of as, ld and libraries. */
- specs_file = alloca (strlen (standard_exec_prefix)
+ specs_file = (char *) alloca (strlen (standard_exec_prefix)
+ strlen (just_machine_suffix) + sizeof ("specs"));
strcpy (specs_file, standard_exec_prefix);
for (i = 0; i < ARRAY_SIZE (driver_self_specs); i++)
do_self_spec (driver_self_specs[i]);
+ if (compare_debug)
+ {
+ enum save_temps save;
+
+ if (!compare_debug_second)
+ {
+ n_switches_debug_check[1] = n_switches;
+ switches_debug_check[1] = XDUPVEC (struct switchstr, switches,
+ n_switches + 1);
+
+ do_self_spec ("%:compare-debug-self-opt()");
+ n_switches_debug_check[0] = n_switches;
+ switches_debug_check[0] = switches;
+
+ n_switches = n_switches_debug_check[1];
+ switches = switches_debug_check[1];
+ }
+
+ /* Avoid crash when computing %j in this early. */
+ save = save_temps_flag;
+ save_temps_flag = SAVE_TEMPS_NONE;
+
+ compare_debug = -compare_debug;
+ do_self_spec ("%:compare-debug-self-opt()");
+
+ save_temps_flag = save;
+
+ if (!compare_debug_second)
+ {
+ n_switches_debug_check[1] = n_switches;
+ switches_debug_check[1] = switches;
+ compare_debug = -compare_debug;
+ n_switches = n_switches_debug_check[0];
+ switches = switches_debug_check[0];
+ }
+ }
+
/* If not cross-compiling, look for executables in the standard
places. */
if (*cross_compile == '0')
if (*md_exec_prefix)
{
add_prefix (&exec_prefixes, md_exec_prefix, "GCC",
- PREFIX_PRIORITY_LAST, 0, NULL, 0);
+ PREFIX_PRIORITY_LAST, 0, 0);
}
}
&& do_spec_2 (sysroot_suffix_spec) == 0)
{
if (argbuf_index > 1)
- error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC.");
+ error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC");
else if (argbuf_index == 1)
target_sysroot_suffix = xstrdup (argbuf[argbuf_index -1]);
}
+#ifdef HAVE_LD_SYSROOT
+ /* Pass the --sysroot option to the linker, if it supports that. If
+ there is a sysroot_suffix_spec, it has already been processed by
+ this point, so target_system_root really is the system root we
+ should be using. */
+ if (target_system_root)
+ {
+ obstack_grow (&obstack, "%(sysroot_spec) ", strlen ("%(sysroot_spec) "));
+ obstack_grow0 (&obstack, link_spec, strlen (link_spec));
+ set_spec ("link", XOBFINISH (&obstack, const char *));
+ }
+#endif
+
/* Process sysroot_hdrs_suffix_spec. */
if (*sysroot_hdrs_suffix_spec != 0
&& do_spec_2 (sysroot_hdrs_suffix_spec) == 0)
{
if (argbuf_index > 1)
- error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC.");
+ error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC");
else if (argbuf_index == 1)
target_sysroot_hdrs_suffix = xstrdup (argbuf[argbuf_index -1]);
}
int ndx;
for (ndx = 0; ndx < argbuf_index; ndx++)
add_sysrooted_prefix (&startfile_prefixes, argbuf[ndx], "BINUTILS",
- PREFIX_PRIORITY_LAST, 0, NULL, 1);
+ PREFIX_PRIORITY_LAST, 0, 1);
}
/* We should eventually get rid of all these and stick to
startfile_prefix_spec exclusively. */
else if (*cross_compile == '0' || target_system_root)
{
- if (*md_exec_prefix)
- add_sysrooted_prefix (&startfile_prefixes, md_exec_prefix, "GCC",
- PREFIX_PRIORITY_LAST, 0, NULL, 1);
-
if (*md_startfile_prefix)
add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix,
- "GCC", PREFIX_PRIORITY_LAST, 0, NULL, 1);
+ "GCC", PREFIX_PRIORITY_LAST, 0, 1);
if (*md_startfile_prefix_1)
add_sysrooted_prefix (&startfile_prefixes, md_startfile_prefix_1,
- "GCC", PREFIX_PRIORITY_LAST, 0, NULL, 1);
+ "GCC", PREFIX_PRIORITY_LAST, 0, 1);
/* If standard_startfile_prefix is relative, base it on
standard_exec_prefix. This lets us move the installed tree
if (IS_ABSOLUTE_PATH (standard_startfile_prefix))
add_sysrooted_prefix (&startfile_prefixes,
standard_startfile_prefix, "BINUTILS",
- PREFIX_PRIORITY_LAST, 0, NULL, 1);
+ PREFIX_PRIORITY_LAST, 0, 1);
else if (*cross_compile == '0')
{
- if (gcc_exec_prefix)
- add_prefix (&startfile_prefixes,
- concat (gcc_exec_prefix, machine_suffix,
- standard_startfile_prefix, NULL),
- NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1);
add_prefix (&startfile_prefixes,
- concat (standard_exec_prefix,
+ concat (gcc_exec_prefix
+ ? gcc_exec_prefix : standard_exec_prefix,
machine_suffix,
standard_startfile_prefix, NULL),
- NULL, PREFIX_PRIORITY_LAST, 0, NULL, 1);
+ NULL, PREFIX_PRIORITY_LAST, 0, 1);
}
- add_sysrooted_prefix (&startfile_prefixes, standard_startfile_prefix_1,
- "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1);
- add_sysrooted_prefix (&startfile_prefixes, standard_startfile_prefix_2,
- "BINUTILS", PREFIX_PRIORITY_LAST, 0, NULL, 1);
-#if 0 /* Can cause surprises, and one can use -B./ instead. */
- add_prefix (&startfile_prefixes, "./", NULL,
- PREFIX_PRIORITY_LAST, 1, NULL, 0);
-#endif
+ /* Sysrooted prefixes are relocated because target_system_root is
+ also relocated by gcc_exec_prefix. */
+ if (*standard_startfile_prefix_1)
+ add_sysrooted_prefix (&startfile_prefixes,
+ standard_startfile_prefix_1, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 0, 1);
+ if (*standard_startfile_prefix_2)
+ add_sysrooted_prefix (&startfile_prefixes,
+ standard_startfile_prefix_2, "BINUTILS",
+ PREFIX_PRIORITY_LAST, 0, 1);
}
/* Process any user specified specs in the order given on the command
for (uptr = user_specs_head; uptr; uptr = uptr->next)
{
char *filename = find_a_file (&startfile_prefixes, uptr->filename,
- R_OK, 0);
+ R_OK, true);
read_specs (filename ? filename : uptr->filename, FALSE);
}
the subdirectory based on the options. */
set_multilib_dir ();
+ /* 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_init (&collect_obstack);
+ obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1);
+ obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1);
+ xputenv (XOBFINISH (&collect_obstack, char *));
+
+ /* Set up to remember the pathname of the lto wrapper. */
+
+ lto_wrapper_spec = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
+ if (lto_wrapper_spec)
+ {
+ obstack_init (&collect_obstack);
+ obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
+ sizeof ("COLLECT_LTO_WRAPPER=") - 1);
+ obstack_grow (&collect_obstack, lto_wrapper_spec,
+ strlen (lto_wrapper_spec) + 1);
+ xputenv (XOBFINISH (&collect_obstack, char *));
+ }
+
/* Warn about any switches that no pass was interested in. */
for (i = 0; (int) i < n_switches; i++)
if (! switches[i].validated)
- error ("unrecognized option `-%s'", switches[i].part1);
+ error ("unrecognized option '-%s'", switches[i].part1);
/* 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));
+ printf (_("install: %s%s\n"),
+ gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix,
+ gcc_exec_prefix ? "" : machine_suffix);
+ printf (_("programs: %s\n"),
+ build_search_list (&exec_prefixes, "", false, false));
+ printf (_("libraries: %s\n"),
+ build_search_list (&startfile_prefixes, "", false, true));
return (0);
}
return (0);
}
+ if (print_sysroot)
+ {
+ if (target_system_root)
+ {
+ if (target_sysroot_suffix)
+ printf ("%s%s\n", target_system_root, target_sysroot_suffix);
+ else
+ printf ("%s\n", target_system_root);
+ }
+ return (0);
+ }
+
if (print_multi_os_directory)
{
if (multilib_os_dir == NULL)
return (0);
}
- if (target_help_flag)
- {
- /* Print if any target specific options. */
-
- /* We do not exit here. Instead we have created a fake input file
- called 'target-dummy' which needs to be compiled, and we pass this
- on to the various sub-processes, along with the --target-help
- switch. */
+ if (print_sysroot_headers_suffix)
+ {
+ if (*sysroot_hdrs_suffix_spec)
+ {
+ printf("%s\n", (target_sysroot_hdrs_suffix
+ ? target_sysroot_hdrs_suffix
+ : ""));
+ return (0);
+ }
+ else
+ /* The error status indicates that only one set of fixed
+ headers should be built. */
+ fatal ("not configured with sysroot headers suffix");
}
if (print_help_list)
/* We do not exit here. Instead we have created a fake input file
called 'help-dummy' which needs to be compiled, and we pass this
- on the various sub-processes, along with the --help switch. */
+ on the various sub-processes, along with the --help switch.
+ Ensure their output appears after ours. */
+ fputc ('\n', stdout);
+ fflush (stdout);
+ }
+
+ if (print_version)
+ {
+ printf (_("%s %s%s\n"), programname, pkgversion_string,
+ version_string);
+ printf ("Copyright %s 2010 Free Software Foundation, Inc.\n",
+ _("(C)"));
+ fputs (_("This is free software; see the source for copying conditions. There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"),
+ stdout);
+ if (! verbose_flag)
+ return 0;
+
+ /* We do not exit here. We use the same mechanism of --help to print
+ the version of the sub-processes. */
+ fputc ('\n', stdout);
+ fflush (stdout);
}
if (verbose_flag)
int n;
const char *thrmod;
+ notice ("Target: %s\n", spec_machine);
notice ("Configured with: %s\n", configuration_arguments);
#ifdef THREAD_MODEL_SPEC
obstack_init (&obstack);
do_spec_1 (THREAD_MODEL_SPEC, 0, thread_model);
obstack_1grow (&obstack, '\0');
- thrmod = obstack_finish (&obstack);
+ thrmod = XOBFINISH (&obstack, const char *);
#else
thrmod = thread_model;
#endif
if (! strncmp (version_string, compiler_version, n)
&& compiler_version[n] == 0)
- notice ("gcc version %s\n", version_string);
+ notice ("gcc version %s %s\n", version_string, pkgversion_string);
else
- notice ("gcc driver version %s executing gcc version %s\n",
- version_string, compiler_version);
+ notice ("gcc driver version %s %sexecuting gcc version %s\n",
+ version_string, pkgversion_string, compiler_version);
if (n_infiles == 0)
return (0);
i = n_infiles;
i += lang_specific_extra_outfiles;
- outfiles = xcalloc (i, sizeof (char *));
+ outfiles = XCNEWVEC (const char *, i);
/* Record which files were specified explicitly as link input. */
- explicit_link_files = xcalloc (1, n_infiles);
+ explicit_link_files = XCNEWVEC (char, n_infiles);
+
+ if (combine_flag)
+ combine_inputs = true;
+ else
+ combine_inputs = false;
+
+ for (i = 0; (int) i < n_infiles; i++)
+ {
+ const char *name = infiles[i].name;
+ struct compiler *compiler = lookup_compiler (name,
+ strlen (name),
+ infiles[i].language);
+
+ if (compiler && !(compiler->combinable))
+ combine_inputs = false;
+
+ if (lang_n_infiles > 0 && compiler != input_file_compiler
+ && infiles[i].language && infiles[i].language[0] != '*')
+ infiles[i].incompiler = compiler;
+ else if (compiler)
+ {
+ lang_n_infiles++;
+ input_file_compiler = compiler;
+ infiles[i].incompiler = compiler;
+ }
+ else
+ {
+ /* Since there is no compiler for this input file, assume it is a
+ linker file. */
+ explicit_link_files[i] = 1;
+ infiles[i].incompiler = NULL;
+ }
+ infiles[i].compiled = false;
+ infiles[i].preprocessed = false;
+ }
+
+ if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
+ fatal ("cannot specify -o with -c, -S or -E with multiple files");
- if (combine_inputs)
+ if (combine_flag && save_temps_flag)
{
- int lang_n_infiles = 0;
- for (i = 0; (int) i < n_infiles; i++)
- {
- const char *name = infiles[i].name;
- struct compiler *compiler
- = lookup_compiler (name, strlen (name), infiles[i].language);
- if (compiler == NULL)
- error ("%s: linker input file unused because linking not done",
- name);
- else if (lang_n_infiles > 0 && compiler != input_file_compiler)
- fatal ("cannot specify -o with -c or -S and multiple languages");
- else
- {
- lang_n_infiles++;
- input_file_compiler = compiler;
- }
- }
+ bool save_combine_inputs = combine_inputs;
+ /* Must do a separate pre-processing pass for C & Objective-C files, to
+ obtain individual .i files. */
+
+ combine_inputs = false;
+ for (i = 0; (int) i < n_infiles; i++)
+ {
+ int this_file_error = 0;
+
+ input_file_number = i;
+ set_input (infiles[i].name);
+ if (infiles[i].incompiler
+ && (infiles[i].incompiler)->needs_preprocessing)
+ input_file_compiler = infiles[i].incompiler;
+ else
+ continue;
+
+ if (input_file_compiler)
+ {
+ if (input_file_compiler->spec[0] == '#')
+ {
+ error ("%s: %s compiler not installed on this system",
+ input_filename, &input_file_compiler->spec[1]);
+ this_file_error = 1;
+ }
+ else
+ {
+ value = do_spec (input_file_compiler->spec);
+ infiles[i].preprocessed = true;
+ if (!have_o_argbuf_index)
+ fatal ("spec '%s' is invalid", input_file_compiler->spec);
+ infiles[i].name = argbuf[have_o_argbuf_index];
+ infiles[i].incompiler
+ = lookup_compiler (infiles[i].name,
+ strlen (infiles[i].name),
+ infiles[i].language);
+
+ if (value < 0)
+ this_file_error = 1;
+ }
+ }
+
+ if (this_file_error)
+ {
+ delete_failure_queue ();
+ error_count++;
+ break;
+ }
+ clear_failure_queue ();
+ }
+ combine_inputs = save_combine_inputs;
}
-
- for (i = 0; (int) i < (combine_inputs ? 1 : n_infiles); i++)
+
+ for (i = 0; (int) i < n_infiles; i++)
{
int this_file_error = 0;
input_file_number = i;
set_input (infiles[i].name);
+ if (infiles[i].compiled)
+ continue;
+
/* Use the same thing in %o, unless cp->spec says otherwise. */
outfiles[i] = input_filename;
input_file_compiler
= lookup_compiler (infiles[i].name, input_filename_length,
infiles[i].language);
+ else
+ input_file_compiler = infiles[i].incompiler;
if (input_file_compiler)
{
}
else
{
+ if (compare_debug)
+ {
+ if (debug_check_temp_file[0])
+ free (debug_check_temp_file[0]);
+ debug_check_temp_file[0] = NULL;
+
+ if (debug_check_temp_file[1])
+ free (debug_check_temp_file[1]);
+ debug_check_temp_file[1] = NULL;
+ }
+
value = do_spec (input_file_compiler->spec);
+ infiles[i].compiled = true;
if (value < 0)
this_file_error = 1;
+ else if (compare_debug && debug_check_temp_file[0])
+ {
+ if (verbose_flag)
+ error ("Recompiling with -fcompare-debug");
+
+ compare_debug = -compare_debug;
+ n_switches = n_switches_debug_check[1];
+ switches = switches_debug_check[1];
+
+ value = do_spec (input_file_compiler->spec);
+
+ compare_debug = -compare_debug;
+ n_switches = n_switches_debug_check[0];
+ switches = switches_debug_check[0];
+
+ if (value < 0)
+ {
+ error ("during -fcompare-debug recompilation");
+ this_file_error = 1;
+ }
+
+ gcc_assert (debug_check_temp_file[1]
+ && strcmp (debug_check_temp_file[0],
+ debug_check_temp_file[1]));
+
+ if (verbose_flag)
+ error ("Comparing final insns dumps");
+
+ if (compare_files (debug_check_temp_file))
+ this_file_error = 1;
+ }
+
+ if (compare_debug)
+ {
+ if (debug_check_temp_file[0])
+ free (debug_check_temp_file[0]);
+ debug_check_temp_file[0] = NULL;
+
+ if (debug_check_temp_file[1])
+ free (debug_check_temp_file[1]);
+ debug_check_temp_file[1] = NULL;
+ }
}
}
clear_failure_queue ();
}
- /* Reset the output file name to the first input file name, for use
- with %b in LINK_SPEC on a target that prefers not to emit a.out
- by default. */
+ /* Reset the input file name to the first compile/object file name, for use
+ with %b in LINK_SPEC. We use the first input file that we can find
+ a compiler to compile it instead of using infiles.language since for
+ languages other than C we use aliases that we then lookup later. */
if (n_infiles > 0)
- set_input (infiles[0].name);
+ {
+ int i;
+
+ for (i = 0; i < n_infiles ; i++)
+ if (infiles[i].language && infiles[i].language[0] != '*')
+ {
+ set_input (infiles[i].name);
+ break;
+ }
+ }
if (error_count == 0)
{
/* Run ld to link all the compiler output files. */
- if (num_linker_inputs > 0 && error_count == 0)
+ if (num_linker_inputs > 0 && error_count == 0 && print_subprocess_help < 2)
{
int tmp = execution_count;
+ const char *fuse_linker_plugin = "fuse-linker-plugin";
/* We'll use ld if we can't find collect2. */
if (! strcmp (linker_name_spec, "collect2"))
{
- char *s = find_a_file (&exec_prefixes, "collect2", X_OK, 0);
+ char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false);
if (s == NULL)
linker_name_spec = "ld";
}
+
+ if (switch_matches (fuse_linker_plugin,
+ fuse_linker_plugin + strlen (fuse_linker_plugin), 0))
+ {
+ linker_plugin_file_spec = find_a_file (&exec_prefixes,
+ "liblto_plugin.so", R_OK,
+ false);
+ if (!linker_plugin_file_spec)
+ fatal ("-fuse-linker-plugin, but liblto_plugin.so not found");
+
+ lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a",
+ R_OK, true);
+ if (!lto_libgcc_spec)
+ fatal ("could not find libgcc.a");
+ }
+ lto_gcc_spec = argv[0];
+
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
- putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH");
- putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV);
+ putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false);
+ putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV, true);
+ if (print_subprocess_help == 1)
+ {
+ printf (_("\nLinker options\n==============\n\n"));
+ printf (_("Use \"-Wl,OPTION\" to pass \"OPTION\""
+ " to the linker.\n\n"));
+ fflush (stdout);
+ }
value = do_spec (link_command_spec);
if (value < 0)
error_count = 1;
if (! linker_was_run && error_count == 0)
for (i = 0; (int) i < n_infiles; i++)
- if (explicit_link_files[i])
+ if (explicit_link_files[i]
+ && !(infiles[i].language && infiles[i].language[0] == '*'))
error ("%s: linker input file unused because linking not done",
outfiles[i]);
}
#if defined (OS2) ||defined (HAVE_DOS_BASED_FILE_SYSTEM)
- /* look again, but case-insensitively this time. */
+ /* Look again, but case-insensitively this time. */
if (cp < compilers)
for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
{
static char *
save_string (const char *s, int len)
{
- char *result = xmalloc (len + 1);
+ char *result = XNEWVEC (char, len + 1);
memcpy (result, s, len);
result[len] = 0;
error ("%s: %s", name, xstrerror (errno));
}
-static void
-pfatal_pexecute (const char *errmsg_fmt, const char *errmsg_arg)
-{
- if (errmsg_arg)
- {
- int save_errno = errno;
-
- /* 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;
-
- errno = save_errno;
- }
-
- pfatal_with_name (errmsg_fmt);
-}
-
/* Output an error message and exit. */
void
-fancy_abort (void)
+fancy_abort (const char *file, int line, const char *func)
{
- fatal ("internal gcc abort");
+ fatal_ice ("internal gcc abort in %s, at %s:%d", func, file, line);
}
\f
/* Output an error message and exit. */
void
-fatal (const char *msgid, ...)
+fatal_ice (const char *cmsgid, ...)
+{
+ va_list ap;
+
+ va_start (ap, cmsgid);
+
+ fprintf (stderr, "%s: ", programname);
+ vfprintf (stderr, _(cmsgid), ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+ delete_temp_files ();
+ exit (pass_exit_codes ? ICE_EXIT_CODE : 1);
+}
+
+void
+fatal (const char *cmsgid, ...)
{
va_list ap;
- va_start (ap, msgid);
+ va_start (ap, cmsgid);
fprintf (stderr, "%s: ", programname);
- vfprintf (stderr, _(msgid), ap);
+ vfprintf (stderr, _(cmsgid), ap);
va_end (ap);
fprintf (stderr, "\n");
delete_temp_files ();
exit (1);
}
+/* The argument is actually c-format, not gcc-internal-format,
+ but because functions with identical names are used through
+ the rest of the compiler with gcc-internal-format, we just
+ need to hope all users of these functions use the common
+ subset between c-format and gcc-internal-format. */
+
void
-error (const char *msgid, ...)
+error (const char *gmsgid, ...)
{
va_list ap;
- va_start (ap, msgid);
+ va_start (ap, gmsgid);
fprintf (stderr, "%s: ", programname);
- vfprintf (stderr, _(msgid), ap);
+ vfprintf (stderr, _(gmsgid), ap);
va_end (ap);
fprintf (stderr, "\n");
}
static void
-notice (const char *msgid, ...)
+notice (const char *cmsgid, ...)
{
va_list ap;
- va_start (ap, msgid);
- vfprintf (stderr, _(msgid), ap);
+ va_start (ap, cmsgid);
+ vfprintf (stderr, _(cmsgid), ap);
va_end (ap);
}
\f
p++;
SKIP_WHITE ();
- if (*p == '.')
+ if (*p == '.' || *p == ',')
suffix = true, p++;
atom = p;
if (*q == ';')
cnt++;
- matches = alloca ((sizeof (struct mswitchstr)) * cnt);
+ matches
+ = (struct mswitchstr *) alloca ((sizeof (struct mswitchstr)) * cnt);
i = 0;
q = multilib_matches;
while (*q != '\0')
while (*q != ' ')
{
if (*q == '\0')
- abort ();
+ {
+ invalid_matches:
+ fatal ("multilib spec '%s' is invalid", multilib_matches);
+ }
q++;
}
matches[i].len = q - matches[i].str;
while (*q != ';' && *q != '\0')
{
if (*q == ' ')
- abort ();
+ goto invalid_matches;
q++;
}
matches[i].rep_len = q - matches[i].replace;
xmalloc from calling fatal, and prevents us from re-executing this
block of code. */
mswitches
- = xmalloc (sizeof (struct mswitchstr)
- * (n_mdswitches + (n_switches ? n_switches : 1)));
+ = XNEWVEC (struct mswitchstr, n_mdswitches + (n_switches ? n_switches : 1));
for (i = 0; i < n_switches; i++)
- {
- int xlen = strlen (switches[i].part1);
- for (j = 0; j < cnt; j++)
- if (xlen == matches[j].len
- && ! strncmp (switches[i].part1, matches[j].str, xlen))
- {
- 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;
- }
- }
+ if ((switches[i].live_cond & SWITCH_IGNORE) == 0)
+ {
+ int xlen = strlen (switches[i].part1);
+ for (j = 0; j < cnt; j++)
+ if (xlen == matches[j].len
+ && ! strncmp (switches[i].part1, matches[j].str, xlen))
+ {
+ 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;
+ }
+ }
/* Add MULTILIB_DEFAULTS switches too, as long as they were not present
on the command line nor any options mutually incompatible with
{
int i = 0;
- mdswitches = xmalloc (sizeof (struct mdswitchstr) * n_mdswitches);
+ mdswitches = XNEWVEC (struct mdswitchstr, n_mdswitches);
for (start = multilib_defaults; *start != '\0'; start = end + 1)
{
while (*start == ' ' || *start == '\t')
obstack_grow (&multilib_obstack, start, end - start);
obstack_1grow (&multilib_obstack, 0);
- mdswitches[i].str = obstack_finish (&multilib_obstack);
+ mdswitches[i].str = XOBFINISH (&multilib_obstack, const char *);
mdswitches[i++].len = end - start;
if (*end == '\0')
while (*p != ';')
{
if (*p == '\0')
- abort ();
+ {
+ invalid_exclusions:
+ fatal ("multilib exclusions '%s' is invalid",
+ multilib_exclusions);
+ }
if (! ok)
{
while (*p != ' ' && *p != ';')
{
if (*p == '\0')
- abort ();
+ goto invalid_exclusions;
++p;
}
while (*p != ' ')
{
if (*p == '\0')
- abort ();
+ {
+ invalid_select:
+ fatal ("multilib select '%s' is invalid",
+ multilib_select);
+ }
++p;
}
this_path_len = p - this_path;
while (*p != ';')
{
if (*p == '\0')
- abort ();
+ goto invalid_select;
if (! ok)
{
while (*p != ' ' && *p != ';')
{
if (*p == '\0')
- abort ();
+ goto invalid_select;
++p;
}
if (this_path_len != 1
|| this_path[0] != '.')
{
- char *new_multilib_dir = xmalloc (this_path_len + 1);
+ char *new_multilib_dir = XNEWVEC (char, this_path_len + 1);
char *q;
strncpy (new_multilib_dir, this_path, this_path_len);
q++;
if (q < end)
{
- char *new_multilib_os_dir = xmalloc (end - q);
+ char *new_multilib_os_dir = XNEWVEC (char, end - q);
memcpy (new_multilib_os_dir, q + 1, end - q - 1);
new_multilib_os_dir[end - q - 1] = '\0';
multilib_os_dir = new_multilib_os_dir;
if (multilib_dir == NULL && multilib_os_dir != NULL
&& strcmp (multilib_os_dir, ".") == 0)
{
- free ((char *) multilib_os_dir);
+ free (CONST_CAST (char *, multilib_os_dir));
multilib_os_dir = NULL;
}
else if (multilib_dir != NULL && multilib_os_dir == NULL)
while (*p != ' ')
{
if (*p == '\0')
- abort ();
+ {
+ invalid_select:
+ fatal ("multilib select '%s' is invalid", multilib_select);
+ }
+
++p;
}
int mp = 0;
if (*e == '\0')
- abort ();
+ {
+ invalid_exclusion:
+ fatal ("multilib exclusion '%s' is invalid",
+ multilib_exclusions);
+ }
if (! m)
{
while (*e != ' ' && *e != ';')
{
if (*e == '\0')
- abort ();
+ goto invalid_exclusion;
++e;
}
int len = e - this_arg;
if (*q == '\0')
- abort ();
+ goto invalid_select;
arg = q;
while (*q != ' ' && *q != ';')
{
if (*q == '\0')
- abort ();
+ goto invalid_select;
++q;
}
- if (! strncmp (arg, this_arg, (len < q - arg) ? q - arg : len) ||
- default_arg (this_arg, e - this_arg))
+ if (! strncmp (arg, this_arg,
+ (len < q - arg) ? q - arg : len)
+ || default_arg (this_arg, e - this_arg))
{
mp = 1;
break;
if (! skip)
{
/* If this is a duplicate, skip it. */
- skip = (last_path != 0 && (unsigned int) (p - this_path) == last_path_len
+ skip = (last_path != 0
+ && (unsigned int) (p - this_path) == last_path_len
&& ! strncmp (last_path, this_path, last_path_len));
last_path = this_path;
const char *arg;
if (*q == '\0')
- abort ();
+ goto invalid_select;
if (*q == '!')
arg = NULL;
while (*q != ' ' && *q != ';')
{
if (*q == '\0')
- abort ();
+ goto invalid_select;
++q;
}
int use_arg;
if (*p == '\0')
- abort ();
+ goto invalid_select;
if (skip)
{
while (*p != ' ' && *p != ';')
{
if (*p == '\0')
- abort ();
+ goto invalid_select;
if (use_arg)
putchar (*p);
++p;
}
}
\f
+/* getenv built-in spec function.
+
+ Returns the value of the environment variable given by its first
+ argument, concatenated with the second argument. If the
+ environment variable is not defined, a fatal error is issued. */
+
+static const char *
+getenv_spec_function (int argc, const char **argv)
+{
+ char *value;
+ char *result;
+ char *ptr;
+ size_t len;
+
+ if (argc != 2)
+ return NULL;
+
+ value = getenv (argv[0]);
+ if (!value)
+ fatal ("environment variable \"%s\" not defined", argv[0]);
+
+ /* We have to escape every character of the environment variable so
+ they are not interpreted as active spec characters. A
+ particularly painful case is when we are reading a variable
+ holding a windows path complete with \ separators. */
+ len = strlen (value) * 2 + strlen (argv[1]) + 1;
+ result = XNEWVAR (char, len);
+ for (ptr = result; *value; ptr += 2)
+ {
+ ptr[0] = '\\';
+ ptr[1] = *value++;
+ }
+
+ strcpy (ptr, argv[1]);
+
+ return result;
+}
+
/* if-exists built-in spec function.
Checks to see if the file specified by the absolute pathname in
return argv[1];
}
+
+/* replace-outfile built-in spec function.
+
+ This looks for the first argument in the outfiles array's name and
+ replaces it with the second argument. */
+
+static const char *
+replace_outfile_spec_function (int argc, const char **argv)
+{
+ int i;
+ /* Must have exactly two arguments. */
+ if (argc != 2)
+ abort ();
+
+ for (i = 0; i < n_infiles; i++)
+ {
+ if (outfiles[i] && !strcmp (outfiles[i], argv[0]))
+ outfiles[i] = xstrdup (argv[1]);
+ }
+ return NULL;
+}
+
+/* Given two version numbers, compares the two numbers.
+ A version number must match the regular expression
+ ([1-9][0-9]*|0)(\.([1-9][0-9]*|0))*
+*/
+static int
+compare_version_strings (const char *v1, const char *v2)
+{
+ int rresult;
+ regex_t r;
+
+ if (regcomp (&r, "^([1-9][0-9]*|0)(\\.([1-9][0-9]*|0))*$",
+ REG_EXTENDED | REG_NOSUB) != 0)
+ abort ();
+ rresult = regexec (&r, v1, 0, NULL, 0);
+ if (rresult == REG_NOMATCH)
+ fatal ("invalid version number `%s'", v1);
+ else if (rresult != 0)
+ abort ();
+ rresult = regexec (&r, v2, 0, NULL, 0);
+ if (rresult == REG_NOMATCH)
+ fatal ("invalid version number `%s'", v2);
+ else if (rresult != 0)
+ abort ();
+
+ return strverscmp (v1, v2);
+}
+
+
+/* version_compare built-in spec function.
+
+ This takes an argument of the following form:
+
+ <comparison-op> <arg1> [<arg2>] <switch> <result>
+
+ and produces "result" if the comparison evaluates to true,
+ and nothing if it doesn't.
+
+ The supported <comparison-op> values are:
+
+ >= true if switch is a later (or same) version than arg1
+ !> opposite of >=
+ < true if switch is an earlier version than arg1
+ !< opposite of <
+ >< true if switch is arg1 or later, and earlier than arg2
+ <> true if switch is earlier than arg1 or is arg2 or later
+
+ If the switch is not present, the condition is false unless
+ the first character of the <comparison-op> is '!'.
+
+ For example,
+ %:version-compare(>= 10.3 mmacosx-version-min= -lmx)
+ adds -lmx if -mmacosx-version-min=10.3.9 was passed. */
+
+static const char *
+version_compare_spec_function (int argc, const char **argv)
+{
+ int comp1, comp2;
+ size_t switch_len;
+ const char *switch_value = NULL;
+ int nargs = 1, i;
+ bool result;
+
+ if (argc < 3)
+ fatal ("too few arguments to %%:version-compare");
+ if (argv[0][0] == '\0')
+ abort ();
+ if ((argv[0][1] == '<' || argv[0][1] == '>') && argv[0][0] != '!')
+ nargs = 2;
+ if (argc != nargs + 3)
+ fatal ("too many arguments to %%:version-compare");
+
+ switch_len = strlen (argv[nargs + 1]);
+ for (i = 0; i < n_switches; i++)
+ if (!strncmp (switches[i].part1, argv[nargs + 1], switch_len)
+ && check_live_switch (i, switch_len))
+ switch_value = switches[i].part1 + switch_len;
+
+ if (switch_value == NULL)
+ comp1 = comp2 = -1;
+ else
+ {
+ comp1 = compare_version_strings (switch_value, argv[1]);
+ if (nargs == 2)
+ comp2 = compare_version_strings (switch_value, argv[2]);
+ else
+ comp2 = -1; /* This value unused. */
+ }
+
+ switch (argv[0][0] << 8 | argv[0][1])
+ {
+ case '>' << 8 | '=':
+ result = comp1 >= 0;
+ break;
+ case '!' << 8 | '<':
+ result = comp1 >= 0 || switch_value == NULL;
+ break;
+ case '<' << 8:
+ result = comp1 < 0;
+ break;
+ case '!' << 8 | '>':
+ result = comp1 < 0 || switch_value == NULL;
+ break;
+ case '>' << 8 | '<':
+ result = comp1 >= 0 && comp2 < 0;
+ break;
+ case '<' << 8 | '>':
+ result = comp1 < 0 || comp2 >= 0;
+ break;
+
+ default:
+ fatal ("unknown operator '%s' in %%:version-compare", argv[0]);
+ }
+ if (! result)
+ return NULL;
+
+ return argv[nargs + 2];
+}
+
+/* %:include builtin spec function. This differs from %include in that it
+ can be nested inside a spec, and thus be conditionalized. It takes
+ one argument, the filename, and looks for it in the startfile path.
+ The result is always NULL, i.e. an empty expansion. */
+
+static const char *
+include_spec_function (int argc, const char **argv)
+{
+ char *file;
+
+ if (argc != 1)
+ abort ();
+
+ file = find_a_file (&startfile_prefixes, argv[0], R_OK, true);
+ read_specs (file ? file : argv[0], FALSE);
+
+ return NULL;
+}
+
+/* %:find-file spec function. This function replace its argument by
+ the file found thru find_file, that is the -print-file-name gcc
+ program option. */
+static const char *
+find_file_spec_function (int argc, const char**argv)
+{
+ const char *file;
+
+ if (argc != 1)
+ abort ();
+
+ file = find_file (argv[0]);
+ return file;
+}
+
+
+/* %:print-asm-header spec function. Print a banner to say that the
+ following output is from the assembler. */
+
+static const char *
+print_asm_header_spec_function (int arg ATTRIBUTE_UNUSED,
+ const char **argv ATTRIBUTE_UNUSED)
+{
+ printf (_("Assembler options\n=================\n\n"));
+ printf (_("Use \"-Wa,OPTION\" to pass \"OPTION\" to the assembler.\n\n"));
+ fflush (stdout);
+ return NULL;
+}
+
+/* Compute a timestamp to initialize flag_random_seed. */
+
+static unsigned
+get_local_tick (void)
+{
+ unsigned ret = 0;
+
+ /* Get some more or less random data. */
+#ifdef HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+ ret = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ }
+#else
+ {
+ time_t now = time (NULL);
+
+ if (now != (time_t)-1)
+ ret = (unsigned) now;
+ }
+#endif
+
+ return ret;
+}
+
+/* %:compare-debug-dump-opt spec function. Save the last argument,
+ expected to be the last -fdump-final-insns option, or generate a
+ temporary. */
+
+static const char *
+compare_debug_dump_opt_spec_function (int arg,
+ const char **argv ATTRIBUTE_UNUSED)
+{
+ const char *ret;
+ char *name;
+ int which;
+ static char random_seed[HOST_BITS_PER_WIDE_INT / 4 + 3];
+
+ if (arg != 0)
+ fatal ("too many arguments to %%:compare-debug-dump-opt");
+
+ do_spec_2 ("%{fdump-final-insns=*:%*}");
+ do_spec_1 (" ", 0, NULL);
+
+ if (argbuf_index > 0 && strcmp (argv[argbuf_index - 1], "."))
+ {
+ if (!compare_debug)
+ return NULL;
+
+ name = xstrdup (argv[argbuf_index - 1]);
+ ret = NULL;
+ }
+ else
+ {
+ const char *ext = NULL;
+
+ if (argbuf_index > 0)
+ {
+ do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}");
+ ext = ".gkd";
+ }
+ else if (!compare_debug)
+ return NULL;
+ else
+ do_spec_2 ("%g.gkd");
+
+ do_spec_1 (" ", 0, NULL);
+
+ gcc_assert (argbuf_index > 0);
+
+ name = concat (argbuf[argbuf_index - 1], ext, NULL);
+
+ ret = concat ("-fdump-final-insns=", name, NULL);
+ }
+
+ which = compare_debug < 0;
+ debug_check_temp_file[which] = name;
+
+ if (!which)
+ {
+ unsigned HOST_WIDE_INT value = get_local_tick () ^ getpid ();
+
+ sprintf (random_seed, HOST_WIDE_INT_PRINT_HEX, value);
+ }
+
+ if (*random_seed)
+ ret = concat ("%{!frandom-seed=*:-frandom-seed=", random_seed, "} ",
+ ret, NULL);
+
+ if (which)
+ *random_seed = 0;
+
+ return ret;
+}
+
+static const char *debug_auxbase_opt;
+
+/* %:compare-debug-self-opt spec function. Expands to the options
+ that are to be passed in the second compilation of
+ compare-debug. */
+
+static const char *
+compare_debug_self_opt_spec_function (int arg,
+ const char **argv ATTRIBUTE_UNUSED)
+{
+ if (arg != 0)
+ fatal ("too many arguments to %%:compare-debug-self-opt");
+
+ if (compare_debug >= 0)
+ return NULL;
+
+ do_spec_2 ("%{c|S:%{o*:%*}}");
+ do_spec_1 (" ", 0, NULL);
+
+ if (argbuf_index > 0)
+ debug_auxbase_opt = concat ("-auxbase-strip ",
+ argbuf[argbuf_index - 1],
+ NULL);
+ else
+ debug_auxbase_opt = NULL;
+
+ return concat ("\
+%<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
+%<fdump-final-insns=* -w -S -o %j \
+%{!fcompare-debug-second:-fcompare-debug-second} \
+", compare_debug_opt, NULL);
+}
+
+/* %:compare-debug-auxbase-opt spec function. Expands to the auxbase
+ options that are to be passed in the second compilation of
+ compare-debug. It expects, as an argument, the basename of the
+ current input file name, with the .gk suffix appended to it. */
+
+static const char *
+compare_debug_auxbase_opt_spec_function (int arg,
+ const char **argv)
+{
+ char *name;
+ int len;
+
+ if (arg == 0)
+ fatal ("too few arguments to %%:compare-debug-auxbase-opt");
+
+ if (arg != 1)
+ fatal ("too many arguments to %%:compare-debug-auxbase-opt");
+
+ if (compare_debug >= 0)
+ return NULL;
+
+ len = strlen (argv[0]);
+ if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
+ fatal ("argument to %%:compare-debug-auxbase-opt does not end in .gk");
+
+ if (debug_auxbase_opt)
+ return debug_auxbase_opt;
+
+#define OPT "-auxbase "
+
+ len -= 3;
+ name = (char*) xmalloc (sizeof (OPT) + len);
+ memcpy (name, OPT, sizeof (OPT) - 1);
+ memcpy (name + sizeof (OPT) - 1, argv[0], len);
+ name[sizeof (OPT) - 1 + len] = '\0';
+
+#undef OPT
+
+ return name;
+}