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)
+{
+}

Reply via email to