/* 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,
- 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2013 Free Software Foundation, Inc.
This file is part of GCC.
#include "diagnostic.h"
#include "flags.h"
#include "opts.h"
+#include "params.h"
#include "vec.h"
+#include "filenames.h"
/* By default there is no special suffix for target executables. */
/* FIXME: when autoconf is fixed, remove the host check - dj */
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 void read_specs (const char *, bool, bool);
+static void set_spec (const char *, const char *, bool);
static struct compiler *lookup_compiler (const char *, size_t, const char *);
static char *build_search_list (const struct path_prefix *, const char *,
bool, bool);
static void do_self_spec (const char *);
static const char *find_file (const char *);
static int is_directory (const char *, bool);
-static const char *validate_switches (const char *);
+static const char *validate_switches (const char *, bool);
static void validate_all_switches (void);
-static inline void validate_switches_from_spec (const char *);
+static inline void validate_switches_from_spec (const char *, bool);
static void give_switch (int, int);
static int used_arg (const char *, int);
static int default_arg (const char *, int);
static const char *compare_debug_self_opt_spec_function (int, const char **);
static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
static const char *pass_through_libs_spec_func (int, const char **);
+static const char *replace_extension_spec_func (int, const char **);
+static char *convert_white_space (char *);
\f
/* The Specs Language
If multilib_dir is set, extra entries are generated with it affixed.
%l process LINK_SPEC as a spec.
%L process LIB_SPEC as a spec.
+ %M Output multilib_os_dir.
%G process LIBGCC_SPEC as a spec.
%R Output the concatenation of target_system_root and
target_sysroot_suffix.
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
The conditional text X in a %{S:X} or similar construct may contain
other nested % constructs or spaces, or even newlines. They are
colon in these constructs, except between . or * and the corresponding
word.
-The -O, -f, -m, and -W switches are handled specifically in these
+The -O, -f, -g, -m, and -W switches are handled specifically in these
constructs. If another value of -O or the negated form of a -f, -m, or
-W switch is found later in the command line, the earlier switch
value is ignored, except with {S*} where S is just one letter; this
/* config.h can define ASM_FINAL_SPEC to run a post processor after
the assembler has run. */
#ifndef ASM_FINAL_SPEC
-#define ASM_FINAL_SPEC ""
+#define ASM_FINAL_SPEC \
+ "%{gsplit-dwarf: \n\
+ objcopy --extract-dwo \
+ %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+ %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
+ objcopy --strip-dwo \
+ %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+ }"
#endif
/* config.h can define CPP_SPEC to provide extra args to the C preprocessor
/* 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\
+ --wrap=mmap --wrap=mmap64 --wrap=munmap --wrap=alloca\
} %{fmudflapth: --wrap=pthread_create\
}} %{fmudflap|fmudflapth: --wrap=main}"
#endif
wrapping. */
#define STACK_SPLIT_SPEC " %{fsplit-stack: --wrap=pthread_create}"
+#ifndef LIBASAN_SPEC
+#ifdef STATIC_LIBASAN_LIBS
+#define ADD_STATIC_LIBASAN_LIBS \
+ " %{static-libasan:" STATIC_LIBASAN_LIBS "}"
+#else
+#define ADD_STATIC_LIBASAN_LIBS
+#endif
+#ifdef LIBASAN_EARLY_SPEC
+#define LIBASAN_SPEC ADD_STATIC_LIBASAN_LIBS
+#elif defined(HAVE_LD_STATIC_DYNAMIC)
+#define LIBASAN_SPEC "%{static-libasan:" LD_STATIC_OPTION \
+ "} -lasan %{static-libasan:" LD_DYNAMIC_OPTION "}" \
+ ADD_STATIC_LIBASAN_LIBS
+#else
+#define LIBASAN_SPEC "-lasan" ADD_STATIC_LIBASAN_LIBS
+#endif
+#endif
+
+#ifndef LIBASAN_EARLY_SPEC
+#define LIBASAN_EARLY_SPEC ""
+#endif
+
+#ifndef LIBTSAN_SPEC
+#ifdef STATIC_LIBTSAN_LIBS
+#define ADD_STATIC_LIBTSAN_LIBS \
+ " %{static-libtsan:" STATIC_LIBTSAN_LIBS "}"
+#else
+#define ADD_STATIC_LIBTSAN_LIBS
+#endif
+#ifdef LIBTSAN_EARLY_SPEC
+#define LIBTSAN_SPEC ADD_STATIC_LIBTSAN_LIBS
+#elif defined(HAVE_LD_STATIC_DYNAMIC)
+#define LIBTSAN_SPEC "%{static-libtsan:" LD_STATIC_OPTION \
+ "} -ltsan %{static-libtsan:" LD_DYNAMIC_OPTION "}" \
+ ADD_STATIC_LIBTSAN_LIBS
+#else
+#define LIBTSAN_SPEC "-ltsan" ADD_STATIC_LIBTSAN_LIBS
+#endif
+#endif
+
+#ifndef LIBTSAN_EARLY_SPEC
+#define LIBTSAN_EARLY_SPEC ""
+#endif
+
/* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
included. */
#ifndef LIBGCC_SPEC
&& defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
# define ASM_DEBUG_SPEC \
(PREFERRED_DEBUGGING_TYPE == DBX_DEBUG \
- ? "%{!g0:%{gdwarf-2*:--gdwarf2}%{!gdwarf-2*:%{g*:--gstabs}}}" ASM_MAP \
+ ? "%{!g0:%{gdwarf*:--gdwarf2}%{!gdwarf*:%{g*:--gstabs}}}" ASM_MAP \
: "%{!g0:%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}}" ASM_MAP)
# else
# if defined(DBX_DEBUGGING_INFO) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
# endif
#endif
-/* Conditional to test whether plugin is used or not.
+/* Conditional to test whether the LTO plugin is used or not.
FIXME: For slim LTO we will need to enable plugin unconditionally. This
still cause problems with PLUGIN_LD != LD and when plugin is built but
not useable. For GCC 4.6 we don't support slim LTO and thus we can enable
plugin only when LTO is enabled. We still honor explicit
- -fuse-linker-plugin. */
-#ifdef HAVE_LTO_PLUGIN
+ -fuse-linker-plugin if the linker used understands -plugin. */
+
+/* The linker has some plugin support. */
+#if HAVE_LTO_PLUGIN > 0
+/* The linker used has full plugin support, use LTO plugin by default. */
+#if HAVE_LTO_PLUGIN == 2
#define PLUGIN_COND "!fno-use-linker-plugin:%{flto|flto=*|fuse-linker-plugin"
#define PLUGIN_COND_CLOSE "}"
#else
+/* The linker used has limited plugin support, use LTO plugin with explicit
+ -fuse-linker-plugin. */
#define PLUGIN_COND "fuse-linker-plugin"
#define PLUGIN_COND_CLOSE ""
#endif
+#define LINK_PLUGIN_SPEC \
+ "%{"PLUGIN_COND": \
+ -plugin %(linker_plugin_file) \
+ -plugin-opt=%(lto_wrapper) \
+ -plugin-opt=-fresolution=%u.res \
+ %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
+ }"PLUGIN_COND_CLOSE
+#else
+/* The linker used doesn't support -plugin, reject -fuse-linker-plugin. */
+#define LINK_PLUGIN_SPEC "%{fuse-linker-plugin:\
+ %e-fuse-linker-plugin is not supported in this configuration}"
+#endif
+/* Linker command line options for -fsanitize= early on the command line. */
+#ifndef SANITIZER_EARLY_SPEC
+#define SANITIZER_EARLY_SPEC "\
+%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_EARLY_SPEC "} \
+ %{fsanitize=thread:" LIBTSAN_EARLY_SPEC "}}}"
+#endif
+
+/* Linker command line options for -fsanitize= late on the command line. */
+#ifndef SANITIZER_SPEC
+#define SANITIZER_SPEC "\
+%{!nostdlib:%{!nodefaultlibs:%{fsanitize=address:" LIBASAN_SPEC "\
+ %{static:%ecannot specify -static with -fsanitize=address}}\
+ %{fsanitize=thread:" LIBTSAN_SPEC "\
+ %{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}}}"
+#endif
/* -u* was put back because both BSD and SysV seem to support it. */
/* %{static:} simply prevents an error message if the target machine
directories. */
/* We pass any -flto flags on to the linker, which is expected
to understand them. In practice, this means it had better be collect2. */
+/* %{e*} includes -export-dynamic; see comment in common.opt. */
#ifndef LINK_COMMAND_SPEC
#define LINK_COMMAND_SPEC "\
%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
- %(linker) \
- %{"PLUGIN_COND": \
- -plugin %(linker_plugin_file) \
- -plugin-opt=%(lto_wrapper) \
- -plugin-opt=-fresolution=%u.res \
- %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
- }"PLUGIN_COND_CLOSE" \
- %{flto|flto=*:%<fcompare-debug*} \
+ %(linker) " \
+ LINK_PLUGIN_SPEC \
+ "%{flto|flto=*:%<fcompare-debug*} \
%{flto} %{flto=*} %l " LINK_PIE_SPEC \
- "%X %{o*} %{e*} %{N} %{n} %{r}\
+ "%{fuse-ld=*:-fuse-ld=%*}\
+ %X %{o*} %{e*} %{N} %{n} %{r}\
%{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}}\
- %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
+ %{static:} %{L*} %(mfwrap) %(link_libgcc) " SANITIZER_EARLY_SPEC " %o\
%{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
+ %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
%(mflib) " STACK_SPLIT_SPEC "\
- %{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
+ %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} " SANITIZER_SPEC " \
%{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
%{!nostdlib:%{!nostartfiles:%E}} %{T*} }}}}}}"
#endif
# define SYSROOT_HEADERS_SUFFIX_SPEC ""
#endif
-static const char *asm_debug;
+static const char *asm_debug = ASM_DEBUG_SPEC;
static const char *cpp_spec = CPP_SPEC;
static const char *cc1_spec = CC1_SPEC;
static const char *cc1plus_spec = CC1PLUS_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;
+static const char *self_spec = "";
/* Standard options to cpp, cc1, and as, to reduce duplication in specs.
There should be no need to override these in target dependent files,
%{coverage:-fprofile-arcs -ftest-coverage}";
static const char *asm_options =
-"%{--target-help:%:print-asm-header()} "
+"%{-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. */
static const char *multilib_matches;
static const char *multilib_defaults;
static const char *multilib_exclusions;
+static const char *multilib_reuse;
/* Check whether a particular argument is a default argument. */
#define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: -pthread}"
#endif
+/* Likewise for -fgnu-tm. */
+#ifndef GTM_SELF_SPECS
+#define GTM_SELF_SPECS "%{fgnu-tm: -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
+ DRIVER_SELF_SPECS, CONFIGURE_SPECS, GOMP_SELF_SPECS, GTM_SELF_SPECS
};
#ifndef OPTION_DEFAULT_SPECS
%W{o*:--output-pch=%*}}%V}}}}}}", 0, 0, 0},
{".i", "@cpp-output", 0, 0, 0},
{"@cpp-output",
- "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 1, 0},
+ "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 0},
{".s", "@assembler", 0, 0, 0},
{"@assembler",
"%{!M:%{!MM:%{!E:%{!S:as %(asm_debug) %(asm_options) %i %A }}}}", 0, 0, 0},
static const int n_default_compilers = ARRAY_SIZE (default_compilers) - 1;
typedef char *char_p; /* For DEF_VEC_P. */
-DEF_VEC_P(char_p);
-DEF_VEC_ALLOC_P(char_p,heap);
/* A vector of options to give to the linker.
These options are accumulated by %x,
and substituted into the linker command with %X. */
-static VEC(char_p,heap) *linker_options;
+static vec<char_p> linker_options;
/* A vector of options to give to the assembler.
These options are accumulated by -Wa,
and substituted into the assembler command with %Y. */
-static VEC(char_p,heap) *assembler_options;
+static vec<char_p> assembler_options;
/* A vector of options to give to the preprocessor.
These options are accumulated by -Wp,
and substituted into the preprocessor command with %Z. */
-static VEC(char_p,heap) *preprocessor_options;
+static vec<char_p> preprocessor_options;
\f
static char *
skip_whitespace (char *p)
set_multilib_dir based on the compilation options. */
static const char *multilib_os_dir;
+
+/* Subdirectory to use for locating libraries in multiarch conventions. Set by
+ set_multilib_dir based on the compilation options. */
+
+static const char *multiarch_dir;
\f
/* Structure to keep track of the specs that have been defined so far.
- These are accessed using %(specname) or %[specname] in a compiler
- or link spec. */
+ These are accessed using %(specname) in a compiler or link
+ spec. */
struct spec_list
{
const char **ptr_spec; /* pointer to the spec itself. */
struct spec_list *next; /* Next spec in linked list. */
int name_len; /* length of the name */
- int alloc_p; /* whether string was allocated */
+ bool user_p; /* whether string come from file spec. */
+ bool alloc_p; /* whether string was allocated */
};
#define INIT_STATIC_SPEC(NAME,PTR) \
-{ NAME, NULL, PTR, (struct spec_list *) 0, sizeof (NAME) - 1, 0 }
+ { NAME, NULL, PTR, (struct spec_list *) 0, sizeof (NAME) - 1, false, false }
/* List of statically defined specs. */
static struct spec_list static_specs[] =
INIT_STATIC_SPEC ("multilib_matches", &multilib_matches),
INIT_STATIC_SPEC ("multilib_exclusions", &multilib_exclusions),
INIT_STATIC_SPEC ("multilib_options", &multilib_options),
+ INIT_STATIC_SPEC ("multilib_reuse", &multilib_reuse),
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 ("sysroot_spec", &sysroot_spec),
INIT_STATIC_SPEC ("sysroot_suffix_spec", &sysroot_suffix_spec),
INIT_STATIC_SPEC ("sysroot_hdrs_suffix_spec", &sysroot_hdrs_suffix_spec),
+ INIT_STATIC_SPEC ("self_spec", &self_spec),
};
#ifdef EXTRA_SPECS /* additional specs needed */
{ "compare-debug-self-opt", compare_debug_self_opt_spec_function },
{ "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
{ "pass-through-libs", pass_through_libs_spec_func },
+ { "replace-extension", replace_extension_spec_func },
#ifdef EXTRA_SPEC_FUNCTIONS
EXTRA_SPEC_FUNCTIONS
#endif
"%{!static:%{!static-libgcc:"
#if USE_LD_AS_NEEDED
"%{!shared-libgcc:",
- static_name, " --as-needed ", shared_name, " --no-as-needed"
+ static_name, " " LD_AS_NEEDED_OPTION " ",
+ shared_name, " " LD_NO_AS_NEEDED_OPTION
"}"
"%{shared-libgcc:",
shared_name, "%{!shared: ", static_name, "}"
}
#endif
-#if defined LINK_EH_SPEC || defined LINK_BUILDID_SPEC
+#if defined LINK_EH_SPEC || defined LINK_BUILDID_SPEC || \
+ defined LINKER_HASH_STYLE
# 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);
# 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
+# ifdef LINKER_HASH_STYLE
+ /* Prepend --hash-style=LINKER_HASH_STYLE to whatever link_spec we had
+ before. */
+ {
+ static const char hash_style[] = "--hash-style=";
+ obstack_grow (&obstack, hash_style, sizeof(hash_style) - 1);
+ obstack_grow (&obstack, LINKER_HASH_STYLE, sizeof(LINKER_HASH_STYLE) - 1);
+ obstack_1grow (&obstack, ' ');
+ }
# endif
obstack_grow0 (&obstack, link_spec, strlen (link_spec));
link_spec = XOBFINISH (&obstack, const char *);
current spec. */
static void
-set_spec (const char *name, const char *spec)
+set_spec (const char *name, const char *spec, bool user_p)
{
struct spec_list *sl;
const char *old_spec;
if (old_spec && sl->alloc_p)
free (CONST_CAST(char *, old_spec));
- sl->alloc_p = 1;
+ sl->user_p = user_p;
+ sl->alloc_p = true;
}
\f
/* Accumulate a command (program name and args), and run it. */
typedef const char *const_char_p; /* For DEF_VEC_P. */
-DEF_VEC_P(const_char_p);
-DEF_VEC_ALLOC_P(const_char_p,heap);
/* Vector of pointers to arguments in the current line of specifications. */
-static VEC(const_char_p,heap) *argbuf;
+static vec<const_char_p> argbuf;
/* Position in the argbuf vector containing the name of the output file
(the value associated with the "-o" flag). */
static void
alloc_args (void)
{
- argbuf = VEC_alloc (const_char_p, heap, 10);
+ argbuf.create (10);
}
/* Clear out the vector of arguments (after a command is executed). */
static void
clear_args (void)
{
- VEC_truncate (const_char_p, argbuf, 0);
+ argbuf.truncate (0);
}
/* Add one argument to the vector at the end.
static void
store_arg (const char *arg, int delete_always, int delete_failure)
{
- VEC_safe_push (const_char_p, heap, argbuf, arg);
+ argbuf.safe_push (arg);
if (strcmp (arg, "-o") == 0)
- have_o_argbuf_index = VEC_length (const_char_p, argbuf);
+ have_o_argbuf_index = argbuf.length ();
if (delete_always || delete_failure)
{
const char *p;
Anything invalid in the file is a fatal error. */
static void
-read_specs (const char *filename, int main_p)
+read_specs (const char *filename, bool main_p, bool user_p)
{
char *buffer;
char *p;
p[-2] = '\0';
new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
- read_specs (new_filename ? new_filename : p1, FALSE);
+ read_specs (new_filename ? new_filename : p1, false, user_p);
continue;
}
else if (!strncmp (p1, "%include_noerr", sizeof "%include_noerr" - 1)
p[-2] = '\0';
new_filename = find_a_file (&startfile_prefixes, p1, R_OK, true);
if (new_filename)
- read_specs (new_filename, FALSE);
+ read_specs (new_filename, false, user_p);
else if (verbose_flag)
fnotice (stderr, "could not find specs file %s\n", p1);
continue;
#endif
}
- set_spec (p2, *(sl->ptr_spec));
+ set_spec (p2, *(sl->ptr_spec), user_p);
if (sl->alloc_p)
free (CONST_CAST (char *, *(sl->ptr_spec)));
if (! strcmp (suffix, "*link_command"))
link_command_spec = spec;
else
- set_spec (suffix + 1, spec);
+ set_spec (suffix + 1, spec, user_p);
}
else
{
{
struct temp_file *temp;
for (temp = always_delete_queue; temp; temp = temp->next)
- if (! strcmp (name, temp->name))
+ if (! filename_cmp (name, temp->name))
goto already1;
temp = XNEW (struct temp_file);
{
struct temp_file *temp;
for (temp = failure_delete_queue; temp; temp = temp->next)
- if (! strcmp (name, temp->name))
- goto already2;
+ if (! filename_cmp (name, temp->name))
+ {
+ free (name);
+ goto already2;
+ }
temp = XNEW (struct temp_file);
temp->next = failure_delete_queue;
struct prefix_list *pl;
const char *multi_dir = NULL;
const char *multi_os_dir = NULL;
+ const char *multiarch_suffix = NULL;
const char *multi_suffix;
const char *just_multi_suffix;
char *path = NULL;
}
if (do_multi && multilib_os_dir && strcmp (multilib_os_dir, ".") != 0)
multi_os_dir = concat (multilib_os_dir, dir_separator_str, NULL);
+ if (multiarch_dir)
+ multiarch_suffix = concat (multiarch_dir, dir_separator_str, NULL);
while (1)
{
size_t multi_dir_len = 0;
size_t multi_os_dir_len = 0;
+ size_t multiarch_len = 0;
size_t suffix_len;
size_t just_suffix_len;
size_t len;
multi_dir_len = strlen (multi_dir);
if (multi_os_dir)
multi_os_dir_len = strlen (multi_os_dir);
+ if (multiarch_suffix)
+ multiarch_len = strlen (multiarch_suffix);
suffix_len = strlen (multi_suffix);
just_suffix_len = strlen (just_multi_suffix);
if (path == NULL)
{
len = paths->max_len + extra_space + 1;
- if (suffix_len > multi_os_dir_len)
- len += suffix_len;
- else
- len += multi_os_dir_len;
+ len += MAX (MAX (suffix_len, multi_os_dir_len), multiarch_len);
path = XNEWVEC (char, len);
}
break;
}
+ /* Now try the multiarch path. */
+ if (!skip_multi_dir
+ && !pl->require_machine_suffix && multiarch_dir)
+ {
+ memcpy (path + len, multiarch_suffix, multiarch_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))
if (target_system_root)
{
+ char *sysroot_no_trailing_dir_separator = xstrdup (target_system_root);
+ size_t sysroot_len = strlen (target_system_root);
+
+ if (sysroot_len > 0
+ && target_system_root[sysroot_len - 1] == DIR_SEPARATOR)
+ sysroot_no_trailing_dir_separator[sysroot_len - 1] = '\0';
+
if (target_sysroot_suffix)
- prefix = concat (target_sysroot_suffix, prefix, NULL);
- prefix = concat (target_system_root, prefix, NULL);
+ prefix = concat (sysroot_no_trailing_dir_separator,
+ target_sysroot_suffix, prefix, NULL);
+ else
+ prefix = concat (sysroot_no_trailing_dir_separator, prefix, NULL);
+
+ free (sysroot_no_trailing_dir_separator);
/* We have to override this because GCC's notion of sysroot
moves along with GCC. */
if (wrapper_string)
{
string = find_a_file (&exec_prefixes,
- VEC_index (const_char_p, argbuf, 0), X_OK, false);
+ argbuf[0], X_OK, false);
if (string)
- VEC_replace (const_char_p, argbuf, 0, string);
+ argbuf[0] = string;
insert_wrapper (wrapper_string);
}
/* Count # of piped commands. */
- for (n_commands = 1, i = 0; VEC_iterate (const_char_p, argbuf, i, arg); i++)
+ for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++)
if (strcmp (arg, "|") == 0)
n_commands++;
and record info about each one.
Also search for the programs that are to be run. */
- VEC_safe_push (const_char_p, heap, argbuf, 0);
+ argbuf.safe_push (0);
- commands[0].prog = VEC_index (const_char_p, argbuf, 0); /* first command. */
- commands[0].argv = VEC_address (const_char_p, argbuf);
+ commands[0].prog = argbuf[0]; /* first command. */
+ commands[0].argv = argbuf.address ();
if (!wrapper_string)
{
commands[0].argv[0] = (string) ? string : commands[0].argv[0];
}
- for (n_commands = 1, i = 0; VEC_iterate (const_char_p, argbuf, i, arg); i++)
+ for (n_commands = 1, i = 0; argbuf.iterate (i, &arg); i++)
if (arg && strcmp (arg, "|") == 0)
{ /* each command. */
#if defined (__MSDOS__) || defined (OS2) || defined (VMS)
fatal_error ("-pipe not supported");
#endif
- VEC_replace (const_char_p, argbuf, i, 0); /* Termination of
+ argbuf[i] = 0; /* Termination of
command args. */
- commands[n_commands].prog = VEC_index (const_char_p, argbuf, i + 1);
+ commands[n_commands].prog = argbuf[i + 1];
commands[n_commands].argv
- = &(VEC_address (const_char_p, argbuf))[i + 1];
+ = &(argbuf.address ())[i + 1];
string = find_a_file (&exec_prefixes, commands[n_commands].prog,
X_OK, false);
if (string)
}
fputc ('"', stderr);
}
+ /* If it's empty, print "". */
+ else if (!**j)
+ fprintf (stderr, " \"\"");
else
fprintf (stderr, " %s", *j);
}
}
else
for (j = commands[i].argv; *j; j++)
- fprintf (stderr, " %s", *j);
+ /* If it's empty, print "". */
+ if (!**j)
+ fprintf (stderr, " \"\"");
+ else
+ fprintf (stderr, " %s", *j);
/* Print a pipe symbol after all but the last command. */
if (i + 1 != n_commands)
const char *part1;
const char **args;
unsigned int live_cond;
- unsigned char validated;
- unsigned char ordering;
+ bool known;
+ bool validated;
+ bool ordering;
};
static struct switchstr *switches;
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 (_(" --help={common|optimizers|params|target|warnings|[^]{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 (_(" -print-libgcc-file-name Display the name of the compiler's companion library\n"), stdout);
fputs (_(" -print-file-name=<lib> Display the full path to library <lib>\n"), stdout);
fputs (_(" -print-prog-name=<prog> Display the full path to compiler component <prog>\n"), stdout);
+ fputs (_("\
+ -print-multiarch Display the target's normalized GNU triplet, used as\n\
+ a component in the library path\n"), stdout);
fputs (_(" -print-multi-directory Display the root directory for versions of libgcc\n"), stdout);
fputs (_("\
-print-multi-lib Display the mapping between command line options and\n\
fputs (_(" -S Compile only; do not assemble or link\n"), stdout);
fputs (_(" -c Compile and assemble, but do not link\n"), stdout);
fputs (_(" -o <file> Place the output into <file>\n"), stdout);
+ fputs (_(" -pie Create a position independent executable\n"), stdout);
+ fputs (_(" -shared Create a shared library\n"), stdout);
fputs (_("\
-x <language> Specify the language of the following input files\n\
Permissible languages include: c c++ assembler none\n\
static void
add_preprocessor_option (const char *option, int len)
{
- VEC_safe_push (char_p, heap, preprocessor_options,
- save_string (option, len));
+ preprocessor_options.safe_push (save_string (option, len));
}
static void
add_assembler_option (const char *option, int len)
{
- VEC_safe_push (char_p, heap, assembler_options, save_string (option, len));
+ assembler_options.safe_push (save_string (option, len));
}
static void
add_linker_option (const char *option, int len)
{
- VEC_safe_push (char_p, heap, linker_options, save_string (option, len));
+ linker_options.safe_push (save_string (option, len));
}
\f
/* Allocate space for an input file in infiles. */
}
/* Save an option OPT with N_ARGS arguments in array ARGS, marking it
- as validated if VALIDATED. */
+ as validated if VALIDATED and KNOWN if it is an internal switch. */
static void
save_switch (const char *opt, size_t n_args, const char *const *args,
- bool validated)
+ bool validated, bool known)
{
alloc_switch ();
switches[n_switches].part1 = opt + 1;
switches[n_switches].live_cond = 0;
switches[n_switches].validated = validated;
+ switches[n_switches].known = known;
switches[n_switches].ordering = 0;
n_switches++;
}
/* Handle an option DECODED that is unknown to the option-processing
- machinery, but may be known to specs. */
+ machinery. */
static bool
driver_unknown_option_callback (const struct cl_decoded_option *decoded)
{
- save_switch (decoded->canonical_option[0],
- decoded->canonical_option_num_elements - 1,
- &decoded->canonical_option[1], false);
-
- return false;
+ const char *opt = decoded->arg;
+ if (opt[1] == 'W' && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-'
+ && !(decoded->errors & CL_ERR_NEGATIVE))
+ {
+ /* Leave unknown -Wno-* options for the compiler proper, to be
+ diagnosed only if there are warnings. */
+ save_switch (decoded->canonical_option[0],
+ decoded->canonical_option_num_elements - 1,
+ &decoded->canonical_option[1], false, true);
+ return false;
+ }
+ if (decoded->opt_index == OPT_SPECIAL_unknown)
+ {
+ /* Give it a chance to define it a a spec file. */
+ save_switch (decoded->canonical_option[0],
+ decoded->canonical_option_num_elements - 1,
+ &decoded->canonical_option[1], false, false);
+ return false;
+ }
+ else
+ return true;
}
/* Handle an option DECODED that is not marked as CL_DRIVER.
options. */
const struct cl_option *option = &cl_options[decoded->opt_index];
- if (option->flags & CL_REJECT_DRIVER)
+ if (option->cl_reject_driver)
error ("unrecognized command line option %qs",
decoded->orig_option_with_args_text);
else
- driver_unknown_option_callback (decoded);
-}
-
-/* Note that an option (index OPT_INDEX, argument ARG, value VALUE)
- has been successfully handled with a handler for mask MASK. */
-
-static void
-driver_post_handling_callback (const struct cl_decoded_option *decoded ATTRIBUTE_UNUSED,
- unsigned int mask ATTRIBUTE_UNUSED)
-{
- /* Nothing to do here. */
+ save_switch (decoded->canonical_option[0],
+ decoded->canonical_option_num_elements - 1,
+ &decoded->canonical_option[1], false, true);
}
static const char *spec_lang = 0;
add_linker_option ("--target-help", 13);
break;
+ case OPT__no_sysroot_suffix:
case OPT_pass_exit_codes:
case OPT_print_search_dirs:
case OPT_print_file_name_:
case OPT_print_multi_directory:
case OPT_print_sysroot:
case OPT_print_multi_os_directory:
+ case OPT_print_multiarch:
case OPT_print_sysroot_headers_suffix:
case OPT_time:
case OPT_wrapper:
compare_debug_with_arg:
gcc_assert (decoded->canonical_option_num_elements == 1);
gcc_assert (arg != NULL);
- if (arg)
+ if (*arg)
compare_debug = 1;
else
compare_debug = -1;
compare_debug_opt = NULL;
else
compare_debug_opt = arg;
- save_switch (compare_debug_replacement_opt, 0, NULL, validated);
+ save_switch (compare_debug_replacement_opt, 0, NULL, validated, true);
return true;
case OPT_Wa_:
case OPT_L:
/* Similarly, canonicalize -L for linkers that may not accept
separate arguments. */
- save_switch (concat ("-L", arg, NULL), 0, NULL, validated);
+ save_switch (concat ("-L", arg, NULL), 0, NULL, validated, true);
+ return true;
+
+ case OPT_F:
+ /* Likewise -F. */
+ save_switch (concat ("-F", arg, NULL), 0, NULL, validated, true);
return true;
case OPT_save_temps:
user_specs_head = user;
user_specs_tail = user;
}
- do_save = false;
+ validated = true;
break;
case OPT__sysroot_:
save_temps_prefix = xstrdup (arg);
/* On some systems, ld cannot handle "-o" without a space. So
split the option from its argument. */
- save_switch ("-o", 1, &arg, validated);
+ save_switch ("-o", 1, &arg, validated, true);
return true;
case OPT_static_libgcc:
if (do_save)
save_switch (decoded->canonical_option[0],
decoded->canonical_option_num_elements - 1,
- &decoded->canonical_option[1], validated);
+ &decoded->canonical_option[1], validated, true);
return true;
}
{
handlers->unknown_option_callback = driver_unknown_option_callback;
handlers->wrong_lang_callback = driver_wrong_lang_callback;
- handlers->post_handling_callback = driver_post_handling_callback;
- handlers->num_handlers = 1;
+ handlers->num_handlers = 3;
handlers->handlers[0].handler = driver_handle_option;
handlers->handlers[0].mask = CL_DRIVER;
+ handlers->handlers[1].handler = common_handle_option;
+ handlers->handlers[1].mask = CL_COMMON;
+ handlers->handlers[2].handler = target_handle_option;
+ handlers->handlers[2].mask = CL_TARGET;
}
/* Create the vector `switches' and its contents.
{
const char *temp;
char *temp1;
- const char *tooldir_prefix;
+ char *tooldir_prefix, *tooldir_prefix2;
char *(*get_relative_prefix) (const char *, const char *,
const char *) = NULL;
struct cl_option_handlers handlers;
{
temp = gcc_exec_prefix + len - sizeof ("/lib/gcc/") + 1;
if (IS_DIR_SEPARATOR (*temp)
- && strncmp (temp + 1, "lib", 3) == 0
+ && filename_ncmp (temp + 1, "lib", 3) == 0
&& IS_DIR_SEPARATOR (temp[4])
- && strncmp (temp + 5, "gcc", 3) == 0)
+ && filename_ncmp (temp + 5, "gcc", 3) == 0)
len -= sizeof ("/lib/gcc/") - 1;
}
}
else
fname = xstrdup (arg);
-
+
if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
perror_with_name (fname);
else
}
gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix));
- tooldir_prefix = concat (tooldir_base_prefix, spec_machine,
- dir_separator_str, NULL);
+ tooldir_prefix2 = concat (tooldir_base_prefix, spec_machine,
+ dir_separator_str, 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);
+ spec_version, dir_separator_str, tooldir_prefix2, NULL);
+ free (tooldir_prefix2);
add_prefix (&exec_prefixes,
concat (tooldir_prefix, "bin", dir_separator_str, NULL),
add_prefix (&startfile_prefixes,
concat (tooldir_prefix, "lib", dir_separator_str, NULL),
"BINUTILS", PREFIX_PRIORITY_LAST, 0, 1);
+ free (tooldir_prefix);
#if defined(TARGET_SYSTEM_ROOT_RELOCATABLE) && !defined(VMS)
/* If the normal TARGET_SYSTEM_ROOT is inside of $exec_prefix,
if (n_infiles == last_language_n_infiles && spec_lang != 0)
warning (0, "%<-x %s%> after last input file has no effect", spec_lang);
+ /* Synthesize -fcompare-debug flag from the GCC_COMPARE_DEBUG
+ environment variable. */
if (compare_debug == 2 || compare_debug == 3)
{
- alloc_switch ();
- 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++;
+ const char *opt = concat ("-fcompare-debug=", compare_debug_opt, NULL);
+ save_switch (opt, 0, NULL, false, true);
compare_debug = 1;
}
int i;
char *buf = xstrdup (wrapper);
char *p = buf;
- unsigned int old_length = VEC_length (const_char_p, argbuf);
+ unsigned int old_length = argbuf.length ();
do
{
}
while ((p = strchr (p, ',')) != NULL);
- VEC_safe_grow (const_char_p, heap, argbuf, old_length + n);
- memmove (VEC_address (const_char_p, argbuf) + n,
- VEC_address (const_char_p, argbuf),
+ argbuf.safe_grow (old_length + n);
+ memmove (argbuf.address () + n,
+ argbuf.address (),
old_length * sizeof (const_char_p));
i = 0;
*p = 0;
p++;
}
- VEC_replace (const_char_p, argbuf, i, p);
+ argbuf[i] = p;
i++;
}
while ((p = strchr (p, ',')) != NULL);
If -pipe, this forces out the last command if it ended in `|'. */
if (value == 0)
{
- if (VEC_length (const_char_p, argbuf) > 0
- && !strcmp (VEC_last (const_char_p, argbuf), "|"))
- VEC_pop (const_char_p, argbuf);
+ if (argbuf.length () > 0
+ && !strcmp (argbuf.last (), "|"))
+ argbuf.pop ();
set_collect_gcc_options ();
- if (VEC_length (const_char_p, argbuf) > 0)
+ if (argbuf.length () > 0)
value = execute ();
}
if ((switches[i].live_cond & SWITCH_IGNORE))
switches[i].live_cond |= SWITCH_IGNORE_PERMANENTLY;
- if (VEC_length (const_char_p, argbuf) > 0)
+ if (argbuf.length () > 0)
{
const char **argbuf_copy;
struct cl_decoded_option *decoded_options;
/* Create a copy of argbuf with a dummy argv[0] entry for
decode_cmdline_options_to_array. */
argbuf_copy = XNEWVEC (const char *,
- VEC_length (const_char_p, argbuf) + 1);
+ argbuf.length () + 1);
argbuf_copy[0] = "";
- memcpy (argbuf_copy + 1, VEC_address (const_char_p, argbuf),
- VEC_length (const_char_p, argbuf) * sizeof (const char *));
+ memcpy (argbuf_copy + 1, argbuf.address (),
+ argbuf.length () * sizeof (const char *));
- decode_cmdline_options_to_array (VEC_length (const_char_p, argbuf) + 1,
+ decode_cmdline_options_to_array (argbuf.length () + 1,
argbuf_copy,
CL_DRIVER, &decoded_options,
&decoded_options_count);
+ free (argbuf_copy);
set_option_handlers (&handlers);
save_switch (decoded_options[j].canonical_option[0],
(decoded_options[j].canonical_option_num_elements
- 1),
- &decoded_options[j].canonical_option[1], false);
+ &decoded_options[j].canonical_option[1], false, true);
break;
default:
/* Process each member of VEC as a spec. */
static void
-do_specs_vec (VEC(char_p,heap) *vec)
+do_specs_vec (vec<char_p> vec)
{
unsigned ix;
char *opt;
- FOR_EACH_VEC_ELT (char_p, vec, ix, opt)
+ FOR_EACH_VEC_ELT (vec, ix, opt)
{
do_spec_1 (opt, 1, NULL);
/* Make each accumulated option a separate argument. */
int i;
int value;
+ /* If it's an empty string argument to a switch, keep it as is. */
+ if (inswitch && !*p)
+ arg_going = 1;
+
while ((c = *p++))
/* If substituting a switch, treat all chars like letters.
Otherwise, NL, SPC, TAB and % are special. */
case '\n':
end_going_arg ();
- if (VEC_length (const_char_p, argbuf) > 0
- && !strcmp (VEC_last (const_char_p, argbuf), "|"))
+ if (argbuf.length () > 0
+ && !strcmp (argbuf.last (), "|"))
{
/* A `|' before the newline means use a pipe here,
but only if -pipe was specified.
break;
}
else
- VEC_pop (const_char_p, argbuf);
+ argbuf.pop ();
}
set_collect_gcc_options ();
- if (VEC_length (const_char_p, argbuf) > 0)
+ if (argbuf.length () > 0)
{
value = execute ();
if (value)
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);
+ temp_filename = save_string (tmp, save_temps_length
+ + suffix_length);
obstack_grow (&obstack, temp_filename,
temp_filename_length);
arg_going = 1;
tmp[basename_length + suffix_length] = '\0';
temp_filename = tmp;
- if (strcmp (temp_filename, gcc_input_filename) != 0)
+ if (filename_cmp (temp_filename, gcc_input_filename) != 0)
{
#ifndef HOST_LACKS_INODE_NUMBERS
struct stat st_temp;
/* Just compare canonical pathnames. */
char* input_realname = lrealpath (gcc_input_filename);
char* temp_realname = lrealpath (temp_filename);
- bool files_differ = strcmp (input_realname, temp_realname);
+ bool files_differ = filename_cmp (input_realname, temp_realname);
free (input_realname);
free (temp_realname);
if (files_differ)
t->filename_length = temp_filename_length;
}
- if (saved_suffix)
- free (saved_suffix);
+ free (saved_suffix);
obstack_grow (&obstack, t->filename, t->filename_length);
delete_this_arg = 1;
do_spec_1 (" ", 0, NULL);
}
+ if (multiarch_dir)
+ {
+ do_spec_1 ("-imultiarch", 1, NULL);
+ /* Make this a separate argument. */
+ do_spec_1 (" ", 0, NULL);
+ do_spec_1 (multiarch_dir, 1, NULL);
+ do_spec_1 (" ", 0, NULL);
+ }
+
if (gcc_exec_prefix)
{
do_spec_1 ("-iprefix", 1, NULL);
case 'W':
{
- unsigned int cur_index = VEC_length (const_char_p, argbuf);
+ unsigned int cur_index = argbuf.length ();
/* Handle the {...} following the %W. */
if (*p != '{')
fatal_error ("spec %qs has invalid %<%%W%c%>", spec, *p);
end_going_arg ();
/* If any args were output, mark the last one for deletion
on failure. */
- if (VEC_length (const_char_p, argbuf) != cur_index)
- record_temp_file (VEC_last (const_char_p, argbuf), 0, 1);
+ if (argbuf.length () != cur_index)
+ record_temp_file (argbuf.last (), 0, 1);
break;
}
string = save_string (p1 + 1, p - p1 - 2);
/* See if we already recorded this option. */
- FOR_EACH_VEC_ELT (char_p, linker_options, ix, opt)
+ FOR_EACH_VEC_ELT (linker_options, ix, opt)
if (! strcmp (string, opt))
{
free (string);
/* This option is new; add it. */
add_linker_option (string, strlen (string));
+ free (string);
}
break;
return value;
break;
+ case 'M':
+ if (multilib_os_dir == NULL)
+ obstack_1grow (&obstack, '.');
+ else
+ obstack_grow (&obstack, multilib_os_dir,
+ strlen (multilib_os_dir));
+ break;
+
case 'G':
value = do_spec_1 (libgcc_spec, 0, NULL);
if (value != 0)
&& (have_wildcard || switches[i].part1[len] == '\0'))
{
switches[i].live_cond |= switch_option;
- switches[i].validated = 1;
+ /* User switch be validated from validate_all_switches.
+ when the definition is seen from the spec file.
+ If not defined anywhere, will be rejected. */
+ if (switches[i].known)
+ switches[i].validated = true;
}
p += len;
case '*':
if (soft_matched_part)
{
- do_spec_1 (soft_matched_part, 1, NULL);
+ if (soft_matched_part[0])
+ do_spec_1 (soft_matched_part, 1, NULL);
do_spec_1 (" ", 0, NULL);
}
else
/* Process a string found as the value of a spec given by name.
This feature allows individual machine descriptions
- to add and use their own specs.
- %[...] modifies -D options the way %P does;
- %(...) uses the spec unmodified. */
- case '[':
- warning (0, "use of obsolete %%[ operator in specs");
+ to add and use their own specs. */
case '(':
{
const char *name = p;
/* The string after the S/P is the name of a spec that is to be
processed. */
- while (*p && *p != ')' && *p != ']')
+ while (*p && *p != ')')
p++;
/* See if it's in the list. */
{
name = *(sl->ptr_spec);
#ifdef DEBUG_SPECS
- fnotice (stderr, "Processing spec %c%s%c, which is '%s'\n",
- c, sl->name, (c == '(') ? ')' : ']', name);
+ fnotice (stderr, "Processing spec (%s), which is '%s'\n",
+ sl->name, name);
#endif
break;
}
if (sl)
{
- if (c == '(')
- {
- value = do_spec_1 (name, 0, NULL);
- if (value != 0)
- return value;
- }
- else
- {
- char *x = (char *) alloca (strlen (name) * 2 + 1);
- char *buf = x;
- const char *y = name;
- int flag = 0;
-
- /* Copy all of NAME into BUF, but put __ after
- every -D and at the end of each arg. */
- while (1)
- {
- if (! strncmp (y, "-D", 2))
- {
- *x++ = '-';
- *x++ = 'D';
- *x++ = '_';
- *x++ = '_';
- y += 2;
- flag = 1;
- continue;
- }
- else if (flag
- && (*y == ' ' || *y == '\t' || *y == '='
- || *y == '}' || *y == 0))
- {
- *x++ = '_';
- *x++ = '_';
- flag = 0;
- }
- if (*y == 0)
- break;
- else
- *x++ = *y++;
- }
- *x = 0;
-
- value = do_spec_1 (buf, 0, NULL);
- if (value != 0)
- return value;
- }
+ value = do_spec_1 (name, 0, NULL);
+ if (value != 0)
+ return value;
}
- /* Discard the closing paren or bracket. */
+ /* Discard the closing paren. */
if (*p)
p++;
}
const char *funcval;
/* Saved spec processing context. */
- VEC(const_char_p,heap) *save_argbuf;
+ vec<const_char_p> save_argbuf;
int save_arg_going;
int save_delete_this_arg;
int save_this_is_linker_script;
const char *save_suffix_subst;
+ int save_growing_size;
+ void *save_growing_value;
sf = lookup_spec_function (func);
if (sf == NULL)
save_input_from_pipe = input_from_pipe;
save_suffix_subst = suffix_subst;
+ /* If we have some object growing now, finalize it so the args and function
+ eval proceed from a cleared context. This is needed to prevent the first
+ constructed arg from mistakenly including the growing value. We'll push
+ this value back on the obstack once the function evaluation is done, to
+ restore a consistent processing context for our caller. This is fine as
+ the address of growing objects isn't guaranteed to remain stable until
+ they are finalized, and we expect this situation to be rare enough for
+ the extra copy not to be an issue. */
+ save_growing_size = obstack_object_size (&obstack);
+ if (save_growing_size > 0)
+ save_growing_value = obstack_finish (&obstack);
+
/* Create a new spec processing context, and build the function
arguments. */
/* argbuf_index is an index for the next argument to be inserted, and
so contains the count of the args already inserted. */
- funcval = (*sf->func) (VEC_length (const_char_p, argbuf),
- VEC_address (const_char_p, argbuf));
+ funcval = (*sf->func) (argbuf.length (),
+ argbuf.address ());
/* Pop the spec processing context. */
- VEC_free (const_char_p, heap, argbuf);
+ argbuf.release ();
argbuf = save_argbuf;
arg_going = save_arg_going;
input_from_pipe = save_input_from_pipe;
suffix_subst = save_suffix_subst;
+ if (save_growing_size > 0)
+ obstack_grow (&obstack, save_growing_value, save_growing_size);
+
return funcval;
}
&& check_live_switch (i, plen))
return true;
+ /* Check if a switch with separated form matching the atom.
+ We check -D and -U switches. */
+ else if (switches[i].args != 0)
+ {
+ if ((*switches[i].part1 == 'D' || *switches[i].part1 == 'U')
+ && *switches[i].part1 == atom[0])
+ {
+ if (!strncmp (switches[i].args[0], &atom[1], len - 1)
+ && (starred || (switches[i].part1[1] == '\0'
+ && switches[i].args[0][len - 1] == '\0'))
+ && check_live_switch (i, (starred ? 1 : -1)))
+ return true;
+ }
+ }
+
return false;
}
on the command line. PREFIX_LENGTH is the length of XXX in an {XXX*}
spec, or -1 if either exact match or %* is used.
- A -O switch is obsoleted by a later -O switch. A -f, -m, or -W switch
+ A -O switch is obsoleted by a later -O switch. A -f, -g, -m, or -W switch
whose value does not begin with "no-" is obsoleted by the same value
with the "no-", similarly for a switch with the "no-" prefix. */
for (i = switchnum + 1; i < n_switches; i++)
if (switches[i].part1[0] == 'O')
{
- switches[switchnum].validated = 1;
+ switches[switchnum].validated = true;
switches[switchnum].live_cond = SWITCH_FALSE;
return 0;
}
break;
- case 'W': case 'f': case 'm':
+ case 'W': case 'f': case 'm': case 'g':
if (! strncmp (name + 1, "no-", 3))
{
/* We have Xno-YYY, search for XYYY. */
if (switches[i].part1[0] == name[0]
&& ! strcmp (&switches[i].part1[1], &name[4]))
{
- switches[switchnum].validated = 1;
+ /* --specs are validated with the validate_switches mechanism. */
+ if (switches[switchnum].known)
+ switches[switchnum].validated = true;
switches[switchnum].live_cond = SWITCH_FALSE;
return 0;
}
&& switches[i].part1[3] == '-'
&& !strcmp (&switches[i].part1[4], &name[1]))
{
- switches[switchnum].validated = 1;
+ /* --specs are validated with the validate_switches mechanism. */
+ if (switches[switchnum].known)
+ switches[switchnum].validated = true;
switches[switchnum].live_cond = SWITCH_FALSE;
return 0;
}
}
do_spec_1 (" ", 0, NULL);
- switches[switchnum].validated = 1;
+ switches[switchnum].validated = true;
}
\f
/* Search for a file named NAME trying various prefixes including the
if (linker
&& IS_DIR_SEPARATOR (path[0])
&& ((cp - path == 6
- && strncmp (path + 1, "lib", 3) == 0)
+ && filename_ncmp (path + 1, "lib", 3) == 0)
|| (cp - path == 10
- && strncmp (path + 1, "usr", 3) == 0
+ && filename_ncmp (path + 1, "usr", 3) == 0
&& IS_DIR_SEPARATOR (path[4])
- && strncmp (path + 5, "lib", 3) == 0)))
+ && filename_ncmp (path + 5, "lib", 3) == 0)))
return 0;
return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
struct cl_decoded_option *decoded_options;
unsigned int decoded_options_count;
- /* 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;
if (argv != old_argv)
at_file_supplied = true;
- global_options = global_options_init;
+ /* Register the language-independent parameters. */
+ global_init_params ();
+ finish_params ();
+
+ init_options_struct (&global_options, &global_options_set);
decode_cmdline_options_to_array (argc, CONST_CAST2 (const char **, char **,
argv),
CL_DRIVER,
&decoded_options, &decoded_options_count);
-#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 ();
diagnostic_initialize (global_dc, 0);
+
+#ifdef GCC_DRIVER_HOST_INITIALIZATION
+ /* Perform host dependent initialization when needed. */
+ GCC_DRIVER_HOST_INITIALIZATION;
+#endif
+
if (atexit (delete_temp_files) != 0)
fatal_error ("atexit failed");
signal (SIGCHLD, SIG_DFL);
#endif
+ /* Parsing and gimplification sometimes need quite large stack.
+ Increase stack size limits if possible. */
+ stack_limit_increase (64 * 1024 * 1024);
+
/* Allocate the argument vector. */
alloc_args ();
obstack_1grow (&multilib_obstack, 0);
multilib_exclusions = XOBFINISH (&multilib_obstack, const char *);
+ q = multilib_reuse_raw;
+ while ((p = *q++) != (char *) 0)
+ obstack_grow (&multilib_obstack, p, strlen (p));
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_reuse = XOBFINISH (&multilib_obstack, const char *);
+
need_space = FALSE;
for (i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
{
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);
+ read_specs (specs_file, true, false);
else
init_spec ();
strcat (specs_file, just_machine_suffix);
strcat (specs_file, "specs");
if (access (specs_file, R_OK) == 0)
- read_specs (specs_file, TRUE);
+ read_specs (specs_file, true, false);
/* Process any configure-time defaults specified for the command line
options, via OPTION_DEFAULT_SPECS. */
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;
- n_switches_alloc_debug_check[1] = n_switches_alloc;
- switches_debug_check[1] = XDUPVEC (struct switchstr, switches,
- n_switches_alloc);
-
- do_self_spec ("%:compare-debug-self-opt()");
- n_switches_debug_check[0] = n_switches;
- n_switches_alloc_debug_check[0] = n_switches_alloc;
- switches_debug_check[0] = switches;
-
- n_switches = n_switches_debug_check[1];
- n_switches_alloc = n_switches_alloc_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;
- n_switches_alloc_debug_check[1] = n_switches_alloc;
- switches_debug_check[1] = switches;
- compare_debug = -compare_debug;
- n_switches = n_switches_debug_check[0];
- n_switches_alloc = 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')
/* Process sysroot_suffix_spec. */
if (*sysroot_suffix_spec != 0
+ && !no_sysroot_suffix
&& do_spec_2 (sysroot_suffix_spec) == 0)
{
- if (VEC_length (const_char_p, argbuf) > 1)
+ if (argbuf.length () > 1)
error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC");
- else if (VEC_length (const_char_p, argbuf) == 1)
- target_sysroot_suffix = xstrdup (VEC_last (const_char_p, argbuf));
+ else if (argbuf.length () == 1)
+ target_sysroot_suffix = xstrdup (argbuf.last ());
}
#ifdef HAVE_LD_SYSROOT
{
obstack_grow (&obstack, "%(sysroot_spec) ", strlen ("%(sysroot_spec) "));
obstack_grow0 (&obstack, link_spec, strlen (link_spec));
- set_spec ("link", XOBFINISH (&obstack, const char *));
+ set_spec ("link", XOBFINISH (&obstack, const char *), false);
}
#endif
/* Process sysroot_hdrs_suffix_spec. */
if (*sysroot_hdrs_suffix_spec != 0
+ && !no_sysroot_suffix
&& do_spec_2 (sysroot_hdrs_suffix_spec) == 0)
{
- if (VEC_length (const_char_p, argbuf) > 1)
+ if (argbuf.length () > 1)
error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC");
- else if (VEC_length (const_char_p, argbuf) == 1)
- target_sysroot_hdrs_suffix = xstrdup (VEC_last (const_char_p, argbuf));
+ else if (argbuf.length () == 1)
+ target_sysroot_hdrs_suffix = xstrdup (argbuf.last ());
}
/* Look for startfiles in the standard places. */
{
const char *arg;
int ndx;
- FOR_EACH_VEC_ELT (const_char_p, argbuf, ndx, arg)
+ FOR_EACH_VEC_ELT (argbuf, ndx, arg)
add_sysrooted_prefix (&startfile_prefixes, arg, "BINUTILS",
PREFIX_PRIORITY_LAST, 0, 1);
}
{
char *filename = find_a_file (&startfile_prefixes, uptr->filename,
R_OK, true);
- read_specs (filename ? filename : uptr->filename, FALSE);
+ read_specs (filename ? filename : uptr->filename, false, true);
}
+ /* Process any user self specs. */
+ {
+ struct spec_list *sl;
+ for (sl = specs; sl; sl = sl->next)
+ if (sl->name_len == sizeof "self_spec" - 1
+ && !strcmp (sl->name, "self_spec"))
+ do_self_spec (*sl->ptr_spec);
+ }
+
+ if (compare_debug)
+ {
+ enum save_temps save;
+
+ if (!compare_debug_second)
+ {
+ n_switches_debug_check[1] = n_switches;
+ n_switches_alloc_debug_check[1] = n_switches_alloc;
+ switches_debug_check[1] = XDUPVEC (struct switchstr, switches,
+ n_switches_alloc);
+
+ do_self_spec ("%:compare-debug-self-opt()");
+ n_switches_debug_check[0] = n_switches;
+ n_switches_alloc_debug_check[0] = n_switches_alloc;
+ switches_debug_check[0] = switches;
+
+ n_switches = n_switches_debug_check[1];
+ n_switches_alloc = n_switches_alloc_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;
+ n_switches_alloc_debug_check[1] = n_switches_alloc;
+ switches_debug_check[1] = switches;
+ compare_debug = -compare_debug;
+ n_switches = n_switches_debug_check[0];
+ n_switches_alloc = n_switches_debug_check[0];
+ switches = switches_debug_check[0];
+ }
+ }
+
+
/* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake. */
if (gcc_exec_prefix)
gcc_exec_prefix = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
/* Set up to remember the pathname of the lto wrapper. */
- lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
+ if (have_c)
+ lto_wrapper_file = NULL;
+ else
+ lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper",
+ X_OK, false);
if (lto_wrapper_file)
{
+ lto_wrapper_file = convert_white_space (lto_wrapper_file);
lto_wrapper_spec = lto_wrapper_file;
obstack_init (&collect_obstack);
obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
xputenv (XOBFINISH (&collect_obstack, char *));
}
- /* Warn about any switches that no pass was interested in. */
+ /* Reject 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 command line option %<-%s%>", switches[i].part1);
/* Obey some of the options. */
return (0);
}
+ if (print_multiarch)
+ {
+ if (multiarch_dir == NULL)
+ printf ("\n");
+ else
+ printf ("%s\n", multiarch_dir);
+ return (0);
+ }
+
if (print_sysroot)
{
if (target_system_root)
{
printf (_("%s %s%s\n"), progname, pkgversion_string,
version_string);
- printf ("Copyright %s 2011 Free Software Foundation, Inc.\n",
+ printf ("Copyright %s 2013 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 (compare_debug)
{
- if (debug_check_temp_file[0])
- free (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]);
+ free (debug_check_temp_file[1]);
debug_check_temp_file[1] = NULL;
}
}
gcc_assert (debug_check_temp_file[1]
- && strcmp (debug_check_temp_file[0],
- debug_check_temp_file[1]));
+ && filename_cmp (debug_check_temp_file[0],
+ debug_check_temp_file[1]));
if (verbose_flag)
inform (0, "comparing final insns dumps");
if (compare_debug)
{
- if (debug_check_temp_file[0])
- free (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]);
+ free (debug_check_temp_file[1]);
debug_check_temp_file[1] = NULL;
}
}
if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
{
int tmp = execution_count;
-#ifdef HAVE_LTO_PLUGIN
- const char *fno_use_linker_plugin = "fno-use-linker-plugin";
+
+ if (! have_c)
+ {
+#if HAVE_LTO_PLUGIN > 0
+#if HAVE_LTO_PLUGIN == 2
+ const char *fno_use_linker_plugin = "fno-use-linker-plugin";
#else
- const char *fuse_linker_plugin = "fuse-linker-plugin";
+ const char *fuse_linker_plugin = "fuse-linker-plugin";
+#endif
#endif
- /* 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, false);
- if (s == NULL)
- linker_name_spec = "ld";
- }
+ /* 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, false);
+ if (s == NULL)
+ linker_name_spec = "ld";
+ }
-#ifdef HAVE_LTO_PLUGIN
- if (!switch_matches (fno_use_linker_plugin,
- fno_use_linker_plugin + strlen (fno_use_linker_plugin), 0))
+#if HAVE_LTO_PLUGIN > 0
+#if HAVE_LTO_PLUGIN == 2
+ if (!switch_matches (fno_use_linker_plugin,
+ fno_use_linker_plugin
+ + strlen (fno_use_linker_plugin), 0))
#else
- if (switch_matches (fuse_linker_plugin,
- fuse_linker_plugin + strlen (fuse_linker_plugin), 0))
+ if (switch_matches (fuse_linker_plugin,
+ fuse_linker_plugin
+ + strlen (fuse_linker_plugin), 0))
#endif
- {
- linker_plugin_file_spec = find_a_file (&exec_prefixes,
- LTOPLUGINSONAME, R_OK,
- false);
- if (!linker_plugin_file_spec)
- fatal_error ("-fuse-linker-plugin, but " LTOPLUGINSONAME " not found");
+ {
+ char *temp_spec = find_a_file (&exec_prefixes,
+ LTOPLUGINSONAME, R_OK,
+ false);
+ if (!temp_spec)
+ fatal_error ("-fuse-linker-plugin, but %s not found",
+ LTOPLUGINSONAME);
+ linker_plugin_file_spec = convert_white_space (temp_spec);
+ }
+#endif
+ lto_gcc_spec = argv[0];
}
- lto_gcc_spec = argv[0];
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
}
\f
static inline void
-validate_switches_from_spec (const char *spec)
+validate_switches_from_spec (const char *spec, bool user)
{
const char *p = spec;
char c;
while ((c = *p++))
if (c == '%' && (*p == '{' || *p == '<' || (*p == 'W' && *++p == '{')))
/* We have a switch spec. */
- p = validate_switches (p + 1);
+ p = validate_switches (p + 1, user);
}
static void
struct spec_list *spec;
for (comp = compilers; comp->spec; comp++)
- validate_switches_from_spec (comp->spec);
+ validate_switches_from_spec (comp->spec, false);
/* Look through the linked list of specs read from the specs file. */
for (spec = specs; spec; spec = spec->next)
- validate_switches_from_spec (*spec->ptr_spec);
+ validate_switches_from_spec (*spec->ptr_spec, spec->user_p);
- validate_switches_from_spec (link_command_spec);
+ validate_switches_from_spec (link_command_spec, false);
}
/* Look at the switch-name that comes after START
and mark as valid all supplied switches that match it. */
static const char *
-validate_switches (const char *start)
+validate_switches (const char *start, bool user_spec)
{
const char *p = start;
const char *atom;
/* Mark all matching switches as valid. */
for (i = 0; i < n_switches; i++)
if (!strncmp (switches[i].part1, atom, len)
- && (starred || switches[i].part1[len] == 0))
- switches[i].validated = 1;
+ && (starred || switches[i].part1[len] == '\0')
+ && (switches[i].known || user_spec))
+ switches[i].validated = true;
}
if (*p) p++;
{
p++;
if (*p == '{' || *p == '<')
- p = validate_switches (p+1);
+ p = validate_switches (p+1, user_spec);
else if (p[0] == 'W' && p[1] == '{')
- p = validate_switches (p+2);
+ p = validate_switches (p+2, user_spec);
}
else
p++;
options are present, then we will ignore this completely. Passing
that, gcc will consider each multilib_select in turn using the same
rules for matching the options. If a match is found, that subdirectory
- will be used. */
+ will be used.
+ A subdirectory name is optionally followed by a colon and the corresponding
+ multiarch name. */
static void
set_multilib_dir (void)
first = 1;
p = multilib_select;
+
+ /* Append multilib reuse rules if any. With those rules, we can reuse
+ one multilib for certain different options sets. */
+ if (strlen (multilib_reuse) > 0)
+ p = concat (p, multilib_reuse, NULL);
+
while (*p != '\0')
{
/* Ignore newlines. */
if (*p == '\0')
{
invalid_select:
- fatal_error ("multilib select %qs is invalid",
- multilib_select);
+ fatal_error ("multilib select %qs %qs is invalid",
+ multilib_select, multilib_reuse);
}
++p;
}
q++;
if (q < end)
{
- 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;
+ const char *q2 = q + 1, *ml_end = end;
+ char *new_multilib_os_dir;
+
+ while (q2 < end && *q2 != ':')
+ q2++;
+ if (*q2 == ':')
+ ml_end = q2;
+ new_multilib_os_dir = XNEWVEC (char, ml_end - q);
+ memcpy (new_multilib_os_dir, q + 1, ml_end - q - 1);
+ new_multilib_os_dir[ml_end - q - 1] = '\0';
+ multilib_os_dir = *new_multilib_os_dir ? new_multilib_os_dir : ".";
+
+ if (q2 < end && *q2 == ':')
+ {
+ char *new_multiarch_dir = XNEWVEC (char, end - q2);
+ memcpy (new_multiarch_dir, q2 + 1, end - q2 - 1);
+ new_multiarch_dir[end - q2 - 1] = '\0';
+ multiarch_dir = new_multiarch_dir;
+ }
break;
}
}
}
/* When --disable-multilib was used but target defines
- MULTILIB_OSDIRNAMES, entries starting with .: are there just
- to find multilib_os_dir, so skip them from output. */
- if (this_path[0] == '.' && this_path[1] == ':')
+ MULTILIB_OSDIRNAMES, entries starting with .: (and not starting
+ with .:: for multiarch configurations) are there just to find
+ multilib_os_dir, so skip them from output. */
+ if (this_path[0] == '.' && this_path[1] == ':' && this_path[2] != ':')
skip = 1;
/* Check for matches with the multilib_exclusions. We don't bother
/* If this is a duplicate, skip it. */
skip = (last_path != 0
&& (unsigned int) (p - this_path) == last_path_len
- && ! strncmp (last_path, this_path, last_path_len));
+ && ! filename_ncmp (last_path, this_path, last_path_len));
last_path = this_path;
last_path_len = p - this_path;
for (i = 0; i < n_infiles; i++)
{
- if (outfiles[i] && !strcmp (outfiles[i], argv[0]))
+ if (outfiles[i] && !filename_cmp (outfiles[i], argv[0]))
outfiles[i] = xstrdup (argv[1]);
}
return NULL;
for (i = 0; i < n_infiles; i++)
{
- if (outfiles[i] && !strcmp (outfiles[i], argv[0]))
+ if (outfiles[i] && !filename_cmp (outfiles[i], argv[0]))
outfiles[i] = NULL;
}
return NULL;
abort ();
file = find_a_file (&startfile_prefixes, argv[0], R_OK, true);
- read_specs (file ? file : argv[0], FALSE);
+ read_specs (file ? file : argv[0], false, false);
return NULL;
}
/* %:find-file spec function. This function replaces its argument by
- the file found thru find_file, that is the -print-file-name gcc
+ the file found through find_file, that is the -print-file-name gcc
program option. */
static const char *
find_file_spec_function (int argc, const char **argv)
/* %:find-plugindir spec function. This function replaces its argument
- by the -iplugindir=<dir> option. `dir' is found thru find_file, that
+ by the -iplugindir=<dir> option. `dir' is found through find_file, that
is the -print-file-name gcc program option. */
static const char *
find_plugindir_spec_function (int argc, const char **argv ATTRIBUTE_UNUSED)
return NULL;
}
-/* Compute a timestamp to initialize flag_random_seed. */
+/* Get a random number for -frandom-seed */
-static unsigned
-get_local_tick (void)
+static unsigned HOST_WIDE_INT
+get_random_number (void)
{
- unsigned ret = 0;
+ unsigned HOST_WIDE_INT ret = 0;
+ int fd;
+
+ fd = open ("/dev/urandom", O_RDONLY);
+ if (fd >= 0)
+ {
+ read (fd, &ret, sizeof (HOST_WIDE_INT));
+ close (fd);
+ if (ret)
+ return ret;
+ }
/* Get some more or less random data. */
#ifdef HAVE_GETTIMEOFDAY
}
#endif
- return ret;
+ return ret ^ getpid();
}
/* %:compare-debug-dump-opt spec function. Save the last argument,
compare_debug_dump_opt_spec_function (int arg,
const char **argv ATTRIBUTE_UNUSED)
{
- const char *ret;
+ char *ret;
char *name;
int which;
static char random_seed[HOST_BITS_PER_WIDE_INT / 4 + 3];
do_spec_2 ("%{fdump-final-insns=*:%*}");
do_spec_1 (" ", 0, NULL);
- if (VEC_length (const_char_p, argbuf) > 0
- && strcmp (argv[VEC_length (const_char_p, argbuf) - 1], "."))
+ if (argbuf.length () > 0
+ && strcmp (argv[argbuf.length () - 1], "."))
{
if (!compare_debug)
return NULL;
- name = xstrdup (argv[VEC_length (const_char_p, argbuf) - 1]);
+ name = xstrdup (argv[argbuf.length () - 1]);
ret = NULL;
}
else
{
const char *ext = NULL;
- if (VEC_length (const_char_p, argbuf) > 0)
+ if (argbuf.length () > 0)
{
do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}");
ext = ".gkd";
do_spec_1 (" ", 0, NULL);
- gcc_assert (VEC_length (const_char_p, argbuf) > 0);
+ gcc_assert (argbuf.length () > 0);
- name = concat (VEC_last (const_char_p, argbuf), ext, NULL);
+ name = concat (argbuf.last (), ext, NULL);
ret = concat ("-fdump-final-insns=", name, NULL);
}
if (!which)
{
- unsigned HOST_WIDE_INT value = get_local_tick () ^ getpid ();
+ unsigned HOST_WIDE_INT value = get_random_number ();
sprintf (random_seed, HOST_WIDE_INT_PRINT_HEX, value);
}
if (*random_seed)
- ret = concat ("%{!frandom-seed=*:-frandom-seed=", random_seed, "} ",
- ret, NULL);
+ {
+ char *tmp = ret;
+ ret = concat ("%{!frandom-seed=*:-frandom-seed=", random_seed, "} ",
+ ret, NULL);
+ free (tmp);
+ }
if (which)
*random_seed = 0;
do_spec_2 ("%{c|S:%{o*:%*}}");
do_spec_1 (" ", 0, NULL);
- if (VEC_length (const_char_p, argbuf) > 0)
+ if (argbuf.length () > 0)
debug_auxbase_opt = concat ("-auxbase-strip ",
- VEC_last (const_char_p, argbuf),
+ argbuf.last (),
NULL);
else
debug_auxbase_opt = NULL;
}
return prepended;
}
+
+/* %:replace-extension spec function. Replaces the extension of the
+ first argument with the second argument. */
+
+const char *
+replace_extension_spec_func (int argc, const char **argv)
+{
+ char *name;
+ char *p;
+ char *result;
+ int i;
+
+ if (argc != 2)
+ fatal_error ("too few arguments to %%:replace-extension");
+
+ name = xstrdup (argv[0]);
+
+ for (i = strlen(name) - 1; i >= 0; i--)
+ if (IS_DIR_SEPARATOR (name[i]))
+ break;
+
+ p = strrchr (name + i + 1, '.');
+ if (p != NULL)
+ *p = '\0';
+
+ result = concat (name, argv[1], NULL);
+
+ free (name);
+ return result;
+}
+
+/* Insert backslash before spaces in ORIG (usually a file path), to
+ avoid being broken by spec parser.
+
+ This function is needed as do_spec_1 treats white space (' ' and '\t')
+ as the end of an argument. But in case of -plugin /usr/gcc install/xxx.so,
+ the file name should be treated as a single argument rather than being
+ broken into multiple. Solution is to insert '\\' before the space in a
+ file name.
+
+ This function converts and only converts all occurrence of ' '
+ to '\\' + ' ' and '\t' to '\\' + '\t'. For example:
+ "a b" -> "a\\ b"
+ "a b" -> "a\\ \\ b"
+ "a\tb" -> "a\\\tb"
+ "a\\ b" -> "a\\\\ b"
+
+ orig: input null-terminating string that was allocated by xalloc. The
+ memory it points to might be freed in this function. Behavior undefined
+ if ORIG wasn't xalloced or was freed already at entry.
+
+ Return: ORIG if no conversion needed. Otherwise a newly allocated string
+ that was converted from ORIG. */
+
+static char *
+convert_white_space (char *orig)
+{
+ int len, number_of_space = 0;
+
+ for (len = 0; orig[len]; len++)
+ if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
+
+ if (number_of_space)
+ {
+ char *new_spec = (char *) xmalloc (len + number_of_space + 1);
+ int j, k;
+ for (j = 0, k = 0; j <= len; j++, k++)
+ {
+ if (orig[j] == ' ' || orig[j] == '\t')
+ new_spec[k++] = '\\';
+ new_spec[k] = orig[j];
+ }
+ free (orig);
+ return new_spec;
+ }
+ else
+ return orig;
+}