Richard Biener <richard.guent...@gmail.com> writes:

> On Wed, May 18, 2022 at 3:47 PM Gaius Mulley via Gcc-patches
> <gcc-patches@gcc.gnu.org> wrote:
>>
>> hello,
>>
>> this file is part-01 of the patch set for the gm2 review.

Hi Richard,

> I think you did a better job last time splitting the patches.

ah many apologies I should have annotated the diff and not split across
strict diffs and new file contents boundaries.  I should have included
gm2spec.cc in this patch set (rather than in 07.patch-set-05).

> This one contains the driver changes for which I have a hard time
> remembering the reason they exist and whether we already discussed it
> to death or not.

the changes do raise questions.  The reason for the changes here are to
allow easy linking for modula-2 users.

  $ gm2 hello.mod

for example will compile and link with all dependent modules (dependants
are generated by analysing module source imports).  The gm2 driver will
add objects and libraries to the link.

> So - with the chance to re-open and old discussion - what's special
> about modula-2 so it needs so many changes here?

Sure, the difference with modula-2 is that upon link it will generate a
scaffold program, compile the application module, compile scaffold and
link both in with all application dependants producing the final
executable.  It also needs the ability to insert include paths and link
paths for the appropriate dialect of modula-2 (although this causes
fewer changes).

But I take your point.  Perhaps it is better that gm2 follows say the C
approach of just compile a module?  Linking could be done using normal
link tools - (plus a few gm2tools for generating scaffold and finding
libraries etc).  Or a different approach?

One option is for me to rewrite the linking if required - I see merit -
not least the changes would have significantly less impact on the code
base.

> Are all of them necessary or are most of them merely "cleanups" that
> could be done as followup?

A few cleanups occurred when wishing to provide external access to the
routines.  For example the handle_opt_b function tidied up the OPT_B
case clause and also allowed gm2 to call fe_handle_opt_b but this could
certainly be done as a followup.

> Thanks,
> Richard.

For clarity here is the gm2spec.cc file from (07.patch-set-05):

regards,
Gaius


/* gm2spec.cc specific flags and argument handling within GNU Modula-2.

Copyright (C) 2007-2022 Free Software Foundation, Inc.
Contributed by Gaius Mulley <ga...@glam.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "xregex.h"
#include "obstack.h"
#include "intl.h"
#include "prefix.h"
#include "opt-suggestions.h"
#include "gcc.h"
#include "opts.h"
#include "vec.h"

#include "m2/gm2version.h"
#include "m2/gm2config.h"

#ifdef HAVE_DIRENT_H
#include <dirent.h>
#else
#ifdef HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#ifdef HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#ifdef HAVE_NDIR_H
#include <ndir.h>
#endif
#endif

#ifndef MATH_LIBRARY
#define MATH_LIBRARY "m"
#endif

#ifndef LIBSTDCXX
#define LIBSTDCXX "stdc++"
#endif

#ifndef DIR_SEPARATOR
#define DIR_SEPARATOR '/'
#endif

/* Most every one is fine with LIBRARY_PATH.  For some, it conflicts.  */
#ifndef LIBRARY_PATH_ENV
#define LIBRARY_PATH_ENV "LIBRARY_PATH"
#endif

#ifndef GM2_PREFIX_ENV
#define GM2_PREFIX_ENV "GM2_PREFIX"
#endif

#ifndef GM2_LIBEXEC_ENV
#define GM2_LIBEXEC_ENV "GM2_LIBEXEC"
#endif

#ifndef GM2IPATH_ENV
#define GM2IPATH_ENV "GM2IPATH"
#endif

#ifndef GM2OPATH_ENV
#define GM2OPATH_ENV "GM2OPATH"
#endif

int lang_specific_extra_outfiles = 0;

/* DEBUGGING will print all the options at various stages with their
   error code, full name etc.  */
#undef DEBUGGING

/* LOCAL_DEBUGGING allows the compiler driver to automatically set a -B
   prefix (assuming one it not user supplied).  It sets the -Bprefix with
   the given path to argv[0].  This allows subprograms to be found in the
   build tree (without having to be installed).  It is only meant as an
   aid to development, not a user feature :-).  It allows developers to
   lazily type:  ./gm2 -c hello.c rather than ./gm2 -B./ -c hello.c
   or /somedirectory/development/build/gcc/gm2 -c hello.c.  */
#undef LOCAL_DEBUGGING

#define DEFAULT_DIALECT "pim"

typedef enum { iso, pim, min, logitech, pimcoroutine, maxlib } libs;

/* These are the library names which are installed as part of gm2 and reflect
   -flibs=name.  The -flibs= option provides the user with a short cut to add
   libraries without having to know the include and link path.  */

static const char *library_name[maxlib]
    = { "m2iso", "m2pim", "m2min", "m2log", "m2cor" };

/* They match the installed archive name for example libm2iso.a,
   libm2pim.a, libm2min.a, libm2log.a and libm2cor.a.  They also match a
   subdirectory name where the definition modules are kept.  The driver
   checks the argument to -flibs= for an entry in library_name or
   alternatively the existance of the subdirectory (to allow for third
   party libraries to coexist).  */

static const char *library_abbrev[maxlib]
    = { "iso", "pim", "min", "log", "cor" };

/* Users may specifiy -flibs=pim,iso etc which are mapped onto
   -flibs=m2pim,m2iso respectively.  This provides a match between
   the dialect of Modula-2 and the library set.  */

int lang_specific_pre_link (void);
static void add_exec_prefix (void);
#if defined(LOCAL_DEBUGGING)
static void add_B_prefix (unsigned int *in_decoded_options_count,
                          struct cl_decoded_option **in_decoded_options);
#endif
static const char *get_objects (int argc, const char *argv[]);
static const char *get_link_args (int argc, const char *argv[]);
static const char *add_exec_dir (int argc, const char *argv[]);
static const char *add_exec_name (int argc, const char *argv[]);
static int is_object (const char *s);
static void remember_object (const char *s);
static void remember_link_arg (const char *opt, const char *s);
static void scan_for_link_args (unsigned int *in_decoded_options_count,
                                struct cl_decoded_option **in_decoded_options);
static void add_link_from_include (struct cl_decoded_option **in_options,
                                   int include);
static void add_lib (size_t opt_index, const char *lib, int joined);
static void check_gm2_root (void);
static const char *add_include (const char *libpath, const char *library);
static const char *gen_gm2_prefix (const char *gm2_root);
static const char *gen_gm2_libexec (const char *path);
static const char *get_libexec (void);
static void insert_option (unsigned int *in_decoded_options_count,
                           struct cl_decoded_option **in_decoded_options,
                           unsigned int position);
static const char *gen_link_path (const char *libpath, const char *dialect);

typedef struct object_list
{
  char *name;
  struct object_list *next;
} object_list;

static object_list *head_objects = NULL;
static object_list *head_link_args = NULL;
static int inclPos = -1;
static int linkPos = -1;
static bool seen_fonlylink = false;
static bool seen_fmakeall0 = false;
static bool seen_fmakeall = false;
static bool seen_B = false;
static const char *B_path = NULL;
static const char *multilib_dir = NULL;

/* By default, the suffix for target object files is ".o".  */
#ifdef TARGET_OBJECT_SUFFIX
#define HAVE_TARGET_OBJECT_SUFFIX
#else
#define TARGET_OBJECT_SUFFIX ".o"
#endif


/* fe_generate_option, wrap up arg and pass it to fe_save_switch.  */

static void
fe_generate_option (size_t opt_index, const char *arg, bool joined)
{
  const struct cl_option *option = &cl_options[opt_index];
  char *opt;

  if (joined)
    {
      const char *old = option->opt_text;
      opt = (char *)xmalloc (strlen (old) + strlen (arg) + 1);
      strcpy (opt, old);
      strcat (opt, arg);
    }
  else
    opt = xstrdup (option->opt_text);

  if (arg == NULL || joined)
    fe_save_switch (opt, 0, NULL, true, false);
  else
    {
      const char **x = (const char **)XCNEWVEC (const char **, 2);

      x[0] = xstrdup (arg);
      x[1] = NULL;

      gcc_assert (opt_index != OPT_l);
      fe_save_switch (opt, 1, x, true, false);
    }
}

#if defined(LOCAL_DEBUGGING)
/* Find_executable_path, if argv0 references an executable filename
   then use this path.  */

static const char *
find_executable_path (const char *argv0)
{
  if (access (argv0, X_OK) == 0)
    {
      const char *n = strrchr (argv0, DIR_SEPARATOR);

      /* Strip off the program name from argv0, but leave the DIR_SEPARATOR.  */
      if (n != NULL)
        {
          char *copy = xstrdup (argv0);
          char *n = strrchr (copy, DIR_SEPARATOR);
          n[1] = (char)0;
          return copy;
        }
    }
  return NULL;
}

/* add_B_prefix, adds the -Bprefix option so that we can tell
   subcomponents of gm2 where to pick up its executables.  But we can
   only do this if the user explicitly gives the path to argv[0].  */

static void
add_B_prefix (unsigned int *in_decoded_options_count ATTRIBUTE_UNUSED,
              struct cl_decoded_option **in_decoded_options)
{
  if ((*in_decoded_options)[0].arg != NULL)
    {
      const char *arg = (*in_decoded_options)[0].arg;
      const char *path = find_executable_path (arg);

      if (path == NULL || (strcmp (path, "") == 0))
        path = gen_gm2_libexec (get_libexec ());

      if (path != NULL && (strcmp (path, "") != 0))
        {
#if defined(DEBUGGING)
          unsigned int i;

          printf ("going to add -B%s\n", path);
          for (i = 0; i < *in_decoded_options_count; i++)
            print_option ("before add -B", i, *in_decoded_options);
#endif
          fe_handle_opt_b (xstrdup (path));
          fe_generate_option (OPT_B, xstrdup (path), 1);

#if defined(DEBUGGING)
          for (i = 0; i < *in_decoded_options_count; i++)
            print_option ("after add -B", i, *in_decoded_options);
#endif
        }
    }
}
#endif

/* add_exec_prefix, adds the -ftarget-ar= option so that we can tell
   gm2lcc where to pick up the `ar' utility.  */

static void
add_exec_prefix (void)
{
  const char *ar = AR_PATH;
  const char *ranlib = RANLIB_PATH;

  fe_generate_option (OPT_ftarget_ar_, ar, true);
  fe_generate_option (OPT_ftarget_ranlib_, ranlib, true);
}

static const char *
get_libexec (void)
{
  const char *libexec = getenv (GM2_LIBEXEC_ENV);

  if (libexec == NULL || (strcmp (libexec, "") == 0))
    return STANDARD_LIBEXEC_PREFIX;
  else
    return libexec;
}

static int
is_object (const char *s)
{
  return (strlen (s) > strlen (TARGET_OBJECT_SUFFIX)
          && (strcmp (s + strlen (s) - strlen (TARGET_OBJECT_SUFFIX),
                      TARGET_OBJECT_SUFFIX)
              == 0));
}

static void
remember_object (const char *s)
{
  object_list *n = (object_list *)xmalloc (sizeof (object_list));
  n->name = xstrdup (s);
  n->next = head_objects;
  head_objects = n;
#if defined(DEBUGGING)
  fprintf (stderr, "remembering object: %s\n", s);
#endif
}

static void
remember_link_arg (const char *opt, const char *s)
{
  object_list *n = (object_list *)xmalloc (sizeof (object_list));
  n->name = (char *)xmalloc (strlen (opt) + strlen (s) + 1);
  strcpy (n->name, opt);
  strcat (n->name, s);
  n->next = head_link_args;
  head_link_args = n;
}

/* add_link_from_include, adds option to (**in_argv)[pos] using the
   include path.  */

static void
add_link_from_include (struct cl_decoded_option **in_options, int include)
{
  struct cl_decoded_option *options = *in_options;
  const char *arg = options[include].arg;

  fe_generate_option (OPT_fobject_path_, arg, true);
}

/* add_lib, add lib to the end of the command line.  */

static void
add_lib (size_t opt_index, const char *lib, int joined)
{
  if (lib == NULL || (strcmp (lib, "") == 0))
    return;

  fe_generate_option (opt_index, lib, joined);
}

/* insert_option, inserts an option at position on the command line.  */

static void
insert_option (unsigned int *in_decoded_options_count,
               struct cl_decoded_option **in_decoded_options,
               unsigned int position)
{
  struct cl_decoded_option *new_decoded_options;
  unsigned int i;

  (*in_decoded_options_count)++;

  gcc_assert (position <= (*in_decoded_options_count));

  new_decoded_options
      = XNEWVEC (struct cl_decoded_option, (*in_decoded_options_count) + 1);
  for (i = 0; i < position; i++)
    new_decoded_options[i] = (*in_decoded_options)[i];
  memset (&new_decoded_options[position], 0,
          sizeof (struct cl_decoded_option));

  for (i = position; i < (*in_decoded_options_count) - 1; i++)
    new_decoded_options[i + 1] = (*in_decoded_options)[i];
  *in_decoded_options = new_decoded_options;
}

/* add_library, adds a library to the command line at arg position.
   It returns the number of arguments added.  If libraryname is NULL or
   empty then zero is returned.  */

static int
add_library (const char *libraryname, unsigned int *in_decoded_options_count,
             struct cl_decoded_option **in_decoded_options,
             unsigned int position)
{
  if (libraryname == NULL || (strcmp (libraryname, "") == 0))
    return 0;

  insert_option (in_decoded_options_count, in_decoded_options, position);

#if defined(DEBUGGING)
  printf ("going to add -l%s at position=%d  count=%d\n", libraryname,
            position, *in_decoded_options_count);
  print_options ("before add_library", *in_decoded_options_count, 
*in_decoded_options);
#endif

  generate_option (OPT_l, libraryname, 1, CL_DRIVER,
                   &(*in_decoded_options)[position]);

#if defined(DEBUGGING)
  print_options ("after add_library", *in_decoded_options_count, 
*in_decoded_options);
#endif
  return 1;
}

/* build_archive_path returns a string containing the a path to the
   archive defined by libpath and dialectLib.  */

static const char *
build_archive_path (const char *libpath, const char *library)
{
  if (library != NULL)
    {
      const char *libdir = (const char *)library;

      if (libdir != NULL)
        {
          int machine_length = 0;
          char dir_sep[2];

          dir_sep[0] = DIR_SEPARATOR;
          dir_sep[1] = (char)0;

          if (multilib_dir != NULL)
            {
              machine_length = strlen (multilib_dir);
              machine_length += strlen (dir_sep);
            }

          int l = strlen (libpath) + 1 + strlen ("m2") + 1
            + strlen (libdir) + 1 + machine_length + 1;
          char *s = (char *)xmalloc (l);

          strcpy (s, libpath);
          strcat (s, dir_sep);
          if (machine_length > 0)
            {
              strcat (s, multilib_dir);
              strcat (s, dir_sep);
            }
          strcat (s, "m2");
          strcat (s, dir_sep);
          strcat (s, libdir);
          return s;
        }
    }
  return NULL;
}

/* safe_strdup, safely duplicates a string.  */

static char *
safe_strdup (const char *s)
{
  if (s != NULL)
    return xstrdup (s);
  return NULL;
}

/* add_default_combination, adds the correct link path and then the
   library name.  */

static void
add_default_combination (const char *libpath, const char *library,
                         unsigned int *in_decoded_options_count,
                         struct cl_decoded_option **in_decoded_options,
                         unsigned int position)
{
  if (library != NULL)
    {
      add_lib (OPT_L, build_archive_path (libpath, library), true);
      add_library (safe_strdup (library), in_decoded_options_count,
                   in_decoded_options, position);
    }
}

/* gen_link_path, generates a link path for the chosen dialect.  */

static const char *
gen_link_path (const char *libpath, const char *dialect)
{
  return add_include (libpath, dialect);
}

/* add_default_archives, adds the default archives to the end of the
   current command line.  */

static int
add_default_archives (const char *libpath, const char *libraries,
                      unsigned int *in_decoded_options_count,
                      struct cl_decoded_option **in_decoded_options,
                      unsigned int position)
{
  const char *prev;
  const char *l = libraries;
  const char *e;
  char *c;
  unsigned int libcount = 0;

  do
    {
      if (libpath == NULL)
        prev = NULL;
      else
        prev = xstrdup (libpath);

      e = index (l, ',');
      if (e == NULL)
        {
          c = xstrdup (l);
          l = NULL;
        }
      else
        {
          c = xstrndup (l, e - l);
          l = e + 1;
        }
      add_default_combination (libpath, c, in_decoded_options_count,
                               in_decoded_options, position + libcount);
      libcount++;
      prev = gen_link_path (libpath, c);

      fe_generate_option (OPT_L, prev, true);
      free (c);
    }
  while ((l != NULL) && (l[0] != (char)0));
  return libcount;
}

/* build_include_path, builds the component of the include path
   referenced by the, which, libs.  */

static const char *
build_include_path (const char *libpath, const char *library)
{
  char dir_sep[2];
  char *gm2libs;
  unsigned int machine_length = 0;

  dir_sep[0] = DIR_SEPARATOR;
  dir_sep[1] = (char)0;

  if (multilib_dir != NULL)
    {
      machine_length = strlen (multilib_dir);
      machine_length += strlen (dir_sep);
    }

  gm2libs = (char *)alloca (strlen (libpath) + strlen (dir_sep) + strlen ("m2")
                            + strlen (dir_sep) + strlen (library) + 1
                            + machine_length + 1);
  strcpy (gm2libs, libpath);
  strcat (gm2libs, dir_sep);
  if (machine_length > 0)
    {
      strcat (gm2libs, multilib_dir);
      strcat (gm2libs, dir_sep);
    }
  strcat (gm2libs, "m2");
  strcat (gm2libs, dir_sep);
  strcat (gm2libs, library);

  return xstrdup (gm2libs);
}

/* add_include add the correct include path given the libpath and
   library.  The new path is returned.  */

static const char *
add_include (const char *libpath, const char *library)
{
  if (library == NULL)
    return NULL;
  else
    return build_include_path (libpath, library);
}

/* add_default_includes, add the appropriate default include paths
   depending upon the style of libraries chosen.  */

static void
add_default_includes (const char *libpath, const char *libraries)
{
  const char *l = libraries;
  const char *e;
  const char *c;
  const char *path;

  do
    {
      e = index (l, ',');
      if (e == NULL)
        {
          c = xstrdup (l);
          l = NULL;
        }
      else
        {
          c = xstrndup (l, e - l);
          l = e + 1;
        }
      path = add_include (libpath, c);
      fe_generate_option (OPT_I, path, true);
    }
  while ((l != NULL) && (l[0] != (char)0));
}

/* build_fobject_path, returns a string containing the a path to the
   objects defined by libpath and dialectLib.  */

static char *
build_fobject_path (const char *prev, const char *libpath, const char *library)
{
  char sepstr[2];
  char *gm2objs;
  const char *libName = library;
  unsigned int machine_length = 0;

  sepstr[0] = DIR_SEPARATOR;
  sepstr[1] = (char)0;

  if (multilib_dir != NULL)
    {
      machine_length = strlen (multilib_dir);
      if (machine_length > 0)
        machine_length += strlen (sepstr);
    }

  if (prev == NULL)
    {
      gm2objs = (char *)alloca (
          strlen (libpath) + strlen (sepstr)
          + machine_length
          + strlen ("m2") + strlen (sepstr)
          + strlen (libName) + 1 + strlen (libpath) + strlen (sepstr)
          + strlen ("m2") + strlen (sepstr) + strlen (libName) + 1);
      strcpy (gm2objs, "");
    }
  else
    {
      gm2objs = (char *)alloca (
          strlen (prev) + strlen (":") + strlen (libpath) + strlen (sepstr)
          + machine_length
          + strlen ("m2") + strlen (sepstr) + strlen (libName) + 1
          + strlen (libpath) + strlen (sepstr) + strlen ("m2")
          + strlen (sepstr) + strlen (libName) + 1);
      strcpy (gm2objs, prev);
      strcat (gm2objs, ":");
    }
  strcat (gm2objs, libpath);
  strcat (gm2objs, sepstr);
  if (machine_length > 0)
    {
      strcat (gm2objs, multilib_dir);
      strcat (gm2objs, sepstr);
    }
  strcat (gm2objs, "m2");
  strcat (gm2objs, sepstr);
  strcat (gm2objs, libName);

  return xstrdup (gm2objs);
}

/* add_fobject_path, add all required path to satisfy the link for library.  */

static void
add_fobject_path (const char *prev, const char *libpath, const char *library)
{
  if (library != NULL)
    fe_generate_option (OPT_fobject_path_,
                        build_fobject_path (prev, libpath, library), true);
}

/* add_default_fobjects, add the appropriate default include paths
   depending upon the libraries chosen.  */

static void
add_default_fobjects (const char *prev, const char *libpath,
                      const char *libraries)
{
  const char *l = libraries;
  const char *e;
  const char *c;

  do
    {
      e = index (l, ',');
      if (e == NULL)
        {
          c = xstrdup (l);
          l = NULL;
        }
      else
        {
          c = xstrndup (l, e - l);
          l = e + 1;
        }
      add_fobject_path (prev, libpath, c);
    }
  while ((l != NULL) && (l[0] != (char)0));
}

static void
scan_for_link_args (unsigned int *in_decoded_options_count,
                    struct cl_decoded_option **in_decoded_options)
{
  struct cl_decoded_option *decoded_options = *in_decoded_options;
  unsigned int i;

  for (i = 0; i < *in_decoded_options_count; i++)
    {
      const char *arg = decoded_options[i].arg;
      size_t opt = decoded_options[i].opt_index;

      if (opt == OPT_l)
        remember_link_arg ("-l", arg);
      else if (opt == OPT_L)
        remember_link_arg ("-L", arg);
    }
}

/* purge_include_options, remove any -I option found from
   in_decoded_options.  */

static void
purge_include_options (unsigned int *in_decoded_options_count,
                       struct cl_decoded_option **in_decoded_options)
{
  struct cl_decoded_option *decoded_options = *in_decoded_options;
  unsigned int i, j;

  for (i = 0; i < *in_decoded_options_count; i++)
    {
      size_t opt = decoded_options[i].opt_index;

      if (opt == OPT_I)
        {
          for (j = i; j + 1 < *in_decoded_options_count; j++)
            decoded_options[j] = decoded_options[j + 1];
          (*in_decoded_options_count)--;
        }
    }
}

/* convert_include_into_link, convert the include path options into
   link path options.  */

static void
convert_include_into_link (struct cl_decoded_option **in_decoded_options,
                           unsigned int *in_decoded_options_count)
{
  unsigned int i;

  for (i = 1; i < *in_decoded_options_count; i++)
    {
      size_t opt = (*in_decoded_options)[i].opt_index;

      if (opt == OPT_I)
        add_link_from_include (in_decoded_options, i);
    }
}

/* build_path, implements export PATH=$(prefix)/bin:$PATH.  */

static void
build_path (const char *prefix)
{
  int l = strlen ("PATH=") + strlen (prefix) + 1 + strlen ("bin") + 1;
  char *s;
  char dir_sep[2];
  const char *path;

  path = getenv ("PATH");
  if (path != NULL && (strcmp (path, "") != 0))
    l += strlen (":") + strlen (path);
  s = (char *)xmalloc (l);
  dir_sep[0] = DIR_SEPARATOR;
  dir_sep[1] = (char)0;

  strcpy (s, "PATH=");
  strcat (s, prefix);
  strcat (s, dir_sep);
  strcat (s, "bin");
  if (path != NULL && (strcmp (path, "") != 0))
    {
      strcat (s, ":");
      strcat (s, path);
    }
  fe_putenv (s);
}

/* gen_gm2_prefix, return the prefix string.  */

static const char *
gen_gm2_prefix (const char *prefix)
{
  int l = strlen (prefix) + 1 + strlen ("lib") + 1 + strlen ("gcc") + 1
          + strlen (DEFAULT_TARGET_MACHINE) + 1
          + strlen (DEFAULT_TARGET_VERSION) + 1;
  char *s = (char *)xmalloc (l);
  char dir_sep[2];

  dir_sep[0] = DIR_SEPARATOR;
  dir_sep[1] = (char)0;

  strcpy (s, prefix);
  strcat (s, dir_sep);
  strcat (s, "lib");
  strcat (s, dir_sep);
  strcat (s, "gcc");
  strcat (s, dir_sep);
  strcat (s, DEFAULT_TARGET_MACHINE);
  strcat (s, dir_sep);
  strcat (s, DEFAULT_TARGET_VERSION);
  return s;
}

/* gen_gm2_libexec, return a libexec string.  */

static const char *
gen_gm2_libexec (const char *libexec)
{
  int l = strlen (libexec) + 1 + strlen (DEFAULT_TARGET_MACHINE) + 1
          + strlen (DEFAULT_TARGET_VERSION) + 1;
  char *s = (char *)xmalloc (l);
  char dir_sep[2];

  dir_sep[0] = DIR_SEPARATOR;
  dir_sep[1] = (char)0;

  strcpy (s, libexec);
  strcat (s, dir_sep);
  strcat (s, DEFAULT_TARGET_MACHINE);
  strcat (s, dir_sep);
  strcat (s, DEFAULT_TARGET_VERSION);
  return s;
}

/* build_library_path, implements export
   LIBRARY_PATH=$(gm2_root)/lib/gcc/\ $(default_target_machine)/\
   $(default_target_version)
   where gm2_root, default_target_machine and default_target_version
   are C strings.  */

static void
build_library_path (const char *prefix)
{
  const char *path = gen_gm2_prefix (prefix);
  int l = strlen ("LIBRARY_PATH=") + strlen (prefix) + 1;
  char *s = (char *)xmalloc (l);

  strcpy (s, "LIBRARY_PATH=");
  strcat (s, path);
  fe_putenv (s);
}

/* build_compiler_path, implements export
   COMPILER_PATH=$(GM2_LIBEXEC)/libexec/gcc/\
   $(default_target_machine)/\ $(default_target_version).  */

static void
build_compiler_path (const char *path)
{
  const char *libexec = gen_gm2_libexec (path);
  int l = strlen ("COMPILER_PATH=") + strlen (libexec) + 1;
  char *s = (char *)xmalloc (l);

  strcpy (s, "COMPILER_PATH=");
  strcat (s, libexec);
  fe_putenv (s);
}

/* check_gm2_root, checks to see whether GM2_PREFIX or GM2_LIBEXEC
   has been defined, if it has and also COMPILER_PATH and LIBRARY_PATH
   are both unset then it sets COMPILER_PATH and LIBRARY_PATH using
   GM2_PREFIX and GM2_LIBEXEC as its prefix.  */

static void
check_gm2_root (void)
{
  const char *library_path;
  const char *compiler_path;
  const char *gm2_prefix;
  const char *gm2_libexec;

  library_path = fe_getenv (LIBRARY_PATH_ENV);
  compiler_path = fe_getenv ("COMPILER_PATH");
  gm2_prefix = fe_getenv (GM2_PREFIX_ENV);
  gm2_libexec = fe_getenv (GM2_LIBEXEC_ENV);

  if ((library_path == NULL || (strcmp (library_path, "") == 0))
      && (compiler_path == NULL || (strcmp (compiler_path, "") == 0)))
    {
#if defined(DEBUGGING)
      fprintf (stderr, "STANDARD_LIBEXEC_PREFIX = %s\n",
               STANDARD_LIBEXEC_PREFIX);
      fprintf (stderr, "STANDARD_BINDIR_PREFIX = %s\n",
               STANDARD_BINDIR_PREFIX);
      fprintf (stderr, "TOOLDIR_BASE_PREFIX = %s\n", TOOLDIR_BASE_PREFIX);
      fprintf (stderr, "DEFAULT_TARGET_VERSION = %s\n",
               DEFAULT_TARGET_VERSION);
      fprintf (stderr, "DEFAULT_TARGET_MACHINE = %s\n",
               DEFAULT_TARGET_MACHINE);
#endif

      if (gm2_prefix != NULL && (strcmp (gm2_prefix, "") != 0))
        {
          build_path (gm2_prefix);
          build_library_path (gm2_prefix);
        }
      if (gm2_libexec != NULL && (strcmp (gm2_libexec, "") != 0))
        build_compiler_path (gm2_libexec);
    }
  else if (gm2_prefix != NULL && !seen_fmakeall0)

    /* No need to issue a warning if seen_fmakeall0 as the parent will
       have set COMPILER_PATH and LIBRARY_PATH because of GM2_ROOT.
       Also users should not be using -fmakeall0 as it is an internal
       option.  */
    error ("it is not advisible to set %qs as well as either %qs or %qs",
           GM2_PREFIX_ENV, LIBRARY_PATH_ENV, "COMPILER_PATH");
}

/* library_installed returns true if directory library is found under
   libpath.  */

static bool
library_installed (const char *libpath, const char *library)
{
#if defined(HAVE_OPENDIR) && defined(HAVE_DIRENT_H)
  const char *complete = build_archive_path (libpath, library);
  DIR *directory = opendir (complete);

  if (directory == NULL || (errno == ENOENT))
    return false;
  /* Directory exists and therefore the library also exists.  */
  closedir (directory);
  return true;
#else
  return false;
#endif
}

/* check_valid check to see that the library is valid.
   It check the library against the default library set in gm2 and
   also against any additional libraries installed in the prefix tree.  */

static bool
check_valid_library (const char *libpath, const char *library)
{
  /* firstly check against the default libraries (which might not be
     installed yet).  */
  for (int i = 0; i < maxlib; i++)
    if (strcmp (library, library_name[i]) == 0)
      return true;
  /* secondly check whether it is installed (a third party library).  */
  return library_installed (libpath, library);
}

/* check_valid_list check to see that the libraries specified are valid.
   It checks against the default library set in gm2 and also against
   any additional libraries installed in the libpath tree.  */

static bool
check_valid_list (const char *libpath, const char *libraries)
{
  const char *start = libraries;
  const char *end;
  const char *copy;

  do
    {
      end = index (start, ',');
      if (end == NULL)
        {
          copy = xstrdup (start);
          start = NULL;
        }
      else
        {
          copy = xstrndup (start, end - start);
          start = end + 1;
        }
      if (! check_valid_library (libpath, copy))
        {
          error ("library specified %sq is either not installed or does not 
exist",
                 copy);
          return false;
        }
    }
  while ((start != NULL) && (start[0] != (char)0));
  return true;
}


/* add_env_option append multiple options, one for each element in
   the path.  */

static void
add_env_option (const char *path, size_t option)
{
  if (path != NULL)
    {
      const char *p = path;
      const char *s = path;
      char *arg;
      int i, l, n;

      l = strlen (path);
      i = 0;
      n = 0;
      while (i < l)
        {
          if (path[i] == ':')
            {
              arg = (char *)xmalloc (n + 1);
              strncpy (arg, s, n);
              arg[n] = (char)0;
              fe_generate_option (option, arg, true);
              n++;
              s = &p[i];
              n = 0;
            }
          else
            {
              n++;
              i++;
            }
        }
      if (n > 0)
        {
          arg = (char *)xmalloc (n + 1);
          strncpy (arg, s, n);
          arg[n] = (char)0;
          fe_generate_option (option, arg, true);
        }
    }
}

/* add_word returns a new string which has the contents of lib
   appended to list.  If list is NULL then lib is duplicated and
   returned otherwise the list is appended by "," and the contents of
   lib.  */

static const char *
add_word (const char *list, const char *lib)
{
  char *copy;
  if (list == NULL)
    return xstrdup (lib);
  copy = (char *) xmalloc (strlen (list) + strlen (lib) + 1 + 1);
  strcpy (copy, list);
  strcat (copy, ",");
  strcat (copy, lib);
  return copy;
}

/* convert_abbreviation checks abbreviation against known library
   abbreviations.  If an abbreviation is found it converts the element
   to the full library name, otherwise the user supplied name is added
   to the full_libraries list.  A new string is returned.  */

static const char *
convert_abbreviation (const char *full_libraries, const char *abbreviation)
{
  for (int i = 0; i < maxlib; i++)
    if (strcmp (abbreviation, library_abbrev[i]) == 0)
      return add_word (full_libraries, library_name[i]);
  /* No abbreviation found therefore assume user specified full library name.  
*/
  return add_word (full_libraries, abbreviation);
}

/* convert_abbreviations checks each element in the library list to
   see if an a known library abbreviation was used.  If found it
   converts the element to the full library name, otherwise the
   element is copied into the list.  A new string is returned.  */

static const char *
convert_abbreviations (const char *libraries)
{
  const char *start = libraries;
  const char *end;
  const char *full_libraries = NULL;

  do
    {
      end = index (start, ',');
      if (end == NULL)
        {
          full_libraries = convert_abbreviation (full_libraries, start);
          start = NULL;
        }
      else
        {
          full_libraries = convert_abbreviation (full_libraries, xstrndup 
(start, end - start));
          start = end + 1;
        }
    }
  while ((start != NULL) && (start[0] != (char)0));
  return full_libraries;
}

/* lang_specific_driver is invoked if we are compiling/linking a
   Modula-2 file.  It checks for module paths and linking requirements
   which are language specific.  */

void
lang_specific_driver (struct cl_decoded_option **in_decoded_options,
                      unsigned int *in_decoded_options_count,
                      int *in_added_libraries)
{
  unsigned int i;

  /* Nonzero if we saw a `-xfoo' language specification on the command
     line.  This function will add a -xmodula-2 if the user has not
     already placed one onto the command line.  */
  bool seen_x_flag = false;
  const char *language = NULL;

  const char *libraries = NULL;
  const char *dialect = DEFAULT_DIALECT;

  bool seen_module_extension = -1;
  bool linking = true;
  bool seen_source = false;
  bool seen_fexceptions = true;
  const char *libpath;
  const char *gm2ipath;
  const char *gm2opath;

  /* By default, we add the math library if we have one.  */
  bool need_math = (strcmp (MATH_LIBRARY, "") == 0);

  /* True if we should add -lpthread to the command-line.  */
  bool need_pthread = true;

  /* True if we should add -fplugin=m2rte to the command-line.  */
  bool need_plugin = true;

  /* True if we should add -shared-libgcc to the command-line.  */
  bool shared_libgcc = true;

  /* The total number of arguments with the new stuff.  */
  unsigned int argc = *in_decoded_options_count;

  /* Initially scan the options for key values.  */
  for (i = 1; i < argc; i++)
    {
      if ((*in_decoded_options)[i].errors & CL_ERR_MISSING_ARG)
        continue;  /* Avoid examining arguments of options missing them.  */
      switch ((*in_decoded_options)[i].opt_index)
        {
        case OPT_fuselist:
          /* Modula-2 link time option, which is used to direct the specs.  */
          (*in_decoded_options)[i].errors = 0;
          break;
        case OPT_fexceptions:
          seen_fexceptions = ((*in_decoded_options)[i].value);
          break;
        case OPT_fonlylink:
          seen_fonlylink = true;
          break;
#if 0
        case OPT_fmakeall:
          seen_fmakeall = true;
          break;
        case OPT_fmakeall0:
          seen_fmakeall0 = true;
          break;
#endif
        case OPT_B:
          seen_B = true;
          B_path = (*in_decoded_options)[i].arg;
          break;
        case OPT_fno_pthread:
          need_pthread = false;
          break;
        case OPT_fno_m2_plugin:
          need_plugin = false;
          break;
        default:
          if (((*in_decoded_options)[i].orig_option_with_args_text != NULL)
              && (strncmp ((*in_decoded_options)[i].orig_option_with_args_text,
                           "-m", 2) == 0))
            multilib_dir = xstrdup 
((*in_decoded_options)[i].orig_option_with_args_text
                                    + 2);
        }
    }

  /* -fmakeall implies that the first invoked driver only does the link
     and should leave all compiles to the makefile otherwise we will try
     and link two main applications.  */
  if (seen_fmakeall && (!seen_fonlylink))
    fe_generate_option (OPT_fonlylink, NULL, false);

  check_gm2_root ();
  libpath = fe_getenv (LIBRARY_PATH_ENV);
  if (libpath == NULL || (strcmp (libpath, "") == 0))
    libpath = LIBSUBDIR;

  gm2ipath = fe_getenv (GM2IPATH_ENV);
  gm2opath = fe_getenv (GM2OPATH_ENV);

#if defined(DEBUGGING)
  print_options ("at beginning", *in_decoded_options_count, 
*in_decoded_options);
#endif
  i = 1;
  for (i = 1; i < *in_decoded_options_count; i++)
    {
      const char *arg = (*in_decoded_options)[i].arg;
      size_t opt = (*in_decoded_options)[i].opt_index;

#if defined(DEBUGGING)
      print_option ("in for", i, *in_decoded_options);
      printf ("argument: %s, %ld\n", arg, opt);
#endif
      if ((opt == OPT_c) || (opt == OPT_S))
        linking = false;
      if (opt == OPT_I)
        {
          fe_generate_option (OPT_I, arg, true);
          inclPos = i;
        }
      if (opt == OPT_fobject_path_)
        linkPos = i;
      if (opt == OPT_fiso)
        dialect = "iso";
      if (opt == OPT_fpim2)
        dialect = "pim2";
      if (opt == OPT_fpim3)
        dialect = "pim3";
      if (opt == OPT_fpim4)
        dialect = "pim4";
      if (opt == OPT_fpim)
        dialect = "pim";
      if (opt == OPT_flibs_)
        libraries = xstrdup (arg);
      if (opt == OPT_fmod_)
        seen_module_extension = true;
      if (opt == OPT_version)
        gm2_version (true);
      if (opt == OPT_fm2_version)
        gm2_version (false);
      if (opt == OPT_x)
        {
          seen_x_flag = true;
          language = arg;
        }
      if (opt == OPT_SPECIAL_input_file)
        {
          if (is_object (arg))
            remember_object (arg);
          else
            seen_source = true;
        }
    }
  if (linking && (!seen_source))
    linking = false;

  if (language != NULL && (strcmp (language, "modula-2") != 0))
    return;
#if defined(DEBUGGING)
  print_options ("in the middle", *in_decoded_options_count, 
*in_decoded_options);
#endif

  /* If the libraries have not been specified by the user and the
     dialect has been specified then select the appropriate libraries.  */

  if (libraries == NULL)
    {
      if (strncmp (dialect, "pim", 3) == 0)
        libraries = xstrdup ("m2pim");
      else if (strcmp (dialect, "iso") == 0)
        libraries = xstrdup ("m2iso,m2pim");
    }

  libraries = convert_abbreviations (libraries);
  if (! check_valid_list (libpath, libraries))
    return;

  if (inclPos != -1 && linkPos == -1)
    {
#if defined(DEBUGGING)
      printf ("inclPos = %d,  linkPos = %d\n", inclPos, linkPos);
#endif
      linkPos = 1;
      convert_include_into_link (in_decoded_options, in_decoded_options_count);
    }
  add_env_option (gm2ipath, OPT_I);
  add_default_includes (libpath, libraries);
  add_exec_prefix ();

#if defined(LOCAL_DEBUGGING)
  if (!seen_B)
    add_B_prefix (in_decoded_options_count, in_decoded_options);
#endif

#if defined(DEBUGGING)
  print_options ("after B prefix", *in_decoded_options_count, 
*in_decoded_options);
#endif

  if (linkPos == -1)
    {
      linkPos = 1;
      if (inclPos == -1)
        add_default_fobjects (NULL, libpath, libraries);
      else
        {
          struct cl_decoded_option *options = *in_decoded_options;
          const char *prev = options[inclPos].arg;

          add_default_fobjects (prev, libpath, libraries);
        }
    }

  if ((!seen_x_flag) && seen_module_extension)
    fe_generate_option (OPT_x, "modula-2", false);

  if (need_plugin)
    fe_generate_option (OPT_fplugin_, "m2rte", true);

  if (linking)
    {
      add_env_option (gm2opath, OPT_fobject_path_);
      (*in_added_libraries) += add_default_archives (
          libpath, libraries, in_decoded_options_count, in_decoded_options,
          *in_decoded_options_count);

      if (need_math)
        (*in_added_libraries)
            += add_library (MATH_LIBRARY, in_decoded_options_count,
                            in_decoded_options, *in_decoded_options_count);

      if (need_pthread)
        (*in_added_libraries)
            += add_library ("pthread", in_decoded_options_count,
                            in_decoded_options, *in_decoded_options_count);

      if (seen_fexceptions)
        (*in_added_libraries)
            += add_library (LIBSTDCXX, in_decoded_options_count,
                            in_decoded_options, *in_decoded_options_count);

      /* There is no point adding -shared-libgcc if we don't have a shared
         libgcc.  */
#if !defined(ENABLE_SHARED_LIBGCC)
      shared_libgcc = false;
#endif
      if (shared_libgcc)
        {
          fe_generate_option (OPT_shared_libgcc, NULL, false);
          (*in_added_libraries)
              += add_library ("gcc_eh", in_decoded_options_count,
                              in_decoded_options, *in_decoded_options_count);
        }
    }
  scan_for_link_args (in_decoded_options_count, in_decoded_options);

#if defined(DEBUGGING)
  print_options ("before include purge", *in_decoded_options_count, 
*in_decoded_options);
#endif
  purge_include_options (in_decoded_options_count, in_decoded_options);
#if defined(DEBUGGING)
  print_options ("after include purge", *in_decoded_options_count, 
*in_decoded_options);
#endif
}

/* lang_specific_pre_link - does nothing.  */

int
lang_specific_pre_link (void)
{
  return 0;
}

/* get_objects returns a string containing all objects specified on
   the command line.  */

static const char *
get_objects (int argc ATTRIBUTE_UNUSED, const char *argv[] ATTRIBUTE_UNUSED)
{
  char *result = (char *)xmalloc (1);
  int len = 0;
  int flen;
  object_list *o;

  *result = (char)0;

  for (o = head_objects; o != NULL; o = o->next)
    {
      len = strlen (result);
      flen = strlen (o->name);
      result = (char *)xrealloc (result, len + flen + 1 + 1);
      strcat (result, o->name);
      strcat (result, " ");
    }
  return result;
}

/* remove_objects return an empty string, but also remove all objects
   from the command line.  */

extern void fe_mark_compiled (const char *);

static const char *
remove_objects (int argc ATTRIBUTE_UNUSED, const char *argv[] ATTRIBUTE_UNUSED)
{
  object_list *o;

  for (o = head_objects; o != NULL; o = o->next)
    fe_mark_compiled (o->name);

  return NULL;
}

/* get_link_args returns a string containing all arguments related to
   the link stage.  */

static const char *
get_link_args (int argc ATTRIBUTE_UNUSED, const char *argv[] ATTRIBUTE_UNUSED)
{
  char *result = (char *)xmalloc (1);
  int len = 0;
  int alen;
  object_list *o;

  *result = (char)0;

  for (o = head_link_args; o != NULL; o = o->next)
    {
      len = strlen (result);
      alen = strlen (o->name);
      result = (char *)xrealloc (result, len + alen + 1 + 1);
      strcat (result, o->name);
      strcat (result, " ");
    }
  return result;
}

/* add_exec_dir prepends the exec path to the given executable filename.  */

static const char *
add_exec_dir (int argc, const char *argv[])
{
  if (argc == 1 && argv[0] != NULL)
    {
      const char *path;

      if (seen_B)
        path = xstrdup (B_path);
      else
        path = gen_gm2_libexec (get_libexec ());

      if (path != NULL)
        {
          char *opt = (char *)xmalloc (strlen ("-fcppprog=") + strlen (path)
                                       + 1 + strlen (argv[0]) + 1);
          char *sep = (char *)alloca (2);

          sep[0] = DIR_SEPARATOR;
          sep[1] = (char)0;

          strcpy (opt, "-fcppprog=");
          strcat (opt, path);
          strcat (opt, sep);
          strcat (opt, argv[0]);
          return opt;
        }
    }
  return "-fcppprog=none";
}

/* add_exec_name generate binary name.  */

static const char *
add_exec_name (int argc, const char *argv[])
{
  if (argc == 1 && argv[0] != NULL)
    return argv[0];
  return xstrdup ("");
}

/* no_link tell gcc.c not to invoke its linker.  */

static const char *
no_link (int argc ATTRIBUTE_UNUSED, const char *argv[] ATTRIBUTE_UNUSED)
{
  allow_linker = false;
  return xstrdup ("");
}

/* exit_callback invoke exit.  */

static const char *
exit_callback (int argc ATTRIBUTE_UNUSED, const char *argv[] ATTRIBUTE_UNUSED)
{
  exit (0);
}

/* 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 ("noobjects", remove_objects);
  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);
  fe_add_spec_function ("exit", exit_callback);
}




>>
>> 1.  all GCC files which have been patched.
>> ==========================================
>>
>> The 'Only in' diff output was:
>>
>> Only in gcc-git-devel-modula2/gcc: m2
>> Only in gcc-git-devel-modula2/gcc/testsuite: gm2
>> Only in gcc-git-devel-modula2/gcc/testsuite/lib: gm2-dg.exp
>> Only in gcc-git-devel-modula2/gcc/testsuite/lib: gm2.exp
>> Only in gcc-git-devel-modula2/gcc/testsuite/lib: gm2-simple.exp
>> Only in gcc-git-devel-modula2/gcc/testsuite/lib: gm2-torture.exp
>> Only in gcc-git-devel-modula2/gcc/doc: gm2.texi
>> Only in gcc-git-devel-modula2: libgm2
>> Only in gcc-git-devel-modula2: gm2tools
>>
>> and the recursive diffs:
>>
>>
>> diff -x '*autom4te*' -rwu gcc/configure.ac gcc-git-devel-modula2/configure.ac
>> --- gcc/configure.ac    2022-05-17 11:20:57.487964366 +0100
>> +++ gcc-git-devel-modula2/configure.ac  2022-05-17 14:41:05.480881101 +0100
>> @@ -140,7 +140,7 @@
>>  # binutils, gas and ld appear in that order because it makes sense to run
>>  # "make check" in that particular order.
>>  # If --enable-gold is used, "gold" may replace "ld".
>> -host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen
> sid sim gdb gdbserver gprof etc expect dejagnu m4 utils guile fastjar
> gnattools libcc1 gotools c++tools"
>> +host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen
> sid sim gdb gdbserver gprof etc expect dejagnu m4 utils guile fastjar
> gnattools libcc1 gm2tools gotools c++tools"
>>
>>  # these libraries are built for the target environment, and are built after
>>  # the host libraries and the host tools (which may be a cross compiler)
>> @@ -162,6 +162,7 @@
>>                 target-libffi \
>>                 target-libobjc \
>>                 target-libada \
>> +               target-libgm2 \
>>                 target-libgo \
>>                 target-libphobos \
>>                 target-zlib"
>> @@ -459,6 +460,14 @@
>>    noconfigdirs="$noconfigdirs gnattools"
>>  fi
>>
>> +AC_ARG_ENABLE(libgm2,
>> +[AS_HELP_STRING([--enable-libgm2], [build libgm2 directory])],
>> +ENABLE_LIBGM2=$enableval,
>> +ENABLE_LIBGM2=no)
>> +if test "${ENABLE_LIBGM2}" != "yes" ; then
>> +  noconfigdirs="$noconfigdirs gm2tools"
>> +fi
>> +
>>  AC_ARG_ENABLE(libssp,
>>  [AS_HELP_STRING([--enable-libssp], [build libssp directory])],
>>  ENABLE_LIBSSP=$enableval,
>> @@ -3617,6 +3626,7 @@
>>  NCN_STRICT_CHECK_TARGET_TOOLS(GFORTRAN_FOR_TARGET, gfortran)
>>  NCN_STRICT_CHECK_TARGET_TOOLS(GOC_FOR_TARGET, gccgo)
>>  NCN_STRICT_CHECK_TARGET_TOOLS(GDC_FOR_TARGET, gdc)
>> +NCN_STRICT_CHECK_TARGET_TOOLS(GM2_FOR_TARGET, gm2)
>>
>>  ACX_CHECK_INSTALLED_TARGET_TOOL(AR_FOR_TARGET, ar)
>>  ACX_CHECK_INSTALLED_TARGET_TOOL(AS_FOR_TARGET, as)
>> @@ -3655,6 +3665,8 @@
>>                 [gcc/gccgo -B$$r/$(HOST_SUBDIR)/gcc/], go)
>>  GCC_TARGET_TOOL(gdc, GDC_FOR_TARGET, GDC,
>>                 [gcc/gdc -B$$r/$(HOST_SUBDIR)/gcc/], d)
>> +GCC_TARGET_TOOL(gm2, GM2_FOR_TARGET, GM2,
>> +               [gcc/gm2 -B$$r/$(HOST_SUBDIR)/gcc/], m2)
>>  GCC_TARGET_TOOL(ld, LD_FOR_TARGET, LD, [ld/ld-new])
>>  GCC_TARGET_TOOL(lipo, LIPO_FOR_TARGET, LIPO)
>>  GCC_TARGET_TOOL(nm, NM_FOR_TARGET, NM, [binutils/nm-new])
>> @@ -3781,6 +3793,9 @@
>>  # Specify what files to not compare during bootstrap.
>>
>>  compare_exclusions="gcc/cc*-checksum\$(objext) | gcc/ada/*tools/*"
>> +compare_exclusions="$compare_exclusions | 
>> gcc/m2/gm2-compiler-boot/M2Version*"
>> +compare_exclusions="$compare_exclusions | gcc/m2/gm2-compiler-boot/SYSTEM*"
>> +compare_exclusions="$compare_exclusions | gcc/m2/gm2version*"
>>  case "$target" in
>>    hppa*64*-*-hpux*) ;;
>>    hppa*-*-hpux*) compare_exclusions="$compare_exclusions | 
>> */libgcc/lib2funcs* | gcc/function-tests.o" ;;
>> diff -x '*autom4te*' -rwu gcc/gcc/c/gccspec.cc 
>> gcc-git-devel-modula2/gcc/c/gccspec.cc
>> --- gcc/gcc/c/gccspec.cc        2022-05-17 11:20:57.919969752 +0100
>> +++ gcc-git-devel-modula2/gcc/c/gccspec.cc      2022-05-17 
>> 14:41:05.552881117 +0100
>> @@ -105,3 +105,9 @@
>>
>>  /* Number of extra output files that lang_specific_pre_link may generate.  
>> */
>>  int lang_specific_extra_outfiles = 0;  /* Not used for C.  */
>> +
>> +/* lang_register_spec_functions.  Not used for C.  */
>> +void
>> +lang_register_spec_functions (void)
>> +{
>> +}
>> diff -x '*autom4te*' -rwu gcc/gcc/c-family/cppspec.cc 
>> gcc-git-devel-modula2/gcc/c-family/cppspec.cc
>> --- gcc/gcc/c-family/cppspec.cc 2022-05-17 11:20:57.911969653 +0100
>> +++ gcc-git-devel-modula2/gcc/c-family/cppspec.cc       2022-05-17 
>> 14:41:05.548881115 +0100
>> @@ -198,3 +198,9 @@
>>
>>  /* Number of extra output files that lang_specific_pre_link may generate.  
>> */
>>  int lang_specific_extra_outfiles = 0;  /* Not used for cpp.  */
>> +
>> +/* lang_register_spec_functions.  Not used for cpp.  */
>> +void
>> +lang_register_spec_functions (void)
>> +{
>> +}
>> diff -x '*autom4te*' -rwu gcc/gcc/cp/g++spec.cc 
>> gcc-git-devel-modula2/gcc/cp/g++spec.cc
>> --- gcc/gcc/cp/g++spec.cc       2022-05-17 11:20:58.163972794 +0100
>> +++ gcc-git-devel-modula2/gcc/cp/g++spec.cc     2022-05-17 
>> 14:41:05.564881118 +0100
>> @@ -434,3 +434,9 @@
>>
>>  /* Number of extra output files that lang_specific_pre_link may generate.  
>> */
>>  int lang_specific_extra_outfiles = 0;  /* Not used for C++.  */
>> +
>> +/* lang_register_spec_functions.  Not used for C++.  */
>> +void
>> +lang_register_spec_functions (void)
>> +{
>> +}
>> diff -x '*autom4te*' -rwu gcc/gcc/d/d-spec.cc 
>> gcc-git-devel-modula2/gcc/d/d-spec.cc
>> --- gcc/gcc/d/d-spec.cc 2022-05-17 11:20:58.183973043 +0100
>> +++ gcc-git-devel-modula2/gcc/d/d-spec.cc       2022-05-17 
>> 14:41:05.580881121 +0100
>> @@ -525,3 +525,10 @@
>>
>>  int lang_specific_extra_outfiles = 0;  /* Not used for D.  */
>>
>> +/* lang_register_spec_functions register the D associated spec
>> +   functions.  Not used for D.  */
>> +
>> +void
>> +lang_register_spec_functions (void)
>> +{
>> +}
>> diff -x '*autom4te*' -rwu gcc/gcc/doc/install.texi 
>> gcc-git-devel-modula2/gcc/doc/install.texi
>> --- gcc/gcc/doc/install.texi    2022-05-17 11:20:58.223973542 +0100
>> +++ gcc-git-devel-modula2/gcc/doc/install.texi  2022-05-17 
>> 14:41:05.600881126 +0100
>> @@ -1832,18 +1832,19 @@
>>  @smallexample
>>  grep ^language= */config-lang.in
>>  @end smallexample
>> -Currently, you can use any of the following:
>> -@code{all}, @code{default}, @code{ada}, @code{c}, @code{c++}, @code{d},
>> -@code{fortran}, @code{go}, @code{jit}, @code{lto}, @code{objc}, 
>> @code{obj-c++}.
>> -Building the Ada compiler has special requirements, see below.
>> -If you do not pass this flag, or specify the option @code{default}, then the
>> -default languages available in the @file{gcc} sub-tree will be configured.
>> -Ada, D, Go, Jit, and Objective-C++ are not default languages.  LTO is not a
>> -default language, but is built by default because @option{--enable-lto} is
>> -enabled by default.  The other languages are default languages.  If
>> -@code{all} is specified, then all available languages are built.  An
>> -exception is @code{jit} language, which requires
>> -@option{--enable-host-shared} to be included with @code{all}.
>> +Currently, you can use any of the following: @code{all},
>> +@code{default}, @code{ada}, @code{c}, @code{c++}, @code{d},
>> +@code{fortran}, @code{go}, @code{jit}, @code{lto}, @code{m2},
>> +@code{objc}, @code{obj-c++}.  Building the Ada compiler has special
>> +requirements, see below.  If you do not pass this flag, or specify the
>> +option @code{default}, then the default languages available in the
>> +@file{gcc} sub-tree will be configured.  Ada, D, Go, Jit,
>> +Objective-C++ and Modula-2 are not default languages.  LTO is not a
>> +default language, but is built by default because
>> +@option{--enable-lto} is enabled by default.  The other languages are
>> +default languages.  If @code{all} is specified, then all available
>> +languages are built.  An exception is @code{jit} language, which
>> +requires @option{--enable-host-shared} to be included with @code{all}.
>>
>>  @item --enable-stage1-languages=@var{lang1},@var{lang2},@dots{}
>>  Specify that a particular subset of compilers and their runtime
>> @@ -1866,6 +1867,10 @@
>>  previous Ada build procedures, when it was required to explicitly
>>  do a @samp{make -C gcc gnatlib_and_tools}.
>>
>> +@item --disable-libgm2
>> +Specify that the run-time libraries and tools used by Modula-2 should not
>> +be built.  This can be useful for debugging.
>> +
>>  @item --disable-libsanitizer
>>  Specify that the run-time libraries for the various sanitizers should
>>  not be built.
>> @@ -3116,10 +3121,10 @@
>>  In order to run sets of tests selectively, there are targets
>>  @samp{make check-gcc} and language specific @samp{make check-c},
>>  @samp{make check-c++}, @samp{make check-d} @samp{make check-fortran},
>> -@samp{make check-ada}, @samp{make check-objc}, @samp{make check-obj-c++},
>> -@samp{make check-lto}
>> -in the @file{gcc} subdirectory of the object directory.  You can also
>> -just run @samp{make check} in a subdirectory of the object directory.
>> +@samp{make check-ada}, @samp{make check-m2}, @samp{make check-objc},
>> +@samp{make check-obj-c++}, @samp{make check-lto} in the @file{gcc}
>> +subdirectory of the object directory.  You can also just run
>> +@samp{make check} in a subdirectory of the object directory.
>>
>>
>>  A more selective way to just run all @command{gcc} execute tests in the
>> diff -x '*autom4te*' -rwu gcc/gcc/doc/sourcebuild.texi 
>> gcc-git-devel-modula2/gcc/doc/sourcebuild.texi
>> --- gcc/gcc/doc/sourcebuild.texi        2022-05-17 11:20:58.231973641 +0100
>> +++ gcc-git-devel-modula2/gcc/doc/sourcebuild.texi      2022-05-17 
>> 14:41:05.604881127 +0100
>> @@ -52,6 +52,9 @@
>>  language front ends, and testsuites.  @xref{gcc Directory, , The
>>  @file{gcc} Subdirectory}, for details.
>>
>> +@item gm2tools
>> +Support tools for Modula-2.
>> +
>>  @item gnattools
>>  Support tools for GNAT.
>>
>> @@ -84,6 +87,9 @@
>>  @item libgfortran
>>  The Fortran runtime library.
>>
>> +@item libgm2
>> +The Modula-2 runtime library.
>> +
>>  @item libgo
>>  The Go runtime library.  The bulk of this library is mirrored from the
>>  @uref{https://github.com/@/golang/go, master Go repository}.
>> @@ -163,13 +169,12 @@
>>  @item @var{language}
>>  Subdirectories for various languages.  Directories containing a file
>>  @file{config-lang.in} are language subdirectories.  The contents of
>> -the subdirectories @file{c} (for C), @file{cp} (for C++),
>> -@file{objc} (for Objective-C), @file{objcp} (for Objective-C++),
>> -and @file{lto} (for LTO) are documented in this
>> -manual (@pxref{Passes, , Passes and Files of the Compiler});
>> -those for other languages are not.  @xref{Front End, ,
>> -Anatomy of a Language Front End}, for details of the files in these
>> -directories.
>> +the subdirectories @file{c} (for C), @file{cp} (for C++), @file{m2}
>> +(for Modula-2), @file{objc} (for Objective-C), @file{objcp} (for
>> +Objective-C++), and @file{lto} (for LTO) are documented in this manual
>> +(@pxref{Passes, , Passes and Files of the Compiler}); those for other
>> +languages are not.  @xref{Front End, , Anatomy of a Language Front
>> +End}, for details of the files in these directories.
>>
>>  @item common
>>  Source files shared between the compiler drivers (such as
>> diff -x '*autom4te*' -rwu gcc/gcc/fortran/gfortranspec.cc 
>> gcc-git-devel-modula2/gcc/fortran/gfortranspec.cc
>> --- gcc/gcc/fortran/gfortranspec.cc     2022-05-17 11:20:58.263974041 +0100
>> +++ gcc-git-devel-modula2/gcc/fortran/gfortranspec.cc   2022-05-17 
>> 14:41:05.608881127 +0100
>> @@ -447,4 +447,12 @@
>>  }
>>
>>  /* Number of extra output files that lang_specific_pre_link may generate.  
>> */
>> -int lang_specific_extra_outfiles = 0;  /* Not used for F77.  */
>> +int lang_specific_extra_outfiles = 0;  /* Not used for Fortran.  */
>> +
>> +/* lang_register_spec_functions register the Fortran associated spec
>> +   functions.  */
>> +
>> +void
>> +lang_register_spec_functions (void)
>> +{
>> +}
>> diff -x '*autom4te*' -rwu gcc/gcc/gcc.cc gcc-git-devel-modula2/gcc/gcc.cc
>> --- gcc/gcc/gcc.cc      2022-05-17 11:20:58.283974290 +0100
>> +++ gcc-git-devel-modula2/gcc/gcc.cc    2022-05-17 14:41:05.616881129 +0100
>> @@ -334,6 +334,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;
>> @@ -1782,6 +1786,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
>> @@ -2950,6 +2958,30 @@
>>    env.xput (string);
>>  }
>>
>> +/* Get the environment variable through the managed env.  */
>> +
>> +static const char *
>> +xgetenv (const char *key)
>> +{
>> +  return env.get (key);
>> +}
>> +
>> +/* Allow front end access to xputenv.  */
>> +
>> +void
>> +fe_putenv (const char *string)
>> +{
>> +  xputenv (string);
>> +}
>> +
>> +/* Allow front end access to xgetenv.  */
>> +
>> +const char *
>> +fe_getenv (const char *key)
>> +{
>> +  return xgetenv (key);
>> +}
>> +
>>  /* Build a list of search directories from PATHS.
>>     PREFIX is a string to prepend to the list.
>>     If CHECK_DIR_P is true we ensure the directory exists.
>> @@ -3916,6 +3948,15 @@
>>    n_switches++;
>>  }
>>
>> +/* Allow front ends to save switches.  */
>> +
>> +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);
>> +}
>> +
>>  /* Set the SOURCE_DATE_EPOCH environment variable to the current time if it 
>> is
>>     not set already.  */
>>
>> @@ -3939,6 +3980,76 @@
>>    setenv ("SOURCE_DATE_EPOCH", source_date_epoch, 0);
>>  }
>>
>> +/* Wrapper providing front end access to link options.  */
>> +
>> +void
>> +fe_add_linker_option (const char *option)
>> +{
>> +  add_linker_option (option, strlen (option));
>> +}
>> +
>> +/* Handle the -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);
>> +}
>> +
>> +/* Wrapper allowing the front end to create a -B option.  */
>> +
>> +void
>> +fe_handle_opt_b (const char *arg)
>> +{
>> +  handle_opt_b (arg);
>> +}
>> +
>> +/* Save the infile.  */
>> +
>> +void
>> +fe_add_infile (const char *infile, const char *lang)
>> +{
>> +  add_infile (infile, lang);
>> +}
>> +
>> +/* Mark a file as compiled.  */
>> +
>> +void
>> +fe_mark_compiled (const char *name)
>> +{
>> +  int max = n_infiles + lang_specific_extra_outfiles;
>> +  int i;
>> +
>> +  for (i = 0; i < max; i++)
>> +    if (filename_cmp (name, infiles[i].name) == 0)
>> +      infiles[i].compiled = true;
>> +}
>> +
>>  /* Handle an option DECODED that is unknown to the option-processing
>>     machinery.  */
>>
>> @@ -4518,33 +4629,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;
>>
>> @@ -4677,6 +4762,69 @@
>>    return ret;
>>  }
>>
>> +/* print_option a debugging routine to display option i with a leading desc
>> +   string.  */
>> +
>> +void
>> +print_option (const char *desc, unsigned int i,
>> +             struct cl_decoded_option *in_decoded_options)
>> +{
>> +  printf (desc);
>> +  printf (" [%d]", i);
>> +  switch (in_decoded_options[i].opt_index)
>> +    {
>> +
>> +    case N_OPTS:
>> +      break;
>> +    case OPT_SPECIAL_unknown:
>> +      printf (" flag <unknown>");
>> +      break;
>> +    case OPT_SPECIAL_ignore:
>> +      printf (" flag <ignore>");
>> +      break;
>> +    case OPT_SPECIAL_program_name:
>> +      printf (" flag <program name>");
>> +      break;
>> +    case OPT_SPECIAL_input_file:
>> +      printf (" flag <input file name>");
>> +      break;
>> +    default:
>> +      printf (" flag [%s]",
>> +              cl_options[in_decoded_options[i].opt_index].opt_text);
>> +    }
>> +
>> +  if (in_decoded_options[i].arg == NULL)
>> +    printf (" no arg");
>> +  else
>> +    printf (" arg [%s]", in_decoded_options[i].arg);
>> +  printf (" orig text [%s]",
>> +          in_decoded_options[i].orig_option_with_args_text);
>> +  /* On some hosts value is declared as a long long int.  */
>> +  printf (" value [%ld]", (long int)in_decoded_options[i].value);
>> +  printf (" error [%d]\n", in_decoded_options[i].errors);
>> +}
>> +
>> +/* print_options display all options with a leading string desc.  */
>> +
>> +void
>> +print_options (const char *desc,
>> +              unsigned int in_decoded_options_count,
>> +              struct cl_decoded_option *in_decoded_options)
>> +{
>> +  for (unsigned int i = 0; i < in_decoded_options_count; i++)
>> +    print_option (desc, i, in_decoded_options);
>> +}
>> +
>> +/* dbg_options display all options.  */
>> +
>> +void
>> +dbg_options (unsigned int in_decoded_options_count,
>> +            struct cl_decoded_option *in_decoded_options)
>> +{
>> +  print_options ("dbg_options", in_decoded_options_count,
>> +                in_decoded_options);
>> +}
>> +
>>  /* Create the vector `switches' and its contents.
>>     Store its length in `n_switches'.  */
>>
>> @@ -6842,6 +6990,35 @@
>>    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 (input_location, "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 *
>> @@ -6853,6 +7030,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;
>>  }
>>
>> @@ -8339,6 +8521,8 @@
>>                            accel_dir_suffix, 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"))
>> @@ -9070,7 +9254,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;
>>
>> @@ -9139,7 +9324,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] == '*'))
>> diff -x '*autom4te*' -rwu gcc/gcc/gcc.h gcc-git-devel-modula2/gcc/gcc.h
>> --- gcc/gcc/gcc.h       2022-05-17 11:20:58.283974290 +0100
>> +++ gcc-git-devel-modula2/gcc/gcc.h     2022-05-17 14:41:05.616881129 +0100
>> @@ -73,9 +73,28 @@
>>  extern int do_spec (const char *);
>>  extern void record_temp_file (const char *, int, int);
>>  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_handle_op_b (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 fe_putenv (const char *value);
>> +extern const char *fe_getenv (const char *key);
>> +extern void print_options (const char *desc,
>> +                          unsigned int in_decoded_options_count,
>> +                          struct cl_decoded_option *in_decoded_options);
>> +extern void print_option (const char *desc, unsigned int i,
>> +                         struct cl_decoded_option *in_decoded_options);
>> +extern void dbg_options (unsigned int in_decoded_options_count,
>> +                        struct cl_decoded_option *in_decoded_options);
>> +
>>
>>  /* Spec files linked with gcc.cc must provide definitions for these.  */
>>
>> +extern void lang_register_spec_functions (void);
>> +
>>  /* Called before processing to change/add/remove arguments.  */
>>  extern void lang_specific_driver (struct cl_decoded_option **,
>>                                   unsigned int *, int *);
>> @@ -97,4 +116,8 @@
>>                                               void *user_data),
>>                                    void *user_data);
>>
>> +/* 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 */
>> diff -x '*autom4te*' -rwu gcc/gcc/go/gospec.cc 
>> gcc-git-devel-modula2/gcc/go/gospec.cc
>> --- gcc/gcc/go/gospec.cc        2022-05-17 11:20:58.323974789 +0100
>> +++ gcc-git-devel-modula2/gcc/go/gospec.cc      2022-05-17 
>> 14:41:05.616881129 +0100
>> @@ -464,3 +464,9 @@
>>
>>  /* Number of extra output files that lang_specific_pre_link may generate.  
>> */
>>  int lang_specific_extra_outfiles = 0;  /* Not used for Go.  */
>> +
>> +/* lang_register_spec_functions.  Not used for Go.  */
>> +void
>> +lang_register_spec_functions (void)
>> +{
>> +}
>> diff -x '*autom4te*' -rwu gcc/gcc/jit/jit-spec.cc 
>> gcc-git-devel-modula2/gcc/jit/jit-spec.cc
>> --- gcc/gcc/jit/jit-spec.cc     2022-05-17 11:20:58.355975188 +0100
>> +++ gcc-git-devel-modula2/gcc/jit/jit-spec.cc   2022-05-17 
>> 14:41:05.620881130 +0100
>> @@ -39,3 +39,9 @@
>>
>>  /* Number of extra output files that lang_specific_pre_link may generate.  
>> */
>>  int lang_specific_extra_outfiles = 0;  /* Not used for jit.  */
>> +
>> +/* lang_register_spec_functions.  Not used for jit.  */
>> +void
>> +lang_register_spec_functions (void)
>> +{
>> +}
>> diff -x '*autom4te*' -rwu gcc/Makefile.def gcc-git-devel-modula2/Makefile.def
>> --- gcc/Makefile.def    2022-05-17 11:20:57.467964117 +0100
>> +++ gcc-git-devel-modula2/Makefile.def  2022-05-17 14:41:05.468881099 +0100
>> @@ -146,6 +146,7 @@
>>                 extra_configure_flags='--enable-shared 
>> @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@';
>>                 extra_make_flags='@extra_linker_plugin_flags@'; };
>>  host_modules= { module= libcc1; extra_configure_flags=--enable-shared; };
>> +host_modules= { module= gm2tools; };
>>  host_modules= { module= gotools; };
>>  host_modules= { module= libctf; bootstrap=true; };
>>
>> @@ -189,6 +190,7 @@
>>  target_modules = { module= zlib; bootstrap=true; };
>>  target_modules = { module= rda; };
>>  target_modules = { module= libada; };
>> +target_modules = { module= libgm2; lib_path=.libs; };
>>  target_modules = { module= libgomp; bootstrap= true; lib_path=.libs; };
>>  target_modules = { module= libitm; lib_path=.libs; };
>>  target_modules = { module= libatomic; bootstrap=true; lib_path=.libs; };
>> @@ -311,6 +313,8 @@
>>  flags_to_pass = { flag= GOCFLAGS_FOR_TARGET ; };
>>  flags_to_pass = { flag= GDC_FOR_TARGET ; };
>>  flags_to_pass = { flag= GDCFLAGS_FOR_TARGET ; };
>> +flags_to_pass = { flag= GM2_FOR_TARGET ; };
>> +flags_to_pass = { flag= GM2FLAGS_FOR_TARGET ; };
>>  flags_to_pass = { flag= LD_FOR_TARGET ; };
>>  flags_to_pass = { flag= LIPO_FOR_TARGET ; };
>>  flags_to_pass = { flag= LDFLAGS_FOR_TARGET ; };
>> @@ -407,6 +411,8 @@
>>  // we want version.o from gcc, and implicitly depend on libcody
>>  dependencies = { module=all-c++tools; on=all-gcc; };
>>  dependencies = { module=all-gotools; on=all-target-libgo; };
>> +dependencies = { module=all-gm2tools; on=all-target-libgm2; };
>> +dependencies = { module=all-gm2tools; on=all-target-libstdc++-v3; };
>>
>>  dependencies = { module=all-utils; on=all-libiberty; };
>>
>> @@ -623,6 +629,8 @@
>>  dependencies = { module=all-target-libgo; on=all-target-libbacktrace; };
>>  dependencies = { module=all-target-libgo; on=all-target-libffi; };
>>  dependencies = { module=all-target-libgo; on=all-target-libatomic; };
>> +dependencies = { module=configure-target-libgm2; 
>> on=all-target-libstdc++-v3; };
>> +dependencies = { module=all-target-libgm2; on=all-target-libatomic; };
>>  dependencies = { module=configure-target-libphobos; 
>> on=configure-target-libbacktrace; };
>>  dependencies = { module=configure-target-libphobos; 
>> on=configure-target-zlib; };
>>  dependencies = { module=all-target-libphobos; on=all-target-libbacktrace; };
>> @@ -681,6 +689,9 @@
>>  languages = { language=go;     gcc-check-target=check-go;
>>                                 lib-check-target=check-target-libgo;
>>                                 lib-check-target=check-gotools; };
>> +languages = { language=m2;     gcc-check-target=check-m2;
>> +                               lib-check-target=check-target-libgm2;
>> +                               lib-check-target=check-gm2tools; };
>>  languages = { language=d;      gcc-check-target=check-d;
>>                                 lib-check-target=check-target-libphobos; };
>>  languages = { language=jit;    gcc-check-target=check-jit; };
>> diff -x '*autom4te*' -rwu gcc/Makefile.tpl gcc-git-devel-modula2/Makefile.tpl
>> --- gcc/Makefile.tpl    2022-05-17 11:20:57.475964217 +0100
>> +++ gcc-git-devel-modula2/Makefile.tpl  2022-05-17 14:41:05.472881100 +0100
>> @@ -166,6 +166,7 @@
>>         GOCFLAGS="$(GOCFLAGS_FOR_BUILD)"; export GOCFLAGS; \
>>         GDC="$(GDC_FOR_BUILD)"; export GDC; \
>>         GDCFLAGS="$(GDCFLAGS_FOR_BUILD)"; export GDCFLAGS; \
>> +       GM2="$(GM2_FOR_BUILD)"; export GM2; \
>>         DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \
>>         DSYMUTIL="$(DSYMUTIL_FOR_BUILD)"; export DSYMUTIL; \
>>         LD="$(LD_FOR_BUILD)"; export LD; \
>> @@ -204,6 +205,7 @@
>>         GFORTRAN="$(GFORTRAN)"; export GFORTRAN; \
>>         GOC="$(GOC)"; export GOC; \
>>         GDC="$(GDC)"; export GDC; \
>> +       GM2="$(GM2)"; export GM2; \
>>         AR="$(AR)"; export AR; \
>>         AS="$(AS)"; export AS; \
>>         CC_FOR_BUILD="$(CC_FOR_BUILD)"; export CC_FOR_BUILD; \
>> @@ -309,6 +311,7 @@
>>         GFORTRAN="$(GFORTRAN_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; 
>> export GFORTRAN; \
>>         GOC="$(GOC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export 
>> GOC; \
>>         GDC="$(GDC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export 
>> GDC; \
>> +       GM2="$(GM2_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export 
>> GM2; \
>>         DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \
>>         DSYMUTIL="$(DSYMUTIL_FOR_TARGET)"; export DSYMUTIL; \
>>         LD="$(COMPILER_LD_FOR_TARGET)"; export LD; \
>> @@ -379,6 +382,7 @@
>>  GFORTRAN_FOR_BUILD = @GFORTRAN_FOR_BUILD@
>>  GOC_FOR_BUILD = @GOC_FOR_BUILD@
>>  GDC_FOR_BUILD = @GDC_FOR_BUILD@
>> +GM2_FOR_BUILD = @GM2_FOR_BUILD@
>>  LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
>>  LD_FOR_BUILD = @LD_FOR_BUILD@
>>  NM_FOR_BUILD = @NM_FOR_BUILD@
>> @@ -449,6 +453,7 @@
>>  LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates
>>  GOCFLAGS = $(CFLAGS)
>>  GDCFLAGS = $(CFLAGS)
>> +GM2FLAGS = $(CFLAGS)
>>
>>  # Pass additional PGO and LTO compiler options to the PGO build.
>>  BUILD_CFLAGS = $(PGO_BUILD_CFLAGS) $(PGO_BUILD_LTO_CFLAGS)
>> @@ -584,6 +589,7 @@
>>  GFORTRAN_FOR_TARGET=$(STAGE_CC_WRAPPER) @GFORTRAN_FOR_TARGET@
>>  GOC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GOC_FOR_TARGET@
>>  GDC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GDC_FOR_TARGET@
>> +GM2_FOR_TARGET=$(STAGE_CC_WRAPPER) @GM2_FOR_TARGET@
>>  DLLTOOL_FOR_TARGET=@DLLTOOL_FOR_TARGET@
>>  DSYMUTIL_FOR_TARGET=@DSYMUTIL_FOR_TARGET@
>>  LD_FOR_TARGET=@LD_FOR_TARGET@
>> @@ -609,6 +615,7 @@
>>  LIBCFLAGS_FOR_TARGET = $(CFLAGS_FOR_TARGET)
>>  LIBCXXFLAGS_FOR_TARGET = $(CXXFLAGS_FOR_TARGET) -fno-implicit-templates
>>  LDFLAGS_FOR_TARGET = @LDFLAGS_FOR_TARGET@
>> +GM2FLAGS_FOR_TARGET = -O2 -g
>>  GOCFLAGS_FOR_TARGET = -O2 -g
>>  GDCFLAGS_FOR_TARGET = -O2 -g
>>
>> @@ -715,6 +722,7 @@
>>         'GFORTRAN=$(GFORTRAN)' \
>>         'GOC=$(GOC)' \
>>         'GDC=$(GDC)' \
>> +       'GM2=$(GM2)' \
>>         'LD=$(LD)' \
>>         'LIPO=$(LIPO)' \
>>         'NM=$(NM)' \
>> @@ -741,6 +749,7 @@
>>         CC="$${CC}" CC_FOR_BUILD="$${CC_FOR_BUILD}" \
>>         CXX="$${CXX}" CXX_FOR_BUILD="$${CXX_FOR_BUILD}" \
>>         GDC="$${GDC}" GDC_FOR_BUILD="$${GDC_FOR_BUILD}" \
>> +       GM2="$${GM2}" GM2_FOR_BUILD="$${GM2_FOR_BUILD}" \
>>         GNATBIND="$${GNATBIND}" \
>>         LDFLAGS="$${LDFLAGS}" \
>>         HOST_LIBS="$${HOST_LIBS}" \
>> @@ -776,6 +785,8 @@
>>         'GOCFLAGS=$$(GOCFLAGS_FOR_TARGET)' \
>>         'GDC=$$(GDC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \
>>         'GDCFLAGS=$$(GDCFLAGS_FOR_TARGET)' \
>> +       'GM2=$$(GM2_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \
>> +       'GM2FLAGS=$$(GM2FLAGS_FOR_TARGET)' \
>>         'LD=$(COMPILER_LD_FOR_TARGET)' \
>>         'LDFLAGS=$$(LDFLAGS_FOR_TARGET)' \
>>         'LIBCFLAGS=$$(LIBCFLAGS_FOR_TARGET)' \
>> @@ -802,6 +813,7 @@
>>  # cross-building scheme.
>>  EXTRA_GCC_FLAGS = \
>>         "GCC_FOR_TARGET=$(GCC_FOR_TARGET)" \
>> +       "GM2_FOR_TARGET=$(GM2_FOR_TARGET)" \
>>         "`echo 'STMP_FIXPROTO=$(STMP_FIXPROTO)' | sed -e 
>> s'/[^=][^=]*=$$/XFOO=/'`" \
>>         "`echo 'LIMITS_H_TEST=$(LIMITS_H_TEST)' | sed -e 
>> s'/[^=][^=]*=$$/XFOO=/'`"
>>
>> @@ -951,7 +963,7 @@
>>         -rm -f texinfo/doc/Makefile texinfo/po/POTFILES
>>         -rmdir texinfo/doc texinfo/info texinfo/intl texinfo/lib 2>/dev/null
>>         -rmdir texinfo/makeinfo texinfo/po texinfo/util 2>/dev/null
>> -       -rmdir c++tools fastjar gcc gnattools gotools 2>/dev/null
>> +       -rmdir c++tools fastjar gcc gnattools gm2tools gotools 2>/dev/null
>>         -rmdir libcc1 libiberty texinfo zlib 2>/dev/null
>>         -find . -name config.cache -exec rm -f {} \; \; 2>/dev/null

Reply via email to