3/19 modula2 front end: gm2 driver files.

Message ID E1ohukR-00Bm08-7e@lancelot
State Accepted, archived
Headers
Series 3/19 modula2 front end: gm2 driver files. |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Gaius Mulley Oct. 10, 2022, 3:31 p.m. UTC
  This patchset contains the c++, h and option related files necessary
to build the driver program gm2.  The patch also consists of the
autoconf/configure related build infastructure sources found in
gcc/m2.  The reviewer might need to look at the 01-02-make patchset.
The gm2 driver is heavily based on the fortran driver, it also adds
the c++ libraries and modula-2 search paths and libraries depending
upon dialect for user convenience.  Users could link modula-2 objects
using g++ if they supply the include and link paths.

 
------8<----------8<----------8<----------8<----------8<----------8<----
  

Comments

Richard Biener Nov. 18, 2022, 10:21 a.m. UTC | #1
On Mon, Oct 10, 2022 at 5:33 PM Gaius Mulley via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
>
>
> This patchset contains the c++, h and option related files necessary
> to build the driver program gm2.  The patch also consists of the
> autoconf/configure related build infastructure sources found in
> gcc/m2.  The reviewer might need to look at the 01-02-make patchset.
> The gm2 driver is heavily based on the fortran driver, it also adds
> the c++ libraries and modula-2 search paths and libraries depending
> upon dialect for user convenience.  Users could link modula-2 objects
> using g++ if they supply the include and link paths.
>
>
> ------8<----------8<----------8<----------8<----------8<----------8<----
> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/gm2spec.cc
> --- /dev/null   2022-08-24 16:22:16.888000070 +0100
> +++ gcc-git-devel-modula2/gcc/m2/gm2spec.cc     2022-10-07 20:21:18.662097087 +0100
> @@ -0,0 +1,937 @@
> +/* gm2spec.cc specific flags and argument handling within GNU Modula-2.
> +
> +Copyright (C) 2007-2022 Free Software Foundation, Inc.
> +Contributed by Gaius Mulley <gaius@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/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
> +
> +/* This bit is set if we saw a `-xfoo' language specification.  */
> +#define LANGSPEC       (1<<1)
> +/* This bit is set if they did `-lm' or `-lmath'.  */
> +#define MATHLIB                (1<<2)
> +/* This bit is set if they did `-lc'.  */
> +#define WITHLIBC       (1<<3)
> +/* Skip this option.  */
> +#define SKIPOPT                (1<<4)
> +
> +#ifndef MATH_LIBRARY
> +#define MATH_LIBRARY "m"
> +#endif
> +#ifndef MATH_LIBRARY_PROFILE
> +#define MATH_LIBRARY_PROFILE MATH_LIBRARY
> +#endif
> +
> +#ifndef LIBSTDCXX
> +#define LIBSTDCXX "stdc++"
> +#endif
> +#ifndef LIBSTDCXX_PROFILE
> +#define LIBSTDCXX_PROFILE LIBSTDCXX
> +#endif
> +#ifndef LIBSTDCXX_STATIC
> +#define LIBSTDCXX_STATIC NULL
> +#endif
> +
> +#ifndef LIBCXX
> +#define LIBCXX "c++"
> +#endif
> +#ifndef LIBCXX_PROFILE
> +#define LIBCXX_PROFILE LIBCXX
> +#endif
> +#ifndef LIBCXX_STATIC
> +#define LIBCXX_STATIC NULL
> +#endif
> +
> +#ifndef LIBCXXABI
> +#define LIBCXXABI "c++abi"
> +#endif
> +#ifndef LIBCXXABI_PROFILE
> +#define LIBCXXABI_PROFILE LIBCXXABI
> +#endif
> +#ifndef LIBCXXABI_STATIC
> +#define LIBCXXABI_STATIC NULL
> +#endif
> +
> +/* The values used here must match those of the stdlib_kind enumeration
> +   in c.opt.  */
> +enum stdcxxlib_kind
> +{
> +  USE_LIBSTDCXX = 1,
> +  USE_LIBCXX = 2
> +};
> +
> +#define DEFAULT_DIALECT "pim"
> +#undef DEBUG_ARG
> +
> +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.  */
> +
> +static const char *add_include (const char *libpath, const char *library);
> +
> +static bool seen_scaffold_static = false;
> +static bool seen_scaffold_dynamic = false;
> +static bool scaffold_static = false;
> +static bool scaffold_dynamic = true;  // Default uses -fscaffold-dynamic.
> +static bool seen_gen_module_list = false;
> +static bool seen_uselist = false;
> +static bool uselist = false;
> +static bool gen_module_list = true;  // Default uses -fgen-module-list=-.
> +static const char *gen_module_filename = "-";
> +static const char *multilib_dir = NULL;
> +/* The original argument list and related info is copied here.  */
> +static unsigned int gm2_xargc;
> +static const struct cl_decoded_option *gm2_x_decoded_options;
> +static void append_arg (const struct cl_decoded_option *);
> +
> +/* The new argument list will be built here.  */
> +static unsigned int gm2_newargc;
> +static struct cl_decoded_option *gm2_new_decoded_options;
> +
> +
> +/* Return whether strings S1 and S2 are both NULL or both the same
> +   string.  */
> +
> +static bool
> +strings_same (const char *s1, const char *s2)
> +{
> +  return s1 == s2 || (s1 != NULL && s2 != NULL && strcmp (s1, s2) == 0);
> +}
> +
> +bool
> +options_same (const struct cl_decoded_option *opt1,
> +             const struct cl_decoded_option *opt2)
> +{
> +  return (opt1->opt_index == opt2->opt_index
> +         && strings_same (opt1->arg, opt2->arg)
> +         && strings_same (opt1->orig_option_with_args_text,
> +                          opt2->orig_option_with_args_text)
> +         && strings_same (opt1->canonical_option[0],
> +                          opt2->canonical_option[0])
> +         && strings_same (opt1->canonical_option[1],
> +                          opt2->canonical_option[1])
> +         && strings_same (opt1->canonical_option[2],
> +                          opt2->canonical_option[2])
> +         && strings_same (opt1->canonical_option[3],
> +                          opt2->canonical_option[3])
> +         && (opt1->canonical_option_num_elements
> +             == opt2->canonical_option_num_elements)
> +         && opt1->value == opt2->value
> +         && opt1->errors == opt2->errors);
> +}
> +
> +/* Append another argument to the list being built.  */
> +
> +static void
> +append_arg (const struct cl_decoded_option *arg)
> +{
> +  static unsigned int newargsize;
> +
> +  if (gm2_new_decoded_options == gm2_x_decoded_options
> +      && gm2_newargc < gm2_xargc
> +      && options_same (arg, &gm2_x_decoded_options[gm2_newargc]))
> +    {
> +      ++gm2_newargc;
> +      return;                  /* Nothing new here.  */
> +    }
> +
> +  if (gm2_new_decoded_options == gm2_x_decoded_options)
> +    {                          /* Make new arglist.  */
> +      unsigned int i;
> +
> +      newargsize = (gm2_xargc << 2) + 20;      /* This should handle all.  */
> +      gm2_new_decoded_options = XNEWVEC (struct cl_decoded_option, newargsize);
> +
> +      /* Copy what has been done so far.  */
> +      for (i = 0; i < gm2_newargc; ++i)
> +       gm2_new_decoded_options[i] = gm2_x_decoded_options[i];
> +    }
> +
> +  if (gm2_newargc == newargsize)
> +    fatal_error (input_location, "overflowed output argument list for %qs",
> +                arg->orig_option_with_args_text);
> +
> +  gm2_new_decoded_options[gm2_newargc++] = *arg;
> +}
> +
> +/* Append an option described by OPT_INDEX, ARG and VALUE to the list
> +   being built.  */
> +
> +static void
> +append_option (size_t opt_index, const char *arg, int value)
> +{
> +  struct cl_decoded_option decoded;
> +
> +  generate_option (opt_index, arg, value, CL_DRIVER, &decoded);
> +  append_arg (&decoded);
> +}
> +
> +/* build_archive_path returns a string containing the 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 bool
> +add_default_combination (const char *libpath, const char *library)
> +{
> +  if (library != NULL)
> +    {
> +      append_option (OPT_L, build_archive_path (libpath, library), 1);
> +      append_option (OPT_l, safe_strdup (library), 1);
> +      return true;
> +    }
> +  return false;
> +}
> +
> +/* 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)
> +{
> +  const char *l = libraries;
> +  const char *e;
> +  char *libname;
> +  unsigned int libcount = 0;
> +
> +  do
> +    {
> +      e = index (l, ',');
> +      if (e == NULL)
> +        {
> +          libname = xstrdup (l);
> +          l = NULL;
> +         if (add_default_combination (libpath, libname))
> +           libcount++;
> +         free (libname);
> +        }
> +      else
> +        {
> +          libname = xstrndup (l, e - l);
> +          l = e + 1;
> +         if (add_default_combination (libpath, libname))
> +           libcount++;
> +         free (libname);
> +        }
> +    }
> +  while ((l != NULL) && (l[0] != (char)0));
> +  return libcount;
> +}
> +
> +/* build_include_path builds the component of the include path
> +   referenced by the library.  */
> +
> +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);
> +      append_option (OPT_I, path, 1);
> +    }
> +  while ((l != NULL) && (l[0] != (char)0));
> +}
> +
> +/* 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_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;
> +}
> +
> +
> +void
> +lang_specific_driver (struct cl_decoded_option **in_decoded_options,
> +                     unsigned int *in_decoded_options_count,
> +                     int *in_added_libraries)
> +{
> +  unsigned int argc = *in_decoded_options_count;
> +  struct cl_decoded_option *decoded_options = *in_decoded_options;
> +  unsigned int i;
> +
> +  /* True 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;
> +
> +  /* If nonzero, the user gave us the `-p' or `-pg' flag.  */
> +  int saw_profile_flag = 0;
> +
> +  /* What action to take for the c++ runtime library:
> +    -1  means we should not link it in.
> +     0  means we should link it if it is needed.
> +     1  means it is needed and should be linked in.
> +     2  means it is needed but should be linked statically.  */
> +  int library = 0;
> +
> +  /* Which c++ runtime library to link.  */
> +  stdcxxlib_kind which_library = USE_LIBSTDCXX;
> +
> +  const char *libraries = NULL;
> +  const char *dialect = DEFAULT_DIALECT;
> +  const char *libpath = LIBSUBDIR;
> +
> +  /* An array used to flag each argument that needs a bit set for
> +     LANGSPEC, MATHLIB, or WITHLIBC.  */
> +  int *args;
> +
> +  /* Have we seen -fmod=?  */
> +  bool seen_module_extension = false;
> +
> +  /* Should the driver perform a link?  */
> +  bool linking = true;
> +
> +  /* "-lm" or "-lmath" if it appears on the command line.  */
> +  const struct cl_decoded_option *saw_math = NULL;
> +
> +  /* "-lc" if it appears on the command line.  */
> +  const struct cl_decoded_option *saw_libc = NULL;
> +
> +  /* By default, we throw on the math library if we have one.  */
> +  int need_math = (MATH_LIBRARY[0] != '\0');
> +
> +  /* 1 if we should add -lpthread to the command-line.  */
> +  int need_pthread = 1;
> +
> +  /* True if we saw -static.  */
> +  int static_link = 0;
> +
> +  /* True if we should add -shared-libgcc to the command-line.  */
> +  int shared_libgcc = 1;
> +
> +  /* Have we seen the -v flag?  */
> +  bool verbose = false;
> +
> +  /* The number of libraries added in.  */
> +  int added_libraries;
> +
> +  /* True if we should add -fplugin=m2rte to the command-line.  */
> +  bool need_plugin = true;
> +
> +  /* True if we should set up include paths and library paths.  */
> +  bool allow_libraries = true;
> +
> +#if defined(DEBUG_ARG)
> +  printf ("argc = %d\n", argc);
> +  fprintf (stderr, "Incoming:");
> +  for (i = 0; i < argc; i++)
> +    fprintf (stderr, " %s", decoded_options[i].orig_option_with_args_text);
> +  fprintf (stderr, "\n");
> +#endif
> +
> +  gm2_xargc = argc;
> +  gm2_x_decoded_options = decoded_options;
> +  gm2_newargc = 0;
> +  gm2_new_decoded_options = decoded_options;
> +  added_libraries = *in_added_libraries;
> +  args = XCNEWVEC (int, argc);
> +
> +  /* First pass through arglist.
> +
> +     If -nostdlib or a "turn-off-linking" option is anywhere in the
> +     command line, don't do any library-option processing (except
> +     relating to -x).  */
> +
> +  for (i = 1; i < argc; i++)
> +    {
> +      const char *arg = decoded_options[i].arg;
> +      args[i] = 0;
> +#if defined(DEBUG_ARG)
> +      printf ("1st pass: %s\n",
> +             decoded_options[i].orig_option_with_args_text);
> +#endif
> +      switch (decoded_options[i].opt_index)
> +       {
> +       case OPT_fiso:
> +         dialect = "iso";
> +         break;
> +       case OPT_fpim2:
> +         dialect = "pim2";
> +         break;
> +       case OPT_fpim3:
> +         dialect = "pim3";
> +         break;
> +       case OPT_fpim4:
> +         dialect = "pim4";
> +         break;
> +       case OPT_fpim:
> +         dialect = "pim";
> +         break;
> +       case OPT_flibs_:
> +         libraries = xstrdup (arg);
> +         allow_libraries = decoded_options[i].value;
> +         break;
> +       case OPT_fmod_:
> +         seen_module_extension = true;
> +         break;
> +        case OPT_fpthread:
> +          need_pthread = decoded_options[i].value;
> +          break;
> +        case OPT_fm2_plugin:
> +          need_plugin = decoded_options[i].value;
> +          break;
> +       case OPT_fscaffold_dynamic:
> +         seen_scaffold_dynamic = true;
> +         scaffold_dynamic = decoded_options[i].value;
> +         break;
> +       case OPT_fscaffold_static:
> +         seen_scaffold_static = true;
> +         scaffold_static = decoded_options[i].value;
> +         break;
> +       case OPT_fgen_module_list_:
> +         seen_gen_module_list = true;
> +         gen_module_list = decoded_options[i].value;
> +         if (gen_module_list)
> +           gen_module_filename = decoded_options[i].arg;
> +         break;
> +       case OPT_fuse_list_:
> +         seen_uselist = true;
> +         uselist = decoded_options[i].value;
> +         break;
> +
> +       case OPT_nostdlib:
> +       case OPT_nostdlib__:
> +       case OPT_nodefaultlibs:
> +         library = -1;
> +         break;
> +
> +       case OPT_l:
> +         if (strcmp (arg, MATH_LIBRARY) == 0)
> +           {
> +             args[i] |= MATHLIB;
> +             need_math = 0;
> +           }
> +         else if (strcmp (arg, "c") == 0)
> +           args[i] |= WITHLIBC;
> +         else
> +           /* Unrecognized libraries (e.g. -lfoo) may require libstdc++.  */
> +           library = (library == 0) ? 1 : library;
> +         break;
> +
> +       case OPT_pg:
> +       case OPT_p:
> +         saw_profile_flag++;
> +         break;
> +
> +       case OPT_x:
> +          seen_x_flag = true;
> +          language = arg;
> +         break;
> +
> +       case OPT_v:
> +         verbose = true;
> +         break;
> +
> +       case OPT_Xlinker:
> +       case OPT_Wl_:
> +         /* Arguments that go directly to the linker might be .o files,
> +            or something, and so might cause libstdc++ to be needed.  */
> +         if (library == 0)
> +           library = 1;
> +         break;
> +
> +       case OPT_c:
> +       case OPT_r:
> +       case OPT_S:
> +       case OPT_E:
> +       case OPT_M:
> +       case OPT_MM:
> +       case OPT_fsyntax_only:
> +         /* Don't specify libraries if we won't link, since that would
> +            cause a warning.  */
> +         linking = false;
> +         library = -1;
> +         break;
> +
> +       case OPT_static:
> +         static_link = 1;
> +         break;
> +
> +       case OPT_static_libgcc:
> +         shared_libgcc = 0;
> +         break;
> +
> +       case OPT_static_libstdc__:
> +         library = library >= 0 ? 2 : library;
> +         args[i] |= SKIPOPT;
> +         break;
> +
> +       case OPT_stdlib_:
> +         which_library = (stdcxxlib_kind) decoded_options[i].value;
> +         break;
> +
> +       default:
> +         if ((decoded_options[i].orig_option_with_args_text != NULL)
> +             && (strncmp (decoded_options[i].orig_option_with_args_text,
> +                          "-m", 2) == 0))
> +           multilib_dir = xstrdup (decoded_options[i].orig_option_with_args_text
> +                                   + 2);
> +       }
> +    }
> +  if (language != NULL && (strcmp (language, "modula-2") != 0))
> +    return;
> +
> +  if (scaffold_static && scaffold_dynamic)
> +    {
> +      if (! seen_scaffold_dynamic)
> +       scaffold_dynamic = false;
> +      if (scaffold_dynamic && scaffold_static)
> +       error ("%qs and %qs cannot both be enabled",
> +              "-fscaffold-dynamic", "-fscaffold-static");
> +    }
> +  if (uselist && gen_module_list)
> +    {
> +      if (! seen_gen_module_list)
> +       gen_module_list = false;
> +      if (uselist && gen_module_list)
> +       error ("%qs and %qs cannot both be enabled",
> +              "-fgen-module-list=", "-fuse-list=");
> +    }
> +
> +
> +  /* There's no point adding -shared-libgcc if we don't have a shared
> +     libgcc.  */
> +#ifndef ENABLE_SHARED_LIBGCC
> +  shared_libgcc = 0;
> +#endif
> +
> +  /* Second pass through arglist, transforming arguments as appropriate.  */
> +
> +  append_arg (&decoded_options[0]); /* Start with command name, of course.  */
> +  for (i = 1; i < argc; ++i)
> +    {
> +#if defined(DEBUG_ARG)
> +      printf ("2nd pass: %s\n",
> +             decoded_options[i].orig_option_with_args_text);
> +#endif
> +      if ((args[i] & SKIPOPT) == 0)
> +       {
> +         append_arg (&decoded_options[i]);
> +         /* Make sure -lstdc++ is before the math library, since libstdc++
> +            itself uses those math routines.  */
> +         if (!saw_math && (args[i] & MATHLIB) && library > 0)
> +           saw_math = &decoded_options[i];
> +
> +         if (!saw_libc && (args[i] & WITHLIBC) && library > 0)
> +           saw_libc = &decoded_options[i];
> +       }
> +#if defined(DEBUG_ARG)
> +      else
> +       printf ("skipping: %s\n",
> +               decoded_options[i].orig_option_with_args_text);
> +#endif
> +    }
> +
> +  /* We now add in extra arguments to facilitate a successful
> +     compile or link.  For example include paths for dialect of Modula-2,
> +     library paths and default scaffold linking options.  */
> +
> +  /* If we have not seen either uselist or gen_module_list and we need
> +     to link then we turn on -fgen_module_list=- as the default.  */
> +  if ((! (seen_uselist || seen_gen_module_list)) && linking)
> +    append_option (OPT_fgen_module_list_, "-", 1);
> +
> +  if (allow_libraries)
> +    {
> +      /* If the libraries have not been specified by the user but the
> +        dialect has been specified then select the appropriate libraries.  */
> +      if (libraries == NULL)
> +       {
> +         if (strcmp (dialect, "iso") == 0)
> +           libraries = xstrdup ("m2iso,m2pim");
> +         else
> +           /* Default to pim libraries if none specified.  */
> +           libraries = xstrdup ("m2pim,m2log,m2iso");
> +       }
> +      libraries = convert_abbreviations (libraries);
> +      if (! check_valid_list (libpath, libraries))
> +       return;
> +      add_default_includes (libpath, libraries);
> +    }
> +  if ((! seen_x_flag) && seen_module_extension)
> +    append_option (OPT_x, "modula-2", 1);
> +
> +  if (need_plugin)
> +    append_option (OPT_fplugin_, "m2rte", 1);
> +
> +  if (linking)
> +    {
> +      if (allow_libraries)
> +       add_default_archives (libpath, libraries);
> +      /* Add `-lstdc++' if we haven't already done so.  */
> +#ifdef HAVE_LD_STATIC_DYNAMIC
> +      if (library > 1 && !static_link)
> +       append_option (OPT_Wl_, LD_STATIC_OPTION, 1);
> +#endif
> +      if (which_library == USE_LIBCXX)
> +       {
> +         append_option (OPT_l, saw_profile_flag ? LIBCXX_PROFILE : LIBCXX, 1);
> +         added_libraries++;
> +         if (LIBCXXABI != NULL)
> +           {
> +             append_option (OPT_l, saw_profile_flag ? LIBCXXABI_PROFILE
> +                            : LIBCXXABI, 1);
> +             added_libraries++;
> +           }
> +       }
> +      else
> +       {
> +         append_option (OPT_l, saw_profile_flag ? LIBSTDCXX_PROFILE
> +                        : LIBSTDCXX, 1);
> +         added_libraries++;
> +       }
> +      /* Add target-dependent static library, if necessary.  */
> +      if ((static_link || library > 1) && LIBSTDCXX_STATIC != NULL)
> +       {
> +         append_option (OPT_l, LIBSTDCXX_STATIC, 1);
> +         added_libraries++;
> +       }
> +#ifdef HAVE_LD_STATIC_DYNAMIC
> +      if (library > 1 && !static_link)
> +       append_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1);
> +#endif
> +    }
> +  if (need_math)
> +    {
> +      append_option (OPT_l, saw_profile_flag ? MATH_LIBRARY_PROFILE :
> +                    MATH_LIBRARY, 1);
> +      added_libraries++;
> +    }
> +  if (need_pthread)
> +    {
> +      append_option (OPT_l, "pthread", 1);
> +      added_libraries++;
> +    }
> +  if (shared_libgcc && !static_link)
> +    append_option (OPT_shared_libgcc, NULL, 1);

It feels like most of the above would usually be handled via lang specific
specs rather than open-coded in the driver?  Is there a specific reason you
opted for explicit handling here?

Otherwise the patch looks generally OK, the string builds using strcat & friends
looks like it neither takes advantage of how obstacks can be used there nor
that we're now C++ and could use std::string - but that's a matter of taste and
no objection.

Thanks,
Richard.

> +  if (verbose && gm2_new_decoded_options != gm2_x_decoded_options)
> +    {
> +      fprintf (stderr, _("Driving:"));
> +      for (i = 0; i < gm2_newargc; i++)
> +       fprintf (stderr, " %s",
> +                gm2_new_decoded_options[i].orig_option_with_args_text);
> +      fprintf (stderr, "\n");
> +      fprintf (stderr, "new argc = %d, added_libraries = %d\n",
> +              gm2_newargc, added_libraries);
> +    }
> +
> +  *in_decoded_options_count = gm2_newargc;
> +  *in_decoded_options = gm2_new_decoded_options;
> +  *in_added_libraries = added_libraries;
> +}
> +
> +/* Called before linking.  Returns 0 on success and -1 on failure.  */
> +int
> +lang_specific_pre_link (void)  /* Not used for M2.  */
> +{
> +  return 0;
> +}
> +
> +/* Number of extra output files that lang_specific_pre_link may generate.  */
> +int lang_specific_extra_outfiles = 0;
> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/lang.opt
> --- /dev/null   2022-08-24 16:22:16.888000070 +0100
> +++ gcc-git-devel-modula2/gcc/m2/lang.opt       2022-10-07 20:21:18.662097087 +0100
> @@ -0,0 +1,356 @@
> +; Options for the Modula-2 front end.
> +;
> +; Copyright (C) 2016-2022 Free Software Foundation, Inc.
> +; Contributed by Gaius Mulley <gaius.mulley@southwales.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 COPYING.  If not,
> +; see <https://www.gnu.org/licenses/>.  *)
> +
> +; See the GCC internals manual for a description of this file's format.
> +
> +; Please try to keep this file in ASCII collating order.
> +
> +Language
> +Modula-2
> +
> +B
> +Modula-2
> +; Documented in c.opt
> +
> +D
> +Modula-2
> +; Documented in c.opt
> +
> +E
> +Modula-2
> +; Documented in c.opt (passed to the preprocessor if -fcpp is used)
> +
> +I
> +Modula-2 Joined Separate
> +; Documented in c.opt
> +
> +L
> +Modula-2 Joined Separate
> +; Not documented
> +
> +M
> +Modula-2
> +; Documented in c.opt
> +
> +O
> +Modula-2
> +; Documented in c.opt
> +
> +Wall
> +Modula-2
> +; Documented in c.opt
> +
> +Wpedantic
> +Modula-2
> +; Documented in common.opt
> +
> +Wpedantic-param-names
> +Modula-2
> +compiler checks to force definition module procedure parameter names with their implementation module counterpart
> +
> +Wpedantic-cast
> +Modula-2
> +compiler warns if a cast is being used on types of differing sizes
> +
> +Wverbose-unbounded
> +Modula-2
> +inform user which parameters will be passed by reference
> +
> +Wstyle
> +Modula-2
> +extra compile time semantic checking, typically tries to catch poor programming style
> +
> +Wunused-variable
> +Modula-2
> +; Documented in c.opt
> +
> +Wunused-parameter
> +Modula-2
> +; Documented in c.opt
> +
> +c
> +Modula-2
> +; Documented in c.opt
> +
> +fauto-init
> +Modula-2
> +automatically initializes all pointers to NIL
> +
> +fbounds
> +Modula-2
> +turns on runtime subrange, array index and indirection via NIL pointer checking
> +
> +fcase
> +Modula-2
> +turns on runtime checking to check whether a CASE statement requires an ELSE clause when on was not specified
> +
> +fobjc-std=objc1
> +Modula-2
> +; Documented in c.opt
> +
> +fcpp
> +Modula-2
> +use cpp to preprocess the module
> +
> +fcpp-end
> +Modula-2
> +passed to the preprocessor if -fcpp is used (internal switch)
> +
> +fcpp-begin
> +Modula-2
> +passed to the preprocessor if -fcpp is used (internal switch)
> +
> +fdebug-builtins
> +Modula-2
> +call a real function, rather than the builtin equivalent
> +
> +fdump-system-exports
> +Modula-2
> +display all inbuilt system items
> +
> +fd
> +Modula-2
> +turn on internal debugging of the compiler
> +
> +fdebug-trace-quad
> +Modula-2
> +turn on quadruple tracing (internal switch)
> +
> +fdebug-trace-api
> +Modula-2
> +turn on the Modula-2 api tracing (internal switch)
> +
> +fdebug-function-line-numbers
> +Modula-2
> +turn on the Modula-2 function line number generation (internal switch)
> +
> +fdef=
> +Modula-2 Joined
> +recognise the specified suffix as a definition module filename
> +
> +fexceptions
> +Modula-2
> +; Documented in common.opt
> +
> +fextended-opaque
> +Modula-2
> +allows opaque types to be implemented as any type (a GNU Modula-2 extension)
> +
> +ffloatvalue
> +Modula-2
> +turns on runtime checking to check whether a floating point number is about to exceed range
> +
> +fgen-module-list=
> +Modula-2 Joined
> +create a topologically sorted module list from all dependent modules used in the application
> +
> +findex
> +Modula-2
> +turns on all range checking for numerical values
> +
> +fiso
> +Modula-2
> +use ISO dialect of Modula-2
> +
> +flibs=
> +Modula-2 Joined
> +specify the library order, currently legal entries include: log, min, pim, iso or their directory name equivalent m2log, m2min, m2pim, m2iso.
> +
> +flocation=
> +Modula-2 Joined
> +set all location values to a specific value (internal switch)
> +
> +fm2-g
> +Modula-2
> +generate extra nops to improve debugging, producing an instruction for every code related keyword
> +
> +fm2-lower-case
> +Modula-2
> +generate error messages which render keywords in lower case
> +
> +fm2-plugin
> +Modula-2
> +insert plugin to identify runtime errors at compiletime (default on)
> +
> +fm2-statistics
> +Modula-2
> +display statistics about the amount of source lines compiled and symbols used
> +
> +fm2-strict-type
> +Modula-2
> +experimental flag to turn on the new strict type checker
> +
> +fm2-whole-program
> +Modula-2
> +compile all implementation modules and program module at once
> +
> +fmod=
> +Modula-2 Joined
> +recognise the specified suffix as implementation and module filenames
> +
> +fnil
> +Modula-2
> +turns on runtime checking to detect accessing data through a NIL value pointer
> +
> +fpim
> +Modula-2
> +use PIM [234] dialect of Modula-2
> +
> +fpim2
> +Modula-2
> +use PIM 2 dialect of Modula-2
> +
> +fpim3
> +Modula-2
> +use PIM 3 dialect of Modula-2
> +
> +fpim4
> +Modula-2
> +use PIM 4 dialect of Modula-2
> +
> +fpositive-mod-floor-div
> +Modula-2
> +force positive result from MOD and DIV result floor
> +
> +fpthread
> +Modula-2
> +link against the pthread library (default on)
> +
> +fq
> +Modula-2
> +internal compiler debugging information, dump the list of quadruples
> +
> +frange
> +Modula-2
> +turns on all range checking for numerical values
> +
> +freturn
> +Modula-2
> +turns on runtime checking for functions which finish without executing a RETURN statement
> +
> +fruntime-modules=
> +Modula-2 Joined
> +specify the list of runtime modules and their initialization order
> +
> +fscaffold-static
> +Modula-2
> +generate static scaffold initialization and finalization for every module inside main
> +
> +fscaffold-dynamic
> +Modula-2
> +the modules initialization order is dynamically determined by M2RTS and application dependancies
> +
> +fscaffold-c
> +Modula-2
> +generate a C source scaffold for the current module being compiled
> +
> +fscaffold-c++
> +Modula-2
> +generate a C++ source scaffold for the current module being compiled
> +
> +fscaffold-main
> +Modula-2
> +generate the main function
> +
> +fshared
> +Modula-2
> +generate a shared library from the module
> +
> +fsoft-check-all
> +Modula-2
> +turns on all software runtime checking (an abbreviation for -fnil -frange -findex -fwholediv -fcase -freturn -fwholediv -ffloatvalue)
> +
> +fsources
> +Modula-2
> +display the location of module source files as they are compiled
> +
> +fswig
> +Modula-2
> +create a swig interface file for the module
> +
> +funbounded-by-reference
> +Modula-2
> +optimize non var unbounded parameters by passing it by reference, providing it is not written to within the callee procedure.
> +
> +fuse-list=
> +Modula-2 Joined
> +orders the initialization/finalializations for scaffold-static or force linking of modules if scaffold-dynamic
> +
> +fversion
> +Modula-2
> +; Documented in common.opt
> +
> +fwholediv
> +Modula-2
> +turns on all division and modulus by zero checking for ordinal values
> +
> +fwholevalue
> +Modula-2
> +turns on runtime checking to check whether a whole number is about to exceed range
> +
> +fxcode
> +Modula-2
> +issue all errors and warnings in the Xcode format
> +
> +iprefix
> +Modula-2
> +; Documented in c.opt
> +
> +isystem
> +Modula-2
> +; Documented in c.opt
> +
> +idirafter
> +Modula-2
> +; Documented in c.opt
> +
> +imultilib
> +Modula-2
> +; Documented in c.opt
> +
> +lang-asm
> +Modula-2
> +; Documented in c.opt
> +
> +-save-temps
> +Modula-2 Alias(save-temps)
> +
> +save-temps
> +Modula-2
> +save temporary preprocessed files
> +
> +save-temps=
> +Modula-2 Joined
> +save temporary preprocessed files
> +
> +traditional-cpp
> +Modula-2
> +; Documented in c.opt
> +
> +v
> +Modula-2
> +; Documented in c.opt
> +
> +x
> +Modula-2 Joined
> +specify the language from the compiler driver
> +
> +; This comment is to ensure we retain the blank line above.
> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/lang-specs.h
> --- /dev/null   2022-08-24 16:22:16.888000070 +0100
> +++ gcc-git-devel-modula2/gcc/m2/lang-specs.h   2022-10-07 20:21:18.662097087 +0100
> @@ -0,0 +1,38 @@
> +/* Definitions for specs for GNU Modula-2.
> +   Copyright (C) 2001-2022 Free Software Foundation, Inc.
> +   Contributed by Gaius Mulley.
> +
> +This file is part of GCC.
> +
> +GCC 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.
> +
> +GCC 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 GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +/* This is the contribution to the `default_compilers' array in gcc.c for
> +   GNU Modula-2.  */
> +
> +/* Pass the preprocessor options on the command line together with
> +   the exec prefix.  */
> +
> +#define M2CPP "%{fcpp:-fcpp-begin " \
> +              "      -E -lang-asm -traditional-cpp " \
> +              "      %(cpp_unique_options) -fcpp-end}"
> +
> +  {".mod", "@modula-2", 0, 0, 0},
> +  {"@modula-2",
> +      "cc1gm2 " M2CPP
> +      "      %(cc1_options) %{B*} %{c*} %{f*} %{+e*} %{I*} "
> +      "      %{MD} %{MMD} %{M} %{MM} %{MA} %{MT*} %{MF*} %V"
> +      "      %{save-temps*}"
> +      "      %i %{!fsyntax-only:%(invoke_as)}",
> +      0, 0, 0},
> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/config-lang.in
> --- /dev/null   2022-08-24 16:22:16.888000070 +0100
> +++ gcc-git-devel-modula2/gcc/m2/config-lang.in 2022-10-07 20:21:18.634096743 +0100
> @@ -0,0 +1,83 @@
> +# Top level configure fragment for GNU Modula-2.
> +# Copyright (C) 2000-2022 Free Software Foundation, Inc.
> +
> +# This file is part of GCC.
> +
> +# GCC 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.
> +
> +# GCC 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 GCC; see the file COPYING3.  If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +# Configure looks for the existence of this file to auto-config each language.
> +# We define several parameters used by configure:
> +#
> +# language     - name of language as it would appear in $(LANGUAGES)
> +# compilers    - value to add to $(COMPILERS)
> +# stagestuff   - files to add to $(STAGESTUFF)
> +
> +language="m2"
> +
> +compilers="cc1gm2\$(exeext)"
> +
> +stagestuff="gm2\$(exeext) cc1gm2\$(exeext) cc1gm2-cross\$(exeext)"
> +
> +target_libs="target-libstdc++-v3 target-libgm2"
> +
> +# The Modula-2 frontend needs C++ compiler during stage 1.
> +lang_requires_boot_languages=c++
> +
> +# Do not build by default.
> +build_by_default="no"
> +
> +gtfiles="\$(srcdir)/m2/gm2-lang.cc \
> +         \$(srcdir)/m2/gm2-lang.h \
> +         \$(srcdir)/m2/gm2-gcc/rtegraph.cc \
> +         \$(srcdir)/m2/gm2-gcc/m2block.cc \
> +         \$(srcdir)/m2/gm2-gcc/m2builtins.cc \
> +         \$(srcdir)/m2/gm2-gcc/m2decl.cc \
> +         \$(srcdir)/m2/gm2-gcc/m2except.cc \
> +         \$(srcdir)/m2/gm2-gcc/m2expr.cc \
> +         \$(srcdir)/m2/gm2-gcc/m2statement.cc \
> +         \$(srcdir)/m2/gm2-gcc/m2type.cc"
> +
> +outputs="m2/config-make \
> +         m2/Make-maintainer \
> +        "
> +
> +mkdir -p m2/gm2-compiler-boot
> +mkdir -p m2/gm2-libs-boot
> +mkdir -p m2/gm2-ici-boot
> +mkdir -p m2/gm2-libiberty
> +mkdir -p m2/gm2-gcc
> +mkdir -p m2/gm2-compiler
> +mkdir -p m2/gm2-libs
> +mkdir -p m2/gm2-libs-iso
> +mkdir -p m2/gm2-compiler-paranoid
> +mkdir -p m2/gm2-libs-paranoid
> +mkdir -p m2/gm2-compiler-verify
> +mkdir -p m2/boot-bin
> +mkdir -p m2/gm2-libs-pim
> +mkdir -p m2/gm2-libs-coroutines
> +mkdir -p m2/gm2-libs-min
> +mkdir -p m2/pge-boot
> +mkdir -p plugin
> +mkdir -p stage1/m2 stage2/m2 stage3/m2 stage4/m2
> +
> +# directories used by Make-maintainer
> +
> +mkdir -p m2/gm2-auto
> +mkdir -p m2/gm2-pg-boot
> +mkdir -p m2/gm2-pge-boot
> +mkdir -p m2/gm2-ppg-boot
> +mkdir -p m2/mc-boot
> +mkdir -p m2/mc-boot-ch
> +mkdir -p m2/mc-boot-gen
> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/config-make.in
> --- /dev/null   2022-08-24 16:22:16.888000070 +0100
> +++ gcc-git-devel-modula2/gcc/m2/config-make.in 2022-10-07 20:21:18.634096743 +0100
> @@ -0,0 +1,2 @@
> +# Target libraries are put under this directory:
> +TARGET_SUBDIR = @target_subdir@
> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/configure.ac
> --- /dev/null   2022-08-24 16:22:16.888000070 +0100
> +++ gcc-git-devel-modula2/gcc/m2/configure.ac   2022-10-07 20:21:18.634096743 +0100
> @@ -0,0 +1,43 @@
> +# configure.ac provides gm2spec.c with access to config values.
> +
> +# Copyright (C) 2001-2022 Free Software Foundation, Inc.
> +# Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
> +
> +# GCC 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.
> +
> +# GCC 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 GCC; see the file COPYING3.  If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +AC_INIT(m2, [ ])
> +
> +# Determine the host, build, and target systems
> +AC_CANONICAL_BUILD
> +AC_CANONICAL_HOST
> +AC_CANONICAL_TARGET
> +
> +AC_CHECK_PROGS(regex_flex, flex)
> +if test x$regex_flex = "x" ; then
> +    AC_MSG_ERROR([flex is required to build GNU Modula-2 (hint install flex).])
> +fi
> +
> +AC_CHECK_PROGS(regex_realpath, realpath)
> +if test x$regex_realpath = "x" ; then
> +    AC_MSG_ERROR([realpath is required to build GNU Modula-2 (hint install coreutils).])
> +fi
> +
> +AC_CHECK_FUNCS([stpcpy])
> +
> +AC_CHECK_HEADERS(sys/types.h)
> +AC_HEADER_DIRENT
> +AC_CHECK_LIB([c],[opendir],[AC_DEFINE([HAVE_OPENDIR],[1],[found opendir])])
> +AC_CONFIG_HEADERS(gm2config.h, [echo timestamp > stamp-h])
> +AC_OUTPUT
> diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/gm2config.h.in
> --- /dev/null   2022-08-24 16:22:16.888000070 +0100
> +++ gcc-git-devel-modula2/gcc/m2/gm2config.h.in 2022-10-07 20:21:18.662097087 +0100
> @@ -0,0 +1,56 @@
> +/* gm2config.h.in template file for values required by gm2spec.c.
> +
> +Copyright (C) 2006-2022 Free Software Foundation, Inc.
> +Contributed by Gaius Mulley <gaius.mulley@southwales.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/>.  */
> +
> +#ifndef PACKAGE_BUGREPORT
> +/* Define to the address where bug reports for this package should be sent. */
> +#undef PACKAGE_BUGREPORT
> +#endif
> +
> +#ifndef PACKAGE_NAME
> +/* Define to the full name of this package. */
> +#undef PACKAGE_NAME
> +#endif
> +
> +#ifndef PACKAGE_STRING
> +/* Define to the full name and version of this package. */
> +#undef PACKAGE_STRING
> +#endif
> +
> +/* Define to 1 if you have the `stpcmp' function. */
> +#undef HAVE_STPCMP
> +
> +/* Define to 1 if you have the dirent.h header. */
> +#undef HAVE_DIRENT_H
> +
> +/* Define to 1 if you have the sys/ndir.h header. */
> +#undef HAVE_SYS_NDIR_H
> +
> +/* Define to 1 if you have the sys/dir.h header. */
> +#undef HAVE_SYS_DIR_H
> +
> +/* Define to 1 if you have the ndir.h header. */
> +#undef HAVE_NDIR_H
> +
> +/* Define to 1 if you have the sys/types.h header. */
> +#undef HAVE_SYS_TYPES_H
> +
> +/* Define to 1 if you have the opendir function.  */
> +#undef HAVE_OPENDIR
  
Gaius Mulley Nov. 21, 2022, 5:42 p.m. UTC | #2
Richard Biener <richard.guenther@gmail.com> writes:

[snip]

> It feels like most of the above would usually be handled via lang specific
> specs rather than open-coded in the driver?  Is there a specific reason you
> opted for explicit handling here?

The last time submitting the patches I perhaps went overboard using
lang-specs - and so tried to adopt the style from C++/fortran this time
around.  I'm happy to utilize lang-specs to reduce the driver code though.

> Otherwise the patch looks generally OK, the string builds using strcat & friends
> looks like it neither takes advantage of how obstacks can be used there nor
> that we're now C++ and could use std::string - but that's a matter of taste and
> no objection.

ok thanks!

regards,
Gaius
  

Patch

diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/gm2spec.cc
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/gm2spec.cc	2022-10-07 20:21:18.662097087 +0100
@@ -0,0 +1,937 @@ 
+/* gm2spec.cc specific flags and argument handling within GNU Modula-2.
+
+Copyright (C) 2007-2022 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaius@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/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
+
+/* This bit is set if we saw a `-xfoo' language specification.  */
+#define LANGSPEC	(1<<1)
+/* This bit is set if they did `-lm' or `-lmath'.  */
+#define MATHLIB		(1<<2)
+/* This bit is set if they did `-lc'.  */
+#define WITHLIBC	(1<<3)
+/* Skip this option.  */
+#define SKIPOPT		(1<<4)
+
+#ifndef MATH_LIBRARY
+#define MATH_LIBRARY "m"
+#endif
+#ifndef MATH_LIBRARY_PROFILE
+#define MATH_LIBRARY_PROFILE MATH_LIBRARY
+#endif
+
+#ifndef LIBSTDCXX
+#define LIBSTDCXX "stdc++"
+#endif
+#ifndef LIBSTDCXX_PROFILE
+#define LIBSTDCXX_PROFILE LIBSTDCXX
+#endif
+#ifndef LIBSTDCXX_STATIC
+#define LIBSTDCXX_STATIC NULL
+#endif
+
+#ifndef LIBCXX
+#define LIBCXX "c++"
+#endif
+#ifndef LIBCXX_PROFILE
+#define LIBCXX_PROFILE LIBCXX
+#endif
+#ifndef LIBCXX_STATIC
+#define LIBCXX_STATIC NULL
+#endif
+
+#ifndef LIBCXXABI
+#define LIBCXXABI "c++abi"
+#endif
+#ifndef LIBCXXABI_PROFILE
+#define LIBCXXABI_PROFILE LIBCXXABI
+#endif
+#ifndef LIBCXXABI_STATIC
+#define LIBCXXABI_STATIC NULL
+#endif
+
+/* The values used here must match those of the stdlib_kind enumeration
+   in c.opt.  */
+enum stdcxxlib_kind
+{
+  USE_LIBSTDCXX = 1,
+  USE_LIBCXX = 2
+};
+
+#define DEFAULT_DIALECT "pim"
+#undef DEBUG_ARG
+
+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.  */
+
+static const char *add_include (const char *libpath, const char *library);
+
+static bool seen_scaffold_static = false;
+static bool seen_scaffold_dynamic = false;
+static bool scaffold_static = false;
+static bool scaffold_dynamic = true;  // Default uses -fscaffold-dynamic.
+static bool seen_gen_module_list = false;
+static bool seen_uselist = false;
+static bool uselist = false;
+static bool gen_module_list = true;  // Default uses -fgen-module-list=-.
+static const char *gen_module_filename = "-";
+static const char *multilib_dir = NULL;
+/* The original argument list and related info is copied here.  */
+static unsigned int gm2_xargc;
+static const struct cl_decoded_option *gm2_x_decoded_options;
+static void append_arg (const struct cl_decoded_option *);
+
+/* The new argument list will be built here.  */
+static unsigned int gm2_newargc;
+static struct cl_decoded_option *gm2_new_decoded_options;
+
+
+/* Return whether strings S1 and S2 are both NULL or both the same
+   string.  */
+
+static bool
+strings_same (const char *s1, const char *s2)
+{
+  return s1 == s2 || (s1 != NULL && s2 != NULL && strcmp (s1, s2) == 0);
+}
+
+bool
+options_same (const struct cl_decoded_option *opt1,
+	      const struct cl_decoded_option *opt2)
+{
+  return (opt1->opt_index == opt2->opt_index
+	  && strings_same (opt1->arg, opt2->arg)
+	  && strings_same (opt1->orig_option_with_args_text,
+			   opt2->orig_option_with_args_text)
+	  && strings_same (opt1->canonical_option[0],
+			   opt2->canonical_option[0])
+	  && strings_same (opt1->canonical_option[1],
+			   opt2->canonical_option[1])
+	  && strings_same (opt1->canonical_option[2],
+			   opt2->canonical_option[2])
+	  && strings_same (opt1->canonical_option[3],
+			   opt2->canonical_option[3])
+	  && (opt1->canonical_option_num_elements
+	      == opt2->canonical_option_num_elements)
+	  && opt1->value == opt2->value
+	  && opt1->errors == opt2->errors);
+}
+
+/* Append another argument to the list being built.  */
+
+static void
+append_arg (const struct cl_decoded_option *arg)
+{
+  static unsigned int newargsize;
+
+  if (gm2_new_decoded_options == gm2_x_decoded_options
+      && gm2_newargc < gm2_xargc
+      && options_same (arg, &gm2_x_decoded_options[gm2_newargc]))
+    {
+      ++gm2_newargc;
+      return;			/* Nothing new here.  */
+    }
+
+  if (gm2_new_decoded_options == gm2_x_decoded_options)
+    {				/* Make new arglist.  */
+      unsigned int i;
+
+      newargsize = (gm2_xargc << 2) + 20;	/* This should handle all.  */
+      gm2_new_decoded_options = XNEWVEC (struct cl_decoded_option, newargsize);
+
+      /* Copy what has been done so far.  */
+      for (i = 0; i < gm2_newargc; ++i)
+	gm2_new_decoded_options[i] = gm2_x_decoded_options[i];
+    }
+
+  if (gm2_newargc == newargsize)
+    fatal_error (input_location, "overflowed output argument list for %qs",
+		 arg->orig_option_with_args_text);
+
+  gm2_new_decoded_options[gm2_newargc++] = *arg;
+}
+
+/* Append an option described by OPT_INDEX, ARG and VALUE to the list
+   being built.  */
+
+static void
+append_option (size_t opt_index, const char *arg, int value)
+{
+  struct cl_decoded_option decoded;
+
+  generate_option (opt_index, arg, value, CL_DRIVER, &decoded);
+  append_arg (&decoded);
+}
+
+/* build_archive_path returns a string containing the 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 bool
+add_default_combination (const char *libpath, const char *library)
+{
+  if (library != NULL)
+    {
+      append_option (OPT_L, build_archive_path (libpath, library), 1);
+      append_option (OPT_l, safe_strdup (library), 1);
+      return true;
+    }
+  return false;
+}
+
+/* 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)
+{
+  const char *l = libraries;
+  const char *e;
+  char *libname;
+  unsigned int libcount = 0;
+
+  do
+    {
+      e = index (l, ',');
+      if (e == NULL)
+        {
+          libname = xstrdup (l);
+          l = NULL;
+	  if (add_default_combination (libpath, libname))
+	    libcount++;
+	  free (libname);
+        }
+      else
+        {
+          libname = xstrndup (l, e - l);
+          l = e + 1;
+	  if (add_default_combination (libpath, libname))
+	    libcount++;
+	  free (libname);
+        }
+    }
+  while ((l != NULL) && (l[0] != (char)0));
+  return libcount;
+}
+
+/* build_include_path builds the component of the include path
+   referenced by the library.  */
+
+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);
+      append_option (OPT_I, path, 1);
+    }
+  while ((l != NULL) && (l[0] != (char)0));
+}
+
+/* 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_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;
+}
+
+
+void
+lang_specific_driver (struct cl_decoded_option **in_decoded_options,
+		      unsigned int *in_decoded_options_count,
+		      int *in_added_libraries)
+{
+  unsigned int argc = *in_decoded_options_count;
+  struct cl_decoded_option *decoded_options = *in_decoded_options;
+  unsigned int i;
+
+  /* True 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;
+
+  /* If nonzero, the user gave us the `-p' or `-pg' flag.  */
+  int saw_profile_flag = 0;
+
+  /* What action to take for the c++ runtime library:
+    -1  means we should not link it in.
+     0  means we should link it if it is needed.
+     1  means it is needed and should be linked in.
+     2  means it is needed but should be linked statically.  */
+  int library = 0;
+
+  /* Which c++ runtime library to link.  */
+  stdcxxlib_kind which_library = USE_LIBSTDCXX;
+
+  const char *libraries = NULL;
+  const char *dialect = DEFAULT_DIALECT;
+  const char *libpath = LIBSUBDIR;
+
+  /* An array used to flag each argument that needs a bit set for
+     LANGSPEC, MATHLIB, or WITHLIBC.  */
+  int *args;
+
+  /* Have we seen -fmod=?  */
+  bool seen_module_extension = false;
+
+  /* Should the driver perform a link?  */
+  bool linking = true;
+
+  /* "-lm" or "-lmath" if it appears on the command line.  */
+  const struct cl_decoded_option *saw_math = NULL;
+
+  /* "-lc" if it appears on the command line.  */
+  const struct cl_decoded_option *saw_libc = NULL;
+
+  /* By default, we throw on the math library if we have one.  */
+  int need_math = (MATH_LIBRARY[0] != '\0');
+
+  /* 1 if we should add -lpthread to the command-line.  */
+  int need_pthread = 1;
+
+  /* True if we saw -static.  */
+  int static_link = 0;
+
+  /* True if we should add -shared-libgcc to the command-line.  */
+  int shared_libgcc = 1;
+
+  /* Have we seen the -v flag?  */
+  bool verbose = false;
+
+  /* The number of libraries added in.  */
+  int added_libraries;
+
+  /* True if we should add -fplugin=m2rte to the command-line.  */
+  bool need_plugin = true;
+
+  /* True if we should set up include paths and library paths.  */
+  bool allow_libraries = true;
+
+#if defined(DEBUG_ARG)
+  printf ("argc = %d\n", argc);
+  fprintf (stderr, "Incoming:");
+  for (i = 0; i < argc; i++)
+    fprintf (stderr, " %s", decoded_options[i].orig_option_with_args_text);
+  fprintf (stderr, "\n");
+#endif
+
+  gm2_xargc = argc;
+  gm2_x_decoded_options = decoded_options;
+  gm2_newargc = 0;
+  gm2_new_decoded_options = decoded_options;
+  added_libraries = *in_added_libraries;
+  args = XCNEWVEC (int, argc);
+
+  /* First pass through arglist.
+
+     If -nostdlib or a "turn-off-linking" option is anywhere in the
+     command line, don't do any library-option processing (except
+     relating to -x).  */
+
+  for (i = 1; i < argc; i++)
+    {
+      const char *arg = decoded_options[i].arg;
+      args[i] = 0;
+#if defined(DEBUG_ARG)
+      printf ("1st pass: %s\n",
+	      decoded_options[i].orig_option_with_args_text);
+#endif
+      switch (decoded_options[i].opt_index)
+	{
+	case OPT_fiso:
+	  dialect = "iso";
+	  break;
+	case OPT_fpim2:
+	  dialect = "pim2";
+	  break;
+	case OPT_fpim3:
+	  dialect = "pim3";
+	  break;
+	case OPT_fpim4:
+	  dialect = "pim4";
+	  break;
+	case OPT_fpim:
+	  dialect = "pim";
+	  break;
+	case OPT_flibs_:
+	  libraries = xstrdup (arg);
+	  allow_libraries = decoded_options[i].value;
+	  break;
+	case OPT_fmod_:
+	  seen_module_extension = true;
+	  break;
+        case OPT_fpthread:
+          need_pthread = decoded_options[i].value;
+          break;
+        case OPT_fm2_plugin:
+          need_plugin = decoded_options[i].value;
+          break;
+	case OPT_fscaffold_dynamic:
+	  seen_scaffold_dynamic = true;
+	  scaffold_dynamic = decoded_options[i].value;
+	  break;
+	case OPT_fscaffold_static:
+	  seen_scaffold_static = true;
+	  scaffold_static = decoded_options[i].value;
+	  break;
+	case OPT_fgen_module_list_:
+	  seen_gen_module_list = true;
+	  gen_module_list = decoded_options[i].value;
+	  if (gen_module_list)
+	    gen_module_filename = decoded_options[i].arg;
+	  break;
+	case OPT_fuse_list_:
+	  seen_uselist = true;
+	  uselist = decoded_options[i].value;
+	  break;
+
+	case OPT_nostdlib:
+	case OPT_nostdlib__:
+	case OPT_nodefaultlibs:
+	  library = -1;
+	  break;
+
+	case OPT_l:
+	  if (strcmp (arg, MATH_LIBRARY) == 0)
+	    {
+	      args[i] |= MATHLIB;
+	      need_math = 0;
+	    }
+	  else if (strcmp (arg, "c") == 0)
+	    args[i] |= WITHLIBC;
+	  else
+	    /* Unrecognized libraries (e.g. -lfoo) may require libstdc++.  */
+	    library = (library == 0) ? 1 : library;
+	  break;
+
+	case OPT_pg:
+	case OPT_p:
+	  saw_profile_flag++;
+	  break;
+
+	case OPT_x:
+          seen_x_flag = true;
+          language = arg;
+	  break;
+
+	case OPT_v:
+	  verbose = true;
+	  break;
+
+	case OPT_Xlinker:
+	case OPT_Wl_:
+	  /* Arguments that go directly to the linker might be .o files,
+	     or something, and so might cause libstdc++ to be needed.  */
+	  if (library == 0)
+	    library = 1;
+	  break;
+
+	case OPT_c:
+	case OPT_r:
+	case OPT_S:
+	case OPT_E:
+	case OPT_M:
+	case OPT_MM:
+	case OPT_fsyntax_only:
+	  /* Don't specify libraries if we won't link, since that would
+	     cause a warning.  */
+	  linking = false;
+	  library = -1;
+	  break;
+
+	case OPT_static:
+	  static_link = 1;
+	  break;
+
+	case OPT_static_libgcc:
+	  shared_libgcc = 0;
+	  break;
+
+	case OPT_static_libstdc__:
+	  library = library >= 0 ? 2 : library;
+	  args[i] |= SKIPOPT;
+	  break;
+
+	case OPT_stdlib_:
+	  which_library = (stdcxxlib_kind) decoded_options[i].value;
+	  break;
+
+	default:
+	  if ((decoded_options[i].orig_option_with_args_text != NULL)
+	      && (strncmp (decoded_options[i].orig_option_with_args_text,
+			   "-m", 2) == 0))
+	    multilib_dir = xstrdup (decoded_options[i].orig_option_with_args_text
+				    + 2);
+	}
+    }
+  if (language != NULL && (strcmp (language, "modula-2") != 0))
+    return;
+
+  if (scaffold_static && scaffold_dynamic)
+    {
+      if (! seen_scaffold_dynamic)
+	scaffold_dynamic = false;
+      if (scaffold_dynamic && scaffold_static)
+	error ("%qs and %qs cannot both be enabled",
+	       "-fscaffold-dynamic", "-fscaffold-static");
+    }
+  if (uselist && gen_module_list)
+    {
+      if (! seen_gen_module_list)
+	gen_module_list = false;
+      if (uselist && gen_module_list)
+	error ("%qs and %qs cannot both be enabled",
+	       "-fgen-module-list=", "-fuse-list=");
+    }
+
+
+  /* There's no point adding -shared-libgcc if we don't have a shared
+     libgcc.  */
+#ifndef ENABLE_SHARED_LIBGCC
+  shared_libgcc = 0;
+#endif
+
+  /* Second pass through arglist, transforming arguments as appropriate.  */
+
+  append_arg (&decoded_options[0]); /* Start with command name, of course.  */
+  for (i = 1; i < argc; ++i)
+    {
+#if defined(DEBUG_ARG)
+      printf ("2nd pass: %s\n",
+	      decoded_options[i].orig_option_with_args_text);
+#endif
+      if ((args[i] & SKIPOPT) == 0)
+	{
+	  append_arg (&decoded_options[i]);
+	  /* Make sure -lstdc++ is before the math library, since libstdc++
+	     itself uses those math routines.  */
+	  if (!saw_math && (args[i] & MATHLIB) && library > 0)
+	    saw_math = &decoded_options[i];
+
+	  if (!saw_libc && (args[i] & WITHLIBC) && library > 0)
+	    saw_libc = &decoded_options[i];
+	}
+#if defined(DEBUG_ARG)
+      else
+	printf ("skipping: %s\n",
+		decoded_options[i].orig_option_with_args_text);
+#endif
+    }
+
+  /* We now add in extra arguments to facilitate a successful
+     compile or link.  For example include paths for dialect of Modula-2,
+     library paths and default scaffold linking options.  */
+
+  /* If we have not seen either uselist or gen_module_list and we need
+     to link then we turn on -fgen_module_list=- as the default.  */
+  if ((! (seen_uselist || seen_gen_module_list)) && linking)
+    append_option (OPT_fgen_module_list_, "-", 1);
+
+  if (allow_libraries)
+    {
+      /* If the libraries have not been specified by the user but the
+	 dialect has been specified then select the appropriate libraries.  */
+      if (libraries == NULL)
+	{
+	  if (strcmp (dialect, "iso") == 0)
+	    libraries = xstrdup ("m2iso,m2pim");
+	  else
+	    /* Default to pim libraries if none specified.  */
+	    libraries = xstrdup ("m2pim,m2log,m2iso");
+	}
+      libraries = convert_abbreviations (libraries);
+      if (! check_valid_list (libpath, libraries))
+	return;
+      add_default_includes (libpath, libraries);
+    }
+  if ((! seen_x_flag) && seen_module_extension)
+    append_option (OPT_x, "modula-2", 1);
+
+  if (need_plugin)
+    append_option (OPT_fplugin_, "m2rte", 1);
+
+  if (linking)
+    {
+      if (allow_libraries)
+	add_default_archives (libpath, libraries);
+      /* Add `-lstdc++' if we haven't already done so.  */
+#ifdef HAVE_LD_STATIC_DYNAMIC
+      if (library > 1 && !static_link)
+	append_option (OPT_Wl_, LD_STATIC_OPTION, 1);
+#endif
+      if (which_library == USE_LIBCXX)
+	{
+	  append_option (OPT_l, saw_profile_flag ? LIBCXX_PROFILE : LIBCXX, 1);
+	  added_libraries++;
+	  if (LIBCXXABI != NULL)
+	    {
+	      append_option (OPT_l, saw_profile_flag ? LIBCXXABI_PROFILE
+			     : LIBCXXABI, 1);
+	      added_libraries++;
+	    }
+	}
+      else
+	{
+	  append_option (OPT_l, saw_profile_flag ? LIBSTDCXX_PROFILE
+			 : LIBSTDCXX, 1);
+	  added_libraries++;
+	}
+      /* Add target-dependent static library, if necessary.  */
+      if ((static_link || library > 1) && LIBSTDCXX_STATIC != NULL)
+	{
+	  append_option (OPT_l, LIBSTDCXX_STATIC, 1);
+	  added_libraries++;
+	}
+#ifdef HAVE_LD_STATIC_DYNAMIC
+      if (library > 1 && !static_link)
+	append_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1);
+#endif
+    }
+  if (need_math)
+    {
+      append_option (OPT_l, saw_profile_flag ? MATH_LIBRARY_PROFILE :
+		     MATH_LIBRARY, 1);
+      added_libraries++;
+    }
+  if (need_pthread)
+    {
+      append_option (OPT_l, "pthread", 1);
+      added_libraries++;
+    }
+  if (shared_libgcc && !static_link)
+    append_option (OPT_shared_libgcc, NULL, 1);
+
+  if (verbose && gm2_new_decoded_options != gm2_x_decoded_options)
+    {
+      fprintf (stderr, _("Driving:"));
+      for (i = 0; i < gm2_newargc; i++)
+	fprintf (stderr, " %s",
+		 gm2_new_decoded_options[i].orig_option_with_args_text);
+      fprintf (stderr, "\n");
+      fprintf (stderr, "new argc = %d, added_libraries = %d\n",
+	       gm2_newargc, added_libraries);
+    }
+
+  *in_decoded_options_count = gm2_newargc;
+  *in_decoded_options = gm2_new_decoded_options;
+  *in_added_libraries = added_libraries;
+}
+
+/* Called before linking.  Returns 0 on success and -1 on failure.  */
+int
+lang_specific_pre_link (void)  /* Not used for M2.  */
+{
+  return 0;
+}
+
+/* Number of extra output files that lang_specific_pre_link may generate.  */
+int lang_specific_extra_outfiles = 0;
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/lang.opt
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/lang.opt	2022-10-07 20:21:18.662097087 +0100
@@ -0,0 +1,356 @@ 
+; Options for the Modula-2 front end.
+;
+; Copyright (C) 2016-2022 Free Software Foundation, Inc.
+; Contributed by Gaius Mulley <gaius.mulley@southwales.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 COPYING.  If not,
+; see <https://www.gnu.org/licenses/>.  *)
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+Modula-2
+
+B
+Modula-2
+; Documented in c.opt
+
+D
+Modula-2
+; Documented in c.opt
+
+E
+Modula-2
+; Documented in c.opt (passed to the preprocessor if -fcpp is used)
+
+I
+Modula-2 Joined Separate
+; Documented in c.opt
+
+L
+Modula-2 Joined Separate
+; Not documented
+
+M
+Modula-2
+; Documented in c.opt
+
+O
+Modula-2
+; Documented in c.opt
+
+Wall
+Modula-2
+; Documented in c.opt
+
+Wpedantic
+Modula-2
+; Documented in common.opt
+
+Wpedantic-param-names
+Modula-2
+compiler checks to force definition module procedure parameter names with their implementation module counterpart
+
+Wpedantic-cast
+Modula-2
+compiler warns if a cast is being used on types of differing sizes
+
+Wverbose-unbounded
+Modula-2
+inform user which parameters will be passed by reference
+
+Wstyle
+Modula-2
+extra compile time semantic checking, typically tries to catch poor programming style
+
+Wunused-variable
+Modula-2
+; Documented in c.opt
+
+Wunused-parameter
+Modula-2
+; Documented in c.opt
+
+c
+Modula-2
+; Documented in c.opt
+
+fauto-init
+Modula-2
+automatically initializes all pointers to NIL
+
+fbounds
+Modula-2
+turns on runtime subrange, array index and indirection via NIL pointer checking
+
+fcase
+Modula-2
+turns on runtime checking to check whether a CASE statement requires an ELSE clause when on was not specified
+
+fobjc-std=objc1
+Modula-2
+; Documented in c.opt
+
+fcpp
+Modula-2
+use cpp to preprocess the module
+
+fcpp-end
+Modula-2
+passed to the preprocessor if -fcpp is used (internal switch)
+
+fcpp-begin
+Modula-2
+passed to the preprocessor if -fcpp is used (internal switch)
+
+fdebug-builtins
+Modula-2
+call a real function, rather than the builtin equivalent
+
+fdump-system-exports
+Modula-2
+display all inbuilt system items
+
+fd
+Modula-2
+turn on internal debugging of the compiler
+
+fdebug-trace-quad
+Modula-2
+turn on quadruple tracing (internal switch)
+
+fdebug-trace-api
+Modula-2
+turn on the Modula-2 api tracing (internal switch)
+
+fdebug-function-line-numbers
+Modula-2
+turn on the Modula-2 function line number generation (internal switch)
+
+fdef=
+Modula-2 Joined
+recognise the specified suffix as a definition module filename
+
+fexceptions
+Modula-2
+; Documented in common.opt
+
+fextended-opaque
+Modula-2
+allows opaque types to be implemented as any type (a GNU Modula-2 extension)
+
+ffloatvalue
+Modula-2
+turns on runtime checking to check whether a floating point number is about to exceed range
+
+fgen-module-list=
+Modula-2 Joined
+create a topologically sorted module list from all dependent modules used in the application
+
+findex
+Modula-2
+turns on all range checking for numerical values
+
+fiso
+Modula-2
+use ISO dialect of Modula-2
+
+flibs=
+Modula-2 Joined
+specify the library order, currently legal entries include: log, min, pim, iso or their directory name equivalent m2log, m2min, m2pim, m2iso.
+
+flocation=
+Modula-2 Joined
+set all location values to a specific value (internal switch)
+
+fm2-g
+Modula-2
+generate extra nops to improve debugging, producing an instruction for every code related keyword
+
+fm2-lower-case
+Modula-2
+generate error messages which render keywords in lower case
+
+fm2-plugin
+Modula-2
+insert plugin to identify runtime errors at compiletime (default on)
+
+fm2-statistics
+Modula-2
+display statistics about the amount of source lines compiled and symbols used
+
+fm2-strict-type
+Modula-2
+experimental flag to turn on the new strict type checker
+
+fm2-whole-program
+Modula-2
+compile all implementation modules and program module at once
+
+fmod=
+Modula-2 Joined
+recognise the specified suffix as implementation and module filenames
+
+fnil
+Modula-2
+turns on runtime checking to detect accessing data through a NIL value pointer
+
+fpim
+Modula-2
+use PIM [234] dialect of Modula-2
+
+fpim2
+Modula-2
+use PIM 2 dialect of Modula-2
+
+fpim3
+Modula-2
+use PIM 3 dialect of Modula-2
+
+fpim4
+Modula-2
+use PIM 4 dialect of Modula-2
+
+fpositive-mod-floor-div
+Modula-2
+force positive result from MOD and DIV result floor
+
+fpthread
+Modula-2
+link against the pthread library (default on)
+
+fq
+Modula-2
+internal compiler debugging information, dump the list of quadruples
+
+frange
+Modula-2
+turns on all range checking for numerical values
+
+freturn
+Modula-2
+turns on runtime checking for functions which finish without executing a RETURN statement
+
+fruntime-modules=
+Modula-2 Joined
+specify the list of runtime modules and their initialization order
+
+fscaffold-static
+Modula-2
+generate static scaffold initialization and finalization for every module inside main
+
+fscaffold-dynamic
+Modula-2
+the modules initialization order is dynamically determined by M2RTS and application dependancies
+
+fscaffold-c
+Modula-2
+generate a C source scaffold for the current module being compiled
+
+fscaffold-c++
+Modula-2
+generate a C++ source scaffold for the current module being compiled
+
+fscaffold-main
+Modula-2
+generate the main function
+
+fshared
+Modula-2
+generate a shared library from the module
+
+fsoft-check-all
+Modula-2
+turns on all software runtime checking (an abbreviation for -fnil -frange -findex -fwholediv -fcase -freturn -fwholediv -ffloatvalue)
+
+fsources
+Modula-2
+display the location of module source files as they are compiled
+
+fswig
+Modula-2
+create a swig interface file for the module
+
+funbounded-by-reference
+Modula-2
+optimize non var unbounded parameters by passing it by reference, providing it is not written to within the callee procedure.
+
+fuse-list=
+Modula-2 Joined
+orders the initialization/finalializations for scaffold-static or force linking of modules if scaffold-dynamic
+
+fversion
+Modula-2
+; Documented in common.opt
+
+fwholediv
+Modula-2
+turns on all division and modulus by zero checking for ordinal values
+
+fwholevalue
+Modula-2
+turns on runtime checking to check whether a whole number is about to exceed range
+
+fxcode
+Modula-2
+issue all errors and warnings in the Xcode format
+
+iprefix
+Modula-2
+; Documented in c.opt
+
+isystem
+Modula-2
+; Documented in c.opt
+
+idirafter
+Modula-2
+; Documented in c.opt
+
+imultilib
+Modula-2
+; Documented in c.opt
+
+lang-asm
+Modula-2
+; Documented in c.opt
+
+-save-temps
+Modula-2 Alias(save-temps)
+
+save-temps
+Modula-2
+save temporary preprocessed files
+
+save-temps=
+Modula-2 Joined
+save temporary preprocessed files
+
+traditional-cpp
+Modula-2
+; Documented in c.opt
+
+v
+Modula-2
+; Documented in c.opt
+
+x
+Modula-2 Joined
+specify the language from the compiler driver
+
+; This comment is to ensure we retain the blank line above.
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/lang-specs.h
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/lang-specs.h	2022-10-07 20:21:18.662097087 +0100
@@ -0,0 +1,38 @@ 
+/* Definitions for specs for GNU Modula-2.
+   Copyright (C) 2001-2022 Free Software Foundation, Inc.
+   Contributed by Gaius Mulley.
+
+This file is part of GCC.
+
+GCC 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.
+
+GCC 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 GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* This is the contribution to the `default_compilers' array in gcc.c for
+   GNU Modula-2.  */
+
+/* Pass the preprocessor options on the command line together with
+   the exec prefix.  */
+
+#define M2CPP "%{fcpp:-fcpp-begin " \
+              "      -E -lang-asm -traditional-cpp " \
+              "      %(cpp_unique_options) -fcpp-end}"
+
+  {".mod", "@modula-2", 0, 0, 0},
+  {"@modula-2",
+      "cc1gm2 " M2CPP
+      "      %(cc1_options) %{B*} %{c*} %{f*} %{+e*} %{I*} "
+      "      %{MD} %{MMD} %{M} %{MM} %{MA} %{MT*} %{MF*} %V"
+      "      %{save-temps*}"
+      "      %i %{!fsyntax-only:%(invoke_as)}",
+      0, 0, 0},
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/config-lang.in
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/config-lang.in	2022-10-07 20:21:18.634096743 +0100
@@ -0,0 +1,83 @@ 
+# Top level configure fragment for GNU Modula-2.
+# Copyright (C) 2000-2022 Free Software Foundation, Inc.
+
+# This file is part of GCC.
+
+# GCC 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.
+
+# GCC 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language	- name of language as it would appear in $(LANGUAGES)
+# compilers	- value to add to $(COMPILERS)
+# stagestuff	- files to add to $(STAGESTUFF)
+
+language="m2"
+
+compilers="cc1gm2\$(exeext)"
+
+stagestuff="gm2\$(exeext) cc1gm2\$(exeext) cc1gm2-cross\$(exeext)"
+
+target_libs="target-libstdc++-v3 target-libgm2"
+
+# The Modula-2 frontend needs C++ compiler during stage 1.
+lang_requires_boot_languages=c++
+
+# Do not build by default.
+build_by_default="no"
+
+gtfiles="\$(srcdir)/m2/gm2-lang.cc \
+         \$(srcdir)/m2/gm2-lang.h \
+         \$(srcdir)/m2/gm2-gcc/rtegraph.cc \
+         \$(srcdir)/m2/gm2-gcc/m2block.cc \
+         \$(srcdir)/m2/gm2-gcc/m2builtins.cc \
+         \$(srcdir)/m2/gm2-gcc/m2decl.cc \
+         \$(srcdir)/m2/gm2-gcc/m2except.cc \
+         \$(srcdir)/m2/gm2-gcc/m2expr.cc \
+         \$(srcdir)/m2/gm2-gcc/m2statement.cc \
+         \$(srcdir)/m2/gm2-gcc/m2type.cc"
+
+outputs="m2/config-make \
+         m2/Make-maintainer \
+        "
+
+mkdir -p m2/gm2-compiler-boot
+mkdir -p m2/gm2-libs-boot
+mkdir -p m2/gm2-ici-boot
+mkdir -p m2/gm2-libiberty
+mkdir -p m2/gm2-gcc
+mkdir -p m2/gm2-compiler
+mkdir -p m2/gm2-libs
+mkdir -p m2/gm2-libs-iso
+mkdir -p m2/gm2-compiler-paranoid
+mkdir -p m2/gm2-libs-paranoid
+mkdir -p m2/gm2-compiler-verify
+mkdir -p m2/boot-bin
+mkdir -p m2/gm2-libs-pim
+mkdir -p m2/gm2-libs-coroutines
+mkdir -p m2/gm2-libs-min
+mkdir -p m2/pge-boot
+mkdir -p plugin
+mkdir -p stage1/m2 stage2/m2 stage3/m2 stage4/m2
+
+# directories used by Make-maintainer
+
+mkdir -p m2/gm2-auto
+mkdir -p m2/gm2-pg-boot
+mkdir -p m2/gm2-pge-boot
+mkdir -p m2/gm2-ppg-boot
+mkdir -p m2/mc-boot
+mkdir -p m2/mc-boot-ch
+mkdir -p m2/mc-boot-gen
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/config-make.in
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/config-make.in	2022-10-07 20:21:18.634096743 +0100
@@ -0,0 +1,2 @@ 
+# Target libraries are put under this directory:
+TARGET_SUBDIR = @target_subdir@
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/configure.ac
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/configure.ac	2022-10-07 20:21:18.634096743 +0100
@@ -0,0 +1,43 @@ 
+# configure.ac provides gm2spec.c with access to config values.
+
+# Copyright (C) 2001-2022 Free Software Foundation, Inc.
+# Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
+
+# GCC 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.
+
+# GCC 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+AC_INIT(m2, [ ])
+
+# Determine the host, build, and target systems
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+
+AC_CHECK_PROGS(regex_flex, flex)
+if test x$regex_flex = "x" ; then
+    AC_MSG_ERROR([flex is required to build GNU Modula-2 (hint install flex).])
+fi
+
+AC_CHECK_PROGS(regex_realpath, realpath)
+if test x$regex_realpath = "x" ; then
+    AC_MSG_ERROR([realpath is required to build GNU Modula-2 (hint install coreutils).])
+fi
+
+AC_CHECK_FUNCS([stpcpy])
+
+AC_CHECK_HEADERS(sys/types.h)
+AC_HEADER_DIRENT
+AC_CHECK_LIB([c],[opendir],[AC_DEFINE([HAVE_OPENDIR],[1],[found opendir])])
+AC_CONFIG_HEADERS(gm2config.h, [echo timestamp > stamp-h])
+AC_OUTPUT
diff -ruw /dev/null gcc-git-devel-modula2/gcc/m2/gm2config.h.in
--- /dev/null	2022-08-24 16:22:16.888000070 +0100
+++ gcc-git-devel-modula2/gcc/m2/gm2config.h.in	2022-10-07 20:21:18.662097087 +0100
@@ -0,0 +1,56 @@ 
+/* gm2config.h.in template file for values required by gm2spec.c.
+
+Copyright (C) 2006-2022 Free Software Foundation, Inc.
+Contributed by Gaius Mulley <gaius.mulley@southwales.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/>.  */
+
+#ifndef PACKAGE_BUGREPORT
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+#endif
+
+#ifndef PACKAGE_NAME
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+#endif
+
+#ifndef PACKAGE_STRING
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+#endif
+
+/* Define to 1 if you have the `stpcmp' function. */
+#undef HAVE_STPCMP
+
+/* Define to 1 if you have the dirent.h header. */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the sys/ndir.h header. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the sys/dir.h header. */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the ndir.h header. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the sys/types.h header. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the opendir function.  */
+#undef HAVE_OPENDIR