Here are some proposed patches which allow front end compiler drivers to add command line arguments, add their own spec functions and also to disable the default linker.
It does mean that each language front end compiler driver will need an additional stub function, which at the very least does nothing. The patches below provide one for --languages=all. As an example of why this is required - the Modula-2 compiler driver uses its own linker. So it needs to both suppress the default linker and also get a list of objects generated from a compiler invocation. For more detail here is the Modula-2 lang_register_spec_functions: /* * lang_register_spec_functions - register the Modula-2 associated * spec functions. */ void lang_register_spec_functions (void) { fe_add_spec_function ("objects", get_objects); fe_add_spec_function ("nolink", no_link); fe_add_spec_function ("linkargs", get_link_args); fe_add_spec_function ("exec_prefix", add_exec_dir); fe_add_spec_function ("exec_name", add_exec_name); } The proposed patches for trunk were tested by configuring --languages=all and building and running the regression testsuite. No further regressions were introduced. Here is a possible gcc/ChangeLog entry: 2013-11-21 Gaius Mulley <gaius.mul...@southwales.ac.uk> * gcc/gcc.c (handle_OPT_B): New function which reduces size of driver_handle_option. Also allows this function to be called by language specific spec option through fe_B_prefix. (fe_add_infile): New function non static. (fe_add_linker_option): New function, non static. (fe_add_spec_function): New function, non static. (fe_B_prefix): New function, non static. (fe_save_switch): New function, non static. * gcc/gcc.h (fe_add_infile): New function prototype. (fe_add_linker_option): New function prototype. (fe_add_spec_function): New function prototype. (fe_B_prefix): New function prototype. (fe_save_switch): New function prototype. allow_linker external declaration. gcc/c/gccspec.c (lang_register_spec_functions): New stub function. gcc/cp/g++spec.c (lang_register_spec_functions): New stub function. gcc/go/gospec.c (lang_register_spec_functions): New stub function. gcc/fortran/gfortranspec.c (lang_register_spec_functions): New stub function. gcc/java/jvspec.c (lang_register_spec_functions): New stub function. The proposed patches follow: --- gcc-trunk-svn/gcc/gcc.h 2013-11-14 14:53:57.000000000 +0000 +++ gcc-trunk/gcc/gcc.h 2013-11-20 15:10:21.264388233 +0000 @@ -36,6 +36,13 @@ extern void record_temp_file (const char *, int, int); extern void pfatal_with_name (const char *) ATTRIBUTE_NORETURN; extern void set_input (const char *); +extern void fe_save_switch (const char *opt, size_t n_args, + const char *const *args, bool validated, bool known); +extern void fe_B_prefix (const char *arg); +extern void fe_add_infile (const char *infile, const char *lang); +extern void fe_add_linker_option (const char *option); +extern void fe_add_spec_function (const char *name, const char *(*func) (int, const char **)); +extern void lang_register_spec_functions (void); /* Spec files linked with gcc.c must provide definitions for these. */ @@ -55,4 +62,8 @@ extern const char **outfiles; +/* Default setting is true, but can be overridden by the language + front end to prohibit the linker from being invoked. */ +extern int allow_linker; + #endif /* ! GCC_GCC_H */ --- gcc-trunk-svn/gcc/gcc.c 2013-11-14 14:53:57.000000000 +0000 +++ gcc-trunk/gcc/gcc.c 2013-11-20 16:49:08.928244038 +0000 @@ -164,6 +164,10 @@ static const char *cross_compile = "0"; #endif +/* The lang specs might wish to override the default linker. + */ +int allow_linker = 1; + /* Greatest exit code of sub-processes that has been encountered up to now. */ static int greatest_status = 1; @@ -267,6 +271,7 @@ static const char *pass_through_libs_spec_func (int, const char **); static const char *replace_extension_spec_func (int, const char **); static char *convert_white_space (char *); +static void handle_OPT_B (const char *arg); /* The Specs Language @@ -757,6 +762,7 @@ /* We pass any -flto flags on to the linker, which is expected to understand them. In practice, this means it had better be collect2. */ /* %{e*} includes -export-dynamic; see comment in common.opt. */ + #ifndef LINK_COMMAND_SPEC #define LINK_COMMAND_SPEC "\ %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\ @@ -1361,6 +1367,10 @@ { 0, 0 } }; +/* front end registered spec functions */ +static struct spec_function *lang_spec_functions = NULL; +static unsigned int lang_spec_functions_length = 0; + static int processing_spec_function; /* Add appropriate libgcc specs to OBSTACK, taking into account @@ -3227,6 +3237,73 @@ n_switches++; } +/* Allow compiler driver to save an option OPT with N_ARGS arguments + in array ARGS, marking it as validated if VALIDATED and KNOWN if + it is an internal switch. */ + +void +fe_save_switch (const char *opt, size_t n_args, const char *const *args, + bool validated, bool known) +{ + save_switch (opt, n_args, args, validated, known); +} + +/* Allow compiler driver to add an OPT_B option. */ + +void fe_B_prefix (const char *arg) +{ + handle_OPT_B (arg); +} + +/* Allow compiler driver to add linker options. */ + +void +fe_add_linker_option (const char *option) +{ + add_linker_option (option, strlen (option)); +} + +/* Handle the OPT_B option by adding the prefix to exec, startfile and + include search paths. */ + +static +void handle_OPT_B (const char *arg) +{ + size_t len = strlen (arg); + + /* Catch the case where the user has forgotten to append a + directory separator to the path. Note, they may be using + -B to add an executable name prefix, eg "i386-elf-", in + order to distinguish between multiple installations of + GCC in the same directory. Hence we must check to see + if appending a directory separator actually makes a + valid directory name. */ + if (!IS_DIR_SEPARATOR (arg[len - 1]) + && is_directory (arg, false)) + { + char *tmp = XNEWVEC (char, len + 2); + strcpy (tmp, arg); + tmp[len] = DIR_SEPARATOR; + tmp[++len] = 0; + arg = tmp; + } + + add_prefix (&exec_prefixes, arg, NULL, + PREFIX_PRIORITY_B_OPT, 0, 0); + add_prefix (&startfile_prefixes, arg, NULL, + PREFIX_PRIORITY_B_OPT, 0, 0); + add_prefix (&include_prefixes, arg, NULL, + PREFIX_PRIORITY_B_OPT, 0, 0); +} + +/* Save the infile */ + +void +fe_add_infile (const char *infile, const char *lang) +{ + add_infile (infile, lang); +} + /* Handle an option DECODED that is unknown to the option-processing machinery. */ @@ -3582,33 +3659,7 @@ break; case OPT_B: - { - size_t len = strlen (arg); - - /* Catch the case where the user has forgotten to append a - directory separator to the path. Note, they may be using - -B to add an executable name prefix, eg "i386-elf-", in - order to distinguish between multiple installations of - GCC in the same directory. Hence we must check to see - if appending a directory separator actually makes a - valid directory name. */ - if (!IS_DIR_SEPARATOR (arg[len - 1]) - && is_directory (arg, false)) - { - char *tmp = XNEWVEC (char, len + 2); - strcpy (tmp, arg); - tmp[len] = DIR_SEPARATOR; - tmp[++len] = 0; - arg = tmp; - } - - add_prefix (&exec_prefixes, arg, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); - add_prefix (&startfile_prefixes, arg, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); - add_prefix (&include_prefixes, arg, NULL, - PREFIX_PRIORITY_B_OPT, 0, 0); - } + handle_OPT_B (arg); validated = true; break; @@ -5438,6 +5489,33 @@ return 0; } +/* Allow the front end to register a spec function. */ + +void fe_add_spec_function (const char *name, const char *(*func) (int, const char **)) +{ + const struct spec_function *f = lookup_spec_function (name); + struct spec_function *fl; + unsigned int i; + + if (f != NULL) + fatal_error ("spec function (%s) already registered", name); + + if (lang_spec_functions == NULL) + lang_spec_functions_length = 1; + + lang_spec_functions_length++; + fl = (struct spec_function *) xmalloc (sizeof (const struct spec_function)*lang_spec_functions_length); + for (i=0; i<lang_spec_functions_length-2; i++) + fl[i] = lang_spec_functions[i]; + free (lang_spec_functions); + lang_spec_functions = fl; + + lang_spec_functions[lang_spec_functions_length-2].name = name; + lang_spec_functions[lang_spec_functions_length-2].func = func; + lang_spec_functions[lang_spec_functions_length-1].name = NULL; + lang_spec_functions[lang_spec_functions_length-1].func = NULL; +} + /* Look up a spec function. */ static const struct spec_function * @@ -5449,6 +5527,11 @@ if (strcmp (sf->name, name) == 0) return sf; + if (lang_spec_functions != NULL) + for (sf = lang_spec_functions; sf->name != NULL; sf++) + if (strcmp (sf->name, name) == 0) + return sf; + return NULL; } @@ -6452,6 +6535,8 @@ spec_version, dir_separator_str, NULL); just_machine_suffix = concat (spec_machine, dir_separator_str, NULL); + lang_register_spec_functions (); + specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true); /* Read the specs file unless it is a default one. */ if (specs_file != 0 && strcmp (specs_file, "specs")) @@ -7054,7 +7139,8 @@ /* Run ld to link all the compiler output files. */ - if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2) + if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2 + && allow_linker) { int tmp = execution_count; @@ -7120,7 +7206,7 @@ /* If options said don't run linker, complain about input files to be given to the linker. */ - if (! linker_was_run && !seen_error ()) + if (! linker_was_run && !seen_error () && allow_linker) for (i = 0; (int) i < n_infiles; i++) if (explicit_link_files[i] && !(infiles[i].language && infiles[i].language[0] == '*')) --- gcc-trunk-svn/gcc/c/gccspec.c 2013-11-14 14:48:29.000000000 +0000 +++ gcc-trunk/gcc/c/gccspec.c 2013-11-20 15:19:31.976372618 +0000 @@ -104,5 +104,11 @@ return 0; /* Not used for C. */ } +/* lang_register_spec_functions. Not used for C. */ +void +lang_register_spec_functions (void) +{ +} + /* Number of extra output files that lang_specific_pre_link may generate. */ int lang_specific_extra_outfiles = 0; /* Not used for C. */ --- gcc-trunk-svn/gcc/c-family/cppspec.c 2013-11-14 14:48:28.000000000 +0000 +++ gcc-trunk/gcc/c-family/cppspec.c 2013-11-20 13:51:02.968499605 +0000 @@ -194,5 +194,11 @@ return 0; /* Not used for cpp. */ } +/* lang_register_spec_functions. Not used for cpp. */ +void +lang_register_spec_functions (void) +{ +} + /* Number of extra output files that lang_specific_pre_link may generate. */ int lang_specific_extra_outfiles = 0; /* Not used for cpp. */ --- gcc-trunk-svn/gcc/cp/g++spec.c 2013-11-14 14:52:52.000000000 +0000 +++ gcc-trunk/gcc/cp/g++spec.c 2013-11-20 13:50:25.676500496 +0000 @@ -369,5 +369,11 @@ return 0; } +/* lang_register_spec_functions. Not used for C++. */ +void +lang_register_spec_functions (void) +{ +} + /* Number of extra output files that lang_specific_pre_link may generate. */ int lang_specific_extra_outfiles = 0; /* Not used for C++. */ --- gcc-trunk-svn/gcc/go/gospec.c 2013-11-14 14:52:54.000000000 +0000 +++ gcc-trunk/gcc/go/gospec.c 2013-11-20 13:52:13.572497916 +0000 @@ -406,5 +406,11 @@ return 0; } +/* lang_register_spec_functions. Not used for Go. */ +void +lang_register_spec_functions (void) +{ +} + /* Number of extra output files that lang_specific_pre_link may generate. */ int lang_specific_extra_outfiles = 0; /* Not used for Go. */ --- gcc-trunk-svn/gcc/fortran/gfortranspec.c 2013-11-14 14:53:29.000000000 +0000 +++ gcc-trunk/gcc/fortran/gfortranspec.c 2013-11-20 15:19:26.984372552 +0000 @@ -480,5 +480,11 @@ return 0; } +/* lang_register_spec_functions. Not used for fortran. */ +void +lang_register_spec_functions (void) +{ +} + /* Number of extra output files that lang_specific_pre_link may generate. */ int lang_specific_extra_outfiles = 0; /* Not used for F77. */ --- gcc-trunk-svn/gcc/java/jvspec.c 2013-11-14 14:48:28.000000000 +0000 +++ gcc-trunk/gcc/java/jvspec.c 2013-11-20 14:51:59.372412643 +0000 @@ -641,3 +641,9 @@ } return err; } + +/* lang_register_spec_functions. Not used for Java. */ +void +lang_register_spec_functions (void) +{ +}