%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=%(lto_gcc) \
+ %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)} \
+ %{static:-plugin-opt=-pass-through=-lc} \
+ %{O*:-plugin-opt=-O%*} \
+ %{w:-plugin-opt=-w} \
+ %{f*:-plugin-opt=-f%*} \
+ } \
+ %{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;
static const char *invoke_as =
#ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT
-"%{fcompare-debug=*:%:compare-debug-dump-opt()}\
- %{!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
-"%{fcompare-debug=*:%:compare-debug-dump-opt()}\
- %{!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[] = {
+ "%{fdump-final-insns:-fdump-final-insns=.} %<fdump-final-insns",
DRIVER_SELF_SPECS, GOMP_SELF_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) \
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),
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 (! 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);
}
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:
}
else
{
+ const char *p = strchr (argv[i], '@');
+ char *fname;
#ifdef HAVE_TARGET_OBJECT_SUFFIX
argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
#endif
+ if (!p)
+ fname = xstrdup (argv[i]);
+ else
+ {
+ fname = (char *)xmalloc (p - argv[i] + 1);
+ memcpy (fname, argv[i], p - argv[i]);
+ fname[p - argv[i]] = '\0';
+ }
+
+ 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];
+ }
- if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0)
- {
- perror_with_name (argv[i]);
- error_count++;
- }
- else
- {
- infiles[n_infiles].language = spec_lang;
- infiles[n_infiles++].name = argv[i];
- }
+ free (fname);
}
}
if ((switches[i].live_cond & SWITCH_IGNORE) != 0)
continue;
- /* Don't use -fwhole-program when compiling the init and fini routines,
- since we'd wrongly assume that the routines aren't needed. */
- if (strcmp (switches[i].part1, "fwhole-program") == 0)
- continue;
-
obstack_grow (&collect_obstack, "'-", 2);
q = switches[i].part1;
while ((p = strchr (q, '\'')))
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;
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 '%':
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 ((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;
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);
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 (!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)
{
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", X_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);
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. */
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");
- if (!compare_debug)
- return NULL;
-
do_spec_2 ("%{fdump-final-insns=*:%*}");
do_spec_1 (" ", 0, NULL);
- if (argbuf_index > 0)
+ if (argbuf_index > 0 && strcmp (argv[argbuf_index - 1], "."))
{
+ if (!compare_debug)
+ return NULL;
+
name = xstrdup (argv[argbuf_index - 1]);
ret = NULL;
}
else
{
-#define OPT "-fdump-final-insns="
- ret = "-fdump-final-insns=%g.gkd";
+ 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_2 (ret + sizeof (OPT) - 1);
do_spec_1 (" ", 0, NULL);
-#undef OPT
gcc_assert (argbuf_index > 0);
- name = xstrdup (argbuf[argbuf_index - 1]);
+ 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 0
- error ("compare-debug: [%i]=\"%s\", ret %s", which, name, ret);
-#endif
+ 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;
}
memcpy (name + sizeof (OPT) - 1, argv[0], len);
name[sizeof (OPT) - 1 + len] = '\0';
+#undef OPT
+
return name;
}