X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fgcc.c;h=2e219d614e9c9f104ab4d1cfbd209ae7e2d21738;hp=9168a3423d033b0dc7ec49143ffe6607e5a6b4d5;hb=15b28e16a2534a62ad2dcc82624368b66efb6598;hpb=0b09525fe1a511596c389a7094c6cb1b0b281339;ds=sidebyside diff --git a/gcc/gcc.c b/gcc/gcc.c index 9168a3423d0..2e219d614e9 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -1,6 +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 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -84,6 +85,18 @@ compilation is specified by a string called a "spec". */ #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 + /* By default there is no special suffix for target executables. */ /* FIXME: when autoconf is fixed, remove the host check - dj */ #if defined(TARGET_EXECUTABLE_SUFFIX) && defined(HOST_EXECUTABLE_SUFFIX) @@ -198,6 +211,10 @@ static int print_subprocess_help; static int report_times; +/* Whether we should report subprocess execution times to a file. */ + +FILE *report_times_to_file = NULL; + /* Nonzero means place this string before uses of /, so that include and library files can be found in an alternate location. */ @@ -387,6 +404,9 @@ static const char *replace_outfile_spec_function (int, const char **); static const char *version_compare_spec_function (int, const char **); static const char *include_spec_function (int, const char **); static const char *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 **); /* The Specs Language @@ -408,7 +428,7 @@ or with constant text in a single argument. %b substitute the basename of the input file being processed. This is the substring up to (and not including) the last period and not including the directory unless -save-temps was specified - to put temporaries in a different location. + to put temporaries in a different location. %B same as %b, but include the file suffix (text after the last period). %gSUFFIX substitute a file name that has suffix SUFFIX and is chosen @@ -545,7 +565,7 @@ or with constant text in a single argument. %{!.S:X} substitutes X, if NOT processing a file with suffix S. %{,S:X} substitutes X, if processing a file which will use spec S. %{!,S:X} substitutes X, if NOT processing a file which will use spec S. - + %{S|T:X} substitutes X if either -S or -T was given to GCC. This may be combined with '!', '.', ',', and '*' as above binding stronger than the OR. @@ -665,9 +685,15 @@ proper position among the other output files. */ #endif /* config.h can define SWITCHES_NEED_SPACES to control which options - require spaces between the option and the argument. */ + require spaces between the option and the argument. + + We define SWITCHES_NEED_SPACES to include "o" by default. This + causes "-ofoo.o" to be split into "-o foo.o" during the initial + processing of the command-line, before being seen by the specs + machinery. This makes sure we record "foo.o" as the temporary file + to be deleted in the case of error, rather than "-ofoo.o". */ #ifndef SWITCHES_NEED_SPACES -#define SWITCHES_NEED_SPACES "" +#define SWITCHES_NEED_SPACES "o" #endif /* config.h can define ENDFILE_SPEC to override the default crtn files. */ @@ -745,10 +771,26 @@ 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 + to understand them. In practice, this means it had better be collect2. */ #ifndef LINK_COMMAND_SPEC #define LINK_COMMAND_SPEC "\ %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\ - %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\ + %(linker) \ + %{fuse-linker-plugin: \ + -plugin %(linker_plugin_file) \ + -plugin-opt=%(lto_wrapper) \ + -plugin-opt=%(lto_gcc) \ + %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)} \ + %{static:-plugin-opt=-pass-through=-lc} \ + %{O*:-plugin-opt=-O%*} \ + %{w:-plugin-opt=-w} \ + %{f*:-plugin-opt=-f%*} \ + %{m*:-plugin-opt=-m%*} \ + %{v:-plugin-opt=-v} \ + } \ + %{flto} %{fwhopr} %l " LINK_PIE_SPEC \ + "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\ %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\ %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\ %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\ @@ -796,6 +838,10 @@ static const char *endfile_spec = ENDFILE_SPEC; static const char *startfile_spec = STARTFILE_SPEC; static const char *switches_need_spaces = SWITCHES_NEED_SPACES; static const char *linker_name_spec = LINKER_NAME; +static const char *linker_plugin_file_spec = ""; +static const char *lto_wrapper_spec = ""; +static const char *lto_gcc_spec = ""; +static const char *lto_libgcc_spec = ""; static const char *link_command_spec = LINK_COMMAND_SPEC; static const char *link_libgcc_spec = LINK_LIBGCC_SPEC; static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC; @@ -848,8 +894,9 @@ static const char *cpp_debug_options = "%{d*}"; /* NB: This is shared amongst all front-ends, except for Ada. */ static const char *cc1_options = "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ - %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\ - %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}}\ + %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{a*}\ + %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \ + %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \ %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\ %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\ %{Qn:-fno-ident} %{--help:--help}\ @@ -871,9 +918,15 @@ static const char *asm_options = static const char *invoke_as = #ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT -"%{!S:-o %|.s |\n as %(asm_options) %|.s %A }"; +"%{!fwpa:\ + %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\ + %{!S:-o %|.s |\n as %(asm_options) %|.s %A }\ + }"; #else -"%{!S:-o %|.s |\n as %(asm_options) %m.s %A }"; +"%{!fwpa:\ + %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\ + %{!S:-o %|.s |\n as %(asm_options) %m.s %A }\ + }"; #endif /* Some compilers have limits on line lengths, and the multilib_select @@ -904,7 +957,8 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS; #endif static const char *const driver_self_specs[] = { - DRIVER_SELF_SPECS, GOMP_SELF_SPECS + "%{fdump-final-insns:-fdump-final-insns=.} %system_microseconds / 1.0e6); if (ut + st != 0) - notice ("# %s %.2f %.2f\n", commands[i].prog, ut, st); + { + if (report_times) + notice ("# %s %.2f %.2f\n", commands[i].prog, ut, st); + + if (report_times_to_file) + { + int c = 0; + const char *const *j; + + fprintf (report_times_to_file, "%g %g", ut, st); + + for (j = &commands[i].prog; *j; j = &commands[i].argv[++c]) + { + const char *p; + for (p = *j; *p; ++p) + if (*p == '"' || *p == '\\' || *p == '$' + || ISSPACE (*p)) + break; + + if (*p) + { + fprintf (report_times_to_file, " \""); + for (p = *j; *p; ++p) + { + if (*p == '"' || *p == '\\' || *p == '$') + fputc ('\\', report_times_to_file); + fputc (*p, report_times_to_file); + } + fputc ('"', report_times_to_file); + } + else + fprintf (report_times_to_file, " %s", *j); + } + + fputc ('\n', report_times_to_file); + } + } } } @@ -3135,12 +3233,15 @@ See %s for instructions.", SWITCH_LIVE to indicate this switch is true in a conditional spec. SWITCH_FALSE to indicate this switch is overridden by a later switch. SWITCH_IGNORE to indicate this switch should be ignored (used in % Do not delete intermediate files\n"), stdout); + fputs (_("\ + -no-canonical-prefixes Do not canonicalize paths when building relative\n\ + prefixes to other gcc components\n"), stdout); fputs (_(" -pipe Use pipes rather than intermediate files\n"), stdout); fputs (_(" -time Time the execution of each subprocess\n"), stdout); fputs (_(" -specs= Override built-in specs with the contents of \n"), stdout); @@ -3355,7 +3482,7 @@ add_linker_option (const char *option, int len) if (! linker_options) linker_options = XNEWVEC (char *, n_linker_options); else - linker_options = XRESIZEVEC (char *, linker_options, n_linker_options); + linker_options = XRESIZEVEC (char *, linker_options, n_linker_options); linker_options [n_linker_options - 1] = save_string (option, len); } @@ -3377,6 +3504,8 @@ process_command (int argc, const char **argv) unsigned int j; #endif const char *tooldir_prefix; + char *(*get_relative_prefix) (const char *, const char *, + const char *) = NULL; GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX"); @@ -3472,6 +3601,26 @@ process_command (int argc, const char **argv) exit (status); } + /* Convert new-style -- options to old-style. */ + translate_options (&argc, + CONST_CAST2 (const char *const **, const char ***, + &argv)); + + /* Handle any -no-canonical-prefixes flag early, to assign the function + that builds relative prefixes. This function creates default search + paths that are needed later in normal option handling. */ + + for (i = 1; i < argc; i++) + { + if (! strcmp (argv[i], "-no-canonical-prefixes")) + { + get_relative_prefix = make_relative_prefix_ignore_links; + break; + } + } + if (! get_relative_prefix) + get_relative_prefix = make_relative_prefix; + /* Set up the default search paths. If there is no GCC_EXEC_PREFIX, see if we can create it from the pathname specified in argv[0]. */ @@ -3480,11 +3629,12 @@ process_command (int argc, const char **argv) /* FIXME: make_relative_prefix doesn't yet work for VMS. */ if (!gcc_exec_prefix) { - gcc_exec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix, - standard_exec_prefix); - gcc_libexec_prefix = make_relative_prefix (argv[0], - standard_bindir_prefix, - standard_libexec_prefix); + gcc_exec_prefix = get_relative_prefix (argv[0], + standard_bindir_prefix, + standard_exec_prefix); + gcc_libexec_prefix = get_relative_prefix (argv[0], + standard_bindir_prefix, + standard_libexec_prefix); if (gcc_exec_prefix) xputenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL)); } @@ -3495,9 +3645,9 @@ process_command (int argc, const char **argv) / (which is ignored by make_relative_prefix), so append a program name. */ char *tmp_prefix = concat (gcc_exec_prefix, "gcc", NULL); - gcc_libexec_prefix = make_relative_prefix (tmp_prefix, - standard_exec_prefix, - standard_libexec_prefix); + gcc_libexec_prefix = get_relative_prefix (tmp_prefix, + standard_exec_prefix, + standard_libexec_prefix); /* The path is unrelocated, so fallback to the original setting. */ if (!gcc_libexec_prefix) @@ -3511,6 +3661,12 @@ process_command (int argc, const char **argv) is relocated. The toolchain was either relocated using GCC_EXEC_PREFIX or an automatically created GCC_EXEC_PREFIX from argv[0]. */ + /* Do language-specific adjustment/addition of flags. */ + lang_specific_driver (&argc, + CONST_CAST2 (const char *const **, const char ***, + &argv), + &added_libraries); + if (gcc_exec_prefix) { int len = strlen (gcc_exec_prefix); @@ -3635,12 +3791,6 @@ process_command (int argc, const char **argv) } } - /* Convert new-style -- options to old-style. */ - translate_options (&argc, (const char *const **) &argv); - - /* Do language-specific adjustment/addition of flags. */ - lang_specific_driver (&argc, (const char *const **) &argv, &added_libraries); - /* Scan argv twice. Here, the first time, just count how many switches there will be in their vector, and how many input files in theirs. Here we also parse the switches that cc itself uses (e.g. -v). */ @@ -3744,6 +3894,38 @@ process_command (int argc, const char **argv) 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; @@ -3836,6 +4018,9 @@ process_command (int argc, const char **argv) else fatal ("'%s' is an unknown -save-temps option", argv[i]); } + else if (strcmp (argv[i], "-no-canonical-prefixes") == 0) + /* Already handled as a special case, so ignored here. */ + ; else if (strcmp (argv[i], "-combine") == 0) { combine_flag = 1; @@ -3871,6 +4056,12 @@ process_command (int argc, const char **argv) } else if (strcmp (argv[i], "-time") == 0) report_times = 1; + else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0) + { + if (report_times_to_file) + fclose (report_times_to_file); + report_times_to_file = fopen (argv[i] + sizeof ("-time=") - 1, "a"); + } else if (strcmp (argv[i], "-pipe") == 0) { /* -pipe has to go into the switches array as well as @@ -3964,6 +4155,7 @@ process_command (int argc, const char **argv) case 'S': case 'c': + case 'E': if (p[1] == 0) { have_c = 1; @@ -3979,7 +4171,7 @@ process_command (int argc, const char **argv) { int skip; - /* Forward scan, just in case -S or -c is specified + /* Forward scan, just in case -S, -E or -c is specified after -o. */ int j = i + 1; if (p[1] == 0) @@ -4010,7 +4202,10 @@ process_command (int argc, const char **argv) argv[i] = convert_filename (argv[i], ! have_c, 0); #endif /* Save the output name in case -save-temps=obj was used. */ - save_temps_prefix = xstrdup ((p[1] == 0) ? argv[i + 1] : argv[i] + 1); + if ((p[1] == 0) && argv[i + 1]) + save_temps_prefix = xstrdup(argv[i + 1]); + else + save_temps_prefix = xstrdup(argv[i] + 1); goto normal_switch; default: @@ -4095,10 +4290,33 @@ process_command (int argc, const char **argv) use_pipes = 0; } + if (!compare_debug) + { + const char *gcd = getenv ("GCC_COMPARE_DEBUG"); + + if (gcd && gcd[0] == '-') + { + compare_debug = 2; + compare_debug_opt = gcd; + n_switches++; + } + else if (gcd && *gcd && strcmp (gcd, "0")) + { + compare_debug = 3; + compare_debug_opt = "-gtoggle"; + n_switches++; + } + } + else if (compare_debug < 0) + { + compare_debug = 0; + gcc_assert (!compare_debug_opt); + } + /* Set up the search paths. We add directories that we expect to contain GNU Toolchain components before directories specified by the machine description so that we will find GNU components (like - the GNU assembler) before those of the host system. */ + the GNU assembler) before those of the host system. */ /* If we don't know where the toolchain has been installed, use the configured-in locations. */ @@ -4116,19 +4334,6 @@ process_command (int argc, const char **argv) PREFIX_PRIORITY_LAST, 1, 0); } - /* If not cross-compiling, search well-known system locations. */ - if (*cross_compile == '0') - { -#ifndef OS2 - add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS", - PREFIX_PRIORITY_LAST, 2, 0); - add_prefix (&exec_prefixes, standard_exec_prefix_2, "BINUTILS", - PREFIX_PRIORITY_LAST, 2, 0); -#endif - add_prefix (&startfile_prefixes, standard_exec_prefix_2, "BINUTILS", - PREFIX_PRIORITY_LAST, 1, 0); - } - gcc_assert (!IS_ABSOLUTE_PATH (tooldir_base_prefix)); tooldir_prefix = concat (tooldir_base_prefix, spec_machine, dir_separator_str, NULL); @@ -4154,9 +4359,9 @@ process_command (int argc, const char **argv) ``make_relative_prefix'' is not compiled for VMS, so don't call it. */ if (target_system_root && gcc_exec_prefix) { - char *tmp_prefix = make_relative_prefix (argv[0], - standard_bindir_prefix, - target_system_root); + char *tmp_prefix = get_relative_prefix (argv[0], + standard_bindir_prefix, + target_system_root); if (tmp_prefix && access_check (tmp_prefix, F_OK) == 0) { target_system_root = tmp_prefix; @@ -4198,6 +4403,8 @@ process_command (int argc, const char **argv) ; 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")) @@ -4283,6 +4490,8 @@ process_command (int argc, const char **argv) ; 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) @@ -4366,26 +4575,51 @@ process_command (int argc, const char **argv) } else { + const char *p = strchr (argv[i], '@'); + char *fname; #ifdef HAVE_TARGET_OBJECT_SUFFIX argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK)); #endif + if (!p) + fname = xstrdup (argv[i]); + else + { + fname = (char *)xmalloc (p - argv[i] + 1); + memcpy (fname, argv[i], p - argv[i]); + fname[p - argv[i]] = '\0'; + } + + if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0) + { + perror_with_name (fname); + error_count++; + } + else + { + infiles[n_infiles].language = spec_lang; + infiles[n_infiles++].name = argv[i]; + } - if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0) - { - perror_with_name (argv[i]); - error_count++; - } - else - { - infiles[n_infiles].language = spec_lang; - infiles[n_infiles++].name = argv[i]; - } + free (fname); } } if (n_infiles == last_language_n_infiles && spec_lang != 0) error ("warning: '-x %s' after last input file has no effect", spec_lang); + if (compare_debug == 2 || compare_debug == 3) + { + switches[n_switches].part1 = concat ("fcompare-debug=", + compare_debug_opt, + NULL); + switches[n_switches].args = 0; + switches[n_switches].live_cond = 0; + switches[n_switches].validated = 0; + switches[n_switches].ordering = 0; + n_switches++; + compare_debug = 1; + } + /* Ensure we only invoke each subprocess once. */ if (print_subprocess_help || print_help_list || print_version) { @@ -4501,6 +4735,13 @@ static int this_is_output_file; search dirs for it. */ static int this_is_library_file; +/* Nonzero means %T has been seen; the next arg to be terminated + is the name of a linker script and we should try all of the + standard search dirs for it. If it is found insert a --script + command line switch and then substitute the full path in place, + otherwise generate an error message. */ +static int this_is_linker_script; + /* Nonzero means that the input of this command is coming from a pipe. */ static int input_from_pipe; @@ -4521,6 +4762,19 @@ end_going_arg (void) string = XOBFINISH (&obstack, const char *); if (this_is_library_file) string = find_file (string); + if (this_is_linker_script) + { + char * full_script_path = find_a_file (&startfile_prefixes, string, R_OK, true); + + if (full_script_path == NULL) + { + error (_("unable to locate default linker script '%s' in the library search paths"), string); + /* Script was not found on search path. */ + return; + } + store_arg ("--script", false, false); + string = full_script_path; + } store_arg (string, delete_this_arg, this_is_output_file); if (this_is_output_file) outfiles[input_file_number] = string; @@ -4610,6 +4864,7 @@ do_spec_2 (const char *spec) delete_this_arg = 0; this_is_output_file = 0; this_is_library_file = 0; + this_is_linker_script = 0; input_from_pipe = 0; suffix_subst = NULL; @@ -4676,33 +4931,81 @@ do_option_spec (const char *name, const char *spec) static void do_self_spec (const char *spec) { + int i; + do_spec_2 (spec); do_spec_1 (" ", 0, NULL); + /* Mark % 0) { - int i, first; + switches = XRESIZEVEC (struct switchstr, switches, + n_switches + argbuf_index + 1); - first = n_switches; - n_switches += argbuf_index; - switches = XRESIZEVEC (struct switchstr, switches, n_switches + 1); - - switches[n_switches] = switches[first]; for (i = 0; i < argbuf_index; i++) { struct switchstr *sw; + const char *p = argbuf[i]; + int c = *p; /* Each switch should start with '-'. */ - if (argbuf[i][0] != '-') + if (c != '-') fatal ("switch '%s' does not start with '-'", argbuf[i]); - sw = &switches[i + first]; - sw->part1 = &argbuf[i][1]; - sw->args = 0; + p++; + c = *p; + + sw = &switches[n_switches++]; + sw->part1 = p; sw->live_cond = 0; sw->validated = 0; sw->ordering = 0; + + /* Deal with option arguments in separate argv elements. */ + if ((SWITCH_TAKES_ARG (c) > (p[1] != 0)) + || WORD_SWITCH_TAKES_ARG (p)) + { + int j = 0; + int n_args = WORD_SWITCH_TAKES_ARG (p); + + if (n_args == 0) + { + /* Count only the option arguments in separate argv elements. */ + n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0); + } + if (i + n_args >= argbuf_index) + fatal ("argument to '-%s' is missing", p); + sw->args + = XNEWVEC (const char *, n_args + 1); + while (j < n_args) + sw->args[j++] = argbuf[++i]; + /* Null-terminate the vector. */ + sw->args[j] = 0; + } + else if (strchr (switches_need_spaces, c)) + { + /* On some systems, ld cannot handle some options without + a space. So split the option from its argument. */ + char *part1 = XNEWVEC (char, 2); + part1[0] = c; + part1[1] = '\0'; + + sw->part1 = part1; + sw->args = XNEWVEC (const char *, 2); + sw->args[0] = xstrdup (p+1); + sw->args[1] = 0; + } + else + sw->args = 0; } + + switches[n_switches].part1 = 0; } } @@ -4856,6 +5159,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) delete_this_arg = 0; this_is_output_file = 0; this_is_library_file = 0; + this_is_linker_script = 0; input_from_pipe = 0; break; @@ -4875,6 +5179,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) delete_this_arg = 0; this_is_output_file = 0; this_is_library_file = 0; + this_is_linker_script = 0; break; case '%': @@ -4888,6 +5193,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) obstack_grow (&obstack, save_temps_prefix, save_temps_length); else obstack_grow (&obstack, input_basename, basename_length); + if (compare_debug < 0) + obstack_grow (&obstack, ".gk", 3); arg_going = 1; break; @@ -4896,6 +5203,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) obstack_grow (&obstack, save_temps_prefix, save_temps_length); else obstack_grow (&obstack, input_basename, suffixed_basename_length); + if (compare_debug < 0) + obstack_grow (&obstack, ".gk", 3); arg_going = 1; break; @@ -4939,7 +5248,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) buf = (char *) alloca (p - q + 1); strncpy (buf, q, p - q); buf[p - q] = 0; - error ("%s", buf); + error ("%s", _(buf)); return -1; } break; @@ -4953,7 +5262,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) buf = (char *) alloca (p - q + 1); strncpy (buf, q, p - q); buf[p - q] = 0; - notice ("%s\n", buf); + notice ("%s\n", _(buf)); if (*p) p++; } @@ -5041,6 +5350,12 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) suffix_length += strlen (TARGET_OBJECT_SUFFIX); } + if (compare_debug < 0) + { + suffix = concat (".gk", suffix, NULL); + suffix_length += 3; + } + /* If -save-temps=obj and -o were specified, use that for the temp file. */ if (save_temps_length) @@ -5312,6 +5627,10 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) this_is_library_file = 1; break; + case 'T': + this_is_linker_script = 1; + break; + case 'V': outfiles[input_file_number] = NULL; break; @@ -5686,6 +6005,7 @@ eval_spec_function (const char *func, const char *args) int save_this_is_output_file; int save_this_is_library_file; int save_input_from_pipe; + int save_this_is_linker_script; const char *save_suffix_subst; @@ -5702,6 +6022,7 @@ eval_spec_function (const char *func, const char *args) save_delete_this_arg = delete_this_arg; save_this_is_output_file = this_is_output_file; save_this_is_library_file = this_is_library_file; + save_this_is_linker_script = this_is_linker_script; save_input_from_pipe = input_from_pipe; save_suffix_subst = suffix_subst; @@ -5727,6 +6048,7 @@ eval_spec_function (const char *func, const char *args) delete_this_arg = save_delete_this_arg; this_is_output_file = save_this_is_output_file; this_is_library_file = save_this_is_library_file; + this_is_linker_script = save_this_is_linker_script; input_from_pipe = save_input_from_pipe; suffix_subst = save_suffix_subst; @@ -5957,7 +6279,7 @@ handle_braces (const char *p) if (atom == end_atom) { if (!n_way_choice || disj_matched || *p == '|' - || a_is_negated || a_is_suffix || a_is_spectype + || a_is_negated || a_is_suffix || a_is_spectype || a_is_starred) goto invalid; @@ -5971,7 +6293,7 @@ handle_braces (const char *p) { if ((a_is_suffix || a_is_spectype) && a_is_starred) goto invalid; - + if (!a_is_starred) disj_starred = false; @@ -5985,7 +6307,7 @@ handle_braces (const char *p) a_matched = input_spec_matches (atom, end_atom); else a_matched = switch_matches (atom, end_atom, a_is_starred); - + if (a_matched != a_is_negated) { disj_matched = true; @@ -6131,18 +6453,20 @@ check_live_switch (int switchnum, int prefix_length) const char *name = switches[switchnum].part1; int i; + /* If we already processed this switch and determined if it was + live or not, return our past determination. */ + if (switches[switchnum].live_cond != 0) + return ((switches[switchnum].live_cond & SWITCH_LIVE) != 0 + && (switches[switchnum].live_cond & SWITCH_FALSE) == 0 + && (switches[switchnum].live_cond & SWITCH_IGNORE_PERMANENTLY) + == 0); + /* In the common case of {*}, a negating switch would always match, so ignore that case. We will just send the conflicting switches to the compiler phase. */ if (prefix_length >= 0 && prefix_length <= 1) return 1; - /* If we already processed this switch and determined if it was - live or not, return our past determination. */ - if (switches[switchnum].live_cond != 0) - return ((switches[switchnum].live_cond & SWITCH_LIVE) != 0 - && (switches[switchnum].live_cond & SWITCH_FALSE) == 0); - /* Now search for duplicate in a manner that depends on the name. */ switch (*name) { @@ -6339,6 +6663,125 @@ fatal_error (int signum) kill (getpid (), signum); } +/* Compare the contents of the two files named CMPFILE[0] and + CMPFILE[1]. Return zero if they're identical, nonzero + otherwise. */ + +static int +compare_files (char *cmpfile[]) +{ + int ret = 0; + FILE *temp[2] = { NULL, NULL }; + int i; + +#if HAVE_MMAP_FILE + { + size_t length[2]; + void *map[2] = { NULL, NULL }; + + for (i = 0; i < 2; i++) + { + struct stat st; + + if (stat (cmpfile[i], &st) < 0 || !S_ISREG (st.st_mode)) + { + error ("%s: could not determine length of compare-debug file %s", + input_filename, cmpfile[i]); + ret = 1; + break; + } + + length[i] = st.st_size; + } + + if (!ret && length[0] != length[1]) + { + error ("%s: -fcompare-debug failure (length)", input_filename); + ret = 1; + } + + if (!ret) + for (i = 0; i < 2; i++) + { + int fd = open (cmpfile[i], O_RDONLY); + if (fd < 0) + { + error ("%s: could not open compare-debug file %s", + input_filename, cmpfile[i]); + ret = 1; + break; + } + + map[i] = mmap (NULL, length[i], PROT_READ, MAP_PRIVATE, fd, 0); + close (fd); + + if (map[i] == (void *) MAP_FAILED) + { + ret = -1; + break; + } + } + + if (!ret) + { + if (memcmp (map[0], map[1], length[0]) != 0) + { + error ("%s: -fcompare-debug failure", input_filename); + ret = 1; + } + } + + for (i = 0; i < 2; i++) + if (map[i]) + munmap ((caddr_t) map[i], length[i]); + + if (ret >= 0) + return ret; + + ret = 0; + } +#endif + + for (i = 0; i < 2; i++) + { + temp[i] = fopen (cmpfile[i], "r"); + if (!temp[i]) + { + error ("%s: could not open compare-debug file %s", + input_filename, cmpfile[i]); + ret = 1; + break; + } + } + + if (!ret && temp[0] && temp[1]) + for (;;) + { + int c0, c1; + c0 = fgetc (temp[0]); + c1 = fgetc (temp[1]); + + if (c0 != c1) + { + error ("%s: -fcompare-debug failure", + input_filename); + ret = 1; + break; + } + + if (c0 == EOF) + break; + } + + for (i = 1; i >= 0; i--) + { + if (temp[i]) + fclose (temp[i]); + } + + return ret; +} + extern int main (int, char **); int @@ -6449,14 +6892,6 @@ main (int argc, char **argv) multilib_defaults = XOBFINISH (&multilib_obstack, const char *); } - /* Set up to remember the pathname of gcc and any options - needed for collect. We use argv[0] instead of programname because - we need the complete pathname. */ - obstack_init (&collect_obstack); - obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1); - obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1); - xputenv (XOBFINISH (&collect_obstack, char *)); - #ifdef INIT_ENVIRONMENT /* Set up any other necessary machine specific environment variables. */ xputenv (INIT_ENVIRONMENT); @@ -6466,7 +6901,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 char **) argv); + process_command (argc, CONST_CAST2 (const char **, char **, argv)); /* Initialize the vector of specs to just the default. This means one element containing 0s, as a terminator. */ @@ -6511,6 +6946,43 @@ 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') @@ -6591,9 +7063,9 @@ main (int argc, char **argv) else if (*cross_compile == '0') { add_prefix (&startfile_prefixes, - concat (gcc_exec_prefix - ? gcc_exec_prefix : standard_exec_prefix, - machine_suffix, + concat (gcc_exec_prefix + ? gcc_exec_prefix : standard_exec_prefix, + machine_suffix, standard_startfile_prefix, NULL), NULL, PREFIX_PRIORITY_LAST, 0, 1); } @@ -6633,6 +7105,27 @@ main (int argc, char **argv) the subdirectory based on the options. */ set_multilib_dir (); + /* Set up to remember the pathname of gcc and any options + needed for collect. We use argv[0] instead of programname because + we need the complete pathname. */ + obstack_init (&collect_obstack); + obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1); + obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1); + xputenv (XOBFINISH (&collect_obstack, char *)); + + /* Set up to remember the pathname of the lto wrapper. */ + + lto_wrapper_spec = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false); + if (lto_wrapper_spec) + { + obstack_init (&collect_obstack); + obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=", + sizeof ("COLLECT_LTO_WRAPPER=") - 1); + obstack_grow (&collect_obstack, lto_wrapper_spec, + strlen (lto_wrapper_spec) + 1); + xputenv (XOBFINISH (&collect_obstack, char *)); + } + /* Warn about any switches that no pass was interested in. */ for (i = 0; (int) i < n_switches; i++) @@ -6741,7 +7234,7 @@ main (int argc, char **argv) { printf (_("%s %s%s\n"), programname, pkgversion_string, version_string); - printf ("Copyright %s 2009 Free Software Foundation, Inc.\n", + printf ("Copyright %s 2010 Free Software Foundation, Inc.\n", _("(C)")); fputs (_("This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"), @@ -6845,7 +7338,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 ("cannot specify -o with -c or -S with multiple files"); + fatal ("cannot specify -o with -c, -S or -E with multiple files"); if (combine_flag && save_temps_flag) { @@ -6939,10 +7432,63 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } else { + if (compare_debug) + { + if (debug_check_temp_file[0]) + free (debug_check_temp_file[0]); + debug_check_temp_file[0] = NULL; + + if (debug_check_temp_file[1]) + free (debug_check_temp_file[1]); + debug_check_temp_file[1] = NULL; + } + value = do_spec (input_file_compiler->spec); infiles[i].compiled = true; if (value < 0) this_file_error = 1; + else if (compare_debug && debug_check_temp_file[0]) + { + if (verbose_flag) + error ("Recompiling with -fcompare-debug"); + + compare_debug = -compare_debug; + n_switches = n_switches_debug_check[1]; + switches = switches_debug_check[1]; + + value = do_spec (input_file_compiler->spec); + + compare_debug = -compare_debug; + n_switches = n_switches_debug_check[0]; + switches = switches_debug_check[0]; + + if (value < 0) + { + error ("during -fcompare-debug recompilation"); + this_file_error = 1; + } + + gcc_assert (debug_check_temp_file[1] + && strcmp (debug_check_temp_file[0], + debug_check_temp_file[1])); + + if (verbose_flag) + error ("Comparing final insns dumps"); + + if (compare_files (debug_check_temp_file)) + this_file_error = 1; + } + + if (compare_debug) + { + if (debug_check_temp_file[0]) + free (debug_check_temp_file[0]); + debug_check_temp_file[0] = NULL; + + if (debug_check_temp_file[1]) + free (debug_check_temp_file[1]); + debug_check_temp_file[1] = NULL; + } } } @@ -7000,6 +7546,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (num_linker_inputs > 0 && error_count == 0 && print_subprocess_help < 2) { int tmp = execution_count; + const char *fuse_linker_plugin = "fuse-linker-plugin"; /* We'll use ld if we can't find collect2. */ if (! strcmp (linker_name_spec, "collect2")) @@ -7008,6 +7555,23 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (s == NULL) linker_name_spec = "ld"; } + + if (switch_matches (fuse_linker_plugin, + fuse_linker_plugin + strlen (fuse_linker_plugin), 0)) + { + linker_plugin_file_spec = find_a_file (&exec_prefixes, + "liblto_plugin.so", X_OK, + false); + if (!linker_plugin_file_spec) + fatal ("-fuse-linker-plugin, but liblto_plugin.so not found"); + + lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a", + R_OK, true); + if (!lto_libgcc_spec) + fatal ("could not find libgcc.a"); + } + lto_gcc_spec = argv[0]; + /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */ putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false); @@ -8015,9 +8579,9 @@ getenv_spec_function (int argc, const char **argv) ptr[0] = '\\'; ptr[1] = *value++; } - + strcpy (ptr, argv[1]); - + return result; } @@ -8227,3 +8791,174 @@ print_asm_header_spec_function (int arg ATTRIBUTE_UNUSED, fflush (stdout); return NULL; } + +/* Compute a timestamp to initialize flag_random_seed. */ + +static unsigned +get_local_tick (void) +{ + unsigned ret = 0; + + /* Get some more or less random data. */ +#ifdef HAVE_GETTIMEOFDAY + { + struct timeval tv; + + gettimeofday (&tv, NULL); + ret = tv.tv_sec * 1000 + tv.tv_usec / 1000; + } +#else + { + time_t now = time (NULL); + + if (now != (time_t)-1) + ret = (unsigned) now; + } +#endif + + return ret; +} + +/* %:compare-debug-dump-opt spec function. Save the last argument, + expected to be the last -fdump-final-insns option, or generate a + temporary. */ + +static const char * +compare_debug_dump_opt_spec_function (int arg, + const char **argv ATTRIBUTE_UNUSED) +{ + const char *ret; + char *name; + int which; + static char random_seed[HOST_BITS_PER_WIDE_INT / 4 + 3]; + + if (arg != 0) + fatal ("too many arguments to %%:compare-debug-dump-opt"); + + do_spec_2 ("%{fdump-final-insns=*:%*}"); + do_spec_1 (" ", 0, NULL); + + if (argbuf_index > 0 && strcmp (argv[argbuf_index - 1], ".")) + { + if (!compare_debug) + return NULL; + + name = xstrdup (argv[argbuf_index - 1]); + ret = NULL; + } + else + { + const char *ext = NULL; + + if (argbuf_index > 0) + { + do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}"); + ext = ".gkd"; + } + else if (!compare_debug) + return NULL; + else + do_spec_2 ("%g.gkd"); + + do_spec_1 (" ", 0, NULL); + + gcc_assert (argbuf_index > 0); + + name = concat (argbuf[argbuf_index - 1], ext, NULL); + + ret = concat ("-fdump-final-insns=", name, NULL); + } + + which = compare_debug < 0; + debug_check_temp_file[which] = name; + + if (!which) + { + unsigned HOST_WIDE_INT value = get_local_tick () ^ getpid (); + + sprintf (random_seed, HOST_WIDE_INT_PRINT_HEX, value); + } + + if (*random_seed) + ret = concat ("%{!frandom-seed=*:-frandom-seed=", random_seed, "} ", + ret, NULL); + + if (which) + *random_seed = 0; + + return ret; +} + +static const char *debug_auxbase_opt; + +/* %:compare-debug-self-opt spec function. Expands to the options + that are to be passed in the second compilation of + compare-debug. */ + +static const char * +compare_debug_self_opt_spec_function (int arg, + const char **argv ATTRIBUTE_UNUSED) +{ + if (arg != 0) + fatal ("too many arguments to %%:compare-debug-self-opt"); + + if (compare_debug >= 0) + return NULL; + + do_spec_2 ("%{c|S:%{o*:%*}}"); + do_spec_1 (" ", 0, NULL); + + if (argbuf_index > 0) + debug_auxbase_opt = concat ("-auxbase-strip ", + argbuf[argbuf_index - 1], + NULL); + else + debug_auxbase_opt = NULL; + + return concat ("\ +%= 0) + return NULL; + + len = strlen (argv[0]); + if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0) + fatal ("argument to %%:compare-debug-auxbase-opt does not end in .gk"); + + if (debug_auxbase_opt) + return debug_auxbase_opt; + +#define OPT "-auxbase " + + len -= 3; + name = (char*) xmalloc (sizeof (OPT) + len); + memcpy (name, OPT, sizeof (OPT) - 1); + memcpy (name + sizeof (OPT) - 1, argv[0], len); + name[sizeof (OPT) - 1 + len] = '\0'; + +#undef OPT + + return name; +}