diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c65a0545f9a9..db6f8ab04247 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2010-11-23 Dave Korn <dave.korn.cygwin@gmail.com> + + PR driver/42690 + * gcc.c (LINK_COMMAND_SPEC): Remove hard-coded pass-through plugin + options, replace by call of pass-through-libs spec function to process + link_gcc_c_sequence spec. + (lto_libgcc_spec): Delete variable. + (static_specs[]): Remove related entry. + (static_spec_functions[]): Add new entry for pass-through-libs. + (main): Don't generate deleted lto_libgcc_spec. + (pass_through_libs_spec_func): New function to implement the new + pass-through-libs spec function. + * doc/invoke.texi (pass-through-libs): Document new spec function. + 2010-11-23 Joseph Myers <joseph@codesourcery.com> * doc/options.texi (Warning, Optimization): Document. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e8d1d1dac229..c2ffea85abd8 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -9690,6 +9690,18 @@ its usage: %:remove-outfile(-lm) @end smallexample +@item @code{pass-through-libs} +The @code{pass-through-libs} spec function takes any number of arguments. It +finds any @option{-l} options and any non-options ending in ".a" (which it +assumes are the names of linker input library archive files) and returns a +result containing all the found arguments each prepended by +@option{-plugin-opt=-pass-through=} and joined by spaces. This list is +intended to be passed to the LTO linker plugin. + +@smallexample +%:pass-through-libs(%G %L %G) +@end smallexample + @item @code{print-asm-header} The @code{print-asm-header} function takes no arguments and simply prints a banner like: diff --git a/gcc/gcc.c b/gcc/gcc.c index 99d4f480d563..c2998bd96b83 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -284,6 +284,7 @@ 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 **); /* The Specs Language @@ -656,8 +657,7 @@ proper position among the other output files. */ -plugin %(linker_plugin_file) \ -plugin-opt=%(lto_wrapper) \ -plugin-opt=-fresolution=%u.res \ - %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)} \ - %{static:-plugin-opt=-pass-through=-lc} \ + %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \ } \ %{flto*:%<fcompare-debug*} \ %{flto*} %l " LINK_PIE_SPEC \ @@ -712,7 +712,6 @@ 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; @@ -1197,7 +1196,6 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("linker_plugin_file", &linker_plugin_file_spec), INIT_STATIC_SPEC ("lto_wrapper", <o_wrapper_spec), INIT_STATIC_SPEC ("lto_gcc", <o_gcc_spec), - INIT_STATIC_SPEC ("lto_libgcc", <o_libgcc_spec), INIT_STATIC_SPEC ("link_libgcc", &link_libgcc_spec), INIT_STATIC_SPEC ("md_exec_prefix", &md_exec_prefix), INIT_STATIC_SPEC ("md_startfile_prefix", &md_startfile_prefix), @@ -1242,6 +1240,7 @@ static const struct spec_function static_spec_functions[] = { "compare-debug-dump-opt", compare_debug_dump_opt_spec_function }, { "compare-debug-self-opt", compare_debug_self_opt_spec_function }, { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function }, + { "pass-through-libs", pass_through_libs_spec_func }, #ifdef EXTRA_SPEC_FUNCTIONS EXTRA_SPEC_FUNCTIONS #endif @@ -6805,11 +6804,6 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" false); if (!linker_plugin_file_spec) fatal_error ("-fuse-linker-plugin, but " LTOPLUGINSONAME " not found"); - - lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a", - R_OK, true); - if (!lto_libgcc_spec) - fatal_error ("could not find libgcc.a"); } lto_gcc_spec = argv[0]; @@ -8190,3 +8184,46 @@ compare_debug_auxbase_opt_spec_function (int arg, return name; } + +/* %:pass-through-libs spec function. Finds all -l options and input + file names in the lib spec passed to it, and makes a list of them + prepended with the plugin option to cause them to be passed through + to the final link after all the new object files have been added. */ + +const char * +pass_through_libs_spec_func (int argc, const char **argv) +{ + char *prepended = xstrdup (" "); + int n; + /* Shlemiel the painter's algorithm. Innately horrible, but at least + we know that there will never be more than a handful of strings to + concat, and it's only once per run, so it's not worth optimising. */ + for (n = 0; n < argc; n++) + { + char *old = prepended; + /* Anything that isn't an option is a full path to an output + file; pass it through if it ends in '.a'. Among options, + pass only -l. */ + if (argv[n][0] == '-' && argv[n][1] == 'l') + { + const char *lopt = argv[n] + 2; + /* Handle both joined and non-joined -l options. If for any + reason there's a trailing -l with no joined or following + arg just discard it. */ + if (!*lopt && ++n >= argc) + break; + else if (!*lopt) + lopt = argv[n]; + prepended = concat (prepended, "-plugin-opt=-pass-through=-l", + lopt, " ", NULL); + } + else if (!strcmp (".a", argv[n] + strlen (argv[n]) - 2)) + { + prepended = concat (prepended, "-plugin-opt=-pass-through=", + argv[n], " ", NULL); + } + if (prepended != old) + free (old); + } + return prepended; +}