X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fgcc.c;h=939dcc8735fc0a959e4299cd7297efddf943c4dc;hp=54da6675bed330eb9119debfef3298b0e808a801;hb=f4a24f32103062b2f0906eb10c91ec98b61bdd2e;hpb=9de1a4d71189958babeb0463176b732f74daa792 diff --git a/gcc/gcc.c b/gcc/gcc.c index 54da6675bed..939dcc8735f 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -1,7 +1,7 @@ /* 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 + 2010, 2011, 2012 Free Software Foundation, Inc. This file is part of GCC. @@ -30,72 +30,22 @@ CC recognizes how to compile each input file by suffixes in the file names. Once it knows which kind of compilation to perform, the procedure for compilation is specified by a string called a "spec". */ -/* A Short Introduction to Adding a Command-Line Option. - - Before adding a command-line option, consider if it is really - necessary. Each additional command-line option adds complexity and - is difficult to remove in subsequent versions. - - In the following, consider adding the command-line argument - `--bar'. - - 1. Each command-line option is specified in the specs file. The - notation is described below in the comment entitled "The Specs - Language". Read it. - - 2. In this file, add an entry to "option_map" equating the long - `--' argument version and any shorter, single letter version. Read - the comments in the declaration of "struct option_map" for an - explanation. Do not omit the first `-'. - - 3. Look in the "specs" file to determine which program or option - list should be given the argument, e.g., "cc1_options". Add the - appropriate syntax for the shorter option version to the - corresponding "const char *" entry in this file. Omit the first - `-' from the option. For example, use `-bar', rather than `--bar'. - - 4. If the argument takes an argument, e.g., `--baz argument1', - modify either DEFAULT_SWITCH_TAKES_ARG or - DEFAULT_WORD_SWITCH_TAKES_ARG in gcc.h. Omit the first `-' - from `--baz'. - - 5. Document the option in this file's display_help(). If the - option is passed to a subprogram, modify its corresponding - function, e.g., cppinit.c:print_help() or toplev.c:display_help(), - instead. - - 6. Compile and test. Make sure that your new specs file is being - read. For example, use a debugger to investigate the value of - "specs_file" in main(). */ - #include "config.h" #include "system.h" #include "coretypes.h" #include "multilib.h" /* before tm.h */ #include "tm.h" -#include -#if ! defined( SIGCHLD ) && defined( SIGCLD ) -# define SIGCHLD SIGCLD -#endif #include "xregex.h" #include "obstack.h" #include "intl.h" #include "prefix.h" #include "gcc.h" +#include "diagnostic.h" #include "flags.h" #include "opts.h" - -#ifdef HAVE_MMAP_FILE -# include -# ifdef HAVE_MINCORE -/* This is on Solaris. */ -# include -# endif -#endif - -#ifndef MAP_FAILED -# define MAP_FAILED ((void *)-1) -#endif +#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 */ @@ -124,10 +74,6 @@ static const char dir_separator_str[] = { DIR_SEPARATOR, 0 }; #define LIBRARY_PATH_ENV "LIBRARY_PATH" #endif -#ifndef HAVE_KILL -#define kill(p,s) raise(s) -#endif - /* If a stage of compilation returns an exit status >= 1, compilation of that file ceases. */ @@ -139,44 +85,9 @@ int is_cpp_driver; /* Flag set to nonzero if an @file argument has been supplied to gcc. */ static bool at_file_supplied; -/* Flag saying to pass the greatest exit code returned by a sub-process - to the calling program. */ -static int pass_exit_codes; - /* Definition of string containing the arguments given to configure. */ #include "configargs.h" -/* Flag saying to print the directories gcc will search through looking for - programs, libraries, etc. */ - -static int print_search_dirs; - -/* Flag saying to print the full filename of this file - as found through our usual search mechanism. */ - -static const char *print_file_name = NULL; - -/* As print_file_name, but search for executable file. */ - -static const char *print_prog_name = NULL; - -/* Flag saying to print the relative path we'd use to - find libgcc.a given the current compiler flags. */ - -static int print_multi_directory; - -static int print_sysroot; - -/* Flag saying to print the relative path we'd use to - find OS libraries given the current compiler flags. */ - -static int print_multi_os_directory; - -/* Flag saying to print the list of subdirectories and - compiler flags used to select them in a standard form. */ - -static int print_multi_lib; - /* Flag saying to print the command line options understood by gcc and its sub-processes. */ @@ -186,15 +97,6 @@ static int print_help_list; static int print_version; -/* Flag saying to print the sysroot suffix used for searching for - headers. */ - -static int print_sysroot_headers_suffix; - -/* Flag indicating whether we should print the command and arguments */ - -static int verbose_flag; - /* Flag indicating whether we should ONLY print the command and arguments (like verbose_flag) without executing the command. Displayed arguments are quoted so that the generated command @@ -206,11 +108,6 @@ static int verbose_only_flag; static int print_subprocess_help; -/* Flag indicating whether we should report subprocess execution times - (if this is supported by the system - see pexecute.c). */ - -static int report_times; - /* Whether we should report subprocess execution times to a file. */ FILE *report_times_to_file = NULL; @@ -249,15 +146,6 @@ static enum save_temps { static char *save_temps_prefix = 0; static size_t save_temps_length = 0; -/* Nonzero means pass multiple source files to the compiler at one time. */ - -static int combine_flag = 0; - -/* Nonzero means use pipes to communicate between subprocesses. - Overridden by either of the above two flags. */ - -static int use_pipes; - /* The compiler version. */ static const char *compiler_version; @@ -279,27 +167,6 @@ static const char *cross_compile = "1"; static const char *cross_compile = "0"; #endif -#ifdef MODIFY_TARGET_NAME - -/* Information on how to alter the target name based on a command-line - switch. The only case we support now is simply appending or deleting a - string to or from the end of the first part of the configuration name. */ - -enum add_del {ADD, DELETE}; - -static const struct modify_target -{ - const char *const sw; - const enum add_del add_del; - const char *const str; -} -modify_target[] = MODIFY_TARGET_NAME; -#endif - -/* The number of errors that have occurred; the link phase will not be - run if this is nonzero. */ -static int error_count = 0; - /* Greatest exit code of sub-processes that has been encountered up to now. */ static int greatest_status = 1; @@ -315,14 +182,6 @@ static struct obstack obstack; static struct obstack collect_obstack; -/* This is a list of a wrapper program and its arguments. - e.g. wrapper_string of "strace,-c" - will cause all programs to run as - strace -c program arguments - instead of just - program arguments */ -static const char *wrapper_string; - /* Forward declaration for prototypes. */ struct path_prefix; struct prefix_list; @@ -345,7 +204,6 @@ static void add_prefix (struct path_prefix *, const char *, const char *, int, int, int); static void add_sysrooted_prefix (struct path_prefix *, const char *, const char *, int, int, int); -static void translate_options (int *, const char *const **); static char *skip_whitespace (char *); static void delete_if_ordinary (const char *); static void delete_temp_files (void); @@ -377,16 +235,12 @@ static int used_arg (const char *, int); static int default_arg (const char *, int); static void set_multilib_dir (void); static void print_multilib_info (void); -static void inform (int, const char *, ...) ATTRIBUTE_PRINTF_2; static void perror_with_name (const char *); -static void internal_error (const char *, ...) - ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN; -static void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2; static void display_help (void); static void add_preprocessor_option (const char *, int); static void add_assembler_option (const char *, int); static void add_linker_option (const char *, int); -static void process_command (int, const char **); +static void process_command (unsigned int, struct cl_decoded_option *); static int execute (void); static void alloc_args (void); static void clear_args (void); @@ -403,13 +257,17 @@ static const char *getenv_spec_function (int, const char **); static const char *if_exists_spec_function (int, const char **); static const char *if_exists_else_spec_function (int, const char **); static const char *replace_outfile_spec_function (int, const char **); +static const char *remove_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 *find_plugindir_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 **); +static const char *pass_through_libs_spec_func (int, const char **); +static char *convert_white_space (char *); /* The Specs Language @@ -535,6 +393,7 @@ or with constant text in a single argument. Note - this command is position dependent. % commands in the spec string before this one will see -S, % commands in the spec string after this one will not. + %>S Similar to "% 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 + /* -u* was put back because both BSD and SysV seem to support it. */ /* %{static:} simply prevents an error message if the target machine @@ -774,27 +662,25 @@ proper position among the other output 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 +/* 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) \ - %{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}}}\ + %(linker) " \ + LINK_PLUGIN_SPEC \ + "%{flto|flto=*:% argument required. - o => argument optional. - j => join argument to equivalent, making one word. - * => require other text after NAME as an argument. */ - const char *const arg_info; -}; - -/* This is the table of mappings. Mappings are tried sequentially - for each option encountered; the first one that matches, wins. */ - -static const struct option_map option_map[] = - { - {"--all-warnings", "-Wall", 0}, - {"--ansi", "-ansi", 0}, - {"--assemble", "-S", 0}, - {"--assert", "-A", "a"}, - {"--classpath", "-fclasspath=", "aj"}, - {"--bootclasspath", "-fbootclasspath=", "aj"}, - {"--CLASSPATH", "-fclasspath=", "aj"}, - {"--combine", "-combine", 0}, - {"--comments", "-C", 0}, - {"--comments-in-macros", "-CC", 0}, - {"--compile", "-c", 0}, - {"--debug", "-g", "oj"}, - {"--define-macro", "-D", "aj"}, - {"--dependencies", "-M", 0}, - {"--dump", "-d", "a"}, - {"--dumpbase", "-dumpbase", "a"}, - {"--dumpdir", "-dumpdir", "a"}, - {"--encoding", "-fencoding=", "aj"}, - {"--entry", "-e", 0}, - {"--extra-warnings", "-W", 0}, - {"--extdirs", "-fextdirs=", "aj"}, - {"--for-assembler", "-Wa", "a"}, - {"--for-linker", "-Xlinker", "a"}, - {"--force-link", "-u", "a"}, - {"--coverage", "-coverage", 0}, - {"--imacros", "-imacros", "a"}, - {"--include", "-include", "a"}, - {"--include-barrier", "-I-", 0}, - {"--include-directory", "-I", "aj"}, - {"--include-directory-after", "-idirafter", "a"}, - {"--include-prefix", "-iprefix", "a"}, - {"--include-with-prefix", "-iwithprefix", "a"}, - {"--include-with-prefix-before", "-iwithprefixbefore", "a"}, - {"--include-with-prefix-after", "-iwithprefix", "a"}, - {"--language", "-x", "a"}, - {"--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}, - {"--no-standard-includes", "-nostdinc", 0}, - {"--no-standard-libraries", "-nostdlib", 0}, - {"--no-warnings", "-w", 0}, - {"--optimize", "-O", "oj"}, - {"--output", "-o", "a"}, - {"--output-class-directory", "-foutput-class-dir=", "ja"}, - {"--param", "--param", "a"}, - {"--pass-exit-codes", "-pass-exit-codes", 0}, - {"--pedantic", "-pedantic", 0}, - {"--pedantic-errors", "-pedantic-errors", 0}, - {"--pie", "-pie", 0}, - {"--pipe", "-pipe", 0}, - {"--prefix", "-B", "a"}, - {"--preprocess", "-E", 0}, - {"--print-search-dirs", "-print-search-dirs", 0}, - {"--print-file-name", "-print-file-name=", "aj"}, - {"--print-libgcc-file-name", "-print-libgcc-file-name", 0}, - {"--print-missing-file-dependencies", "-MG", 0}, - {"--print-multi-lib", "-print-multi-lib", 0}, - {"--print-multi-directory", "-print-multi-directory", 0}, - {"--print-multi-os-directory", "-print-multi-os-directory", 0}, - {"--print-prog-name", "-print-prog-name=", "aj"}, - {"--print-sysroot", "-print-sysroot", 0}, - {"--print-sysroot-headers-suffix", "-print-sysroot-headers-suffix", 0}, - {"--profile", "-p", 0}, - {"--profile-blocks", "-a", 0}, - {"--quiet", "-q", 0}, - {"--resource", "-fcompile-resource=", "aj"}, - {"--save-temps", "-save-temps", 0}, - {"--shared", "-shared", 0}, - {"--silent", "-q", 0}, - {"--specs", "-specs=", "aj"}, - {"--static", "-static", 0}, - {"--std", "-std=", "aj"}, - {"--symbolic", "-symbolic", 0}, - {"--sysroot", "--sysroot=", "aj"}, - {"--time", "-time", 0}, - {"--trace-includes", "-H", 0}, - {"--traditional", "-traditional", 0}, - {"--traditional-cpp", "-traditional-cpp", 0}, - {"--trigraphs", "-trigraphs", 0}, - {"--undefine-macro", "-U", "aj"}, - {"--user-dependencies", "-MM", 0}, - {"--verbose", "-v", 0}, - {"--warn-", "-W", "*j"}, - {"--write-dependencies", "-MD", 0}, - {"--write-user-dependencies", "-MMD", 0}, - {"--", "-f", "*j"} - }; - - -#ifdef TARGET_OPTION_TRANSLATE_TABLE -static const struct { - const char *const option_found; - const char *const replacements; -} target_option_translations[] = -{ - TARGET_OPTION_TRANSLATE_TABLE, - { 0, 0 } -}; -#endif - -/* Translate the options described by *ARGCP and *ARGVP. - Make a new vector and store it back in *ARGVP, - and store its length in *ARGCP. */ - -static void -translate_options (int *argcp, const char *const **argvp) -{ - int i; - int argc = *argcp; - const char *const *argv = *argvp; - int newvsize = (argc + 2) * 2 * sizeof (const char *); - const char **newv = XNEWVAR (const char *, newvsize); - int newindex = 0; - - i = 0; - newv[newindex++] = argv[i++]; - - while (i < argc) - { -#ifdef TARGET_OPTION_TRANSLATE_TABLE - int tott_idx; - - for (tott_idx = 0; - target_option_translations[tott_idx].option_found; - tott_idx++) - { - if (strcmp (target_option_translations[tott_idx].option_found, - argv[i]) == 0) - { - int spaces = 1; - const char *sp; - char *np; - - for (sp = target_option_translations[tott_idx].replacements; - *sp; sp++) - { - if (*sp == ' ') - spaces ++; - } - - newvsize += spaces * sizeof (const char *); - newv = XRESIZEVAR (const char *, newv, newvsize); - - sp = target_option_translations[tott_idx].replacements; - np = xstrdup (sp); - - while (1) - { - while (*np == ' ') - np++; - if (*np == 0) - break; - newv[newindex++] = np; - while (*np != ' ' && *np) - np++; - if (*np == 0) - break; - *np++ = 0; - } - - i ++; - break; - } - } - if (target_option_translations[tott_idx].option_found) - continue; -#endif - - /* Translate -- options. */ - if (argv[i][0] == '-' && argv[i][1] == '-') - { - size_t j; - /* Find a mapping that applies to this option. */ - for (j = 0; j < ARRAY_SIZE (option_map); j++) - { - size_t optlen = strlen (option_map[j].name); - size_t arglen = strlen (argv[i]); - size_t complen = arglen > optlen ? optlen : arglen; - const char *arginfo = option_map[j].arg_info; - - if (arginfo == 0) - arginfo = ""; - - if (!strncmp (argv[i], option_map[j].name, complen)) - { - const char *arg = 0; - - if (arglen < optlen) - { - size_t k; - for (k = j + 1; k < ARRAY_SIZE (option_map); k++) - if (strlen (option_map[k].name) >= arglen - && !strncmp (argv[i], option_map[k].name, arglen)) - { - error ("ambiguous abbreviation %s", argv[i]); - break; - } - - if (k != ARRAY_SIZE (option_map)) - break; - } - - if (arglen > optlen) - { - /* If the option has an argument, accept that. */ - if (argv[i][optlen] == '=') - arg = argv[i] + optlen + 1; - - /* If this mapping requires extra text at end of name, - accept that as "argument". */ - else if (strchr (arginfo, '*') != 0) - arg = argv[i] + optlen; - - /* Otherwise, extra text at end means mismatch. - Try other mappings. */ - else - continue; - } - - else if (strchr (arginfo, '*') != 0) - { - error ("incomplete '%s' option", option_map[j].name); - break; - } - - /* Handle arguments. */ - if (strchr (arginfo, 'a') != 0) - { - if (arg == 0) - { - if (i + 1 == argc) - { - error ("missing argument to '%s' option", - option_map[j].name); - break; - } - - arg = argv[++i]; - } - } - else if (strchr (arginfo, '*') != 0) - ; - else if (strchr (arginfo, 'o') == 0) - { - if (arg != 0) - error ("extraneous argument to '%s' option", - option_map[j].name); - arg = 0; - } - - /* Store the translation as one argv elt or as two. */ - if (arg != 0 && strchr (arginfo, 'j') != 0) - newv[newindex++] = concat (option_map[j].equivalent, arg, - NULL); - else if (arg != 0) - { - newv[newindex++] = option_map[j].equivalent; - newv[newindex++] = arg; - } - else - newv[newindex++] = option_map[j].equivalent; - - break; - } - } - i++; - } - - /* Handle old-fashioned options--just copy them through, - with their arguments. */ - else if (argv[i][0] == '-') - { - const char *p = argv[i] + 1; - int c = *p; - int nskip = 1; - - if (SWITCH_TAKES_ARG (c) > (p[1] != 0)) - nskip += SWITCH_TAKES_ARG (c) - (p[1] != 0); - else if (WORD_SWITCH_TAKES_ARG (p)) - nskip += WORD_SWITCH_TAKES_ARG (p); - else if ((c == 'B' || c == 'b' || c == 'x') - && p[1] == 0) - nskip += 1; - else if (! strcmp (p, "Xlinker")) - nskip += 1; - else if (! strcmp (p, "Xpreprocessor")) - nskip += 1; - else if (! strcmp (p, "Xassembler")) - nskip += 1; - - /* Watch out for an option at the end of the command line that - is missing arguments, and avoid skipping past the end of the - command line. */ - if (nskip + i > argc) - nskip = argc - i; - - while (nskip > 0) - { - newv[newindex++] = argv[i++]; - nskip--; - } - } - else - /* Ordinary operands, or +e options. */ - newv[newindex++] = argv[i++]; - } - - newv[newindex] = 0; - - *argvp = newv; - *argcp = newindex; -} +static VEC(char_p,heap) *preprocessor_options; static char * skip_whitespace (char *p) @@ -1626,10 +1154,15 @@ static const char *multilib_dir; 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; /* 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 { @@ -1675,7 +1208,6 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("link_gomp", &link_gomp_spec), INIT_STATIC_SPEC ("libgcc", &libgcc_spec), INIT_STATIC_SPEC ("startfile", &startfile_spec), - INIT_STATIC_SPEC ("switches_need_spaces", &switches_need_spaces), INIT_STATIC_SPEC ("cross_compile", &cross_compile), INIT_STATIC_SPEC ("version", &compiler_version), INIT_STATIC_SPEC ("multilib", &multilib_select), @@ -1688,7 +1220,6 @@ static struct spec_list static_specs[] = 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), @@ -1697,6 +1228,7 @@ static struct spec_list static_specs[] = 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 */ @@ -1724,13 +1256,16 @@ static const struct spec_function static_spec_functions[] = { "if-exists", if_exists_spec_function }, { "if-exists-else", if_exists_else_spec_function }, { "replace-outfile", replace_outfile_spec_function }, + { "remove-outfile", remove_outfile_spec_function }, { "version-compare", version_compare_spec_function }, { "include", include_spec_function }, { "find-file", find_file_spec_function }, + { "find-plugindir", find_plugindir_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 }, + { "pass-through-libs", pass_through_libs_spec_func }, #ifdef EXTRA_SPEC_FUNCTIONS EXTRA_SPEC_FUNCTIONS #endif @@ -1869,7 +1404,8 @@ init_spec (void) "-lgcc_eh" #ifdef USE_LIBUNWIND_EXCEPTIONS # ifdef HAVE_LD_STATIC_DYNAMIC - " %{!static:-Bstatic} -lunwind %{!static:-Bdynamic}" + " %{!static:" LD_STATIC_OPTION "} -lunwind" + " %{!static:" LD_DYNAMIC_OPTION "}" # else " -lunwind" # endif @@ -1916,7 +1452,8 @@ init_spec (void) } #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); @@ -1925,6 +1462,16 @@ init_spec (void) /* 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 *); #endif @@ -1994,19 +1541,15 @@ set_spec (const char *name, const char *spec) /* Accumulate a command (program name and args), and run it. */ -/* Vector of pointers to arguments in the current line of specifications. */ - -static const char **argbuf; +typedef const char *const_char_p; /* For DEF_VEC_P. */ +DEF_VEC_P(const_char_p); +DEF_VEC_ALLOC_P(const_char_p,heap); -/* Number of elements allocated in argbuf. */ - -static int argbuf_length; - -/* Number of elements in argbuf currently in use (containing args). */ +/* Vector of pointers to arguments in the current line of specifications. */ -static int argbuf_index; +static VEC(const_char_p,heap) *argbuf; -/* Position in the argbuf array containing the name of the output file +/* Position in the argbuf vector containing the name of the output file (the value associated with the "-o" flag). */ static int have_o_argbuf_index = 0; @@ -2037,18 +1580,13 @@ static int execution_count; /* Number of commands that exited with a signal. */ static int signal_count; - -/* Name with which this program was invoked. */ - -static const char *programname; /* Allocate the argument vector. */ static void alloc_args (void) { - argbuf_length = 10; - argbuf = XNEWVEC (const char *, argbuf_length); + argbuf = VEC_alloc (const_char_p, heap, 10); } /* Clear out the vector of arguments (after a command is executed). */ @@ -2056,7 +1594,7 @@ alloc_args (void) static void clear_args (void) { - argbuf_index = 0; + VEC_truncate (const_char_p, argbuf, 0); } /* Add one argument to the vector at the end. @@ -2069,14 +1607,10 @@ clear_args (void) static void store_arg (const char *arg, int delete_always, int delete_failure) { - if (argbuf_index + 1 == argbuf_length) - argbuf = XRESIZEVEC (const char *, argbuf, (argbuf_length *= 2)); - - argbuf[argbuf_index++] = arg; - argbuf[argbuf_index] = 0; + VEC_safe_push (const_char_p, heap, argbuf, arg); if (strcmp (arg, "-o") == 0) - have_o_argbuf_index = argbuf_index; + have_o_argbuf_index = VEC_length (const_char_p, argbuf); if (delete_always || delete_failure) { const char *p; @@ -2293,8 +1827,8 @@ read_specs (const char *filename, int main_p) for (newsl = specs; newsl; newsl = newsl->next) if (strcmp (newsl->name, p2) == 0) - fatal_error ("%s: attempt to rename spec '%s' to " - "already defined spec '%s'", + fatal_error ("%s: attempt to rename spec %qs to " + "already defined spec %qs", filename, p1, p2); if (verbose_flag) @@ -2441,7 +1975,7 @@ record_temp_file (const char *filename, int always_delete, int fail_delete) { 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); @@ -2456,7 +1990,7 @@ record_temp_file (const char *filename, int always_delete, int fail_delete) { struct temp_file *temp; for (temp = failure_delete_queue; temp; temp = temp->next) - if (! strcmp (name, temp->name)) + if (! filename_cmp (name, temp->name)) goto already2; temp = XNEW (struct temp_file); @@ -2550,6 +2084,7 @@ for_each_path (const struct path_prefix *paths, 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; @@ -2567,11 +2102,14 @@ for_each_path (const struct path_prefix *paths, } 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; @@ -2580,16 +2118,15 @@ for_each_path (const struct path_prefix *paths, 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); } @@ -2618,6 +2155,16 @@ for_each_path (const struct path_prefix *paths, 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)) @@ -2919,13 +2466,21 @@ add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix, int require_machine_suffix, int os_multilib) { if (!IS_ABSOLUTE_PATH (prefix)) - fatal_error ("system path '%s' is not absolute", prefix); + fatal_error ("system path %qs is not absolute", prefix); 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, prefix, NULL); + free (sysroot_no_trailing_dir_separator); /* We have to override this because GCC's notion of sysroot moves along with GCC. */ @@ -2954,6 +2509,7 @@ execute (void) const char *prog; /* program name. */ const char **argv; /* vector of args. */ }; + const char *arg; struct command *commands; /* each command buffer with above info. */ @@ -2961,14 +2517,16 @@ execute (void) if (wrapper_string) { - string = find_a_file (&exec_prefixes, argbuf[0], X_OK, false); - argbuf[0] = (string) ? string : argbuf[0]; + string = find_a_file (&exec_prefixes, + VEC_index (const_char_p, argbuf, 0), X_OK, false); + if (string) + VEC_replace (const_char_p, argbuf, 0, string); insert_wrapper (wrapper_string); } /* Count # of piped commands. */ - for (n_commands = 1, i = 0; i < argbuf_index; i++) - if (strcmp (argbuf[i], "|") == 0) + for (n_commands = 1, i = 0; VEC_iterate (const_char_p, argbuf, i, arg); i++) + if (strcmp (arg, "|") == 0) n_commands++; /* Get storage for each command. */ @@ -2978,8 +2536,10 @@ execute (void) and record info about each one. Also search for the programs that are to be run. */ - commands[0].prog = argbuf[0]; /* first command. */ - commands[0].argv = &argbuf[0]; + VEC_safe_push (const_char_p, heap, argbuf, 0); + + commands[0].prog = VEC_index (const_char_p, argbuf, 0); /* first command. */ + commands[0].argv = VEC_address (const_char_p, argbuf); if (!wrapper_string) { @@ -2987,15 +2547,17 @@ execute (void) commands[0].argv[0] = (string) ? string : commands[0].argv[0]; } - for (n_commands = 1, i = 0; i < argbuf_index; i++) - if (strcmp (argbuf[i], "|") == 0) + for (n_commands = 1, i = 0; VEC_iterate (const_char_p, argbuf, i, arg); i++) + if (arg && strcmp (arg, "|") == 0) { /* each command. */ #if defined (__MSDOS__) || defined (OS2) || defined (VMS) fatal_error ("-pipe not supported"); #endif - argbuf[i] = 0; /* termination of command args. */ - commands[n_commands].prog = argbuf[i + 1]; - commands[n_commands].argv = &argbuf[i + 1]; + VEC_replace (const_char_p, argbuf, i, 0); /* Termination of + command args. */ + commands[n_commands].prog = VEC_index (const_char_p, argbuf, i + 1); + commands[n_commands].argv + = &(VEC_address (const_char_p, argbuf))[i + 1]; string = find_a_file (&exec_prefixes, commands[n_commands].prog, X_OK, false); if (string) @@ -3003,8 +2565,6 @@ execute (void) n_commands++; } - argbuf[argbuf_index] = 0; - /* If -v, print what we are about to do, and maybe query. */ if (verbose_flag) @@ -3038,13 +2598,20 @@ execute (void) } 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) @@ -3105,9 +2672,9 @@ execute (void) pex = pex_init (PEX_USE_PIPES | ((report_times || report_times_to_file) ? PEX_RECORD_TIMES : 0), - programname, temp_filename); + progname, temp_filename); if (pex == NULL) - pfatal_with_name (_("pex_init failed")); + fatal_error ("pex_init failed: %m"); for (i = 0; i < n_commands; i++) { @@ -3146,13 +2713,13 @@ execute (void) statuses = (int *) alloca (n_commands * sizeof (int)); if (!pex_get_status (pex, n_commands, statuses)) - pfatal_with_name (_("failed to get exit status")); + fatal_error ("failed to get exit status: %m"); 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)) - pfatal_with_name (_("failed to get process times")); + fatal_error ("failed to get process times: %m"); } pex_free (pex); @@ -3178,12 +2745,8 @@ execute (void) } else #endif - internal_error ("\ -Internal error: %s (program %s)\n\ -Please submit a full bug report.\n\ -See %s for instructions.", - strsignal (WTERMSIG (status)), commands[i].prog, - bug_report_url); + internal_error ("%s (program %s)", + strsignal (WTERMSIG (status)), commands[i].prog); } else if (WIFEXITED (status) && WEXITSTATUS (status) >= MIN_FATAL_STATUS) @@ -3264,10 +2827,11 @@ See %s for instructions.", 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_IGNORE_PERMANENTLY 0x8 +#define SWITCH_LIVE (1 << 0) +#define SWITCH_FALSE (1 << 1) +#define SWITCH_IGNORE (1 << 2) +#define SWITCH_IGNORE_PERMANENTLY (1 << 3) +#define SWITCH_KEEP_FOR_GCC (1 << 4) struct switchstr { @@ -3282,6 +2846,8 @@ static struct switchstr *switches; static int n_switches; +static int n_switches_alloc; + /* 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 @@ -3303,6 +2869,8 @@ static struct switchstr *switches_debug_check[2]; static int n_switches_debug_check[2]; +static int n_switches_alloc_debug_check[2]; + static char *debug_check_temp_file[2]; /* Language is one of three things: @@ -3327,6 +2895,8 @@ static struct infile *infiles; int n_infiles; +static int n_infiles_alloc; + /* True if multiple input files are being compiled to a single assembly file. */ @@ -3401,13 +2971,13 @@ convert_filename (const char *name, int do_exe ATTRIBUTE_UNUSED, static void display_help (void) { - printf (_("Usage: %s [options] file...\n"), programname); + printf (_("Usage: %s [options] file...\n"), progname); fputs (_("Options:\n"), stdout); 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); @@ -3419,6 +2989,9 @@ display_help (void) fputs (_(" -print-libgcc-file-name Display the name of the compiler's companion library\n"), stdout); fputs (_(" -print-file-name= Display the full path to library \n"), stdout); fputs (_(" -print-prog-name= Display the full path to compiler component \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\ @@ -3432,7 +3005,6 @@ display_help (void) fputs (_(" -Xassembler Pass on to the assembler\n"), stdout); fputs (_(" -Xpreprocessor Pass on to the preprocessor\n"), stdout); fputs (_(" -Xlinker Pass on to the linker\n"), stdout); - fputs (_(" -combine Pass multiple source files to compiler at once\n"), stdout); fputs (_(" -save-temps Do not delete intermediate files\n"), stdout); fputs (_(" -save-temps= Do not delete intermediate files\n"), stdout); fputs (_("\ @@ -3452,6 +3024,8 @@ display_help (void) fputs (_(" -S Compile only; do not assemble or link\n"), stdout); fputs (_(" -c Compile and assemble, but do not link\n"), stdout); fputs (_(" -o Place the output into \n"), stdout); + fputs (_(" -pie Create a position independent executable\n"), stdout); + fputs (_(" -shared Create a shared library\n"), stdout); fputs (_("\ -x Specify the language of the following input files\n\ Permissible languages include: c c++ assembler none\n\ @@ -3463,7 +3037,7 @@ display_help (void) \nOptions starting with -g, -f, -m, -O, -W, or --param are automatically\n\ passed on to the various sub-processes invoked by %s. In order to pass\n\ other options on to these processes the -W options must be used.\n\ -"), programname); +"), progname); /* The rest of the options are displayed by invocations of the various sub-processes. */ @@ -3472,97 +3046,573 @@ display_help (void) static void add_preprocessor_option (const char *option, int len) { - n_preprocessor_options++; - - if (! preprocessor_options) - preprocessor_options = XNEWVEC (char *, n_preprocessor_options); - else - preprocessor_options = XRESIZEVEC (char *, preprocessor_options, - n_preprocessor_options); - - preprocessor_options [n_preprocessor_options - 1] = - save_string (option, len); + VEC_safe_push (char_p, heap, preprocessor_options, + save_string (option, len)); } static void add_assembler_option (const char *option, int len) { - n_assembler_options++; - - if (! assembler_options) - assembler_options = XNEWVEC (char *, n_assembler_options); - else - assembler_options = XRESIZEVEC (char *, assembler_options, - n_assembler_options); - - assembler_options [n_assembler_options - 1] = save_string (option, len); + VEC_safe_push (char_p, heap, assembler_options, save_string (option, len)); } static void add_linker_option (const char *option, int len) { - n_linker_options++; - - if (! linker_options) - linker_options = XNEWVEC (char *, n_linker_options); - else - linker_options = XRESIZEVEC (char *, linker_options, n_linker_options); - - linker_options [n_linker_options - 1] = save_string (option, len); + VEC_safe_push (char_p, heap, linker_options, save_string (option, len)); } -/* Create the vector `switches' and its contents. - Store its length in `n_switches'. */ +/* Allocate space for an input file in infiles. */ static void -process_command (int argc, const char **argv) +alloc_infile (void) { - int i; - const char *temp; - char *temp1; - const char *spec_lang = 0; - int last_language_n_infiles; - int lang_n_infiles = 0; -#ifdef MODIFY_TARGET_NAME - int is_modify_target_name; - unsigned int j; -#endif - const char *tooldir_prefix; - char *(*get_relative_prefix) (const char *, const char *, - const char *) = NULL; + if (n_infiles_alloc == 0) + { + n_infiles_alloc = 16; + infiles = XNEWVEC (struct infile, n_infiles_alloc); + } + else if (n_infiles_alloc == n_infiles) + { + n_infiles_alloc *= 2; + infiles = XRESIZEVEC (struct infile, infiles, n_infiles_alloc); + } +} - GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX"); +/* Store an input file with the given NAME and LANGUAGE in + infiles. */ - n_switches = 0; - n_infiles = 0; - added_libraries = 0; +static void +add_infile (const char *name, const char *language) +{ + alloc_infile (); + infiles[n_infiles].name = name; + infiles[n_infiles++].language = language; +} - /* Figure compiler version from version string. */ +/* Allocate space for a switch in switches. */ - compiler_version = temp1 = xstrdup (version_string); +static void +alloc_switch (void) +{ + if (n_switches_alloc == 0) + { + n_switches_alloc = 16; + switches = XNEWVEC (struct switchstr, n_switches_alloc); + } + else if (n_switches_alloc == n_switches) + { + n_switches_alloc *= 2; + switches = XRESIZEVEC (struct switchstr, switches, n_switches_alloc); + } +} - for (; *temp1; ++temp1) +/* Save an option OPT with N_ARGS arguments in array ARGS, marking it + as validated if VALIDATED. */ + +static void +save_switch (const char *opt, size_t n_args, const char *const *args, + bool validated) +{ + alloc_switch (); + switches[n_switches].part1 = opt + 1; + if (n_args == 0) + switches[n_switches].args = 0; + else { - if (*temp1 == ' ') - { - *temp1 = '\0'; - break; - } + switches[n_switches].args = XNEWVEC (const char *, n_args + 1); + memcpy (switches[n_switches].args, args, n_args * sizeof (const char *)); + switches[n_switches].args[n_args] = NULL; } - /* Convert new-style -- options to old-style. */ - translate_options (&argc, - CONST_CAST2 (const char *const **, const char ***, - &argv)); + switches[n_switches].live_cond = 0; + switches[n_switches].validated = validated; + switches[n_switches].ordering = 0; + n_switches++; +} - /* 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. */ +/* Handle an option DECODED that is unknown to the option-processing + machinery. */ - for (i = 1; i < argc; i++) +static bool +driver_unknown_option_callback (const struct cl_decoded_option *decoded) +{ + const char *opt = decoded->arg; + if (opt[1] == 'W' && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-' + && !(decoded->errors & CL_ERR_NEGATIVE)) { - if (! strcmp (argv[i], "-no-canonical-prefixes")) - { + /* 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); + return false; + } + else + return true; +} + +/* Handle an option DECODED that is not marked as CL_DRIVER. + LANG_MASK will always be CL_DRIVER. */ + +static void +driver_wrong_lang_callback (const struct cl_decoded_option *decoded, + unsigned int lang_mask ATTRIBUTE_UNUSED) +{ + /* At this point, non-driver options are accepted (and expected to + be passed down by specs) unless marked to be rejected by the + driver. Options to be rejected by the driver but accepted by the + compilers proper are treated just like completely unknown + options. */ + const struct cl_option *option = &cl_options[decoded->opt_index]; + + if (option->cl_reject_driver) + error ("unrecognized command line option %qs", + decoded->orig_option_with_args_text); + else + save_switch (decoded->canonical_option[0], + decoded->canonical_option_num_elements - 1, + &decoded->canonical_option[1], false); +} + +static const char *spec_lang = 0; +static int last_language_n_infiles; + +/* Handle a driver option; arguments and return value as for + handle_option. */ + +static bool +driver_handle_option (struct gcc_options *opts, + struct gcc_options *opts_set, + const struct cl_decoded_option *decoded, + unsigned int lang_mask ATTRIBUTE_UNUSED, int kind, + location_t loc, + const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED, + diagnostic_context *dc) +{ + size_t opt_index = decoded->opt_index; + const char *arg = decoded->arg; + const char *compare_debug_replacement_opt; + int value = decoded->value; + bool validated = false; + bool do_save = true; + + gcc_assert (opts == &global_options); + gcc_assert (opts_set == &global_options_set); + gcc_assert (kind == DK_UNSPECIFIED); + gcc_assert (loc == UNKNOWN_LOCATION); + gcc_assert (dc == global_dc); + + switch (opt_index) + { + case OPT_dumpspecs: + { + struct spec_list *sl; + init_spec (); + for (sl = specs; sl; sl = sl->next) + printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec)); + if (link_command_spec) + printf ("*link_command:\n%s\n\n", link_command_spec); + exit (0); + } + + case OPT_dumpversion: + printf ("%s\n", spec_version); + exit (0); + + case OPT_dumpmachine: + printf ("%s\n", spec_machine); + exit (0); + + case OPT__version: + print_version = 1; + + /* CPP driver cannot obtain switch from cc1_options. */ + if (is_cpp_driver) + add_preprocessor_option ("--version", strlen ("--version")); + add_assembler_option ("--version", strlen ("--version")); + add_linker_option ("--version", strlen ("--version")); + break; + + case OPT__help: + print_help_list = 1; + + /* CPP driver cannot obtain switch from cc1_options. */ + if (is_cpp_driver) + add_preprocessor_option ("--help", 6); + add_assembler_option ("--help", 6); + add_linker_option ("--help", 6); + break; + + case OPT__help_: + print_subprocess_help = 2; + break; + + case OPT__target_help: + print_subprocess_help = 1; + + /* CPP driver cannot obtain switch from cc1_options. */ + if (is_cpp_driver) + add_preprocessor_option ("--target-help", 13); + add_assembler_option ("--target-help", 13); + add_linker_option ("--target-help", 13); + break; + + case OPT_pass_exit_codes: + case OPT_print_search_dirs: + case OPT_print_file_name_: + case OPT_print_prog_name_: + case OPT_print_multi_lib: + 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: + /* These options set the variables specified in common.opt + automatically, and do not need to be saved for spec + processing. */ + do_save = false; + break; + + case OPT_print_libgcc_file_name: + print_file_name = "libgcc.a"; + do_save = false; + break; + + case OPT_fcompare_debug_second: + compare_debug_second = 1; + break; + + case OPT_fcompare_debug: + switch (value) + { + case 0: + compare_debug_replacement_opt = "-fcompare-debug="; + arg = ""; + goto compare_debug_with_arg; + + case 1: + compare_debug_replacement_opt = "-fcompare-debug=-gtoggle"; + arg = "-gtoggle"; + goto compare_debug_with_arg; + + default: + gcc_unreachable (); + } + break; + + case OPT_fcompare_debug_: + compare_debug_replacement_opt = decoded->canonical_option[0]; + compare_debug_with_arg: + gcc_assert (decoded->canonical_option_num_elements == 1); + gcc_assert (arg != NULL); + if (*arg) + compare_debug = 1; + else + compare_debug = -1; + if (compare_debug < 0) + compare_debug_opt = NULL; + else + compare_debug_opt = arg; + save_switch (compare_debug_replacement_opt, 0, NULL, validated); + return true; + + case OPT_Wa_: + { + int prev, j; + /* Pass the rest of this option to the assembler. */ + + /* Split the argument at commas. */ + prev = 0; + for (j = 0; arg[j]; j++) + if (arg[j] == ',') + { + add_assembler_option (arg + prev, j - prev); + prev = j + 1; + } + + /* Record the part after the last comma. */ + add_assembler_option (arg + prev, j - prev); + } + do_save = false; + break; + + case OPT_Wp_: + { + int prev, j; + /* Pass the rest of this option to the preprocessor. */ + + /* Split the argument at commas. */ + prev = 0; + for (j = 0; arg[j]; j++) + if (arg[j] == ',') + { + add_preprocessor_option (arg + prev, j - prev); + prev = j + 1; + } + + /* Record the part after the last comma. */ + add_preprocessor_option (arg + prev, j - prev); + } + do_save = false; + break; + + case OPT_Wl_: + { + int prev, j; + /* Split the argument at commas. */ + prev = 0; + for (j = 0; arg[j]; j++) + if (arg[j] == ',') + { + add_infile (save_string (arg + prev, j - prev), "*"); + prev = j + 1; + } + /* Record the part after the last comma. */ + add_infile (arg + prev, "*"); + } + do_save = false; + break; + + case OPT_Xlinker: + add_infile (arg, "*"); + do_save = false; + break; + + case OPT_Xpreprocessor: + add_preprocessor_option (arg, strlen (arg)); + do_save = false; + break; + + case OPT_Xassembler: + add_assembler_option (arg, strlen (arg)); + do_save = false; + break; + + case OPT_l: + /* POSIX allows separation of -l and the lib arg; canonicalize + by concatenating -l with its arg */ + add_infile (concat ("-l", arg, NULL), "*"); + do_save = false; + break; + + case OPT_L: + /* Similarly, canonicalize -L for linkers that may not accept + separate arguments. */ + save_switch (concat ("-L", arg, NULL), 0, NULL, validated); + return true; + + case OPT_F: + /* Likewise -F. */ + save_switch (concat ("-F", arg, NULL), 0, NULL, validated); + return true; + + case OPT_save_temps: + save_temps_flag = SAVE_TEMPS_CWD; + validated = true; + break; + + case OPT_save_temps_: + if (strcmp (arg, "cwd") == 0) + save_temps_flag = SAVE_TEMPS_CWD; + else if (strcmp (arg, "obj") == 0 + || strcmp (arg, "object") == 0) + save_temps_flag = SAVE_TEMPS_OBJ; + else + fatal_error ("%qs is an unknown -save-temps option", + decoded->orig_option_with_args_text); + break; + + case OPT_no_canonical_prefixes: + /* Already handled as a special case, so ignored here. */ + do_save = false; + break; + + case OPT_pipe: + validated = true; + /* These options set the variables specified in common.opt + automatically, but do need to be saved for spec + processing. */ + break; + + case OPT_specs_: + { + struct user_specs *user = XNEW (struct user_specs); + + user->next = (struct user_specs *) 0; + user->filename = arg; + if (user_specs_tail) + user_specs_tail->next = user; + else + user_specs_head = user; + user_specs_tail = user; + } + do_save = false; + break; + + case OPT__sysroot_: + target_system_root = arg; + target_system_root_changed = 1; + do_save = false; + break; + + case OPT_time_: + if (report_times_to_file) + fclose (report_times_to_file); + report_times_to_file = fopen (arg, "a"); + do_save = false; + break; + + case OPT____: + /* "-###" + This is similar to -v except that there is no execution + of the commands and the echoed arguments are quoted. It + is intended for use in shell scripts to capture the + driver-generated command line. */ + verbose_only_flag++; + verbose_flag = 1; + do_save = false; + break; + + case OPT_B: + { + size_t len = strlen (arg); + + /* Catch the case where the user has forgotten to append a + directory separator to the path. Note, they may be using + -B to add an executable name prefix, eg "i386-elf-", in + order to distinguish between multiple installations of + GCC in the same directory. Hence we must check to see + if appending a directory separator actually makes a + valid directory name. */ + if (!IS_DIR_SEPARATOR (arg[len - 1]) + && is_directory (arg, false)) + { + char *tmp = XNEWVEC (char, len + 2); + strcpy (tmp, arg); + tmp[len] = DIR_SEPARATOR; + tmp[++len] = 0; + arg = tmp; + } + + add_prefix (&exec_prefixes, arg, NULL, + PREFIX_PRIORITY_B_OPT, 0, 0); + add_prefix (&startfile_prefixes, arg, NULL, + PREFIX_PRIORITY_B_OPT, 0, 0); + add_prefix (&include_prefixes, arg, NULL, + PREFIX_PRIORITY_B_OPT, 0, 0); + } + validated = true; + break; + + case OPT_x: + spec_lang = arg; + if (!strcmp (spec_lang, "none")) + /* Suppress the warning if -xnone comes after the last input + file, because alternate command interfaces like g++ might + find it useful to place -xnone after each input file. */ + spec_lang = 0; + else + last_language_n_infiles = n_infiles; + do_save = false; + break; + + case OPT_o: + have_o = 1; +#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX) + arg = convert_filename (arg, ! have_c, 0); +#endif + /* Save the output name in case -save-temps=obj was used. */ + 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); + return true; + + case OPT_static_libgcc: + case OPT_shared_libgcc: + case OPT_static_libgfortran: + case OPT_static_libstdc__: + /* These are always valid, since gcc.c itself understands the + first two, gfortranspec.c understands -static-libgfortran and + g++spec.c understands -static-libstdc++ */ + validated = true; + break; + + default: + /* Various driver options need no special processing at this + point, having been handled in a prescan above or being + handled by specs. */ + break; + } + + if (do_save) + save_switch (decoded->canonical_option[0], + decoded->canonical_option_num_elements - 1, + &decoded->canonical_option[1], validated); + return true; +} + +/* Put the driver's standard set of option handlers in *HANDLERS. */ + +static void +set_option_handlers (struct cl_option_handlers *handlers) +{ + handlers->unknown_option_callback = driver_unknown_option_callback; + handlers->wrong_lang_callback = driver_wrong_lang_callback; + 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. + Store its length in `n_switches'. */ + +static void +process_command (unsigned int decoded_options_count, + struct cl_decoded_option *decoded_options) +{ + const char *temp; + char *temp1; + const char *tooldir_prefix; + char *(*get_relative_prefix) (const char *, const char *, + const char *) = NULL; + struct cl_option_handlers handlers; + unsigned int j; + + gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX"); + + n_switches = 0; + n_infiles = 0; + added_libraries = 0; + + /* Figure compiler version from version string. */ + + compiler_version = temp1 = xstrdup (version_string); + + for (; *temp1; ++temp1) + { + if (*temp1 == ' ') + { + *temp1 = '\0'; + break; + } + } + + /* Handle any -no-canonical-prefixes flag early, to assign the function + that builds relative prefixes. This function creates default search + paths that are needed later in normal option handling. */ + + for (j = 1; j < decoded_options_count; j++) + { + if (decoded_options[j].opt_index == OPT_no_canonical_prefixes) + { get_relative_prefix = make_relative_prefix_ignore_links; break; } @@ -3571,17 +3621,18 @@ process_command (int argc, const char **argv) 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]. */ + see if we can create it from the pathname specified in + decoded_options[0].arg. */ gcc_libexec_prefix = standard_libexec_prefix; #ifndef VMS /* FIXME: make_relative_prefix doesn't yet work for VMS. */ if (!gcc_exec_prefix) { - gcc_exec_prefix = get_relative_prefix (argv[0], + gcc_exec_prefix = get_relative_prefix (decoded_options[0].arg, standard_bindir_prefix, standard_exec_prefix); - gcc_libexec_prefix = get_relative_prefix (argv[0], + gcc_libexec_prefix = get_relative_prefix (decoded_options[0].arg, standard_bindir_prefix, standard_libexec_prefix); if (gcc_exec_prefix) @@ -3608,12 +3659,11 @@ process_command (int argc, const char **argv) #endif /* From this point onward, gcc_exec_prefix is non-null if the toolchain is relocated. The toolchain was either relocated using GCC_EXEC_PREFIX - or an automatically created GCC_EXEC_PREFIX from argv[0]. */ + or an automatically created GCC_EXEC_PREFIX from + decoded_options[0].arg. */ /* Do language-specific adjustment/addition of flags. */ - lang_specific_driver (&argc, - CONST_CAST2 (const char *const **, const char ***, - &argv), + lang_specific_driver (&decoded_options, &decoded_options_count, &added_libraries); if (gcc_exec_prefix) @@ -3625,9 +3675,9 @@ process_command (int argc, const char **argv) { 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; } @@ -3641,7 +3691,7 @@ process_command (int argc, const char **argv) /* COMPILER_PATH and LIBRARY_PATH have values that are lists of directory names with colons. */ - GET_ENVIRONMENT (temp, "COMPILER_PATH"); + temp = getenv ("COMPILER_PATH"); if (temp) { const char *startp, *endp; @@ -3675,7 +3725,7 @@ process_command (int argc, const char **argv) } } - GET_ENVIRONMENT (temp, LIBRARY_PATH_ENV); + temp = getenv (LIBRARY_PATH_ENV); if (temp && *cross_compile == '0') { const char *startp, *endp; @@ -3708,7 +3758,7 @@ process_command (int argc, const char **argv) } /* Use LPATH like LIBRARY_PATH (for the CMU build program). */ - GET_ENVIRONMENT (temp, "LPATH"); + temp = getenv ("LPATH"); if (temp && *cross_compile == '0') { const char *startp, *endp; @@ -3740,467 +3790,73 @@ process_command (int argc, const char **argv) } } - /* 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). */ - - for (i = 1; i < argc; i++) - { - if (! strcmp (argv[i], "-dumpspecs")) - { - struct spec_list *sl; - init_spec (); - for (sl = specs; sl; sl = sl->next) - printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec)); - if (link_command_spec) - printf ("*link_command:\n%s\n\n", link_command_spec); - exit (0); - } - else if (! strcmp (argv[i], "-dumpversion")) - { - printf ("%s\n", spec_version); - exit (0); - } - else if (! strcmp (argv[i], "-dumpmachine")) - { - printf ("%s\n", spec_machine); - exit (0); - } - else if (strcmp (argv[i], "-fversion") == 0) - { - /* translate_options () has turned --version into -fversion. */ - print_version = 1; - - /* We will be passing a dummy file on to the sub-processes. */ - n_infiles++; - n_switches++; - - /* CPP driver cannot obtain switch from cc1_options. */ - if (is_cpp_driver) - add_preprocessor_option ("--version", strlen ("--version")); - add_assembler_option ("--version", strlen ("--version")); - add_linker_option ("--version", strlen ("--version")); - } - else if (strcmp (argv[i], "-fhelp") == 0) - { - /* translate_options () has turned --help into -fhelp. */ - print_help_list = 1; - - /* We will be passing a dummy file on to the sub-processes. */ - n_infiles++; - n_switches++; - - /* CPP driver cannot obtain switch from cc1_options. */ - if (is_cpp_driver) - add_preprocessor_option ("--help", 6); - add_assembler_option ("--help", 6); - add_linker_option ("--help", 6); - } - else if (strncmp (argv[i], "-fhelp=", 7) == 0) - { - /* translate_options () has turned --help into -fhelp. */ - print_subprocess_help = 2; + /* Process the options and store input files and switches in their + vectors. */ - /* We will be passing a dummy file on to the sub-processes. */ - n_infiles++; - n_switches++; - } - else if (strcmp (argv[i], "-ftarget-help") == 0) - { - /* translate_options() has turned --target-help into -ftarget-help. */ - print_subprocess_help = 1; - - /* We will be passing a dummy file on to the sub-processes. */ - n_infiles++; - n_switches++; - - /* CPP driver cannot obtain switch from cc1_options. */ - if (is_cpp_driver) - add_preprocessor_option ("--target-help", 13); - add_assembler_option ("--target-help", 13); - add_linker_option ("--target-help", 13); - } - else if (! strcmp (argv[i], "-pass-exit-codes")) - { - pass_exit_codes = 1; - n_switches++; - } - else if (! strcmp (argv[i], "-print-search-dirs")) - print_search_dirs = 1; - else if (! strcmp (argv[i], "-print-libgcc-file-name")) - print_file_name = "libgcc.a"; - else if (! strncmp (argv[i], "-print-file-name=", 17)) - print_file_name = argv[i] + 17; - else if (! strncmp (argv[i], "-print-prog-name=", 17)) - print_prog_name = argv[i] + 17; - else if (! strcmp (argv[i], "-print-multi-lib")) - print_multi_lib = 1; - else if (! strcmp (argv[i], "-print-multi-directory")) - print_multi_directory = 1; - else if (! strcmp (argv[i], "-print-sysroot")) - print_sysroot = 1; - else if (! strcmp (argv[i], "-print-multi-os-directory")) - print_multi_os_directory = 1; - else if (! strcmp (argv[i], "-print-sysroot-headers-suffix")) - print_sysroot_headers_suffix = 1; - else if (! strcmp (argv[i], "-fcompare-debug-second")) - { - compare_debug_second = 1; - n_switches++; - } - else if (! strcmp (argv[i], "-fno-compare-debug")) - { - argv[i] = "-fcompare-debug="; - goto compare_debug_with_arg; - } - else if (! strcmp (argv[i], "-fcompare-debug")) - { - argv[i] = "-fcompare-debug=-gtoggle"; - goto compare_debug_with_arg; - } -#define OPT "-fcompare-debug=" - else if (! strncmp (argv[i], OPT, sizeof (OPT) - 1)) - { - const char *opt; - compare_debug_with_arg: - opt = argv[i] + sizeof (OPT) - 1; -#undef OPT - if (*opt) - compare_debug = 1; - else - compare_debug = -1; - if (compare_debug < 0) - compare_debug_opt = NULL; - else - compare_debug_opt = opt; - n_switches++; - } - else if (! strncmp (argv[i], "-Wa,", 4)) - { - int prev, j; - /* Pass the rest of this option to the assembler. */ - - /* Split the argument at commas. */ - prev = 4; - for (j = 4; argv[i][j]; j++) - if (argv[i][j] == ',') - { - add_assembler_option (argv[i] + prev, j - prev); - prev = j + 1; - } - - /* Record the part after the last comma. */ - add_assembler_option (argv[i] + prev, j - prev); - } - else if (! strncmp (argv[i], "-Wp,", 4)) - { - int prev, j; - /* Pass the rest of this option to the preprocessor. */ - - /* Split the argument at commas. */ - prev = 4; - for (j = 4; argv[i][j]; j++) - if (argv[i][j] == ',') - { - add_preprocessor_option (argv[i] + prev, j - prev); - prev = j + 1; - } - - /* Record the part after the last comma. */ - add_preprocessor_option (argv[i] + prev, j - prev); - } - else if (argv[i][0] == '+' && argv[i][1] == 'e') - /* The +e options to the C++ front-end. */ - n_switches++; - else if (strncmp (argv[i], "-Wl,", 4) == 0) - { - int j; - /* Split the argument at commas. */ - for (j = 3; argv[i][j]; j++) - n_infiles += (argv[i][j] == ','); - } - else if (strcmp (argv[i], "-Xlinker") == 0) - { - if (i + 1 == argc) - fatal_error ("argument to '-Xlinker' is missing"); - - n_infiles++; - i++; - } - else if (strcmp (argv[i], "-Xpreprocessor") == 0) - { - if (i + 1 == argc) - fatal_error ("argument to '-Xpreprocessor' is missing"); - - add_preprocessor_option (argv[i+1], strlen (argv[i+1])); - } - else if (strcmp (argv[i], "-Xassembler") == 0) - { - if (i + 1 == argc) - fatal_error ("argument to '-Xassembler' is missing"); + last_language_n_infiles = -1; - add_assembler_option (argv[i+1], strlen (argv[i+1])); - } - else if (strcmp (argv[i], "-l") == 0) - { - if (i + 1 == argc) - fatal_error ("argument to '-l' is missing"); + set_option_handlers (&handlers); - n_infiles++; - i++; - } - else if (strncmp (argv[i], "-l", 2) == 0) - n_infiles++; - else if (strcmp (argv[i], "-save-temps") == 0) - { - save_temps_flag = SAVE_TEMPS_CWD; - n_switches++; - } - else if (strncmp (argv[i], "-save-temps=", 12) == 0) - { - n_switches++; - if (strcmp (argv[i]+12, "cwd") == 0) - save_temps_flag = SAVE_TEMPS_CWD; - else if (strcmp (argv[i]+12, "obj") == 0 - || strcmp (argv[i]+12, "object") == 0) - save_temps_flag = SAVE_TEMPS_OBJ; - else - fatal_error ("'%s' is an unknown -save-temps option", argv[i]); - } - else if (strcmp (argv[i], "-no-canonical-prefixes") == 0) - /* Already handled as a special case, so ignored here. */ - ; - else if (strcmp (argv[i], "-combine") == 0) - { - combine_flag = 1; - n_switches++; - } - else if (strcmp (argv[i], "-specs") == 0) - { - struct user_specs *user = XNEW (struct user_specs); - if (++i >= argc) - fatal_error ("argument to '-specs' is missing"); - - user->next = (struct user_specs *) 0; - user->filename = argv[i]; - if (user_specs_tail) - user_specs_tail->next = user; - else - user_specs_head = user; - user_specs_tail = user; - } - else if (strncmp (argv[i], "-specs=", 7) == 0) - { - struct user_specs *user = XNEW (struct user_specs); - if (strlen (argv[i]) == 7) - fatal_error ("argument to '-specs=' is missing"); - - user->next = (struct user_specs *) 0; - user->filename = argv[i] + 7; - if (user_specs_tail) - user_specs_tail->next = user; - else - user_specs_head = user; - user_specs_tail = user; - } - 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) + for (j = 1; j < decoded_options_count; j++) + { + switch (decoded_options[j].opt_index) { - /* -pipe has to go into the switches array as well as - setting a flag. */ - use_pipes = 1; - n_switches++; + case OPT_S: + case OPT_c: + case OPT_E: + have_c = 1; + break; } - else if (strcmp (argv[i], "-wrapper") == 0) - { - if (++i >= argc) - fatal_error ("argument to '-wrapper' is missing"); + if (have_c) + break; + } - wrapper_string = argv[i]; - n_switches++; - n_switches++; - } - else if (strcmp (argv[i], "-###") == 0) - { - /* This is similar to -v except that there is no execution - of the commands and the echoed arguments are quoted. It - is intended for use in shell scripts to capture the - driver-generated command line. */ - verbose_only_flag++; - verbose_flag++; - } - else if (argv[i][0] == '-' && argv[i][1] != 0) + for (j = 1; j < decoded_options_count; j++) + { + if (decoded_options[j].opt_index == OPT_SPECIAL_input_file) { - const char *p = &argv[i][1]; - int c = *p; - - switch (c) + const char *arg = decoded_options[j].arg; + const char *p = strrchr (arg, '@'); + char *fname; + long offset; + int consumed; +#ifdef HAVE_TARGET_OBJECT_SUFFIX + arg = convert_filename (arg, 0, access (arg, F_OK)); +#endif + /* 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 != arg + && sscanf (p, "@%li%n", &offset, &consumed) >= 1 + && strlen (p) == (unsigned int)consumed) { - case 'B': - { - const char *value; - int len; - - if (p[1] == 0 && i + 1 == argc) - fatal_error ("argument to '-B' is missing"); - if (p[1] == 0) - value = argv[++i]; - else - value = p + 1; - - len = strlen (value); - - /* Catch the case where the user has forgotten to append a - directory separator to the path. Note, they may be using - -B to add an executable name prefix, eg "i386-elf-", in - order to distinguish between multiple installations of - GCC in the same directory. Hence we must check to see - if appending a directory separator actually makes a - valid directory name. */ - if (! IS_DIR_SEPARATOR (value [len - 1]) - && is_directory (value, false)) - { - char *tmp = XNEWVEC (char, len + 2); - strcpy (tmp, value); - tmp[len] = DIR_SEPARATOR; - tmp[++ len] = 0; - value = tmp; - } - - add_prefix (&exec_prefixes, value, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); - add_prefix (&startfile_prefixes, value, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); - add_prefix (&include_prefixes, value, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); - n_switches++; - } - break; - - case 'v': /* Print our subcommands and print versions. */ - n_switches++; - /* If they do anything other than exactly `-v', don't set - verbose_flag; rather, continue on to give the error. */ - if (p[1] != 0) - break; - verbose_flag++; - break; - - case 'S': - case 'c': - case 'E': - if (p[1] == 0) - { - have_c = 1; - n_switches++; - break; - } - goto normal_switch; - - case 'o': - have_o = 1; -#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) - if (! have_c) + fname = (char *)xmalloc (p - arg + 1); + memcpy (fname, arg, p - arg); + fname[p - arg] = '\0'; + /* Only accept non-stdin and existing FNAME parts, otherwise + try with the full name. */ + if (strcmp (fname, "-") == 0 || access (fname, F_OK) < 0) { - int skip; - - /* Forward scan, just in case -S, -E or -c is specified - after -o. */ - int j = i + 1; - if (p[1] == 0) - ++j; - while (j < argc) - { - if (argv[j][0] == '-') - { - if (SWITCH_CURTAILS_COMPILATION (argv[j][1]) - && argv[j][2] == 0) - { - have_c = 1; - break; - } - else if ((skip = SWITCH_TAKES_ARG (argv[j][1]))) - j += skip - (argv[j][2] != 0); - else if ((skip = WORD_SWITCH_TAKES_ARG (argv[j] + 1))) - j += skip; - } - j++; - } + free (fname); + fname = xstrdup (arg); } -#endif -#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX) - if (p[1] == 0) - argv[i + 1] = convert_filename (argv[i + 1], ! have_c, 0); - else - argv[i] = convert_filename (argv[i], ! have_c, 0); -#endif - /* Save the output name in case -save-temps=obj was used. */ - if ((p[1] == 0) && argv[i + 1]) - save_temps_prefix = xstrdup(argv[i + 1]); - else - save_temps_prefix = xstrdup(argv[i] + 1); - goto normal_switch; - - default: - normal_switch: - -#ifdef MODIFY_TARGET_NAME - is_modify_target_name = 0; - - for (j = 0; j < ARRAY_SIZE (modify_target); j++) - if (! strcmp (argv[i], modify_target[j].sw)) - { - char *new_name = XNEWVEC (char, strlen (modify_target[j].str) - + strlen (spec_machine)); - const char *p, *r; - char *q; - int made_addition = 0; - - is_modify_target_name = 1; - for (p = spec_machine, q = new_name; *p != 0; ) - { - if (modify_target[j].add_del == DELETE - && (! strncmp (q, modify_target[j].str, - strlen (modify_target[j].str)))) - p += strlen (modify_target[j].str); - else if (modify_target[j].add_del == ADD - && ! made_addition && *p == '-') - { - for (r = modify_target[j].str; *r != 0; ) - *q++ = *r++; - made_addition = 1; - } - - *q++ = *p++; - } - - spec_machine = new_name; - } - - if (is_modify_target_name) - break; -#endif - - n_switches++; - - if (SWITCH_TAKES_ARG (c) > (p[1] != 0)) - i += SWITCH_TAKES_ARG (c) - (p[1] != 0); - else if (WORD_SWITCH_TAKES_ARG (p)) - i += WORD_SWITCH_TAKES_ARG (p); } + else + fname = xstrdup (arg); + + if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0) + perror_with_name (fname); + else + add_infile (arg, spec_lang); + + free (fname); + continue; } - else - { - n_infiles++; - lang_n_infiles++; - } + + read_cmdline_option (&global_options, &global_options_set, + decoded_options + j, UNKNOWN_LOCATION, + CL_DRIVER, &handlers, global_dc); } /* If -save-temps=obj and -o name, create the prefix to use for %b. @@ -4238,13 +3894,11 @@ process_command (int argc, const char **argv) { 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) @@ -4297,9 +3951,9 @@ process_command (int argc, const char **argv) then consider it to relocate with the rest of the GCC installation if GCC_EXEC_PREFIX is set. ``make_relative_prefix'' is not compiled for VMS, so don't call it. */ - if (target_system_root && gcc_exec_prefix) + if (target_system_root && !target_system_root_changed && gcc_exec_prefix) { - char *tmp_prefix = get_relative_prefix (argv[0], + char *tmp_prefix = get_relative_prefix (decoded_options[0].arg, standard_bindir_prefix, target_system_root); if (tmp_prefix && access_check (tmp_prefix, F_OK) == 0) @@ -4313,259 +3967,12 @@ process_command (int argc, const char **argv) /* More prefixes are enabled in main, after we read the specs file and determine whether this is cross-compilation or not. */ - /* Then create the space for the vectors and scan again. */ - - switches = XNEWVEC (struct switchstr, n_switches + 1); - infiles = XNEWVEC (struct infile, n_infiles + 1); - n_switches = 0; - n_infiles = 0; - last_language_n_infiles = -1; - - /* This, time, copy the text of each switch and store a pointer - to the copy in the vector of switches. - Store all the infiles in their vector. */ - - for (i = 1; i < argc; i++) - { - /* Just skip the switches that were handled by the preceding loop. */ -#ifdef MODIFY_TARGET_NAME - is_modify_target_name = 0; - - for (j = 0; j < ARRAY_SIZE (modify_target); j++) - if (! strcmp (argv[i], modify_target[j].sw)) - is_modify_target_name = 1; - - if (is_modify_target_name) - ; - else -#endif - if (! strncmp (argv[i], "-Wa,", 4)) - ; - else if (! strncmp (argv[i], "-Wp,", 4)) - ; - else if (! strcmp (argv[i], "-no-canonical-prefixes")) - ; - else if (! strcmp (argv[i], "-pass-exit-codes")) - ; - else if (! strcmp (argv[i], "-print-search-dirs")) - ; - else if (! strcmp (argv[i], "-print-libgcc-file-name")) - ; - else if (! strncmp (argv[i], "-print-file-name=", 17)) - ; - else if (! strncmp (argv[i], "-print-prog-name=", 17)) - ; - else if (! strcmp (argv[i], "-print-multi-lib")) - ; - else if (! strcmp (argv[i], "-print-multi-directory")) - ; - else if (! strcmp (argv[i], "-print-sysroot")) - ; - else if (! strcmp (argv[i], "-print-multi-os-directory")) - ; - else if (! strcmp (argv[i], "-print-sysroot-headers-suffix")) - ; - else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot="))) - { - target_system_root = argv[i] + strlen ("--sysroot="); - target_system_root_changed = 1; - } - else if (argv[i][0] == '+' && argv[i][1] == 'e') - { - /* Compensate for the +e options to the C++ front-end; - they're there simply for cfront call-compatibility. We do - some magic in default_compilers to pass them down properly. - Note we deliberately start at the `+' here, to avoid passing - -e0 or -e1 down into the linker. */ - switches[n_switches].part1 = &argv[i][0]; - switches[n_switches].args = 0; - switches[n_switches].live_cond = 0; - switches[n_switches].validated = 0; - n_switches++; - } - else if (strncmp (argv[i], "-Wl,", 4) == 0) - { - int prev, j; - /* Split the argument at commas. */ - prev = 4; - for (j = 4; argv[i][j]; j++) - if (argv[i][j] == ',') - { - infiles[n_infiles].language = "*"; - infiles[n_infiles++].name - = save_string (argv[i] + prev, j - prev); - prev = j + 1; - } - /* Record the part after the last comma. */ - infiles[n_infiles].language = "*"; - infiles[n_infiles++].name = argv[i] + prev; - } - else if (strcmp (argv[i], "-Xlinker") == 0) - { - infiles[n_infiles].language = "*"; - infiles[n_infiles++].name = argv[++i]; - } - /* Xassembler and Xpreprocessor were already handled in the first argv - scan, so all we need to do here is ignore them and their argument. */ - else if (strcmp (argv[i], "-Xassembler") == 0) - i++; - else if (strcmp (argv[i], "-Xpreprocessor") == 0) - i++; - else if (strcmp (argv[i], "-l") == 0) - { /* POSIX allows separation of -l and the lib arg; - canonicalize by concatenating -l with its arg */ - infiles[n_infiles].language = "*"; - infiles[n_infiles++].name = concat ("-l", argv[++i], NULL); - } - else if (strncmp (argv[i], "-l", 2) == 0) - { - infiles[n_infiles].language = "*"; - infiles[n_infiles++].name = argv[i]; - } - else if (strcmp (argv[i], "-wrapper") == 0) - i++; - else if (strcmp (argv[i], "-specs") == 0) - i++; - else if (strncmp (argv[i], "-specs=", 7) == 0) - ; - else if (strcmp (argv[i], "-time") == 0) - ; - else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0) - ; - else if (strcmp (argv[i], "-###") == 0) - ; - else if (argv[i][0] == '-' && argv[i][1] != 0) - { - const char *p = &argv[i][1]; - int c = *p; - - if (c == 'x') - { - if (p[1] == 0 && i + 1 == argc) - fatal_error ("argument to '-x' is missing"); - if (p[1] == 0) - spec_lang = argv[++i]; - else - spec_lang = p + 1; - if (! strcmp (spec_lang, "none")) - /* Suppress the warning if -xnone comes after the last input - file, because alternate command interfaces like g++ might - find it useful to place -xnone after each input file. */ - spec_lang = 0; - else - last_language_n_infiles = n_infiles; - continue; - } - switches[n_switches].part1 = p; - /* 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 >= argc) - fatal_error ("argument to '-%s' is missing", p); - switches[n_switches].args - = XNEWVEC (const char *, n_args + 1); - while (j < n_args) - switches[n_switches].args[j++] = argv[++i]; - /* Null-terminate the vector. */ - switches[n_switches].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'; - - switches[n_switches].part1 = part1; - switches[n_switches].args = XNEWVEC (const char *, 2); - switches[n_switches].args[0] = xstrdup (p+1); - switches[n_switches].args[1] = 0; - } - else - switches[n_switches].args = 0; - - switches[n_switches].live_cond = 0; - switches[n_switches].validated = 0; - switches[n_switches].ordering = 0; - /* These are always valid, since gcc.c itself understands the - first four, gfortranspec.c understands -static-libgfortran - and g++spec.c understands -static-libstdc++ */ - if (!strcmp (p, "save-temps") - || !strcmp (p, "static-libgcc") - || !strcmp (p, "shared-libgcc") - || !strcmp (p, "pipe") - || !strcmp (p, "static-libgfortran") - || !strcmp (p, "static-libstdc++")) - switches[n_switches].validated = 1; - else - { - char ch = switches[n_switches].part1[0]; - if (ch == 'B') - switches[n_switches].validated = 1; - } - n_switches++; - } - 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 - /* 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) - { - 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 - 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) - warning (0, "'-x %s' after last input file has no effect", spec_lang); + warning (0, "%<-x %s%> after last input file has no effect", spec_lang); if (compare_debug == 2 || compare_debug == 3) { + alloc_switch (); switches[n_switches].part1 = concat ("fcompare-debug=", compare_debug_opt, NULL); @@ -4580,15 +3987,16 @@ process_command (int argc, const char **argv) /* Ensure we only invoke each subprocess once. */ if (print_subprocess_help || print_help_list || print_version) { - n_infiles = 1; + n_infiles = 0; /* Create a dummy input file, so that we can pass the help option on to the various sub-processes. */ - infiles[0].language = "c"; - infiles[0].name = "help-dummy"; + add_infile ("help-dummy", "c"); } + alloc_switch (); switches[n_switches].part1 = 0; + alloc_infile (); infiles[n_infiles].name = 0; } @@ -4617,7 +4025,9 @@ set_collect_gcc_options (void) first_time = FALSE; /* Ignore elided switches. */ - if ((switches[i].live_cond & SWITCH_IGNORE) != 0) + if ((switches[i].live_cond + & (SWITCH_IGNORE | SWITCH_KEEP_FOR_GCC)) + == SWITCH_IGNORE) continue; obstack_grow (&collect_obstack, "'-", 2); @@ -4658,7 +4068,7 @@ set_collect_gcc_options (void) sans all directory names, and basename_length is the number of characters starting there excluding the suffix .c or whatever. */ -static const char *input_filename; +static const char *gcc_input_filename; static int input_file_number; size_t input_filename_length; static int basename_length; @@ -4725,7 +4135,7 @@ end_going_arg (void) if (full_script_path == NULL) { - error ("unable to locate default linker script '%s' in the library search paths", string); + error ("unable to locate default linker script %qs in the library search paths", string); /* Script was not found on search path. */ return; } @@ -4750,6 +4160,7 @@ insert_wrapper (const char *wrapper) int i; char *buf = xstrdup (wrapper); char *p = buf; + unsigned int old_length = VEC_length (const_char_p, argbuf); do { @@ -4759,15 +4170,10 @@ insert_wrapper (const char *wrapper) } while ((p = strchr (p, ',')) != NULL); - if (argbuf_index + n >= argbuf_length) - { - argbuf_length = argbuf_length * 2; - while (argbuf_length < argbuf_index + n) - argbuf_length *= 2; - argbuf = XRESIZEVEC (const char *, argbuf, argbuf_length); - } - for (i = argbuf_index - 1; i >= 0; i--) - argbuf[i + n] = argbuf[i]; + 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), + old_length * sizeof (const_char_p)); i = 0; p = buf; @@ -4778,11 +4184,11 @@ insert_wrapper (const char *wrapper) *p = 0; p++; } - argbuf[i++] = p; + VEC_replace (const_char_p, argbuf, i, p); + i++; } while ((p = strchr (p, ',')) != NULL); gcc_assert (i == n); - argbuf_index += n; } /* Process the spec SPEC and run the commands specified therein. @@ -4799,12 +4205,13 @@ do_spec (const char *spec) If -pipe, this forces out the last command if it ended in `|'. */ if (value == 0) { - if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|")) - argbuf_index--; + if (VEC_length (const_char_p, argbuf) > 0 + && !strcmp (VEC_last (const_char_p, argbuf), "|")) + VEC_pop (const_char_p, argbuf); set_collect_gcc_options (); - if (argbuf_index > 0) + if (VEC_length (const_char_p, argbuf) > 0) value = execute (); } @@ -4900,68 +4307,64 @@ do_self_spec (const char *spec) if ((switches[i].live_cond & SWITCH_IGNORE)) switches[i].live_cond |= SWITCH_IGNORE_PERMANENTLY; - if (argbuf_index > 0) + if (VEC_length (const_char_p, argbuf) > 0) { - switches = XRESIZEVEC (struct switchstr, switches, - n_switches + argbuf_index + 1); - - for (i = 0; i < argbuf_index; i++) + const char **argbuf_copy; + struct cl_decoded_option *decoded_options; + struct cl_option_handlers handlers; + unsigned int decoded_options_count; + unsigned int j; + + /* 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_copy[0] = ""; + memcpy (argbuf_copy + 1, VEC_address (const_char_p, argbuf), + VEC_length (const_char_p, argbuf) * sizeof (const char *)); + + decode_cmdline_options_to_array (VEC_length (const_char_p, argbuf) + 1, + argbuf_copy, + CL_DRIVER, &decoded_options, + &decoded_options_count); + + set_option_handlers (&handlers); + + for (j = 1; j < decoded_options_count; j++) { - struct switchstr *sw; - const char *p = argbuf[i]; - int c = *p; - - /* Each switch should start with '-'. */ - if (c != '-') - fatal_error ("switch '%s' does not start with '-'", argbuf[i]); - - 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)) + switch (decoded_options[j].opt_index) { - int j = 0; - int n_args = WORD_SWITCH_TAKES_ARG (p); + case OPT_SPECIAL_input_file: + /* Specs should only generate options, not input + files. */ + if (strcmp (decoded_options[j].arg, "-") != 0) + fatal_error ("switch %qs does not start with %<-%>", + decoded_options[j].arg); + else + fatal_error ("spec-generated switch is just %<-%>"); + break; - 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_error ("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; + case OPT_fcompare_debug_second: + case OPT_fcompare_debug: + case OPT_fcompare_debug_: + case OPT_o: + /* Avoid duplicate processing of some options from + compare-debug specs; just save them here. */ + save_switch (decoded_options[j].canonical_option[0], + (decoded_options[j].canonical_option_num_elements + - 1), + &decoded_options[j].canonical_option[1], false); + break; + + default: + read_cmdline_option (&global_options, &global_options_set, + decoded_options + j, UNKNOWN_LOCATION, + CL_DRIVER, &handlers, global_dc); + break; } - else - sw->args = 0; } + alloc_switch (); switches[n_switches].part1 = 0; } } @@ -5060,6 +4463,22 @@ compile_input_file_p (struct infile *infile) return false; } +/* Process each member of VEC as a spec. */ + +static void +do_specs_vec (VEC(char_p,heap) *vec) +{ + unsigned ix; + char *opt; + + FOR_EACH_VEC_ELT (char_p, vec, ix, opt) + { + do_spec_1 (opt, 1, NULL); + /* Make each accumulated option a separate argument. */ + do_spec_1 (" ", 0, NULL); + } +} + /* Process the sub-spec SPEC as a portion of a larger spec. This is like processing a whole spec except that we do not initialize at the beginning and we do not supply a @@ -5080,6 +4499,10 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) 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. */ @@ -5088,7 +4511,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) case '\n': end_going_arg (); - if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|")) + if (VEC_length (const_char_p, argbuf) > 0 + && !strcmp (VEC_last (const_char_p, argbuf), "|")) { /* A `|' before the newline means use a pipe here, but only if -pipe was specified. @@ -5099,12 +4523,12 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) break; } else - argbuf_index--; + VEC_pop (const_char_p, argbuf); } set_collect_gcc_options (); - if (argbuf_index > 0) + if (VEC_length (const_char_p, argbuf) > 0) { value = execute (); if (value) @@ -5143,7 +4567,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) switch (c = *p++) { case 0: - fatal_error ("spec '%s' invalid", spec); + fatal_error ("spec %qs invalid", spec); case 'b': if (save_temps_length) @@ -5292,7 +4716,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) p += 2; /* We don't support extra suffix characters after %O. */ if (*p == '.' || ISALNUM ((unsigned char) *p)) - fatal_error ("spec '%s' has invalid '%%0%c'", spec, *p); + fatal_error ("spec %qs has invalid %<%%0%c%>", spec, *p); if (suffix_length == 0) suffix = TARGET_OBJECT_SUFFIX; else @@ -5333,7 +4757,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) break; } - /* If the input_filename has the same suffix specified + /* If the gcc_input_filename has the same suffix specified for the %g, %u, or %U, and -save-temps is specified, we could end up using that file as an intermediate thus clobbering the user's source file (.e.g., @@ -5351,7 +4775,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) tmp[basename_length + suffix_length] = '\0'; temp_filename = tmp; - if (strcmp (temp_filename, input_filename) != 0) + if (filename_cmp (temp_filename, gcc_input_filename) != 0) { #ifndef HOST_LACKS_INODE_NUMBERS struct stat st_temp; @@ -5359,12 +4783,13 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) /* Note, set_input() resets input_stat_set to 0. */ if (input_stat_set == 0) { - input_stat_set = stat (input_filename, &input_stat); + input_stat_set = stat (gcc_input_filename, + &input_stat); if (input_stat_set >= 0) input_stat_set = 1; } - /* If we have the stat for the input_filename + /* If we have the stat for the gcc_input_filename and we can do the stat for the temp_filename then the they could still refer to the same file if st_dev/st_ino's are the same. */ @@ -5374,9 +4799,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) || input_stat.st_ino != st_temp.st_ino) #else /* Just compare canonical pathnames. */ - char* input_realname = lrealpath (input_filename); + 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) @@ -5426,8 +4851,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) 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; @@ -5476,7 +4900,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) } else { - obstack_grow (&obstack, input_filename, input_filename_length); + obstack_grow (&obstack, gcc_input_filename, + input_filename_length); arg_going = 1; } break; @@ -5494,6 +4919,15 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) 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); @@ -5598,18 +5032,18 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) case 'W': { - int cur_index = argbuf_index; + unsigned int cur_index = VEC_length (const_char_p, argbuf); /* Handle the {...} following the %W. */ if (*p != '{') - fatal_error ("spec '%s' has invalid '%%W%c", spec, *p); + fatal_error ("spec %qs has invalid %<%%W%c%>", spec, *p); p = handle_braces (p + 1); if (p == 0) return -1; end_going_arg (); /* If any args were output, mark the last one for deletion on failure. */ - if (argbuf_index != cur_index) - record_temp_file (argbuf[argbuf_index - 1], 0, 1); + if (VEC_length (const_char_p, argbuf) != cur_index) + record_temp_file (VEC_last (const_char_p, argbuf), 0, 1); break; } @@ -5618,17 +5052,19 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) { const char *p1 = p; char *string; + char *opt; + unsigned ix; /* Skip past the option value and make a copy. */ if (*p != '{') - fatal_error ("spec '%s' has invalid '%%x%c'", spec, *p); + fatal_error ("spec %qs has invalid %<%%x%c%>", spec, *p); while (*p++ != '}') ; string = save_string (p1 + 1, p - p1 - 2); /* See if we already recorded this option. */ - for (i = 0; i < n_linker_options; i++) - if (! strcmp (string, linker_options[i])) + FOR_EACH_VEC_ELT (char_p, linker_options, ix, opt) + if (! strcmp (string, opt)) { free (string); return 0; @@ -5641,32 +5077,17 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) /* Dump out the options accumulated previously using %x. */ case 'X': - for (i = 0; i < n_linker_options; i++) - { - do_spec_1 (linker_options[i], 1, NULL); - /* Make each accumulated option a separate argument. */ - do_spec_1 (" ", 0, NULL); - } + do_specs_vec (linker_options); break; /* Dump out the options accumulated previously using -Wa,. */ case 'Y': - for (i = 0; i < n_assembler_options; i++) - { - do_spec_1 (assembler_options[i], 1, NULL); - /* Make each accumulated option a separate argument. */ - do_spec_1 (" ", 0, NULL); - } + do_specs_vec (assembler_options); break; /* Dump out the options accumulated previously using -Wp,. */ case 'Z': - for (i = 0; i < n_preprocessor_options; i++) - { - do_spec_1 (preprocessor_options[i], 1, NULL); - /* Make each accumulated option a separate argument. */ - do_spec_1 (" ", 0, NULL); - } + do_specs_vec (preprocessor_options); break; /* Here are digits and numbers that just process @@ -5783,10 +5204,17 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) /* Henceforth ignore the option(s) matching the pattern after the %<. */ case '<': + case '>': { unsigned len = 0; int have_wildcard = 0; int i; + int switch_option; + + if (c == '>') + switch_option = SWITCH_IGNORE | SWITCH_KEEP_FOR_GCC; + else + switch_option = SWITCH_IGNORE; while (p[len] && p[len] != ' ' && p[len] != '\t') len++; @@ -5798,7 +5226,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) if (!strncmp (switches[i].part1, p, len - have_wildcard) && (have_wildcard || switches[i].part1[len] == '\0')) { - switches[i].live_cond |= SWITCH_IGNORE; + switches[i].live_cond |= switch_option; switches[i].validated = 1; } @@ -5809,23 +5237,20 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) 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 /* Catch the case where a spec string contains something like '%{foo:%*}'. i.e. there is no * in the pattern on the left hand side of the :. */ - error ("spec failure: '%%*' has not been initialized by pattern match"); + error ("spec failure: %<%%*%> has not been initialized by pattern match"); break; /* 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; @@ -5834,7 +5259,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) /* 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. */ @@ -5843,70 +5268,27 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) { 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++; } break; default: - error ("spec failure: unrecognized spec option '%c'", c); + error ("spec failure: unrecognized spec option %qc", c); break; } break; @@ -5953,9 +5335,7 @@ eval_spec_function (const char *func, const char *args) const char *funcval; /* Saved spec processing context. */ - int save_argbuf_index; - int save_argbuf_length; - const char **save_argbuf; + VEC(const_char_p,heap) *save_argbuf; int save_arg_going; int save_delete_this_arg; @@ -5968,11 +5348,9 @@ eval_spec_function (const char *func, const char *args) sf = lookup_spec_function (func); if (sf == NULL) - fatal_error ("unknown spec function '%s'", func); + fatal_error ("unknown spec function %qs", func); /* Push the spec processing context. */ - save_argbuf_index = argbuf_index; - save_argbuf_length = argbuf_length; save_argbuf = argbuf; save_arg_going = arg_going; @@ -5988,17 +5366,16 @@ eval_spec_function (const char *func, const char *args) alloc_args (); if (do_spec_2 (args) < 0) - fatal_error ("error in args to spec function '%s'", func); + fatal_error ("error in args to spec function %qs", func); /* 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) (argbuf_index, argbuf); + funcval = (*sf->func) (VEC_length (const_char_p, argbuf), + VEC_address (const_char_p, argbuf)); /* Pop the spec processing context. */ - argbuf_index = save_argbuf_index; - argbuf_length = save_argbuf_length; - free (argbuf); + VEC_free (const_char_p, heap, argbuf); argbuf = save_argbuf; arg_going = save_arg_going; @@ -6116,6 +5493,21 @@ switch_matches (const char *atom, const char *end_atom, int starred) && 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; } @@ -6305,7 +5697,7 @@ handle_braces (const char *p) return p; invalid: - fatal_error ("braced spec '%s' is invalid at '%c'", orig, *p); + fatal_error ("braced spec %qs is invalid at %qc", orig, *p); #undef SKIP_WHITE } @@ -6393,7 +5785,7 @@ process_brace_body (const char *p, const char *atom, const char *end_atom, return p; invalid: - fatal_error ("braced spec body '%s' is invalid", body); + fatal_error ("braced spec body %qs is invalid", body); } /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch @@ -6564,11 +5956,11 @@ is_directory (const char *path1, bool linker) 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)); @@ -6582,9 +5974,9 @@ set_input (const char *filename) { const char *p; - input_filename = filename; - input_filename_length = strlen (input_filename); - input_basename = lbasename (input_filename); + gcc_input_filename = filename; + input_filename_length = strlen (gcc_input_filename); + input_basename = lbasename (gcc_input_filename); /* Find a suffix starting with the last period, and set basename_length to exclude that suffix. */ @@ -6602,7 +5994,7 @@ set_input (const char *filename) input_suffix = ""; /* If a spec for 'g', 'u', or 'U' is seen with -save-temps then - we will need to do a stat on the input_filename. The + we will need to do a stat on the gcc_input_filename. The INPUT_STAT_SET signals that the stat is needed. */ input_stat_set = 0; } @@ -6643,7 +6035,7 @@ compare_files (char *cmpfile[]) 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]); + gcc_input_filename, cmpfile[i]); ret = 1; break; } @@ -6653,7 +6045,7 @@ compare_files (char *cmpfile[]) if (!ret && length[0] != length[1]) { - error ("%s: -fcompare-debug failure (length)", input_filename); + error ("%s: -fcompare-debug failure (length)", gcc_input_filename); ret = 1; } @@ -6664,7 +6056,7 @@ compare_files (char *cmpfile[]) if (fd < 0) { error ("%s: could not open compare-debug file %s", - input_filename, cmpfile[i]); + gcc_input_filename, cmpfile[i]); ret = 1; break; } @@ -6683,7 +6075,7 @@ compare_files (char *cmpfile[]) { if (memcmp (map[0], map[1], length[0]) != 0) { - error ("%s: -fcompare-debug failure", input_filename); + error ("%s: -fcompare-debug failure", gcc_input_filename); ret = 1; } } @@ -6705,7 +6097,7 @@ compare_files (char *cmpfile[]) if (!temp[i]) { error ("%s: could not open compare-debug file %s", - input_filename, cmpfile[i]); + gcc_input_filename, cmpfile[i]); ret = 1; break; } @@ -6721,7 +6113,7 @@ compare_files (char *cmpfile[]) if (c0 != c1) { error ("%s: -fcompare-debug failure", - input_filename); + gcc_input_filename); ret = 1; break; } @@ -6751,9 +6143,12 @@ main (int argc, char **argv) int num_linker_inputs = 0; char *explicit_link_files; char *specs_file; + char *lto_wrapper_file; const char *p; struct user_specs *uptr; char **old_argv = argv; + 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. */ @@ -6762,9 +6157,9 @@ main (int argc, char **argv) p = argv[0] + strlen (argv[0]); while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) --p; - programname = p; + progname = p; - xmalloc_set_program_name (programname); + xmalloc_set_program_name (progname); expandargv (&argc, &argv); @@ -6772,7 +6167,16 @@ main (int argc, char **argv) if (argv != old_argv) at_file_supplied = true; - prune_options (&argc, &argv); + /* 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. */ @@ -6784,6 +6188,10 @@ main (int argc, char **argv) gcc_init_libintl (); + diagnostic_initialize (global_dc, 0); + if (atexit (delete_temp_files) != 0) + fatal_error ("atexit failed"); + if (signal (SIGINT, SIG_IGN) != SIG_IGN) signal (SIGINT, fatal_signal); #ifdef SIGHUP @@ -6802,6 +6210,10 @@ main (int argc, char **argv) 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 (); @@ -6858,7 +6270,7 @@ main (int argc, char **argv) Make a table of specified input files (infiles, n_infiles). Decode switches that are handled locally. */ - process_command (argc, CONST_CAST2 (const char **, char **, argv)); + process_command (decoded_options_count, decoded_options); /* Initialize the vector of specs to just the default. This means one element containing 0s, as a terminator. */ @@ -6903,43 +6315,6 @@ main (int argc, char **argv) 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') @@ -6955,10 +6330,10 @@ main (int argc, char **argv) if (*sysroot_suffix_spec != 0 && do_spec_2 (sysroot_suffix_spec) == 0) { - if (argbuf_index > 1) + if (VEC_length (const_char_p, argbuf) > 1) error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC"); - else if (argbuf_index == 1) - target_sysroot_suffix = xstrdup (argbuf[argbuf_index -1]); + else if (VEC_length (const_char_p, argbuf) == 1) + target_sysroot_suffix = xstrdup (VEC_last (const_char_p, argbuf)); } #ifdef HAVE_LD_SYSROOT @@ -6978,10 +6353,10 @@ main (int argc, char **argv) if (*sysroot_hdrs_suffix_spec != 0 && do_spec_2 (sysroot_hdrs_suffix_spec) == 0) { - if (argbuf_index > 1) + if (VEC_length (const_char_p, argbuf) > 1) error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC"); - else if (argbuf_index == 1) - target_sysroot_hdrs_suffix = xstrdup (argbuf[argbuf_index -1]); + else if (VEC_length (const_char_p, argbuf) == 1) + target_sysroot_hdrs_suffix = xstrdup (VEC_last (const_char_p, argbuf)); } /* Look for startfiles in the standard places. */ @@ -6989,9 +6364,10 @@ main (int argc, char **argv) && do_spec_2 (startfile_prefix_spec) == 0 && do_spec_1 (" ", 0, NULL) == 0) { + const char *arg; int ndx; - for (ndx = 0; ndx < argbuf_index; ndx++) - add_sysrooted_prefix (&startfile_prefixes, argbuf[ndx], "BINUTILS", + FOR_EACH_VEC_ELT (const_char_p, argbuf, ndx, arg) + add_sysrooted_prefix (&startfile_prefixes, arg, "BINUTILS", PREFIX_PRIORITY_LAST, 0, 1); } /* We should eventually get rid of all these and stick to @@ -7048,6 +6424,58 @@ main (int argc, char **argv) read_specs (filename ? filename : uptr->filename, FALSE); } + /* 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, @@ -7063,7 +6491,7 @@ main (int argc, char **argv) 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 + needed for collect. We use argv[0] instead of progname because we need the complete pathname. */ obstack_init (&collect_obstack); obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1); @@ -7072,9 +6500,15 @@ main (int argc, char **argv) /* 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) + 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=", sizeof ("COLLECT_LTO_WRAPPER=") - 1); @@ -7087,7 +6521,7 @@ main (int argc, char **argv) for (i = 0; (int) i < n_switches; i++) if (! switches[i].validated) - error ("unrecognized option '-%s'", switches[i].part1); + error ("unrecognized option %<-%s%>", switches[i].part1); /* Obey some of the options. */ @@ -7131,6 +6565,15 @@ main (int argc, char **argv) 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) @@ -7189,9 +6632,9 @@ main (int argc, char **argv) if (print_version) { - printf (_("%s %s%s\n"), programname, pkgversion_string, + printf (_("%s %s%s\n"), progname, pkgversion_string, version_string); - printf ("Copyright %s 2010 Free Software Foundation, Inc.\n", + printf ("Copyright %s 2012 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"), @@ -7249,6 +6692,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (n_infiles == added_libraries) fatal_error ("no input files"); + if (seen_error ()) + goto out; + /* Make a place to record the compiler output file names that correspond to the input files. */ @@ -7260,10 +6706,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" explicit_link_files = XCNEWVEC (char, n_infiles); - if (combine_flag) - combine_inputs = true; - else - combine_inputs = false; + combine_inputs = have_o || flag_wpa; for (i = 0; (int) i < n_infiles; i++) { @@ -7296,63 +6739,7 @@ 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_error ("cannot specify -o with -c, -S or -E with multiple files"); - - if (combine_flag && save_temps_flag) - { - bool save_combine_inputs = combine_inputs; - /* Must do a separate pre-processing pass for C & Objective-C files, to - obtain individual .i files. */ - - combine_inputs = false; - for (i = 0; (int) i < n_infiles; i++) - { - int this_file_error = 0; - - input_file_number = i; - set_input (infiles[i].name); - if (infiles[i].incompiler - && (infiles[i].incompiler)->needs_preprocessing) - input_file_compiler = infiles[i].incompiler; - else - continue; - - if (input_file_compiler) - { - if (input_file_compiler->spec[0] == '#') - { - error ("%s: %s compiler not installed on this system", - input_filename, &input_file_compiler->spec[1]); - this_file_error = 1; - } - else - { - value = do_spec (input_file_compiler->spec); - infiles[i].preprocessed = true; - if (!have_o_argbuf_index) - fatal_error ("spec '%s' is invalid", - input_file_compiler->spec); - infiles[i].name = argbuf[have_o_argbuf_index]; - infiles[i].incompiler - = lookup_compiler (infiles[i].name, - strlen (infiles[i].name), - infiles[i].language); - - if (value < 0) - this_file_error = 1; - } - } - - if (this_file_error) - { - delete_failure_queue (); - error_count++; - break; - } - clear_failure_queue (); - } - combine_inputs = save_combine_inputs; - } + fatal_error ("cannot specify -o with -c, -S or -E with multiple files"); for (i = 0; (int) i < n_infiles; i++) { @@ -7368,16 +6755,13 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" /* Use the same thing in %o, unless cp->spec says otherwise. */ - outfiles[i] = input_filename; + outfiles[i] = gcc_input_filename; /* Figure out which compiler from the file's suffix. */ - if (! combine_inputs) - input_file_compiler - = lookup_compiler (infiles[i].name, input_filename_length, - infiles[i].language); - else - input_file_compiler = infiles[i].incompiler; + input_file_compiler + = lookup_compiler (infiles[i].name, input_filename_length, + infiles[i].language); if (input_file_compiler) { @@ -7386,19 +6770,17 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (input_file_compiler->spec[0] == '#') { error ("%s: %s compiler not installed on this system", - input_filename, &input_file_compiler->spec[1]); + gcc_input_filename, &input_file_compiler->spec[1]); this_file_error = 1; } else { 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; } @@ -7413,12 +6795,14 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" compare_debug = -compare_debug; n_switches = n_switches_debug_check[1]; + n_switches_alloc = n_switches_alloc_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]; + n_switches_alloc = n_switches_alloc_debug_check[0]; switches = switches_debug_check[0]; if (value < 0) @@ -7428,8 +6812,8 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } 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"); @@ -7440,12 +6824,10 @@ 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; } } @@ -7463,7 +6845,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (this_file_error) { delete_failure_queue (); - error_count++; + errorcount++; } /* If this compilation succeeded, don't delete those files later. */ clear_failure_queue (); @@ -7478,20 +6860,21 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" int i; for (i = 0; i < n_infiles ; i++) - if (infiles[i].language && infiles[i].language[0] != '*') + if (infiles[i].incompiler + || (infiles[i].language && infiles[i].language[0] != '*')) { set_input (infiles[i].name); break; } } - if (error_count == 0) + if (!seen_error ()) { /* Make sure INPUT_FILE_NUMBER points to first available open slot. */ input_file_number = n_infiles; if (lang_specific_pre_link ()) - error_count++; + errorcount++; } /* Determine if there are any linker input files. */ @@ -7502,34 +6885,50 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" /* Run ld to link all the compiler output files. */ - if (num_linker_inputs > 0 && error_count == 0 && print_subprocess_help < 2) + if (num_linker_inputs > 0 && !seen_error () && 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 (! have_c) { - char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false); - if (s == NULL) - linker_name_spec = "ld"; - } +#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"; +#endif +#endif - 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_error ("-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_error ("could not find libgcc.a"); + /* 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"; + } + +#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)) +#endif + { + 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. */ @@ -7545,14 +6944,14 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } value = do_spec (link_command_spec); if (value < 0) - error_count = 1; + errorcount = 1; linker_was_run = (tmp != execution_count); } /* If options said don't run linker, complain about input files to be given to the linker. */ - if (! linker_was_run && error_count == 0) + if (! linker_was_run && !seen_error ()) for (i = 0; (int) i < n_infiles; i++) if (explicit_link_files[i] && !(infiles[i].language && infiles[i].language[0] == '*')) @@ -7561,7 +6960,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" /* Delete some or all of the temporary files we made. */ - if (error_count) + if (seen_error ()) delete_failure_queue (); delete_temp_files (); @@ -7571,8 +6970,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" printf ("%s\n", bug_report_url); } + out: return (signal_count != 0 ? 2 - : error_count > 0 ? (pass_exit_codes ? greatest_status : 1) + : seen_error () ? (pass_exit_codes ? greatest_status : 1) : 0); } @@ -7667,103 +7067,7 @@ pfatal_with_name (const char *name) static void perror_with_name (const char *name) { - error ("%s: %s", name, xstrerror (errno)); -} - -/* Output an error message and exit. */ - -void -fancy_abort (const char *file, int line, const char *func) -{ - internal_error ("internal gcc abort in %s, at %s:%d", func, file, line); -} - -/* Output an error message and exit. */ - -void -internal_error (const char *gmsgid, ...) -{ - va_list ap; - - va_start (ap, gmsgid); - - fprintf (stderr, "%s: ", programname); - vfprintf (stderr, _(gmsgid), ap); - va_end (ap); - fprintf (stderr, "\n"); - delete_temp_files (); - exit (pass_exit_codes ? ICE_EXIT_CODE : 1); -} - -void -fatal_error (const char *gmsgid, ...) -{ - va_list ap; - - va_start (ap, gmsgid); - - fprintf (stderr, "%s: ", programname); - vfprintf (stderr, _(gmsgid), ap); - va_end (ap); - fprintf (stderr, "\n"); - delete_temp_files (); - exit (1); -} - -/* The argument is actually c-format, not gcc-internal-format, - but because functions with identical names are used through - the rest of the compiler with gcc-internal-format, we just - need to hope all users of these functions use the common - subset between c-format and gcc-internal-format. */ - -void -error (const char *gmsgid, ...) -{ - va_list ap; - - va_start (ap, gmsgid); - error_count++; - fprintf (stderr, "%s: %s", programname, _("error: ")); - vfprintf (stderr, _(gmsgid), ap); - va_end (ap); - - fprintf (stderr, "\n"); -} - -void -warning (int dummy ATTRIBUTE_UNUSED, const char *gmsgid, ...) -{ - va_list ap; - - va_start (ap, gmsgid); - fprintf (stderr, "%s: %s", programname, _("warning: ")); - vfprintf (stderr, _(gmsgid), ap); - va_end (ap); - - fprintf (stderr, "\n"); -} - -static void -inform (int dummy ATTRIBUTE_UNUSED, const char *gmsgid, ...) -{ - va_list ap; - - va_start (ap, gmsgid); - fprintf (stderr, "%s: %s", programname, _("note: ")); - vfprintf (stderr, _(gmsgid), ap); - va_end (ap); - - fprintf (stderr, "\n"); -} - -static void -fnotice (FILE *fp, const char *cmsgid, ...) -{ - va_list ap; - - va_start (ap, cmsgid); - vfprintf (fp, _(cmsgid), ap); - va_end (ap); + error ("%s: %m", name); } static inline void @@ -7918,7 +7222,7 @@ used_arg (const char *p, int len) if (*q == '\0') { invalid_matches: - fatal_error ("multilib spec '%s' is invalid", + fatal_error ("multilib spec %qs is invalid", multilib_matches); } q++; @@ -8041,7 +7345,9 @@ default_arg (const char *p, int len) 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) @@ -8110,7 +7416,7 @@ set_multilib_dir (void) if (*p == '\0') { invalid_exclusions: - fatal_error ("multilib exclusions '%s' is invalid", + fatal_error ("multilib exclusions %qs is invalid", multilib_exclusions); } @@ -8168,7 +7474,7 @@ set_multilib_dir (void) if (*p == '\0') { invalid_select: - fatal_error ("multilib select '%s' is invalid", + fatal_error ("multilib select %qs is invalid", multilib_select); } ++p; @@ -8253,10 +7559,25 @@ set_multilib_dir (void) 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; } } @@ -8309,16 +7630,17 @@ print_multilib_info (void) if (*p == '\0') { invalid_select: - fatal_error ("multilib select '%s' is invalid", multilib_select); + fatal_error ("multilib select %qs is invalid", multilib_select); } ++p; } /* 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 @@ -8347,7 +7669,7 @@ print_multilib_info (void) if (*e == '\0') { invalid_exclusion: - fatal_error ("multilib exclusion '%s' is invalid", + fatal_error ("multilib exclusion %qs is invalid", multilib_exclusions); } @@ -8419,7 +7741,7 @@ print_multilib_info (void) /* 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; @@ -8553,7 +7875,7 @@ getenv_spec_function (int argc, const char **argv) value = getenv (argv[0]); if (!value) - fatal_error ("environment variable \"%s\" not defined", argv[0]); + fatal_error ("environment variable %qs not defined", argv[0]); /* We have to escape every character of the environment variable so they are not interpreted as active spec characters. A @@ -8623,12 +7945,33 @@ replace_outfile_spec_function (int argc, const char **argv) 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; } +/* remove-outfile built-in spec function. + * + * This looks for the first argument in the outfiles array's name and + * removes it. */ + +static const char * +remove_outfile_spec_function (int argc, const char **argv) +{ + int i; + /* Must have exactly one argument. */ + if (argc != 1) + abort (); + + for (i = 0; i < n_infiles; i++) + { + if (outfiles[i] && !filename_cmp (outfiles[i], argv[0])) + outfiles[i] = NULL; + } + return NULL; +} + /* Given two version numbers, compares the two numbers. A version number must match the regular expression ([1-9][0-9]*|0)(\.([1-9][0-9]*|0))* @@ -8644,12 +7987,12 @@ compare_version_strings (const char *v1, const char *v2) abort (); rresult = regexec (&r, v1, 0, NULL, 0); if (rresult == REG_NOMATCH) - fatal_error ("invalid version number `%s'", v1); + fatal_error ("invalid version number %qs", v1); else if (rresult != 0) abort (); rresult = regexec (&r, v2, 0, NULL, 0); if (rresult == REG_NOMATCH) - fatal_error ("invalid version number `%s'", v2); + fatal_error ("invalid version number %qs", v2); else if (rresult != 0) abort (); @@ -8739,7 +8082,7 @@ version_compare_spec_function (int argc, const char **argv) break; default: - fatal_error ("unknown operator '%s' in %%:version-compare", argv[0]); + fatal_error ("unknown operator %qs in %%:version-compare", argv[0]); } if (! result) return NULL; @@ -8766,11 +8109,11 @@ include_spec_function (int argc, const char **argv) return NULL; } -/* %:find-file spec function. This function replace its argument by +/* %:find-file spec function. This function replaces 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) +find_file_spec_function (int argc, const char **argv) { const char *file; @@ -8782,6 +8125,22 @@ find_file_spec_function (int argc, const char**argv) } +/* %:find-plugindir spec function. This function replaces its argument + by the -iplugindir= option. `dir' is found thru 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) +{ + const char *option; + + if (argc != 0) + abort (); + + option = concat ("-iplugindir=", find_file ("plugin"), NULL); + return option; +} + + /* %:print-asm-header spec function. Print a banner to say that the following output is from the assembler. */ @@ -8795,12 +8154,22 @@ print_asm_header_spec_function (int arg 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 @@ -8819,7 +8188,7 @@ get_local_tick (void) } #endif - return ret; + return ret ^ getpid(); } /* %:compare-debug-dump-opt spec function. Save the last argument, @@ -8841,19 +8210,20 @@ compare_debug_dump_opt_spec_function (int arg, do_spec_2 ("%{fdump-final-insns=*:%*}"); do_spec_1 (" ", 0, NULL); - if (argbuf_index > 0 && strcmp (argv[argbuf_index - 1], ".")) + if (VEC_length (const_char_p, argbuf) > 0 + && strcmp (argv[VEC_length (const_char_p, argbuf) - 1], ".")) { if (!compare_debug) return NULL; - name = xstrdup (argv[argbuf_index - 1]); + name = xstrdup (argv[VEC_length (const_char_p, argbuf) - 1]); ret = NULL; } else { const char *ext = NULL; - if (argbuf_index > 0) + if (VEC_length (const_char_p, argbuf) > 0) { do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}"); ext = ".gkd"; @@ -8865,9 +8235,9 @@ compare_debug_dump_opt_spec_function (int arg, do_spec_1 (" ", 0, NULL); - gcc_assert (argbuf_index > 0); + gcc_assert (VEC_length (const_char_p, argbuf) > 0); - name = concat (argbuf[argbuf_index - 1], ext, NULL); + name = concat (VEC_last (const_char_p, argbuf), ext, NULL); ret = concat ("-fdump-final-insns=", name, NULL); } @@ -8877,7 +8247,7 @@ compare_debug_dump_opt_spec_function (int arg, 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); } @@ -8911,9 +8281,9 @@ compare_debug_self_opt_spec_function (int arg, do_spec_2 ("%{c|S:%{o*:%*}}"); do_spec_1 (" ", 0, NULL); - if (argbuf_index > 0) + if (VEC_length (const_char_p, argbuf) > 0) debug_auxbase_opt = concat ("-auxbase-strip ", - argbuf[argbuf_index - 1], + VEC_last (const_char_p, argbuf), NULL); else debug_auxbase_opt = NULL; @@ -8966,3 +8336,94 @@ compare_debug_auxbase_opt_spec_function (int arg, return name; } + +/* %:pass-through-libs spec function. Finds all -l options and input + file names in the lib spec passed to it, and makes a list of them + prepended with the plugin option to cause them to be passed through + to the final link after all the new object files have been added. */ + +const char * +pass_through_libs_spec_func (int argc, const char **argv) +{ + char *prepended = xstrdup (" "); + int n; + /* Shlemiel the painter's algorithm. Innately horrible, but at least + we know that there will never be more than a handful of strings to + concat, and it's only once per run, so it's not worth optimising. */ + for (n = 0; n < argc; n++) + { + char *old = prepended; + /* Anything that isn't an option is a full path to an output + file; pass it through if it ends in '.a'. Among options, + pass only -l. */ + if (argv[n][0] == '-' && argv[n][1] == 'l') + { + const char *lopt = argv[n] + 2; + /* Handle both joined and non-joined -l options. If for any + reason there's a trailing -l with no joined or following + arg just discard it. */ + if (!*lopt && ++n >= argc) + break; + else if (!*lopt) + lopt = argv[n]; + prepended = concat (prepended, "-plugin-opt=-pass-through=-l", + lopt, " ", NULL); + } + else if (!strcmp (".a", argv[n] + strlen (argv[n]) - 2)) + { + prepended = concat (prepended, "-plugin-opt=-pass-through=", + argv[n], " ", NULL); + } + if (prepended != old) + free (old); + } + return prepended; +} + +/* 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; +}