/* Wrapper to call lto. Used by collect2 and the linker plugin.
- Copyright (C) 2009-2015 Free Software Foundation, Inc.
+ Copyright (C) 2009-2017 Free Software Foundation, Inc.
Factored out of collect2 by Rafael Espindola <espindola@google.com>
static char **input_names;
static char **output_names;
static char **offload_names;
-static const char *offloadbegin, *offloadend;
+static char *offload_objects_file_name;
static char *makefile;
+static char *debug_obj;
const char tool_name[] = "lto-wrapper";
maybe_unlink (ltrans_output_file);
if (flto_out)
maybe_unlink (flto_out);
+ if (offload_objects_file_name)
+ maybe_unlink (offload_objects_file_name);
if (makefile)
maybe_unlink (makefile);
+ if (debug_obj)
+ maybe_unlink (debug_obj);
for (i = 0; i < nr; ++i)
{
maybe_unlink (input_names[i]);
sizeof (struct cl_decoded_option));
}
+/* Remove option number INDEX from DECODED_OPTIONS, update
+ DECODED_OPTIONS_COUNT. */
+
+static void
+remove_option (struct cl_decoded_option **decoded_options,
+ int index, unsigned int *decoded_options_count)
+{
+ --*decoded_options_count;
+ memmove (&(*decoded_options)[index + 1],
+ &(*decoded_options)[index],
+ sizeof (struct cl_decoded_option)
+ * (*decoded_options_count - index));
+}
+
/* Try to merge and complain about options FDECODED_OPTIONS when applied
ontop of DECODED_OPTIONS. */
unsigned int fdecoded_options_count)
{
unsigned int i, j;
+ struct cl_decoded_option *pic_option = NULL;
+ struct cl_decoded_option *pie_option = NULL;
/* ??? Merge options from files. Most cases can be
handled by either unioning or intersecting
break;
/* Fallthru. */
- case OPT_fPIC:
- case OPT_fpic:
- case OPT_fPIE:
- case OPT_fpie:
+ case OPT_fdiagnostics_show_caret:
+ case OPT_fdiagnostics_show_option:
+ case OPT_fdiagnostics_show_location_:
+ case OPT_fshow_column:
case OPT_fcommon:
- case OPT_fexceptions:
- case OPT_fnon_call_exceptions:
case OPT_fgnu_tm:
/* Do what the old LTO code did - collect exactly one option
setting per OPT code, we pick the first we encounter.
append_option (decoded_options, decoded_options_count, foption);
break;
- case OPT_ftrapv:
- case OPT_fstrict_overflow:
- case OPT_ffp_contract_:
- /* For selected options we can merge conservatively. */
- for (j = 0; j < *decoded_options_count; ++j)
- if ((*decoded_options)[j].opt_index == foption->opt_index)
- break;
- if (j == *decoded_options_count)
- append_option (decoded_options, decoded_options_count, foption);
- /* FP_CONTRACT_OFF < FP_CONTRACT_ON < FP_CONTRACT_FAST,
- -fno-trapv < -ftrapv,
- -fno-strict-overflow < -fstrict-overflow */
- else if (foption->value < (*decoded_options)[j].value)
- (*decoded_options)[j] = *foption;
+ /* Figure out what PIC/PIE level wins and merge the results. */
+ case OPT_fPIC:
+ case OPT_fpic:
+ pic_option = foption;
+ break;
+ case OPT_fPIE:
+ case OPT_fpie:
+ pie_option = foption;
break;
- case OPT_fmath_errno:
- case OPT_fsigned_zeros:
- case OPT_ftrapping_math:
- case OPT_fwrapv:
case OPT_fopenmp:
case OPT_fopenacc:
+ case OPT_fcheck_pointer_bounds:
/* For selected options we can merge conservatively. */
for (j = 0; j < *decoded_options_count; ++j)
if ((*decoded_options)[j].opt_index == foption->opt_index)
break;
if (j == *decoded_options_count)
append_option (decoded_options, decoded_options_count, foption);
- /* -fmath-errno > -fno-math-errno,
- -fsigned-zeros > -fno-signed-zeros,
- -ftrapping-math -> -fno-trapping-math,
- -fwrapv > -fno-wrapv. */
+ /* -fopenmp > -fno-openmp,
+ -fopenacc > -fno-openacc,
+ -fcheck_pointer_bounds > -fcheck_pointer_bounds */
else if (foption->value > (*decoded_options)[j].value)
(*decoded_options)[j] = *foption;
break;
- case OPT_freg_struct_return:
- case OPT_fpcc_struct_return:
- case OPT_fshort_double:
- for (j = 0; j < *decoded_options_count; ++j)
- if ((*decoded_options)[j].opt_index == foption->opt_index)
- break;
- if (j == *decoded_options_count)
- fatal_error (input_location,
- "Option %s not used consistently in all LTO input"
- " files", foption->orig_option_with_args_text);
- break;
-
- case OPT_foffload_abi_:
+ case OPT_fopenacc_dim_:
+ /* Append or check identical. */
for (j = 0; j < *decoded_options_count; ++j)
if ((*decoded_options)[j].opt_index == foption->opt_index)
break;
if (j == *decoded_options_count)
append_option (decoded_options, decoded_options_count, foption);
- else if (foption->value != (*decoded_options)[j].value)
+ else if (strcmp ((*decoded_options)[j].arg, foption->arg))
fatal_error (input_location,
- "Option %s not used consistently in all LTO input"
- " files", foption->orig_option_with_args_text);
+ "Option %s with different values",
+ foption->orig_option_with_args_text);
break;
case OPT_O:
(*decoded_options)[j].value = 1;
}
break;
+
+
+ case OPT_foffload_abi_:
+ for (j = 0; j < *decoded_options_count; ++j)
+ if ((*decoded_options)[j].opt_index == foption->opt_index)
+ break;
+ if (j == *decoded_options_count)
+ append_option (decoded_options, decoded_options_count, foption);
+ else if (foption->value != (*decoded_options)[j].value)
+ fatal_error (input_location,
+ "Option %s not used consistently in all LTO input"
+ " files", foption->orig_option_with_args_text);
+ break;
+
case OPT_foffload_:
append_option (decoded_options, decoded_options_count, foption);
break;
}
}
+
+ /* Merge PIC options:
+ -fPIC + -fpic = -fpic
+ -fPIC + -fno-pic = -fno-pic
+ -fpic/-fPIC + nothin = nothing.
+ It is a common mistake to mix few -fPIC compiled objects into otherwise
+ non-PIC code. We do not want to build everything with PIC then.
+
+ It would be good to warn on mismatches, but it is bit hard to do as
+ we do not know what nothing translates to. */
+
+ for (unsigned int j = 0; j < *decoded_options_count;)
+ if ((*decoded_options)[j].opt_index == OPT_fPIC
+ || (*decoded_options)[j].opt_index == OPT_fpic)
+ {
+ if (!pic_option
+ || (pic_option->value > 0) != ((*decoded_options)[j].value > 0))
+ remove_option (decoded_options, j, decoded_options_count);
+ else if (pic_option->opt_index == OPT_fPIC
+ && (*decoded_options)[j].opt_index == OPT_fpic)
+ {
+ (*decoded_options)[j] = *pic_option;
+ j++;
+ }
+ else
+ j++;
+ }
+ else if ((*decoded_options)[j].opt_index == OPT_fPIE
+ || (*decoded_options)[j].opt_index == OPT_fpie)
+ {
+ if (!pie_option
+ || pie_option->value != (*decoded_options)[j].value)
+ remove_option (decoded_options, j, decoded_options_count);
+ else if (pie_option->opt_index == OPT_fPIE
+ && (*decoded_options)[j].opt_index == OPT_fpie)
+ {
+ (*decoded_options)[j] = *pie_option;
+ j++;
+ }
+ else
+ j++;
+ }
+ else
+ j++;
}
/* Auxiliary function that frees elements of PTR and PTR itself.
on any CL_TARGET flag and a few selected others. */
switch (option->opt_index)
{
+ case OPT_fdiagnostics_show_caret:
+ case OPT_fdiagnostics_show_option:
+ case OPT_fdiagnostics_show_location_:
+ case OPT_fshow_column:
case OPT_fPIC:
case OPT_fpic:
case OPT_fPIE:
case OPT_fpie:
case OPT_fcommon:
- case OPT_fexceptions:
- case OPT_fnon_call_exceptions:
case OPT_fgnu_tm:
- case OPT_freg_struct_return:
- case OPT_fpcc_struct_return:
- case OPT_fshort_double:
- case OPT_ffp_contract_:
- case OPT_fmath_errno:
- case OPT_fsigned_zeros:
- case OPT_ftrapping_math:
- case OPT_fwrapv:
case OPT_fopenmp:
case OPT_fopenacc:
- case OPT_ftrapv:
- case OPT_fstrict_overflow:
+ case OPT_fopenacc_dim_:
case OPT_foffload_abi_:
case OPT_O:
case OPT_Ofast:
case OPT_Og:
case OPT_Os:
+ case OPT_fcheck_pointer_bounds:
break;
default:
}
}
+/* Append diag options in OPTS with length COUNT to ARGV_OBSTACK. */
+
+static void
+append_diag_options (obstack *argv_obstack, struct cl_decoded_option *opts,
+ unsigned int count)
+{
+ /* Append compiler driver arguments as far as they were merged. */
+ for (unsigned int j = 1; j < count; ++j)
+ {
+ struct cl_decoded_option *option = &opts[j];
+
+ switch (option->opt_index)
+ {
+ case OPT_fdiagnostics_color_:
+ case OPT_fdiagnostics_show_caret:
+ case OPT_fdiagnostics_show_option:
+ case OPT_fdiagnostics_show_location_:
+ case OPT_fshow_column:
+ break;
+ default:
+ continue;
+ }
+
+ /* Pass the option on. */
+ for (unsigned int i = 0; i < option->canonical_option_num_elements; ++i)
+ obstack_ptr_grow (argv_obstack, option->canonical_option[i]);
+ }
+}
+
+
/* Append linker options OPTS to ARGV_OBSTACK. */
static void
/* We've handled these LTO options, do not pass them on. */
continue;
- case OPT_freg_struct_return:
- case OPT_fpcc_struct_return:
- case OPT_fshort_double:
- /* Ignore these, they are determined by the input files.
- ??? We fail to diagnose a possible mismatch here. */
- continue;
+ case OPT_fopenmp:
+ case OPT_fopenacc:
+ /* Ignore -fno-XXX form of these options, as otherwise
+ corresponding builtins will not be enabled. */
+ if (option->value == 0)
+ continue;
+ break;
default:
break;
else
{
opts = strchr (option->arg, '=');
+ /* If there are offload targets specified, but no actual options,
+ there is nothing to do here. */
if (!opts)
continue;
next = opts;
next = (next > opts) ? opts : next;
+ /* Are we looking for this offload target? */
if (strlen (target) == (size_t) (next - cur)
&& strncmp (target, cur, next - cur) == 0)
break;
+ /* Skip the comma or equal sign. */
cur = next + 1;
}
struct obstack argv_obstack;
obstack_init (&argv_obstack);
obstack_ptr_grow (&argv_obstack, compiler);
+ if (save_temps)
+ obstack_ptr_grow (&argv_obstack, "-save-temps");
+ if (verbose)
+ obstack_ptr_grow (&argv_obstack, "-v");
obstack_ptr_grow (&argv_obstack, "-o");
obstack_ptr_grow (&argv_obstack, filename);
/* Append options from offload_lto sections. */
append_compiler_options (&argv_obstack, compiler_opts,
compiler_opt_count);
+ append_diag_options (&argv_obstack, linker_opts, linker_opt_count);
/* Append options specified by -foffload last. In case of conflicting
options we expect offload compiler to choose the latest. */
return;
unsigned num_targets = parse_env_var (target_names, &names, NULL);
+ int next_name_entry = 0;
const char *compiler_path = getenv ("COMPILER_PATH");
if (!compiler_path)
goto out;
offload_names = XCNEWVEC (char *, num_targets + 1);
for (unsigned i = 0; i < num_targets; i++)
{
- offload_names[i]
+ /* HSA does not use LTO-like streaming and a different compiler, skip
+ it. */
+ if (strcmp (names[i], "hsa") == 0)
+ continue;
+
+ offload_names[next_name_entry]
= compile_offload_image (names[i], compiler_path, in_argc, in_argv,
compiler_opts, compiler_opt_count,
linker_opts, linker_opt_count);
- if (!offload_names[i])
+ if (!offload_names[next_name_entry])
fatal_error (input_location,
"problem with building target image for %s\n", names[i]);
+ next_name_entry++;
}
out:
fatal_error (input_location, "writing output file");
}
}
+ fclose (d);
+ fclose (s);
}
-/* Find the crtoffloadbegin.o and crtoffloadend.o files in LIBRARY_PATH, make
- copies and store the names of the copies in offloadbegin and offloadend. */
+/* Find the crtoffloadtable.o file in LIBRARY_PATH, make copy and pass name of
+ the copy to the linker. */
static void
-find_offloadbeginend (void)
+find_crtoffloadtable (void)
{
char **paths = NULL;
const char *library_path = getenv ("LIBRARY_PATH");
if (!library_path)
return;
- unsigned n_paths = parse_env_var (library_path, &paths, "/crtoffloadbegin.o");
+ unsigned n_paths = parse_env_var (library_path, &paths, "/crtoffloadtable.o");
unsigned i;
for (i = 0; i < n_paths; i++)
if (access_check (paths[i], R_OK) == 0)
{
- size_t len = strlen (paths[i]);
- char *tmp = xstrdup (paths[i]);
- strcpy (paths[i] + len - strlen ("begin.o"), "end.o");
- if (access_check (paths[i], R_OK) != 0)
- fatal_error (input_location,
- "installation error, can't find crtoffloadend.o");
- /* The linker will delete the filenames we give it, so make
- copies. */
- offloadbegin = make_temp_file (".o");
- offloadend = make_temp_file (".o");
- copy_file (offloadbegin, tmp);
- copy_file (offloadend, paths[i]);
- free (tmp);
+ /* The linker will delete the filename we give it, so make a copy. */
+ char *crtoffloadtable = make_temp_file (".crtoffloadtable.o");
+ copy_file (crtoffloadtable, paths[i]);
+ printf ("%s\n", crtoffloadtable);
+ XDELETEVEC (crtoffloadtable);
break;
}
if (i == n_paths)
fatal_error (input_location,
- "installation error, can't find crtoffloadbegin.o");
+ "installation error, can't find crtoffloadtable.o");
free_array_of_ptrs ((void **) paths, n_paths);
}
return true;
}
+/* Copy early debug info sections from INFILE to a new file whose name
+ is returned. Return NULL on error. */
+
+const char *
+debug_objcopy (const char *infile)
+{
+ const char *outfile;
+ const char *errmsg;
+ int err;
+
+ const char *p;
+ off_t inoff = 0;
+ long loffset;
+ int consumed;
+ if ((p = strrchr (infile, '@'))
+ && p != infile
+ && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (p) == (unsigned int) consumed)
+ {
+ char *fname = xstrdup (infile);
+ fname[p - infile] = '\0';
+ infile = fname;
+ inoff = (off_t) loffset;
+ }
+ int infd = open (infile, O_RDONLY);
+ if (infd == -1)
+ return NULL;
+ simple_object_read *inobj = simple_object_start_read (infd, inoff,
+ "__GNU_LTO",
+ &errmsg, &err);
+ if (!inobj)
+ return NULL;
+
+ off_t off, len;
+ if (simple_object_find_section (inobj, ".gnu.debuglto_.debug_info",
+ &off, &len, &errmsg, &err) != 1)
+ {
+ if (errmsg)
+ fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+
+ simple_object_release_read (inobj);
+ close (infd);
+ return NULL;
+ }
+
+ outfile = make_temp_file ("debugobjtem");
+ errmsg = simple_object_copy_lto_debug_sections (inobj, outfile, &err);
+ if (errmsg)
+ {
+ unlink_if_ordinary (outfile);
+ fatal_error (0, "%s: %s\n", errmsg, xstrerror (err));
+ }
+
+ simple_object_release_read (inobj);
+ close (infd);
+
+ return outfile;
+}
+
+
+
/* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */
static void
int new_head_argc;
bool have_lto = false;
bool have_offload = false;
- unsigned lto_argc = 0, offload_argc = 0;
- char **lto_argv, **offload_argv;
+ unsigned lto_argc = 0, ltoobj_argc = 0;
+ char **lto_argv, **ltoobj_argv;
+ bool skip_debug = false;
+ unsigned n_debugobj;
/* Get the driver and options. */
collect_gcc = getenv ("COLLECT_GCC");
&decoded_options,
&decoded_options_count);
- /* Allocate arrays for input object files with LTO or offload IL,
+ /* Allocate array for input object files with LTO IL,
and for possible preceding arguments. */
lto_argv = XNEWVEC (char *, argc);
- offload_argv = XNEWVEC (char *, argc);
+ ltoobj_argv = XNEWVEC (char *, argc);
/* Look at saved options in the IL files. */
for (i = 1; i < argc; ++i)
int consumed;
char *filename = argv[i];
+ if (strncmp (argv[i], "-foffload-objects=",
+ sizeof ("-foffload-objects=") - 1) == 0)
+ {
+ have_offload = true;
+ offload_objects_file_name
+ = argv[i] + sizeof ("-foffload-objects=") - 1;
+ continue;
+ }
+
if ((p = strrchr (argv[i], '@'))
&& p != argv[i]
&& sscanf (p, "@%li%n", &loffset, &consumed) >= 1
collect_gcc))
{
have_lto = true;
- lto_argv[lto_argc++] = argv[i];
+ ltoobj_argv[ltoobj_argc++] = argv[i];
}
-
- if (find_and_merge_options (fd, file_offset, OFFLOAD_SECTION_NAME_PREFIX,
- &offload_fdecoded_options,
- &offload_fdecoded_options_count, collect_gcc))
- {
- have_offload = true;
- offload_argv[offload_argc++] = argv[i];
- }
-
close (fd);
}
}
}
+ /* Output lto-wrapper invocation command. */
+ if (verbose)
+ {
+ for (i = 0; i < argc; ++i)
+ {
+ fputs (argv[i], stderr);
+ fputc (' ', stderr);
+ }
+ fputc ('\n', stderr);
+ }
+
if (no_partition)
{
lto_mode = LTO_MODE_LTO;
if (have_offload)
{
- compile_images_for_offload_targets (offload_argc, offload_argv,
+ unsigned i, num_offload_files;
+ char **offload_argv;
+ FILE *f;
+
+ f = fopen (offload_objects_file_name, "r");
+ if (f == NULL)
+ fatal_error (input_location, "cannot open %s: %m",
+ offload_objects_file_name);
+ if (fscanf (f, "%u ", &num_offload_files) != 1)
+ fatal_error (input_location, "cannot read %s: %m",
+ offload_objects_file_name);
+ offload_argv = XCNEWVEC (char *, num_offload_files);
+
+ /* Read names of object files with offload. */
+ for (i = 0; i < num_offload_files; i++)
+ {
+ const unsigned piece = 32;
+ char *buf, *filename = XNEWVEC (char, piece);
+ size_t len;
+
+ buf = filename;
+cont1:
+ if (!fgets (buf, piece, f))
+ break;
+ len = strlen (filename);
+ if (filename[len - 1] != '\n')
+ {
+ filename = XRESIZEVEC (char, filename, len + piece);
+ buf = filename + len;
+ goto cont1;
+ }
+ filename[len - 1] = '\0';
+ offload_argv[i] = filename;
+ }
+ fclose (f);
+ if (offload_argv[num_offload_files - 1] == NULL)
+ fatal_error (input_location, "invalid format of %s",
+ offload_objects_file_name);
+ maybe_unlink (offload_objects_file_name);
+ offload_objects_file_name = NULL;
+
+ /* Look at saved offload options in files. */
+ for (i = 0; i < num_offload_files; i++)
+ {
+ char *p;
+ long loffset;
+ int fd, consumed;
+ off_t file_offset = 0;
+ char *filename = offload_argv[i];
+
+ if ((p = strrchr (offload_argv[i], '@'))
+ && p != offload_argv[i]
+ && sscanf (p, "@%li%n", &loffset, &consumed) >= 1
+ && strlen (p) == (unsigned int) consumed)
+ {
+ filename = XNEWVEC (char, p - offload_argv[i] + 1);
+ memcpy (filename, offload_argv[i], p - offload_argv[i]);
+ filename[p - offload_argv[i]] = '\0';
+ file_offset = (off_t) loffset;
+ }
+ fd = open (filename, O_RDONLY | O_BINARY);
+ if (fd == -1)
+ fatal_error (input_location, "cannot open %s: %m", filename);
+ if (!find_and_merge_options (fd, file_offset,
+ OFFLOAD_SECTION_NAME_PREFIX,
+ &offload_fdecoded_options,
+ &offload_fdecoded_options_count,
+ collect_gcc))
+ fatal_error (input_location, "cannot read %s: %m", filename);
+ close (fd);
+ if (filename != offload_argv[i])
+ XDELETEVEC (filename);
+ }
+
+ compile_images_for_offload_targets (num_offload_files, offload_argv,
offload_fdecoded_options,
offload_fdecoded_options_count,
decoded_options,
decoded_options_count);
+
+ free_array_of_ptrs ((void **) offload_argv, num_offload_files);
+
if (offload_names)
{
- find_offloadbeginend ();
+ find_crtoffloadtable ();
for (i = 0; offload_names[i]; i++)
printf ("%s\n", offload_names[i]);
free_array_of_ptrs ((void **) offload_names, i);
}
}
- if (offloadbegin)
- printf ("%s\n", offloadbegin);
-
/* If object files contain offload sections, but do not contain LTO sections,
then there is no need to perform a link-time recompilation, i.e.
lto-wrapper is used only for a compilation of offload images. */
if (have_offload && !have_lto)
- {
- for (i = 1; i < argc; ++i)
- if (strncmp (argv[i], "-fresolution=", sizeof ("-fresolution=") - 1))
- {
- char *out_file;
- /* Can be ".o" or ".so". */
- char *ext = strrchr (argv[i], '.');
- if (ext == NULL)
- out_file = make_temp_file ("");
- else
- out_file = make_temp_file (ext);
- /* The linker will delete the files we give it, so make copies. */
- copy_file (out_file, argv[i]);
- printf ("%s\n", out_file);
- }
- goto finish;
- }
+ goto finish;
if (lto_mode == LTO_MODE_LTO)
{
obstack_ptr_grow (&argv_obstack, "-fwpa");
}
- /* Append the input objects and possible preceding arguments. */
+ /* Append input arguments. */
for (i = 0; i < lto_argc; ++i)
obstack_ptr_grow (&argv_obstack, lto_argv[i]);
+ /* Append the input objects. */
+ for (i = 0; i < ltoobj_argc; ++i)
+ obstack_ptr_grow (&argv_obstack, ltoobj_argv[i]);
obstack_ptr_grow (&argv_obstack, NULL);
new_argv = XOBFINISH (&argv_obstack, const char **);
argv_ptr = &new_argv[new_head_argc];
fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
+ /* Handle early generated debug information. At compile-time
+ we output early DWARF debug info into .gnu.debuglto_ prefixed
+ sections. LTRANS object DWARF debug info refers to that.
+ So we need to transfer the .gnu.debuglto_ sections to the final
+ link. Ideally the linker plugin interface would allow us to
+ not claim those sections and instruct the linker to keep
+ them, renaming them in the process. For now we extract and
+ rename those sections via a simple-object interface to produce
+ regular objects containing only the early debug info. We
+ then partially link those to a single early debug info object
+ and pass that as additional output back to the linker plugin. */
+
+ /* Prepare the partial link to gather the compile-time generated
+ debug-info into a single input for the final link. */
+ debug_obj = make_temp_file ("debugobj");
+ obstack_ptr_grow (&argv_obstack, collect_gcc);
+ for (i = 1; i < decoded_options_count; ++i)
+ {
+ /* Retain linker choice and -B. */
+ if (decoded_options[i].opt_index == OPT_B
+ || decoded_options[i].opt_index == OPT_fuse_ld_bfd
+ || decoded_options[i].opt_index == OPT_fuse_ld_gold)
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ /* Retain all target options, this preserves -m32 for example. */
+ if (cl_options[decoded_options[i].opt_index].flags & CL_TARGET)
+ append_linker_options (&argv_obstack, &decoded_options[i-1], 2);
+ /* Recognize -g0. */
+ if (decoded_options[i].opt_index == OPT_g
+ && strcmp (decoded_options[i].arg, "0") == 0)
+ skip_debug = true;
+ }
+ obstack_ptr_grow (&argv_obstack, "-r");
+ obstack_ptr_grow (&argv_obstack, "-nostdlib");
+ obstack_ptr_grow (&argv_obstack, "-o");
+ obstack_ptr_grow (&argv_obstack, debug_obj);
+
+ /* Copy the early generated debug info from the objects to temporary
+ files and append those to the partial link commandline. */
+ n_debugobj = 0;
+ if (! skip_debug)
+ for (i = 0; i < ltoobj_argc; ++i)
+ {
+ const char *tem;
+ if ((tem = debug_objcopy (ltoobj_argv[i])))
+ {
+ obstack_ptr_grow (&argv_obstack, tem);
+ n_debugobj++;
+ }
+ }
+
+ /* Link them all into a single object. Ideally this would reduce
+ disk space usage mainly due to .debug_str merging but unfortunately
+ GNU ld doesn't perform this with -r. */
+ if (n_debugobj)
+ {
+ obstack_ptr_grow (&argv_obstack, NULL);
+ const char **debug_link_argv = XOBFINISH (&argv_obstack, const char **);
+ fork_execute (debug_link_argv[0],
+ CONST_CAST (char **, debug_link_argv), false);
+
+ /* And dispose the temporaries. */
+ for (i = 0; debug_link_argv[i]; ++i)
+ ;
+ for (--i; i > 0; --i)
+ {
+ if (strcmp (debug_link_argv[i], debug_obj) == 0)
+ break;
+ maybe_unlink (debug_link_argv[i]);
+ }
+ }
+ else
+ {
+ unlink_if_ordinary (debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ skip_debug = true;
+ }
+
if (lto_mode == LTO_MODE_LTO)
{
printf ("%s\n", flto_out);
+ if (!skip_debug)
+ {
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ }
free (flto_out);
flto_out = NULL;
}
for (i = 0; i < nr; ++i)
maybe_unlink (input_names[i]);
}
+ if (!skip_debug)
+ {
+ printf ("%s\n", debug_obj);
+ free (debug_obj);
+ debug_obj = NULL;
+ }
for (i = 0; i < nr; ++i)
{
fputs (output_names[i], stdout);
}
finish:
- if (offloadend)
- printf ("%s\n", offloadend);
-
XDELETE (lto_argv);
- XDELETE (offload_argv);
obstack_free (&argv_obstack, NULL);
}
{
const char *p;
- gcc_obstack_init (&opts_obstack);
+ init_opts_obstack ();
p = argv[0] + strlen (argv[0]);
while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))