aboutsummaryrefslogtreecommitdiff
path: root/gcc/gcc.c
diff options
context:
space:
mode:
authorAlexandre Oliva <oliva@adacore.com>2020-05-26 04:30:15 -0300
committerAlexandre Oliva <oliva@gnu.org>2020-05-26 04:30:15 -0300
commit1dedc12d186a110854537e1279b4e6c29f2df35a (patch)
treeb7d3f5e261169b8780d70b5a4c606258a81868f2 /gcc/gcc.c
parent4945b4c2c8628bdd61b348ea5bd1f9b72537a36e (diff)
downloadgcc-1dedc12d186a110854537e1279b4e6c29f2df35a.zip
gcc-1dedc12d186a110854537e1279b4e6c29f2df35a.tar.gz
gcc-1dedc12d186a110854537e1279b4e6c29f2df35a.tar.bz2
revamp dump and aux output names
This patch simplifies (!!!) the logic governing the naming of dump files and auxiliary output files in the driver, in the compiler, and in the LTO wrapper. No changes are made to the naming of primary outputs, there are often ways to restore past behavior, and a number of inconsistencies are fixed. Some internal options are removed (-auxbase and -auxbase-strip), sensible existing uses of -dumpdir and -dumpbase options remain unchanged, additional useful cases are added, making for what is still admittedly quite complex. Extensive documentation and testcases provide numerous examples, from normal to corner cases. The most visible changes are: - aux and dump files now always go in the same directory, that defaults to the directory of the primary output, but that can be overridden with -dumpdir, -save-temps=*, or, preserving past behavior, with a -dumpbase with a directory component. - driver and compiler now have the same notion of naming of auxiliary outputs, e.g. .dwo files will no longer be in one location while the debug info suggests they are elsewhere, and -save-temps and .dwo auxiliary outputs now go in the same location as .su, .ci and coverage data, with consistent naming. - explicitly-specified primary output names guide not only the location of aux and dump outputs: the output base name is also used in their base name, as a prefix when also linking (e.g. foo.c bar.c -o foobar creates foobar-foo.dwo and foobar-bar.dwo with -gsplit-dwarf), or as the base name instead of the input name (foo.c -c -o whatever.o creates whatever.su rather than foo.su with -fstack-usage). The preference for the input file base name, quite useful for our testsuite, can be restored with -dumpbase "". When compiling and linking tests in the testsuite with additional inputs, we now use this flag. Files named in dejagnu board ldflags, libs, and ldscripts are now quoted in the gcc testsuite with -Wl, so that they are not counted as additional inputs by the compiler driver. - naming a -dumpbase when compiling multiple sources used to cause dumps from later compiles to overwrite those of earlier ones; it is now used as a prefix when compiling multiple sources, like an executable name above. - the dumpbase, explicitly specified or computed from output or input names, now also governs the naming of aux outputs; since aux outputs usually replaced the suffix from the input name, while dump outputs append their own additional suffixes, a -dumpbase-ext option is introduced to enable a chosen suffix to be dropped from dumpbase to form aux output names. - LTO dump and aux outputs were quite a mess, sometimes leaking temporary output names into -save-temps output names, sometimes conversely generating desirable aux outputs in temporary locations. They now obey the same logic of compiler aux and dump outputs, landing in the expected location and taking the linker output name or an explicit dumpbase overrider into account. - Naming of -fdump-final-insns outputs now follows the dump file naming logic for the .gkd files, and the .gk dump files generated in the second -fcompare-debug compilation get the .gk inserted before the suffix that -dumpbase-ext drops in aux outputs. gcc/ChangeLog: * common.opt (aux_base_name): Define. (dumpbase, dumpdir): Mark as Driver options. (-dumpbase, -dumpdir): Likewise. (dumpbase-ext, -dumpbase-ext): New. (auxbase, auxbase-strip): Drop. * doc/invoke.texi (-dumpbase, -dumpbase-ext, -dumpdir): Document. (-o): Introduce the notion of primary output, mention it influences auxiliary and dump output names as well, add examples. (-save-temps): Adjust, move examples into -dump*. (-save-temps=cwd, -save-temps=obj): Likewise. (-fdump-final-insns): Adjust. * dwarf2out.c (gen_producer_string): Drop auxbase and auxbase_strip; add dumpbase_ext. * gcc.c (enum save_temps): Add SAVE_TEMPS_DUMP. (save_temps_prefix, save_temps_length): Drop. (save_temps_overrides_dumpdir): New. (dumpdir, dumpbase, dumpbase_ext): New. (dumpdir_length, dumpdir_trailing_dash_added): New. (outbase, outbase_length): New. (The Specs Language): Introduce %". Adjust %b and %B. (ASM_FINAL_SPEC): Use %b.dwo for an aux output name always. Precede object file with %w when it's the primary output. (cpp_debug_options): Do not pass on incoming -dumpdir, -dumpbase and -dumpbase-ext options; recompute them with %:dumps. (cc1_options): Drop auxbase with and without compare-debug; use cpp_debug_options instead of dumpbase. Mark asm output with %w when it's the primary output. (static_spec_functions): Drop %:compare-debug-auxbase-opt and %:replace-exception. Add %:dumps. (driver_handle_option): Implement -save-temps=*/-dumpdir mutual overriding logic. Save dumpdir, dumpbase and dumpbase-ext options. Do not save output_file in save_temps_prefix. (adds_single_suffix_p): New. (single_input_file_index): New. (process_command): Combine output dir, output base name, and dumpbase into dumpdir and outbase. (set_collect_gcc_options): Pass a possibly-adjusted -dumpdir. (do_spec_1): Optionally dumpdir instead of save_temps_prefix, and outbase instead of input_basename in %b, %B and in -save-temps aux files. Handle empty argument %". (driver::maybe_run_linker): Adjust dumpdir and auxbase. (compare_debug_dump_opt_spec_function): Adjust gkd dump file naming. Spec-quote the computed -fdump-final-insns file name. (debug_auxbase_opt): Drop. (compare_debug_self_opt_spec_function): Drop auxbase-strip computation. (compare_debug_auxbase_opt_spec_function): Drop. (not_actual_file_p): New. (replace_extension_spec_func): Drop. (dumps_spec_func): New. (convert_white_space): Split-out parts into... (quote_string, whitespace_to_convert_p): ... these. New. (quote_spec_char_p, quote_spec, quote_spec_arg): New. (driver::finalize): Release and reset new variables; drop removed ones. * lto-wrapper.c (HAVE_TARGET_EXECUTABLE_SUFFIX): Define if... (TARGET_EXECUTABLE_SUFFIX): ... is defined; define this to the empty string otherwise. (DUMPBASE_SUFFIX): Drop leading period. (debug_objcopy): Use concat. (run_gcc): Recognize -save-temps=* as -save-temps too. Obey -dumpdir. Pass on empty dumpdir and dumpbase with a directory component. Simplify temp file names. * opts.c (finish_options): Drop aux base name handling. (common_handle_option): Drop auxbase-strip handling. * toplev.c (print_switch_values): Drop auxbase, add dumpbase-ext. (process_options): Derive aux_base_name from dump_base_name and dump_base_ext. (lang_dependent_init): Compute dump_base_ext along with dump_base_name. Disable stack usage and callgraph-info during lto generation and compare-debug recompilation. gcc/fortran/ChangeLog: * options.c (gfc_get_option_string): Drop auxbase, add dumpbase_ext. gcc/ada/ChangeLog: * gcc-interface/lang-specs.h: Drop auxbase and auxbase-strip. Use %:dumps instead of -dumpbase. Add %w for implicit .s primary output. * switch.adb (Is_Internal_GCC_Switch): Recognize dumpdir and dumpbase-ext. Drop auxbase and auxbase-strip. lto-plugin/ChangeLog: * lto-plugin.c (skip_in_suffix): New. (exec_lto_wrapper): Use skip_in_suffix and concat to build non-temporary output names. (onload): Look for -dumpdir in COLLECT_GCC_OPTIONS, and override link_output_name with it. contrib/ChangeLog: * compare-debug: Adjust for .gkd files named as dump files, with the source suffix rather than the object suffix. gcc/testsuite/ChangeLog: * gcc.misc-tests/outputs.exp: New. * gcc.misc-tests/outputs-0.c: New. * gcc.misc-tests/outputs-1.c: New. * gcc.misc-tests/outputs-2.c: New. * lib/gcc-defs.exp (gcc_adjusted_linker_flags): New. (gcc_adjust_linker_flags): New. (dg-additional-files-options): Call it. Pass -dumpbase "" when there are additional sources. * lib/profopt.exp (profopt-execute): Pass the executable suffix with -dumpbase-ext. * lib/scandump.exp (dump-base): Mention -dumpbase "" use. * lib/scanltranstree.exp: Adjust dump suffix expectation. * lib/scanwpaipa.exp: Likewise.
Diffstat (limited to 'gcc/gcc.c')
-rw-r--r--gcc/gcc.c938
1 files changed, 765 insertions, 173 deletions
diff --git a/gcc/gcc.c b/gcc/gcc.c
index b0d0308..8c851d7 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -270,12 +270,36 @@ static const char *target_sysroot_hdrs_suffix = 0;
static enum save_temps {
SAVE_TEMPS_NONE, /* no -save-temps */
SAVE_TEMPS_CWD, /* -save-temps in current directory */
+ SAVE_TEMPS_DUMP, /* -save-temps in dumpdir */
SAVE_TEMPS_OBJ /* -save-temps in object directory */
} save_temps_flag;
-/* Output file to use to get the object directory for -save-temps=obj */
-static char *save_temps_prefix = 0;
-static size_t save_temps_length = 0;
+/* Set this iff the dumppfx implied by a -save-temps=* option is to
+ override a -dumpdir option, if any. */
+static bool save_temps_overrides_dumpdir = false;
+
+/* -dumpdir, -dumpbase and -dumpbase-ext flags passed in, possibly
+ rearranged as they are to be passed down, e.g., dumpbase and
+ dumpbase_ext may be cleared if integrated with dumpdir or
+ dropped. */
+static char *dumpdir, *dumpbase, *dumpbase_ext;
+
+/* Usually the length of the string in dumpdir. However, during
+ linking, it may be shortened to omit a driver-added trailing dash,
+ by then replaced with a trailing period, that is still to be passed
+ to sub-processes in -dumpdir, but not to be generally used in spec
+ filename expansions. See maybe_run_linker. */
+static size_t dumpdir_length = 0;
+
+/* Set if the last character in dumpdir is (or was) a dash that the
+ driver added to dumpdir after dumpbase or linker output name. */
+static bool dumpdir_trailing_dash_added = false;
+
+/* Basename of dump and aux outputs, computed from dumpbase (given or
+ derived from output name), to override input_basename in non-%w %b
+ et al. */
+static char *outbase;
+static size_t outbase_length = 0;
/* The compiler version. */
@@ -402,13 +426,16 @@ 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 const char *replace_extension_spec_func (int, const char **);
+static const char *dumps_spec_func (int, const char **);
static const char *greater_than_spec_func (int, const char **);
static const char *debug_level_greater_than_spec_func (int, const char **);
static const char *find_fortran_preinclude_file (int, const char **);
static char *convert_white_space (char *);
+static char *quote_spec (char *);
+static char *quote_spec_arg (char *);
+static bool not_actual_file_p (const char *);
+
/* The Specs Language
@@ -426,12 +453,19 @@ expanding these sequences; therefore, you can concatenate them together
or with constant text in a single argument.
%% substitute one % into the program name or argument.
+ %" substitute an empty argument.
%i substitute the name of the input file being processed.
- %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.
- %B same as %b, but include the file suffix (text after the last period).
+ %b substitute the basename for outputs related with the input file
+ being processed. This is often a substring of the input file name,
+ up to (and not including) the last period but, unless %w is active,
+ it is affected by the directory selected by -save-temps=*, by
+ -dumpdir, and, in case of multiple compilations, even by -dumpbase
+ and -dumpbase-ext and, in case of linking, by the linker output
+ name. When %w is active, it derives the main output name only from
+ the input file base name; when it is not, it names aux/dump output
+ file.
+ %B same as %b, but include the input file suffix (text after the last
+ period).
%gSUFFIX
substitute a file name that has suffix SUFFIX and is chosen
once per compilation, and mark the argument a la %d. To reduce
@@ -641,10 +675,10 @@ proper position among the other output files. */
#define ASM_FINAL_SPEC \
"%{gsplit-dwarf: \n\
objcopy --extract-dwo \
- %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
- %{c:%{o*:%:replace-extension(%{o*:%*} .dwo)}%{!o*:%b.dwo}}%{!c:%b.dwo} \n\
+ %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
+ %b.dwo \n\
objcopy --strip-dwo \
- %{c:%{o*:%*}%{!o*:%b%O}}%{!c:%U%O} \
+ %{c:%{o*:%*}%{!o*:%w%b%O}}%{!c:%U%O} \
}"
#endif
@@ -1144,22 +1178,20 @@ static const char *cpp_options =
/* This contains cpp options which are not passed when the preprocessor
output will be used by another program. */
-static const char *cpp_debug_options = "%{d*}";
+static const char *cpp_debug_options = "%<dumpdir %<dumpbase %<dumpbase-ext %{d*} %:dumps()";
/* 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}}\
%{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
- %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{aux-info*}\
- %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
- %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
+ %1 %{!Q:-quiet} %(cpp_debug_options) %{m*} %{aux-info*}\
%{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
%{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
%{Qn:-fno-ident} %{Qy:} %{-help:--help}\
%{-target-help:--target-help}\
%{-version:--version}\
%{-help=*:--help=%*}\
- %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
+ %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %w%b.s}}}\
%{fsyntax-only:-o %j} %{-param*}\
%{coverage:-fprofile-arcs -ftest-coverage}\
%{fprofile-arcs|fprofile-generate*|coverage:\
@@ -1647,9 +1679,8 @@ static const struct spec_function static_spec_functions[] =
{ "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 },
- { "replace-extension", replace_extension_spec_func },
+ { "dumps", dumps_spec_func },
{ "gt", greater_than_spec_func },
{ "debug-level-gt", debug_level_greater_than_spec_func },
{ "fortran-preinclude-file", find_fortran_preinclude_file},
@@ -4145,7 +4176,8 @@ driver_handle_option (struct gcc_options *opts,
return true;
case OPT_save_temps:
- save_temps_flag = SAVE_TEMPS_CWD;
+ if (!save_temps_flag)
+ save_temps_flag = SAVE_TEMPS_DUMP;
validated = true;
break;
@@ -4158,6 +4190,23 @@ driver_handle_option (struct gcc_options *opts,
else
fatal_error (input_location, "%qs is an unknown %<-save-temps%> option",
decoded->orig_option_with_args_text);
+ save_temps_overrides_dumpdir = true;
+ break;
+
+ case OPT_dumpdir:
+ free (dumpdir);
+ dumpdir = xstrdup (arg);
+ save_temps_overrides_dumpdir = false;
+ break;
+
+ case OPT_dumpbase:
+ free (dumpbase);
+ dumpbase = xstrdup (arg);
+ break;
+
+ case OPT_dumpbase_ext:
+ free (dumpbase_ext);
+ dumpbase_ext = xstrdup (arg);
break;
case OPT_no_canonical_prefixes:
@@ -4264,8 +4313,6 @@ driver_handle_option (struct gcc_options *opts,
arg = convert_filename (arg, ! have_c, 0);
#endif
output_file = arg;
- /* 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, true);
@@ -4308,6 +4355,19 @@ driver_handle_option (struct gcc_options *opts,
return true;
}
+/* Return true if F2 is F1 followed by a single suffix, i.e., by a
+ period and additional characters other than a period. */
+
+static inline bool
+adds_single_suffix_p (const char *f2, const char *f1)
+{
+ size_t len = strlen (f1);
+
+ return (strncmp (f1, f2, len) == 0
+ && f2[len] == '.'
+ && strchr (f2 + len + 1, '.') == NULL);
+}
+
/* Put the driver's standard set of option handlers in *HANDLERS. */
static void
@@ -4324,6 +4384,32 @@ set_option_handlers (struct cl_option_handlers *handlers)
handlers->handlers[2].mask = CL_TARGET;
}
+
+/* Return the index into infiles for the single non-library
+ non-lto-wpa input file, -1 if there isn't any, or -2 if there is
+ more than one. */
+static inline int
+single_input_file_index ()
+{
+ int ret = -1;
+
+ for (int i = 0; i < n_infiles; i++)
+ {
+ if (infiles[i].language
+ && (infiles[i].language[0] == '*'
+ || (flag_wpa
+ && strcmp (infiles[i].language, "lto") == 0)))
+ continue;
+
+ if (ret != -1)
+ return -2;
+
+ ret = i;
+ }
+
+ return ret;
+}
+
/* Create the vector `switches' and its contents.
Store its length in `n_switches'. */
@@ -4636,23 +4722,371 @@ process_command (unsigned int decoded_options_count,
if (output_file != NULL && output_file[0] == '\0')
fatal_error (input_location, "output filename may not be empty");
+ /* -dumpdir and -save-temps=* both specify the location of aux/dump
+ outputs; the one that appears last prevails. When compiling
+ multiple sources, an explicit dumpbase (minus -ext) may be
+ combined with an explicit or implicit dumpdir, whereas when
+ linking, a specified or implied link output name (minus
+ extension) may be combined with a prevailing -save-temps=* or an
+ otherwise implied dumpdir, but not override a prevailing
+ -dumpdir. Primary outputs (e.g., linker output when linking
+ without -o, or .i, .s or .o outputs when processing multiple
+ inputs with -E, -S or -c, respectively) are NOT affected by these
+ -save-temps=/-dump* options, always landing in the current
+ directory and with the same basename as the input when an output
+ name is not given, but when they're intermediate outputs, they
+ are named like other aux outputs, so the options affect their
+ location and name.
+
+ Here are some examples. There are several more in the
+ documentation of -o and -dump*, and some quite exhaustive tests
+ in gcc.misc-tests/outputs.exp.
+
+ When compiling any number of sources, no -dump* nor
+ -save-temps=*, all outputs in cwd without prefix:
+
+ # gcc -c b.c -gsplit-dwarf
+ -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
+
+ # gcc -c b.c d.c -gsplit-dwarf
+ -> cc1 [-dumpdir ./] -dumpbase b.c -dumpbase-ext .c # b.o b.dwo
+ && cc1 [-dumpdir ./] -dumpbase d.c -dumpbase-ext .c # d.o d.dwo
+
+ When compiling and linking, no -dump* nor -save-temps=*, .o
+ outputs are temporary, aux outputs land in the dir of the output,
+ prefixed with the basename of the linker output:
+
+ # gcc b.c d.c -o ab -gsplit-dwarf
+ -> cc1 -dumpdir ab- -dumpbase b.c -dumpbase-ext .c # ab-b.dwo
+ && cc1 -dumpdir ab- -dumpbase d.c -dumpbase-ext .c # ab-d.dwo
+ && link ... -o ab
+
+ # gcc b.c d.c [-o a.out] -gsplit-dwarf
+ -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.dwo
+ && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.dwo
+ && link ... [-o a.out]
+
+ When compiling and linking, a prevailing -dumpdir fully overrides
+ the prefix of aux outputs given by the output name:
+
+ # gcc -dumpdir f b.c d.c -gsplit-dwarf [-o [dir/]whatever]
+ -> cc1 -dumpdir f -dumpbase b.c -dumpbase-ext .c # fb.dwo
+ && cc1 -dumpdir f -dumpbase d.c -dumpbase-ext .c # fd.dwo
+ && link ... [-o whatever]
+
+ When compiling multiple inputs, an explicit -dumpbase is combined
+ with -dumpdir, affecting aux outputs, but not the .o outputs:
+
+ # gcc -dumpdir f -dumpbase g- b.c d.c -gsplit-dwarf -c
+ -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # b.o fg-b.dwo
+ && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # d.o fg-d.dwo
+
+ When compiling and linking with -save-temps, the .o outputs that
+ would have been temporary become aux outputs, so they get
+ affected by -dump* flags:
+
+ # gcc -dumpdir f -dumpbase g- -save-temps b.c d.c
+ -> cc1 -dumpdir fg- -dumpbase b.c -dumpbase-ext .c # fg-b.o
+ && cc1 -dumpdir fg- -dumpbase d.c -dumpbase-ext .c # fg-d.o
+ && link
+
+ If -save-temps=* prevails over -dumpdir, however, the explicit
+ -dumpdir is discarded, as if it wasn't there. The basename of
+ the implicit linker output, a.out or a.exe, becomes a- as the aux
+ output prefix for all compilations:
+
+ # gcc [-dumpdir f] -save-temps=cwd b.c d.c
+ -> cc1 -dumpdir a- -dumpbase b.c -dumpbase-ext .c # a-b.o
+ && cc1 -dumpdir a- -dumpbase d.c -dumpbase-ext .c # a-d.o
+ && link
+
+ A single -dumpbase, applying to multiple inputs, overrides the
+ linker output name, implied or explicit, as the aux output prefix:
+
+ # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c
+ -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+ && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
+ && link
+
+ # gcc [-dumpdir f] -dumpbase g- -save-temps=cwd b.c d.c -o dir/h.out
+ -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+ && cc1 -dumpdir g- -dumpbase d.c -dumpbase-ext .c # g-d.o
+ && link -o dir/h.out
+
+ Now, if the linker output is NOT overridden as a prefix, but
+ -save-temps=* overrides implicit or explicit -dumpdir, the
+ effective dump dir combines the dir selected by the -save-temps=*
+ option with the basename of the specified or implied link output:
+
+ # gcc [-dumpdir f] -save-temps=cwd b.c d.c -o dir/h.out
+ -> cc1 -dumpdir h- -dumpbase b.c -dumpbase-ext .c # h-b.o
+ && cc1 -dumpdir h- -dumpbase d.c -dumpbase-ext .c # h-d.o
+ && link -o dir/h.out
+
+ # gcc [-dumpdir f] -save-temps=obj b.c d.c -o dir/h.out
+ -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
+ && cc1 -dumpdir dir/h- -dumpbase d.c -dumpbase-ext .c # dir/h-d.o
+ && link -o dir/h.out
+
+ But then again, a single -dumpbase applying to multiple inputs
+ gets used instead of the linker output basename in the combined
+ dumpdir:
+
+ # gcc [-dumpdir f] -dumpbase g- -save-temps=obj b.c d.c -o dir/h.out
+ -> cc1 -dumpdir dir/g- -dumpbase b.c -dumpbase-ext .c # dir/g-b.o
+ && cc1 -dumpdir dir/g- -dumpbase d.c -dumpbase-ext .c # dir/g-d.o
+ && link -o dir/h.out
+
+ With a single input being compiled, the output basename does NOT
+ affect the dumpdir prefix.
+
+ # gcc -save-temps=obj b.c -gsplit-dwarf -c -o dir/b.o
+ -> cc1 -dumpdir dir/ -dumpbase b.c -dumpbase-ext .c # dir/b.o dir/b.dwo
+
+ but when compiling and linking even a single file, it does:
+
+ # gcc -save-temps=obj b.c -o dir/h.out
+ -> cc1 -dumpdir dir/h- -dumpbase b.c -dumpbase-ext .c # dir/h-b.o
+
+ unless an explicit -dumpdir prevails:
+
+ # gcc -save-temps[=obj] -dumpdir g- b.c -o dir/h.out
+ -> cc1 -dumpdir g- -dumpbase b.c -dumpbase-ext .c # g-b.o
+
+ */
+
+ bool explicit_dumpdir = dumpdir;
+
+ if (!save_temps_overrides_dumpdir && explicit_dumpdir)
+ {
+ /* Do nothing. */
+ }
+
/* If -save-temps=obj and -o name, create the prefix to use for %b.
Otherwise just make -save-temps=obj the same as -save-temps=cwd. */
- if (save_temps_flag == SAVE_TEMPS_OBJ && save_temps_prefix != NULL)
+ else if (save_temps_flag != SAVE_TEMPS_CWD && output_file != NULL)
+ {
+ free (dumpdir);
+ dumpdir = NULL;
+ temp = lbasename (output_file);
+ if (temp != output_file)
+ dumpdir = xstrndup (output_file,
+ strlen (output_file) - strlen (temp));
+ }
+ else if (dumpdir)
+ {
+ free (dumpdir);
+ dumpdir = NULL;
+ }
+
+ if (save_temps_flag)
+ save_temps_flag = SAVE_TEMPS_DUMP;
+
+ /* If there is any pathname component in an explicit -dumpbase, it
+ overrides dumpdir entirely, so discard it right away. Although
+ the presence of an explicit -dumpdir matters for the driver, it
+ shouldn't matter for other processes, that get all that's needed
+ from the -dumpdir and -dumpbase always passed to them. */
+ if (dumpdir && dumpbase && lbasename (dumpbase) != dumpbase)
{
- save_temps_length = strlen (save_temps_prefix);
- temp = strrchr (lbasename (save_temps_prefix), '.');
- if (temp)
+ free (dumpdir);
+ dumpdir = NULL;
+ }
+
+ /* Check that dumpbase_ext matches the end of dumpbase, drop it
+ otherwise. */
+ if (dumpbase_ext && dumpbase && *dumpbase)
+ {
+ int lendb = strlen (dumpbase);
+ int lendbx = strlen (dumpbase_ext);
+
+ if (lendbx >= lendb
+ || strcmp (dumpbase + lendb - lendbx, dumpbase_ext) != 0)
{
- save_temps_length -= strlen (temp);
- save_temps_prefix[save_temps_length] = '\0';
+ free (dumpbase_ext);
+ dumpbase_ext = NULL;
}
+ }
+
+ /* -dumpbase with multiple sources goes into dumpdir. With a single
+ source, it does only if linking and if dumpdir was not explicitly
+ specified. */
+ if (dumpbase && *dumpbase
+ && (single_input_file_index () == -2
+ || (!have_c && !explicit_dumpdir)))
+ {
+ char *prefix;
+ if (dumpbase_ext)
+ /* We checked that they match above. */
+ dumpbase[strlen (dumpbase) - strlen (dumpbase_ext)] = '\0';
+
+ if (dumpdir)
+ prefix = concat (dumpdir, dumpbase, "-", NULL);
+ else
+ prefix = concat (dumpbase, "-", NULL);
+
+ free (dumpdir);
+ free (dumpbase);
+ free (dumpbase_ext);
+ dumpbase = dumpbase_ext = NULL;
+ dumpdir = prefix;
+ dumpdir_trailing_dash_added = true;
+ }
+
+ /* If dumpbase was not brought into dumpdir but we're linking, bring
+ output_file into dumpdir unless dumpdir was explicitly specified.
+ The test for !explicit_dumpdir is further below, because we want
+ to use the obase computation for a ghost outbase, passed to
+ GCC_COLLECT_OPTIONS. */
+ else if (!have_c && (!explicit_dumpdir || (dumpbase && !*dumpbase)))
+ {
+ /* If we get here, we know dumpbase was not specified, or it was
+ specified as an empty string. If it was anything else, it
+ would have combined with dumpdir above, because the condition
+ for dumpbase to be used when present is broader than the
+ condition that gets us here. */
+ gcc_assert (!dumpbase || !*dumpbase);
+
+ const char *obase;
+ char *tofree = NULL;
+ if (!output_file || not_actual_file_p (output_file))
+ obase = "a";
+ else
+ {
+ obase = lbasename (output_file);
+ size_t blen = strlen (obase), xlen;
+ /* Drop the suffix if it's dumpbase_ext, if given,
+ otherwise .exe or the target executable suffix, or if the
+ output was explicitly named a.out, but not otherwise. */
+ if (dumpbase_ext
+ ? (blen > (xlen = strlen (dumpbase_ext))
+ && strcmp ((temp = (obase + blen - xlen)),
+ dumpbase_ext) == 0)
+ : ((temp = strrchr (obase + 1, '.'))
+ && (xlen = strlen (temp))
+ && (strcmp (temp, ".exe") == 0
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
+ || strcmp (temp, TARGET_EXECUTABLE_SUFFIX) == 0
+#endif
+ || strcmp (obase, "a.out") == 0)))
+ {
+ tofree = xstrndup (obase, blen - xlen);
+ obase = tofree;
+ }
+ }
+
+ /* We wish to save this basename to the -dumpdir passed through
+ GCC_COLLECT_OPTIONS within maybe_run_linker, for e.g. LTO,
+ but we do NOT wish to add it to e.g. %b, so we keep
+ outbase_length as zero. */
+ gcc_assert (!outbase);
+ outbase_length = 0;
+
+ /* If we're building [dir1/]foo[.exe] out of a single input
+ [dir2/]foo.c that shares the same basename, dump to
+ [dir2/]foo.c.* rather than duplicating the basename into
+ [dir2/]foo-foo.c.*. */
+ int idxin;
+ if (dumpbase
+ || ((idxin = single_input_file_index ()) >= 0
+ && adds_single_suffix_p (lbasename (infiles[idxin].name),
+ obase)))
+ {
+ if (obase == tofree)
+ outbase = tofree;
+ else
+ {
+ outbase = xstrdup (obase);
+ free (tofree);
+ }
+ obase = tofree = NULL;
+ }
+ else
+ {
+ if (dumpdir)
+ {
+ char *p = concat (dumpdir, obase, "-", NULL);
+ free (dumpdir);
+ dumpdir = p;
+ }
+ else
+ dumpdir = concat (obase, "-", NULL);
+
+ dumpdir_trailing_dash_added = true;
+
+ free (tofree);
+ obase = tofree = NULL;
+ }
+
+ if (!explicit_dumpdir || dumpbase)
+ {
+ /* Absent -dumpbase and present -dumpbase-ext have been applied
+ to the linker output name, so compute fresh defaults for each
+ compilation. */
+ free (dumpbase_ext);
+ dumpbase_ext = NULL;
+ }
+ }
+
+ /* Now, if we're compiling, or if we haven't used the dumpbase
+ above, then outbase (%B) is derived from dumpbase, if given, or
+ from the output name, given or implied. We can't precompute
+ implied output names, but that's ok, since they're derived from
+ input names. Just make sure we skip this if dumpbase is the
+ empty string: we want to use input names then, so don't set
+ outbase. */
+ if ((dumpbase || have_c)
+ && !(dumpbase && !*dumpbase))
+ {
+ gcc_assert (!outbase);
+
+ if (dumpbase)
+ {
+ gcc_assert (single_input_file_index () != -2);
+ /* We do not want lbasename here; dumpbase with dirnames
+ overrides dumpdir entirely, even if dumpdir is
+ specified. */
+ if (dumpbase_ext)
+ /* We've already checked above that the suffix matches. */
+ outbase = xstrndup (dumpbase,
+ strlen (dumpbase) - strlen (dumpbase_ext));
+ else
+ outbase = xstrdup (dumpbase);
+ }
+ else if (output_file && !not_actual_file_p (output_file))
+ {
+ outbase = xstrdup (lbasename (output_file));
+ char *p = strrchr (outbase + 1, '.');
+ if (p)
+ *p = '\0';
+ }
+
+ if (outbase)
+ outbase_length = strlen (outbase);
}
- else if (save_temps_prefix != NULL)
+
+ /* If there is any pathname component in an explicit -dumpbase, do
+ not use dumpdir, but retain it to pass it on to the compiler. */
+ if (dumpdir)
+ dumpdir_length = strlen (dumpdir);
+ else
+ dumpdir_length = 0;
+
+ /* Check that dumpbase_ext, if still present, still matches the end
+ of dumpbase, if present, and drop it otherwise. We only retained
+ it above when dumpbase was absent to maybe use it to drop the
+ extension from output_name before combining it with dumpdir. */
+ if (dumpbase_ext)
{
- free (save_temps_prefix);
- save_temps_prefix = NULL;
+ if (!dumpbase)
+ {
+ free (dumpbase_ext);
+ dumpbase_ext = NULL;
+ }
+ else
+ gcc_assert (strcmp (dumpbase + strlen (dumpbase)
+ - strlen (dumpbase_ext), dumpbase_ext) == 0);
}
if (save_temps_flag && use_pipes)
@@ -4848,6 +5282,28 @@ set_collect_gcc_options (void)
obstack_grow (&collect_obstack, "'", 1);
}
}
+
+ if (dumpdir)
+ {
+ if (!first_time)
+ obstack_grow (&collect_obstack, " ", 1);
+ first_time = FALSE;
+
+ obstack_grow (&collect_obstack, "'-dumpdir' '", 12);
+ const char *p, *q;
+
+ q = dumpdir;
+ while ((p = strchr (q, '\'')))
+ {
+ obstack_grow (&collect_obstack, q, p - q);
+ obstack_grow (&collect_obstack, "'\\''", 4);
+ q = ++p;
+ }
+ obstack_grow (&collect_obstack, q, strlen (q));
+
+ obstack_grow (&collect_obstack, "'", 1);
+ }
+
obstack_grow (&collect_obstack, "\0", 1);
xputenv (XOBFINISH (&collect_obstack, char *));
}
@@ -5366,22 +5822,33 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
fatal_error (input_location, "spec %qs invalid", spec);
case 'b':
- if (save_temps_length)
- obstack_grow (&obstack, save_temps_prefix, save_temps_length);
- else
+ /* Don't use %b in the linker command. */
+ gcc_assert (suffixed_basename_length);
+ if (!this_is_output_file && dumpdir_length)
+ obstack_grow (&obstack, dumpdir, dumpdir_length);
+ if (this_is_output_file || !outbase_length)
obstack_grow (&obstack, input_basename, basename_length);
+ else
+ obstack_grow (&obstack, outbase, outbase_length);
if (compare_debug < 0)
obstack_grow (&obstack, ".gk", 3);
arg_going = 1;
break;
case 'B':
- if (save_temps_length)
- obstack_grow (&obstack, save_temps_prefix, save_temps_length);
+ /* Don't use %B in the linker command. */
+ gcc_assert (suffixed_basename_length);
+ if (!this_is_output_file && dumpdir_length)
+ obstack_grow (&obstack, dumpdir, dumpdir_length);
+ if (this_is_output_file || !outbase_length)
+ obstack_grow (&obstack, input_basename, basename_length);
else
- obstack_grow (&obstack, input_basename, suffixed_basename_length);
+ obstack_grow (&obstack, outbase, outbase_length);
if (compare_debug < 0)
obstack_grow (&obstack, ".gk", 3);
+ obstack_grow (&obstack, input_basename + basename_length,
+ suffixed_basename_length - basename_length);
+
arg_going = 1;
break;
@@ -5534,42 +6001,44 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
suffix_length += 3;
}
- /* If -save-temps=obj and -o were specified, use that for the
+ /* If -save-temps was specified, use that for the
temp file. */
- if (save_temps_length)
- {
- char *tmp;
- temp_filename_length
- = save_temps_length + suffix_length + 1;
- tmp = (char *) alloca (temp_filename_length);
- memcpy (tmp, save_temps_prefix, save_temps_length);
- memcpy (tmp + save_temps_length, suffix, suffix_length);
- tmp[save_temps_length + suffix_length] = '\0';
- temp_filename = save_string (tmp, save_temps_length
- + suffix_length);
- obstack_grow (&obstack, temp_filename,
- temp_filename_length);
- arg_going = 1;
- delete_this_arg = 0;
- break;
- }
-
- /* 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.,
- gcc -save-temps foo.s would clobber foo.s with the
- output of cpp0). So check for this condition and
- generate a temp file as the intermediate. */
-
if (save_temps_flag)
{
char *tmp;
- temp_filename_length = basename_length + suffix_length + 1;
+ bool adjusted_suffix = false;
+ if (suffix_length
+ && !outbase_length && !basename_length
+ && !dumpdir_trailing_dash_added)
+ {
+ adjusted_suffix = true;
+ suffix++;
+ suffix_length--;
+ }
+ temp_filename_length
+ = dumpdir_length + suffix_length + 1;
+ if (!outbase_length)
+ temp_filename_length += basename_length;
+ else
+ temp_filename_length += outbase_length;
tmp = (char *) alloca (temp_filename_length);
- memcpy (tmp, input_basename, basename_length);
- memcpy (tmp + basename_length, suffix, suffix_length);
- tmp[basename_length + suffix_length] = '\0';
+ if (dumpdir_length)
+ memcpy (tmp, dumpdir, dumpdir_length);
+ if (!outbase_length)
+ memcpy (tmp + dumpdir_length, input_basename,
+ basename_length);
+ else
+ memcpy (tmp + dumpdir_length, outbase,
+ outbase_length);
+ memcpy (tmp + temp_filename_length - suffix_length - 1,
+ suffix, suffix_length);
+ if (adjusted_suffix)
+ {
+ adjusted_suffix = false;
+ suffix--;
+ suffix_length++;
+ }
+ tmp[temp_filename_length - 1] = '\0';
temp_filename = tmp;
if (filename_cmp (temp_filename, gcc_input_filename) != 0)
@@ -6080,6 +6549,14 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
}
break;
+ case '"':
+ /* End a previous argument, if there is one, then issue an
+ empty argument. */
+ end_going_arg ();
+ arg_going = 1;
+ end_going_arg ();
+ break;
+
default:
error ("spec failure: unrecognized spec option %qc", c);
break;
@@ -6090,6 +6567,9 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
/* Backslash: treat next character as ordinary. */
c = *p++;
+ /* When adding more cases that previously matched default, make
+ sure to adjust quote_spec_char_p as well. */
+
/* Fall through. */
default:
/* Ordinary character: put it into the current argument. */
@@ -8296,6 +8776,40 @@ driver::maybe_run_linker (const char *argv0) const
if (explicit_link_files[i] || outfiles[i] != NULL)
num_linker_inputs++;
+ /* Arrange for temporary file names created during linking to take
+ on names related with the linker output rather than with the
+ inputs when appropriate. */
+ if (outbase && *outbase)
+ {
+ if (dumpdir)
+ {
+ char *tofree = dumpdir;
+ gcc_checking_assert (strlen (dumpdir) == dumpdir_length);
+ dumpdir = concat (dumpdir, outbase, ".", NULL);
+ free (tofree);
+ }
+ else
+ dumpdir = concat (outbase, ".", NULL);
+ dumpdir_length += strlen (outbase) + 1;
+ dumpdir_trailing_dash_added = true;
+ }
+ else if (dumpdir_trailing_dash_added)
+ {
+ gcc_assert (dumpdir[dumpdir_length - 1] == '-');
+ dumpdir[dumpdir_length - 1] = '.';
+ }
+
+ if (dumpdir_trailing_dash_added)
+ {
+ gcc_assert (dumpdir_length > 0);
+ gcc_assert (dumpdir[dumpdir_length - 1] == '.');
+ dumpdir_length--;
+ }
+
+ free (outbase);
+ input_basename = outbase = NULL;
+ outbase_length = suffixed_basename_length = basename_length = 0;
+
/* Run ld to link all the compiler output files. */
if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
@@ -9766,7 +10280,7 @@ compare_debug_dump_opt_spec_function (int arg,
do_spec_1 (" ", 0, NULL);
if (argbuf.length () > 0
- && strcmp (argv[argbuf.length () - 1], "."))
+ && strcmp (argv[argbuf.length () - 1], ".") != 0)
{
if (!compare_debug)
return NULL;
@@ -9776,25 +10290,22 @@ compare_debug_dump_opt_spec_function (int arg,
}
else
{
- const char *ext = NULL;
-
if (argbuf.length () > 0)
- {
- do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}", NULL);
- ext = ".gkd";
- }
+ do_spec_2 ("%B.gkd", NULL);
else if (!compare_debug)
return NULL;
else
- do_spec_2 ("%g.gkd", NULL);
+ do_spec_2 ("%{!save-temps*:%g.gkd}%{save-temps*:%B.gkd}", NULL);
do_spec_1 (" ", 0, NULL);
gcc_assert (argbuf.length () > 0);
- name = concat (argbuf.last (), ext, NULL);
+ name = xstrdup (argbuf.last ());
- ret = concat ("-fdump-final-insns=", name, NULL);
+ char *arg = quote_spec (xstrdup (name));
+ ret = concat ("-fdump-final-insns=", arg, NULL);
+ free (arg);
}
which = compare_debug < 0;
@@ -9821,8 +10332,6 @@ compare_debug_dump_opt_spec_function (int arg,
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. */
@@ -9838,16 +10347,6 @@ compare_debug_self_opt_spec_function (int arg,
if (compare_debug >= 0)
return NULL;
- do_spec_2 ("%{c|S:%{o*:%*}}", NULL);
- do_spec_1 (" ", 0, NULL);
-
- if (argbuf.length () > 0)
- debug_auxbase_opt = concat ("-auxbase-strip ",
- argbuf.last (),
- NULL);
- else
- debug_auxbase_opt = NULL;
-
return concat ("\
%<o %<MD %<MMD %<MF* %<MG %<MP %<MQ* %<MT* \
%<fdump-final-insns=* -w -S -o %j \
@@ -9855,50 +10354,6 @@ compare_debug_self_opt_spec_function (int arg,
", compare_debug_opt, NULL);
}
-/* %:compare-debug-auxbase-opt spec function. Expands to the auxbase
- options that are to be passed in the second compilation of
- compare-debug. It expects, as an argument, the basename of the
- current input file name, with the .gk suffix appended to it. */
-
-static const char *
-compare_debug_auxbase_opt_spec_function (int arg,
- const char **argv)
-{
- char *name;
- int len;
-
- if (arg == 0)
- fatal_error (input_location,
- "too few arguments to %%:compare-debug-auxbase-opt");
-
- if (arg != 1)
- fatal_error (input_location,
- "too many arguments to %%:compare-debug-auxbase-opt");
-
- if (compare_debug >= 0)
- return NULL;
-
- len = strlen (argv[0]);
- if (len < 3 || strcmp (argv[0] + len - 3, ".gk") != 0)
- fatal_error (input_location, "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;
-}
-
/* %: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
@@ -9942,34 +10397,105 @@ pass_through_libs_spec_func (int argc, const char **argv)
return prepended;
}
-/* %:replace-extension spec function. Replaces the extension of the
- first argument with the second argument. */
+static bool
+not_actual_file_p (const char *name)
+{
+ return (strcmp (name, "-") == 0
+ || strcmp (output_file, HOST_BIT_BUCKET) == 0);
+}
+/* %:dumps spec function. Take an optional argument that overrides
+ the default extension for -dumpbase and -dumpbase-ext.
+ Return -dumpdir, -dumpbase and -dumpbase-ext, if needed. */
const char *
-replace_extension_spec_func (int argc, const char **argv)
+dumps_spec_func (int argc, const char **argv ATTRIBUTE_UNUSED)
{
- char *name;
+ const char *ext = dumpbase_ext;
char *p;
- char *result;
- int i;
- if (argc != 2)
- fatal_error (input_location, "too few arguments to %%:replace-extension");
+ char *args[3] = { NULL, NULL, NULL };
+ int nargs = 0;
- name = xstrdup (argv[0]);
+ /* Do not compute a default for -dumpbase-ext when -dumpbase was
+ given explicitly. */
+ if (dumpbase && *dumpbase && !ext)
+ ext = "";
- for (i = strlen (name) - 1; i >= 0; i--)
- if (IS_DIR_SEPARATOR (name[i]))
- break;
+ if (argc == 1)
+ {
+ /* Do not override the explicitly-specified -dumpbase-ext with
+ the specs-provided overrider. */
+ if (!ext)
+ ext = argv[0];
+ }
+ else if (argc != 0)
+ fatal_error (input_location, "too many arguments for %%:dumps");
- p = strrchr (name + i + 1, '.');
- if (p != NULL)
- *p = '\0';
+ if (dumpdir)
+ {
+ p = quote_spec_arg (xstrdup (dumpdir));
+ args[nargs++] = concat (" -dumpdir ", p, NULL);
+ free (p);
+ }
- result = concat (name, argv[1], NULL);
+ if (!ext)
+ ext = input_basename + basename_length;
- free (name);
- return result;
+ /* Use the precomputed outbase, or compute dumpbase from
+ input_basename, just like %b would. */
+ char *base;
+
+ if (dumpbase && *dumpbase)
+ {
+ base = xstrdup (dumpbase);
+ p = base + outbase_length;
+ gcc_checking_assert (strncmp (base, outbase, outbase_length) == 0);
+ gcc_checking_assert (strcmp (p, ext) == 0);
+ }
+ else if (outbase_length)
+ {
+ base = xstrndup (outbase, outbase_length);
+ p = NULL;
+ }
+ else
+ {
+ base = xstrndup (input_basename, suffixed_basename_length);
+ p = base + basename_length;
+ }
+
+ if (compare_debug < 0 || !p || strcmp (p, ext) != 0)
+ {
+ if (p)
+ *p = '\0';
+
+ const char *gk;
+ if (compare_debug < 0)
+ gk = ".gk";
+ else
+ gk = "";
+
+ p = concat (base, gk, ext, NULL);
+
+ free (base);
+ base = p;
+ }
+
+ base = quote_spec_arg (base);
+ args[nargs++] = concat (" -dumpbase ", base, NULL);
+ free (base);
+
+ if (*ext)
+ {
+ p = quote_spec_arg (xstrdup (ext));
+ args[nargs++] = concat (" -dumpbase-ext ", p, NULL);
+ free (p);
+ }
+
+ const char *ret = concat (args[0], args[1], args[2], NULL);
+ while (nargs > 0)
+ free (args[--nargs]);
+
+ return ret;
}
/* Returns "" if ARGV[ARGC - 2] is greater than ARGV[ARGC-1].
@@ -10075,6 +10601,44 @@ find_fortran_preinclude_file (int argc, const char **argv)
return result;
}
+/* If any character in ORIG fits QUOTE_P (_, P), reallocate the string
+ so as to precede every one of them with a backslash. Return the
+ original string or the reallocated one. */
+
+static inline char *
+quote_string (char *orig, bool (*quote_p)(char, void *), void *p)
+{
+ int len, number_of_space = 0;
+
+ for (len = 0; orig[len]; len++)
+ if (quote_p (orig[len], p))
+ 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 (quote_p (orig[j], p))
+ new_spec[k++] = '\\';
+ new_spec[k] = orig[j];
+ }
+ free (orig);
+ return new_spec;
+ }
+ else
+ return orig;
+}
+
+/* Return true iff C is any of the characters convert_white_space
+ should quote. */
+
+static inline bool
+whitespace_to_convert_p (char c, void *)
+{
+ return (c == ' ' || c == '\t');
+}
/* Insert backslash before spaces in ORIG (usually a file path), to
avoid being broken by spec parser.
@@ -10102,26 +10666,50 @@ find_fortran_preinclude_file (int argc, const char **argv)
static char *
convert_white_space (char *orig)
{
- int len, number_of_space = 0;
+ return quote_string (orig, whitespace_to_convert_p, NULL);
+}
- for (len = 0; orig[len]; len++)
- if (orig[len] == ' ' || orig[len] == '\t') number_of_space++;
+/* Return true iff C matches any of the spec active characters. */
+static inline bool
+quote_spec_char_p (char c, void *)
+{
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '|':
+ case '%':
+ case '\\':
+ return true;
- if (number_of_space)
+ default:
+ return false;
+ }
+}
+
+/* Like convert_white_space, but deactivate all active spec chars by
+ quoting them. */
+
+static inline char *
+quote_spec (char *orig)
+{
+ return quote_string (orig, quote_spec_char_p, NULL);
+}
+
+/* Like quote_spec, but also turn an empty string into the spec for an
+ empty argument. */
+
+static inline char *
+quote_spec_arg (char *orig)
+{
+ if (!*orig)
{
- 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;
+ return xstrdup ("%\"");
+ }
+
+ return quote_spec (orig);
}
/* Restore all state within gcc.c to the initial state, so that the driver
@@ -10158,8 +10746,14 @@ driver::finalize ()
target_sysroot_suffix = 0;
target_sysroot_hdrs_suffix = 0;
save_temps_flag = SAVE_TEMPS_NONE;
- save_temps_prefix = 0;
- save_temps_length = 0;
+ save_temps_overrides_dumpdir = false;
+ dumpdir_trailing_dash_added = false;
+ free (dumpdir);
+ free (dumpbase);
+ free (dumpbase_ext);
+ free (outbase);
+ dumpdir = dumpbase = dumpbase_ext = outbase = NULL;
+ dumpdir_length = outbase_length = 0;
spec_machine = DEFAULT_TARGET_MACHINE;
greatest_status = 1;
@@ -10298,8 +10892,6 @@ driver::finalize ()
mdswitches = NULL;
n_mdswitches = 0;
- debug_auxbase_opt = NULL;
-
used_arg.finalize ();
}