/* 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, 2005, 2006, 2007, 2008, 2009
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "flags.h"
#include "opts.h"
+#ifdef HAVE_MMAP_FILE
+# include <sys/mman.h>
+# ifdef HAVE_MINCORE
+/* This is on Solaris. */
+# include <sys/types.h>
+# endif
+#endif
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void *)-1)
+#endif
+
/* By default there is no special suffix for target executables. */
/* FIXME: when autoconf is fixed, remove the host check - dj */
#if defined(TARGET_EXECUTABLE_SUFFIX) && defined(HOST_EXECUTABLE_SUFFIX)
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. */
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;
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
%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 unless -save-temps was specified
- to put temporaries in a different location.
+ 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
%{!.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 GCC. This may be
combined with '!', '.', ',', and '*' as above binding stronger
than the OR.
#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. */
/* 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*} %(mfwrap) %(link_libgcc) %o\
%{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
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;
%{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
%{!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}\
/* 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*}\
- %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}}\
+ %{!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}\
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
#endif
static const char *const driver_self_specs[] = {
- DRIVER_SELF_SPECS, GOMP_SELF_SPECS
+ "%{fdump-final-insns:-fdump-final-insns=.} %<fdump-final-insns",
+ DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS
};
#ifndef 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) \
{"--dependencies", "-M", 0},
{"--dump", "-d", "a"},
{"--dumpbase", "-dumpbase", "a"},
+ {"--dumpdir", "-dumpdir", "a"},
{"--encoding", "-fencoding=", "aj"},
{"--entry", "-e", 0},
{"--extra-warnings", "-W", 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},
/* 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 *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 *md_startfile_prefix = MD_STARTFILE_PREFIX;
static const char *md_startfile_prefix_1 = MD_STARTFILE_PREFIX_1;
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),
{ "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
static int have_o_argbuf_index = 0;
-/* Were the options -c or -S passed. */
+/* Were the options -c, -S or -E passed. */
static int have_c = 0;
/* Was the option -o passed. */
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
commands[0].prog = argbuf[0]; /* first command. */
commands[0].argv = &argbuf[0];
-
+
if (!wrapper_string)
{
string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false);
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
/* Run each piped subprocess. */
- pex = pex_init (PEX_USE_PIPES | (report_times ? PEX_RECORD_TIMES : 0),
+ 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"));
if (!pex_get_status (pex, n_commands, statuses))
pfatal_with_name (_("failed to get exit status"));
- if (report_times)
+ if (report_times || report_times_to_file)
{
times = (struct pex_time *) alloca (n_commands * sizeof (struct pex_time));
if (!pex_get_times (pex, n_commands, times))
ret_code = -1;
}
- if (report_times)
+ if (report_times || report_times_to_file)
{
struct pex_time *pt = ×[i];
double ut, st;
+ (double) pt->system_microseconds / 1.0e6);
if (ut + st != 0)
- notice ("# %s %.2f %.2f\n", commands[i].prog, ut, st);
+ {
+ 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);
+ }
+ }
}
}
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_LIVE 0x1
-#define SWITCH_FALSE 0x2
-#define SWITCH_IGNORE 0x4
+#define SWITCH_LIVE 0x1
+#define SWITCH_FALSE 0x2
+#define SWITCH_IGNORE 0x4
+#define SWITCH_IGNORE_PERMANENTLY 0x8
struct switchstr
{
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.
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);
--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);
if (! linker_options)
linker_options = XNEWVEC (char *, n_linker_options);
else
- linker_options = XRESIZEVEC (char *, linker_options, n_linker_options);
+ linker_options = XRESIZEVEC (char *, linker_options, n_linker_options);
linker_options [n_linker_options - 1] = save_string (option, len);
}
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.
- Use heuristic that all configuration names must have at least
- one dash '-'. This allows us to pass options starting with -b. */
- if (argc > 1 && argv[1][0] == '-'
- && (argv[1][1] == 'V'
- || (argv[1][1] == 'b'
- && (argv[1][2] == '\0'
- || NULL != strchr (argv[1] + 2, '-')))))
- {
- 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;
- int status = 0;
- int err = 0;
- const char *errmsg;
-
- while (argc > 1 && argv[1][0] == '-'
- && (argv[1][1] == 'V'
- || (argv[1][1] == 'b'
- && (argv[1][2] == '\0'
- || NULL != strchr (argv[1] + 2, '-')))))
- {
- 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]))
- break;
- new_argv0 = XDUPVAR (char, 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 = XDUPVEC (char *, argv, argc + 1);
- new_argv[0] = new_argv0;
+ /* Convert new-style -- options to old-style. */
+ translate_options (&argc,
+ CONST_CAST2 (const char *const **, const char ***,
+ &argv));
- errmsg = pex_one (PEX_SEARCH, new_argv0, new_argv, progname, NULL,
- NULL, &status, &err);
+ /* 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. */
- if (errmsg)
+ for (i = 1; i < argc; i++)
+ {
+ if (! strcmp (argv[i], "-no-canonical-prefixes"))
{
- if (err == 0)
- fatal ("couldn't run '%s': %s", new_argv0, errmsg);
- else
- fatal ("couldn't run '%s': %s: %s", new_argv0, errmsg,
- xstrerror (err));
- }
- exit (status);
+ get_relative_prefix = make_relative_prefix_ignore_links;
+ break;
+ }
}
+ 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)
xputenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL));
}
/ (which is ignored by make_relative_prefix), so append a
program name. */
char *tmp_prefix = concat (gcc_exec_prefix, "gcc", NULL);
- gcc_libexec_prefix = make_relative_prefix (tmp_prefix,
- standard_exec_prefix,
- standard_libexec_prefix);
+ 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)
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)
{
int len = strlen (gcc_exec_prefix);
}
}
- /* Convert new-style -- options to old-style. */
- translate_options (&argc, (const char *const **) &argv);
-
- /* Do language-specific adjustment/addition of flags. */
- lang_specific_driver (&argc, (const char *const **) &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). */
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
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;
}
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
switch (c)
{
- case 'b':
- if (p[1] && NULL == strchr (argv[i] + 2, '-'))
- goto normal_switch;
-
- /* Fall through. */
- case 'V':
- fatal ("'-%c' must come at the start of the command line", c);
- break;
-
case 'B':
{
const char *value;
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)
argv[i] = convert_filename (argv[i], ! have_c, 0);
#endif
/* Save the output name in case -save-temps=obj was used. */
- save_temps_prefix = xstrdup ((p[1] == 0) ? argv[i + 1] : argv[i] + 1);
+ 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:
use_pipes = 0;
}
+ 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. */
+ the GNU assembler) before those of the host system. */
/* If we don't know where the toolchain has been installed, use the
configured-in locations. */
PREFIX_PRIORITY_LAST, 1, 0);
}
- /* If not cross-compiling, search well-known system locations. */
- if (*cross_compile == '0')
- {
-#ifndef OS2
- add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS",
- PREFIX_PRIORITY_LAST, 2, 0);
- add_prefix (&exec_prefixes, standard_exec_prefix_2, "BINUTILS",
- PREFIX_PRIORITY_LAST, 2, 0);
-#endif
- add_prefix (&startfile_prefixes, standard_exec_prefix_2, "BINUTILS",
- PREFIX_PRIORITY_LAST, 1, 0);
- }
-
gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix));
tooldir_prefix = concat (tooldir_base_prefix, spec_machine,
dir_separator_str, NULL);
``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;
;
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], "-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)
switches[n_switches].validated = 0;
switches[n_switches].ordering = 0;
/* These are always valid, since gcc.c itself understands the
- first four and gfortranspec.c understands -static-libgfortran. */
+ 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, "static-libgfortran"))
+ || !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);
+ 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 (print_subprocess_help || print_help_list || print_version)
{
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;
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;
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;
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 = XRESIZEVEC (struct switchstr, switches, 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] != '-')
+ if (c != '-')
fatal ("switch '%s' does not start with '-'", argbuf[i]);
- sw = &switches[i + first];
- sw->part1 = &argbuf[i][1];
- sw->args = 0;
+ p++;
+ c = *p;
+
+ sw = &switches[n_switches++];
+ sw->part1 = p;
sw->live_cond = 0;
sw->validated = 0;
sw->ordering = 0;
+
+ /* 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;
}
}
delete_this_arg = 0;
this_is_output_file = 0;
this_is_library_file = 0;
+ this_is_linker_script = 0;
input_from_pipe = 0;
break;
delete_this_arg = 0;
this_is_output_file = 0;
this_is_library_file = 0;
+ this_is_linker_script = 0;
break;
case '%':
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;
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;
buf = (char *) alloca (p - q + 1);
strncpy (buf, q, p - q);
buf[p - q] = 0;
- error ("%s", buf);
+ error ("%s", _(buf));
return -1;
}
break;
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++;
}
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)
this_is_library_file = 1;
break;
+ case 'T':
+ this_is_linker_script = 1;
+ break;
+
case 'V':
outfiles[input_file_number] = NULL;
break;
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;
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;
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;
if (atom == end_atom)
{
if (!n_way_choice || disj_matched || *p == '|'
- || a_is_negated || a_is_suffix || a_is_spectype
+ || a_is_negated || a_is_suffix || a_is_spectype
|| a_is_starred)
goto invalid;
{
if ((a_is_suffix || a_is_spectype) && a_is_starred)
goto invalid;
-
+
if (!a_is_starred)
disj_starred = false;
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;
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 & SWITCH_LIVE) != 0
- && (switches[switchnum].live_cond & SWITCH_FALSE) == 0);
-
/* Now search for duplicate in a manner that depends on the name. */
switch (*name)
{
kill (getpid (), signum);
}
+/* Compare the contents of the two files named CMPFILE[0] and
+ CMPFILE[1]. Return zero if they're identical, nonzero
+ otherwise. */
+
+static int
+compare_files (char *cmpfile[])
+{
+ int ret = 0;
+ FILE *temp[2] = { NULL, NULL };
+ int i;
+
+#if HAVE_MMAP_FILE
+ {
+ size_t length[2];
+ void *map[2] = { NULL, NULL };
+
+ for (i = 0; i < 2; i++)
+ {
+ struct stat st;
+
+ 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;
+ }
+
+ length[i] = st.st_size;
+ }
+
+ 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
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);
- xputenv (XOBFINISH (&collect_obstack, char *));
-
#ifdef INIT_ENVIRONMENT
/* Set up any other necessary machine specific environment variables. */
xputenv (INIT_ENVIRONMENT);
Make a table of specified input files (infiles, n_infiles).
Decode switches that are handled locally. */
- process_command (argc, (const char **) 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. */
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')
else if (*cross_compile == '0')
{
add_prefix (&startfile_prefixes,
- concat (gcc_exec_prefix
- ? gcc_exec_prefix : standard_exec_prefix,
- machine_suffix,
+ concat (gcc_exec_prefix
+ ? gcc_exec_prefix : standard_exec_prefix,
+ machine_suffix,
standard_startfile_prefix, NULL),
NULL, PREFIX_PRIORITY_LAST, 0, 1);
}
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++)
{
printf (_("%s %s%s\n"), programname, pkgversion_string,
version_string);
- printf ("Copyright %s 2009 Free Software Foundation, Inc.\n",
+ 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"),
}
if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
- fatal ("cannot specify -o with -c or -S with multiple files");
+ fatal ("cannot specify -o with -c, -S or -E with multiple files");
if (combine_flag && save_temps_flag)
{
}
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;
+ }
}
}
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"))
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", false);
ptr[0] = '\\';
ptr[1] = *value++;
}
-
+
strcpy (ptr, argv[1]);
-
+
return result;
}
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. */
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;
+}