Modula-2: merge proposal/review: 1/9 01.patch-set-01

Message ID E1nrJzu-00FH4F-Uc@lancelot
State New
Headers
Series Modula-2: merge proposal/review: 1/9 01.patch-set-01 |

Commit Message

Gaius Mulley May 18, 2022, 1:45 p.m. UTC
  hello,

this file is part-01 of the patch set for the gm2 review.


1.  all GCC files which have been patched.
==========================================

The 'Only in' diff output was:

Only in gcc-git-devel-modula2/gcc: m2
Only in gcc-git-devel-modula2/gcc/testsuite: gm2
Only in gcc-git-devel-modula2/gcc/testsuite/lib: gm2-dg.exp
Only in gcc-git-devel-modula2/gcc/testsuite/lib: gm2.exp
Only in gcc-git-devel-modula2/gcc/testsuite/lib: gm2-simple.exp
Only in gcc-git-devel-modula2/gcc/testsuite/lib: gm2-torture.exp
Only in gcc-git-devel-modula2/gcc/doc: gm2.texi
Only in gcc-git-devel-modula2: libgm2
Only in gcc-git-devel-modula2: gm2tools

and the recursive diffs:
  

Comments

Richard Biener May 20, 2022, 11:45 a.m. UTC | #1
On Wed, May 18, 2022 at 3:47 PM Gaius Mulley via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> hello,
>
> this file is part-01 of the patch set for the gm2 review.

I think you did a better job last time splitting the patches.  This
one contains the
driver changes for which I have a hard time remembering the reason they exist
and whether we already discussed it to death or not.

So - with the chance to re-open and old discussion - what's special about
modula-2 so it needs so many changes here?  Are all of them necessary
or are most of them merely "cleanups" that could be done as followup?

Thanks,
Richard.

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

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

Hi Richard,

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

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

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

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

  $ gm2 hello.mod

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

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

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

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

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

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

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

> Thanks,
> Richard.

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

regards,
Gaius


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

Copyright (C) 2007-2022 Free Software Foundation, Inc.
Contributed by Gaius Mulley <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/gm2version.h"
#include "m2/gm2config.h"

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

#ifndef MATH_LIBRARY
#define MATH_LIBRARY "m"
#endif

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

#ifndef DIR_SEPARATOR
#define DIR_SEPARATOR '/'
#endif

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

#ifndef GM2_PREFIX_ENV
#define GM2_PREFIX_ENV "GM2_PREFIX"
#endif

#ifndef GM2_LIBEXEC_ENV
#define GM2_LIBEXEC_ENV "GM2_LIBEXEC"
#endif

#ifndef GM2IPATH_ENV
#define GM2IPATH_ENV "GM2IPATH"
#endif

#ifndef GM2OPATH_ENV
#define GM2OPATH_ENV "GM2OPATH"
#endif

int lang_specific_extra_outfiles = 0;

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

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

#define DEFAULT_DIALECT "pim"

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  fe_generate_option (OPT_fobject_path_, arg, true);
}

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

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

  fe_generate_option (opt_index, lib, joined);
}

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

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

  (*in_decoded_options_count)++;

  gcc_assert (position <= (*in_decoded_options_count));

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

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

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

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

  insert_option (in_decoded_options_count, in_decoded_options, position);

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

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

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

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

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

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

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

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

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

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

/* safe_strdup, safely duplicates a string.  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  return xstrdup (gm2libs);
}

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

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

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

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

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

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

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

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

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

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

  return xstrdup (gm2objs);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* gen_gm2_prefix, return the prefix string.  */

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

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

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

/* gen_gm2_libexec, return a libexec string.  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

          add_default_fobjects (prev, libpath, libraries);
        }
    }

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

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

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

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

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

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

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

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

/* lang_specific_pre_link - does nothing.  */

int
lang_specific_pre_link (void)
{
  return 0;
}

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

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

  *result = (char)0;

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

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

extern void fe_mark_compiled (const char *);

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

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

  return NULL;
}

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

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

  *result = (char)0;

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

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

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

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

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

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

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

/* add_exec_name generate binary name.  */

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

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

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

/* exit_callback invoke exit.  */

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

/* lang_register_spec_functions register the Modula-2 associated spec
   functions.  */

void
lang_register_spec_functions (void)
{
  fe_add_spec_function ("objects", get_objects);
  fe_add_spec_function ("nolink", no_link);
  fe_add_spec_function ("noobjects", remove_objects);
  fe_add_spec_function ("linkargs", get_link_args);
  fe_add_spec_function ("exec_prefix", add_exec_dir);
  fe_add_spec_function ("exec_name", add_exec_name);
  fe_add_spec_function ("exit", exit_callback);
}




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

Gaius wrote:

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

>  $ gm2 hello.mod

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

in more detail the gm2 driver does the following:

  $ gm2 -v hello.mod

full output below, but to summarise and annotate:

cc1gm2 generates an assembler file from hello.mod
 as --64 /tmp/cc8BoL3d.s -o hello.o
 
 # gm2l generates a list of all dependent modules from parsing all imports
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2l -v \
 -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -o \
 /tmp/ccSMojUb.l hello.mod

 # gm2lorder reorders the critical runtime modules
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lorder \
    /tmp/ccSMojUb.l -o /tmp/ccHDRdde.lst

 # gm2lgen generates a C++ scaffold from the reordered module list
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lgen -fcpp \
    /tmp/ccHDRdde.lst -o a-hello_m2.cpp

 # cc1plus compiles the scaffold
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/cc1plus -v \
 -mtune=generic -march=x86-64 \
 -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
 -quiet a-hello_m2.cpp -o a-hello_m2.s
 as --64 a-hello_m2.s -o a-hello_m2.o

 # gm2lcc creates an archive from the list of modules and the scaffold
/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lcc \
  -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
  -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib \
-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
  --exec --startup a-hello_m2.o --ar -o /tmp/ccNJ60fa.a --mainobject \
  a-hello_m2.o /tmp/ccHDRdde.lst

/usr/bin/ar rc /tmp/ccNJ60fa.a  hello.o a-hello_m2.o
/usr/bin/ranlib /tmp/ccNJ60fa.a

# finally collect2 performs the link from the archive and any default
  libraries

hope this helps

regards,
Gaius






$ ~/opt/bin/gm2 -v hello.mod
Using built-in specs.
COLLECT_GCC=/home/gaius/opt/bin/gm2
COLLECT_LTO_WRAPPER=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /home/gaius/GM2/graft-combine/gcc-git-devel-modula2/configure --prefix=/home/gaius/opt --libexecdir=/home/gaius/opt/lib --enable-threads=posix --enable-clocale=gnu --enable-languages=m2 --enable-multilib --enable-checking --enable-long-longx --enable-bootstrap --with-build-config=bootstrap-Og
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 13.0.0 20220519 (experimental) (GCC)
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/cc1gm2 -iplugindir=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/plugin -quiet -dumpdir a- -dumpbase hello.mod -dumpbase-ext .mod -mtune=generic -march=x86-64 -version -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -fplugin=m2rte -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -fplugin=m2rte -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -o /tmp/cc8BoL3d.s hello.mod
GNU Modula-2  1.9.5  (20220520)
  grafted onto GCC 13.0.0
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv2: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
GNU Modula-2 (GCC) version 13.0.0 20220519 (experimental) (x86_64-pc-linux-gnu)
	compiled by GNU C version 13.0.0 20220519 (experimental), GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP

GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096
Versions of loaded plugins:
 m2rte: Unknown version.
GNU Modula-2 (GCC) version 13.0.0 20220519 (experimental) (x86_64-pc-linux-gnu)
	compiled by GNU C version 13.0.0 20220519 (experimental), GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP

GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096
Versions of loaded plugins:
 m2rte: Unknown version.
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 as --64 /tmp/cc8BoL3d.s -o hello.o
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2l -v -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -o /tmp/ccSMojUb.l hello.mod
gm2l >>> open source file: hello.mod
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lorder /tmp/ccSMojUb.l -o /tmp/ccHDRdde.lst
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lgen -fcpp /tmp/ccHDRdde.lst -o a-hello_m2.cpp
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/cc1plus -v -mtune=generic -march=x86-64 -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -quiet a-hello_m2.cpp -o a-hello_m2.s
ignoring nonexistent directory "/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/x86_64-pc-linux-gnu
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/backward
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/include
 /usr/local/include
 /home/gaius/opt/include
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/include-fixed
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 as --64 a-hello_m2.s -o a-hello_m2.o
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 rm -f /tmp/ccNJ60fa.a
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lcc -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -v --exec --startup a-hello_m2.o --ar -o /tmp/ccNJ60fa.a --mainobject a-hello_m2.o /tmp/ccHDRdde.lst
/usr/bin/ar rc /tmp/ccNJ60fa.a  hello.o a-hello_m2.o
/usr/bin/ranlib /tmp/ccNJ60fa.a
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
COMPILER_PATH=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/
LIBRARY_PATH=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib64/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.'
 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/collect2 -plugin /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/liblto_plugin.so -plugin-opt=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccyNQjVa.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/crt1.o /lib/x86_64-linux-gnu/crti.o /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/crtbegin.o -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0 -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../.. /tmp/ccNJ60fa.a -lm2pim -lpthread -lstdc++ -lgcc_eh -lgcc_s -lgcc -lc -lgcc_s -lgcc /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/crtend.o /lib/x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.'
  
Richard Biener May 24, 2022, 10:26 a.m. UTC | #4
On Sat, May 21, 2022 at 3:11 AM Gaius Mulley <gaiusmod2@gmail.com> wrote:
>
>
> Hi,
>
> Gaius wrote:
>
> > the changes do raise questions.  The reason for the changes here are to
> > allow easy linking for modula-2 users.
>
> >  $ gm2 hello.mod
>
> > for example will compile and link with all dependent modules (dependants
> > are generated by analysing module source imports).  The gm2 driver will
> > add objects and libraries to the link.
>
> in more detail the gm2 driver does the following:
>
>   $ gm2 -v hello.mod
>
> full output below, but to summarise and annotate:
>
> cc1gm2 generates an assembler file from hello.mod
>  as --64 /tmp/cc8BoL3d.s -o hello.o
>
>  # gm2l generates a list of all dependent modules from parsing all imports
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2l -v \
>  -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -o \
>  /tmp/ccSMojUb.l hello.mod
>
>  # gm2lorder reorders the critical runtime modules
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lorder \
>     /tmp/ccSMojUb.l -o /tmp/ccHDRdde.lst
>
>  # gm2lgen generates a C++ scaffold from the reordered module list
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lgen -fcpp \
>     /tmp/ccHDRdde.lst -o a-hello_m2.cpp
>
>  # cc1plus compiles the scaffold
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/cc1plus -v \
>  -mtune=generic -march=x86-64 \
>  -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
>  -quiet a-hello_m2.cpp -o a-hello_m2.s
>  as --64 a-hello_m2.s -o a-hello_m2.o
>
>  # gm2lcc creates an archive from the list of modules and the scaffold
> /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lcc \
>   -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
>   -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib \
> -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
>   --exec --startup a-hello_m2.o --ar -o /tmp/ccNJ60fa.a --mainobject \
>   a-hello_m2.o /tmp/ccHDRdde.lst
>
> /usr/bin/ar rc /tmp/ccNJ60fa.a  hello.o a-hello_m2.o
> /usr/bin/ranlib /tmp/ccNJ60fa.a
>
> # finally collect2 performs the link from the archive and any default
>   libraries
>
> hope this helps

Yes, it does.  So historically when there was complex massaging required
like this it was offloaded to a "helper driver".  With -flto there's lto-wrapper
(but here invoked by the linker), with ada there's gnatmake and others
and with certain targets collect2 does extra processing producing global
CTORs (or for C++ with -frepo even invoked additional compilations).

I do think that this might all belong into the main driver code but then
maybe all the different language compilation models will just make that
very hard to maintain.

As for modula-2, does

$ gm2 -c hello.mod
$ gm2 hello.o

"work"?  And what intermediate files are build systems expecting to
prevail?  Like for C/C++ code and GNU make there's the preprocessor
driven dependence generation, but otherwise a single TU usually
produces a single object file.  OTOH for GFortran a single TU might produce
multiple .mod files for example.

Btw, does

$ gcc -c hello.mod

"work" (or with -x m2 if the extension isn't auto detected)?

Richard.

>
> regards,
> Gaius
>
>
>
>
>
>
> $ ~/opt/bin/gm2 -v hello.mod
> Using built-in specs.
> COLLECT_GCC=/home/gaius/opt/bin/gm2
> COLLECT_LTO_WRAPPER=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/lto-wrapper
> Target: x86_64-pc-linux-gnu
> Configured with: /home/gaius/GM2/graft-combine/gcc-git-devel-modula2/configure --prefix=/home/gaius/opt --libexecdir=/home/gaius/opt/lib --enable-threads=posix --enable-clocale=gnu --enable-languages=m2 --enable-multilib --enable-checking --enable-long-longx --enable-bootstrap --with-build-config=bootstrap-Og
> Thread model: posix
> Supported LTO compression algorithms: zlib
> gcc version 13.0.0 20220519 (experimental) (GCC)
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/cc1gm2 -iplugindir=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/plugin -quiet -dumpdir a- -dumpbase hello.mod -dumpbase-ext .mod -mtune=generic -march=x86-64 -version -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -fplugin=m2rte -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -fplugin=m2rte -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -o /tmp/cc8BoL3d.s hello.mod
> GNU Modula-2  1.9.5  (20220520)
>   grafted onto GCC 13.0.0
> Copyright (C) 2022 Free Software Foundation, Inc.
> License GPLv2: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
> This is free software: you are free to change and redistribute it.
> There is NO WARRANTY, to the extent permitted by law.
> GNU Modula-2 (GCC) version 13.0.0 20220519 (experimental) (x86_64-pc-linux-gnu)
>         compiled by GNU C version 13.0.0 20220519 (experimental), GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
>
> GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096
> Versions of loaded plugins:
>  m2rte: Unknown version.
> GNU Modula-2 (GCC) version 13.0.0 20220519 (experimental) (x86_64-pc-linux-gnu)
>         compiled by GNU C version 13.0.0 20220519 (experimental), GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
>
> GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096
> Versions of loaded plugins:
>  m2rte: Unknown version.
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  as --64 /tmp/cc8BoL3d.s -o hello.o
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2l -v -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -o /tmp/ccSMojUb.l hello.mod
> gm2l >>> open source file: hello.mod
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lorder /tmp/ccSMojUb.l -o /tmp/ccHDRdde.lst
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lgen -fcpp /tmp/ccHDRdde.lst -o a-hello_m2.cpp
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/cc1plus -v -mtune=generic -march=x86-64 -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -quiet a-hello_m2.cpp -o a-hello_m2.s
> ignoring nonexistent directory "/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../x86_64-pc-linux-gnu/include"
> #include "..." search starts here:
> #include <...> search starts here:
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/x86_64-pc-linux-gnu
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../include/c++/13.0.0/backward
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/include
>  /usr/local/include
>  /home/gaius/opt/include
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/include-fixed
>  /usr/include
> End of search list.
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  as --64 a-hello_m2.s -o a-hello_m2.o
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  rm -f /tmp/ccNJ60fa.a
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lcc -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -v --exec --startup a-hello_m2.o --ar -o /tmp/ccNJ60fa.a --mainobject a-hello_m2.o /tmp/ccHDRdde.lst
> /usr/bin/ar rc /tmp/ccNJ60fa.a  hello.o a-hello_m2.o
> /usr/bin/ranlib /tmp/ccNJ60fa.a
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a-'
> COMPILER_PATH=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/
> LIBRARY_PATH=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib64/:/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../:/lib/:/usr/lib/
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.'
>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/collect2 -plugin /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/liblto_plugin.so -plugin-opt=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccyNQjVa.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/crt1.o /lib/x86_64-linux-gnu/crti.o /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/crtbegin.o -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0 -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/../../.. /tmp/ccNJ60fa.a -lm2pim -lpthread -lstdc++ -lgcc_eh -lgcc_s -lgcc -lc -lgcc_s -lgcc /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/crtend.o /lib/x86_64-linux-gnu/crtn.o
> COLLECT_GCC_OPTIONS='-I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-ftarget-ar=/usr/bin/ar' '-ftarget-ranlib=/usr/bin/ranlib' '-fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-x' 'modula-2' '-fplugin=m2rte' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim' '-shared-libgcc' '-v' '-mtune=generic' '-march=x86-64' '-dumpdir' 'a.'
  
Gaius Mulley May 24, 2022, 3:45 p.m. UTC | #5
Richard Biener <richard.guenther@gmail.com> writes:

> On Sat, May 21, 2022 at 3:11 AM Gaius Mulley <gaiusmod2@gmail.com> wrote:
>>
>>
>> Hi,
>>
>> Gaius wrote:
>>
>> > the changes do raise questions.  The reason for the changes here are to
>> > allow easy linking for modula-2 users.
>>
>> >  $ gm2 hello.mod
>>
>> > for example will compile and link with all dependent modules (dependants
>> > are generated by analysing module source imports).  The gm2 driver will
>> > add objects and libraries to the link.
>>
>> in more detail the gm2 driver does the following:
>>
>>   $ gm2 -v hello.mod
>>
>> full output below, but to summarise and annotate:
>>
>> cc1gm2 generates an assembler file from hello.mod
>>  as --64 /tmp/cc8BoL3d.s -o hello.o
>>
>>  # gm2l generates a list of all dependent modules from parsing all imports
>>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2l -v \
>>  -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -o \
>>  /tmp/ccSMojUb.l hello.mod
>>
>>  # gm2lorder reorders the critical runtime modules
>>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lorder \
>>     /tmp/ccSMojUb.l -o /tmp/ccHDRdde.lst
>>
>>  # gm2lgen generates a C++ scaffold from the reordered module list
>>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lgen -fcpp \
>>     /tmp/ccHDRdde.lst -o a-hello_m2.cpp
>>
>>  # cc1plus compiles the scaffold
>>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/cc1plus -v \
>>  -mtune=generic -march=x86-64 \
>>  -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
>>  -quiet a-hello_m2.cpp -o a-hello_m2.s
>>  as --64 a-hello_m2.s -o a-hello_m2.o
>>
>>  # gm2lcc creates an archive from the list of modules and the scaffold
>> /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lcc \
>>   -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
>>   -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib \
>> -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
>>   --exec --startup a-hello_m2.o --ar -o /tmp/ccNJ60fa.a --mainobject \
>>   a-hello_m2.o /tmp/ccHDRdde.lst
>>
>> /usr/bin/ar rc /tmp/ccNJ60fa.a  hello.o a-hello_m2.o
>> /usr/bin/ranlib /tmp/ccNJ60fa.a
>>
>> # finally collect2 performs the link from the archive and any default
>>   libraries
>>
>> hope this helps
>
> Yes, it does.  So historically when there was complex massaging required
> like this it was offloaded to a "helper driver".  With -flto there's lto-wrapper
> (but here invoked by the linker), with ada there's gnatmake and others
> and with certain targets collect2 does extra processing producing global
> CTORs (or for C++ with -frepo even invoked additional compilations).

Hi Richard,

interesting thank you for the information about different languages (yes
I recall years ago the lang-specs used to be much more complex).  global
CTORs would work might be helpful, although I wonder if they are overly
complex for modula-2?  (As we still need to control order).  I guess
there would be pros/cons for multi-lingual projects.

I wonder whether it could be resolved in the modula-2 front end by
placing the scaffold generation inside cc1gm2 (which is generated when a
program module is seen - and/or perhaps forced by a switch if a user
really wanted to link an implementation module as the application,
say by -fm2-scaffold).  So by default the proposal would be that

  $ gm2 -c programmodule.mod

generates programmodule.o (which contains main and a scaffold to
construct/deconstruct every module as well as the user level code).
There could be a switch to emit the scaffold in C or C++ should users
want to interfere.

Overall much of the modula-2 code inside /gm2tools would go into cc1gm2
and many 100s of C lines of code would disappear from the 'gm2' driver
and the code base would clean up :-).  In the process it would become
more like the other GCC language drivers.

Some of the gm2 link options could be passed into cc1gm2 (those forcing
the order of module initialization and user specified scaffold list
override).  The make dependencies could also be emitted if required
as cc1gm2 now has knowledge of all imports.

> I do think that this might all belong into the main driver code but then
> maybe all the different language compilation models will just make that
> very hard to maintain.

indeed I can see it could become problematic making the above quite
attractive, maybe?

> As for modula-2, does
>
> $ gm2 -c hello.mod

$ ~/opt/bin/gm2 -c hello.mod

> $ gm2 hello.o

$ ~/opt/bin/gm2 hello.o
/usr/bin/ld: /lib/x86_64-linux-gnu/crt1.o: in function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status

alas no as there is no scaffold inside hello.o

> "work"?  And what intermediate files are build systems expecting to
> prevail?  Like for C/C++ code and GNU make there's the preprocessor
> driven dependence generation, but otherwise a single TU usually
> produces a single object file.  OTOH for GFortran a single TU might
> produce multiple .mod files for example.

currently in gm2 there is the single .o file and possibly a .i swig file
if -fswig is present.  (There is a gm2m tool which is not currently
deployed - this could be pruned and integrated into cc1gm2 - to generate
make dependencies).

> Btw, does
>
> $ gcc -c hello.mod

yes, well to a degree:

  $ ~/opt/bin/gcc -c hello.mod
  <built-in>: error: the file containing the definition module ‘SYSTEM’ cannot be found

but if we supply the include path then all is ok (maybe the default path
should be embedded into cc1gm2).

  $ ~/opt/bin/gcc -c -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim hello.mod
  $ 

> "work" (or with -x m2 if the extension isn't auto detected)?

sure yes (all handled via the lang-specs.h)

regards,
Gaius
  
Richard Biener May 25, 2022, 9:10 a.m. UTC | #6
On Tue, May 24, 2022 at 5:45 PM Gaius Mulley <gaiusmod2@gmail.com> wrote:
>
> Richard Biener <richard.guenther@gmail.com> writes:
>
> > On Sat, May 21, 2022 at 3:11 AM Gaius Mulley <gaiusmod2@gmail.com> wrote:
> >>
> >>
> >> Hi,
> >>
> >> Gaius wrote:
> >>
> >> > the changes do raise questions.  The reason for the changes here are to
> >> > allow easy linking for modula-2 users.
> >>
> >> >  $ gm2 hello.mod
> >>
> >> > for example will compile and link with all dependent modules (dependants
> >> > are generated by analysing module source imports).  The gm2 driver will
> >> > add objects and libraries to the link.
> >>
> >> in more detail the gm2 driver does the following:
> >>
> >>   $ gm2 -v hello.mod
> >>
> >> full output below, but to summarise and annotate:
> >>
> >> cc1gm2 generates an assembler file from hello.mod
> >>  as --64 /tmp/cc8BoL3d.s -o hello.o
> >>
> >>  # gm2l generates a list of all dependent modules from parsing all imports
> >>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2l -v \
> >>  -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim -o \
> >>  /tmp/ccSMojUb.l hello.mod
> >>
> >>  # gm2lorder reorders the critical runtime modules
> >>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lorder \
> >>     /tmp/ccSMojUb.l -o /tmp/ccHDRdde.lst
> >>
> >>  # gm2lgen generates a C++ scaffold from the reordered module list
> >>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lgen -fcpp \
> >>     /tmp/ccHDRdde.lst -o a-hello_m2.cpp
> >>
> >>  # cc1plus compiles the scaffold
> >>  /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/cc1plus -v \
> >>  -mtune=generic -march=x86-64 \
> >>  -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
> >>  -quiet a-hello_m2.cpp -o a-hello_m2.s
> >>  as --64 a-hello_m2.s -o a-hello_m2.o
> >>
> >>  # gm2lcc creates an archive from the list of modules and the scaffold
> >> /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/gm2lcc \
> >>   -L/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
> >>   -ftarget-ar=/usr/bin/ar -ftarget-ranlib=/usr/bin/ranlib \
> >> -fobject-path=/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim \
> >>   --exec --startup a-hello_m2.o --ar -o /tmp/ccNJ60fa.a --mainobject \
> >>   a-hello_m2.o /tmp/ccHDRdde.lst
> >>
> >> /usr/bin/ar rc /tmp/ccNJ60fa.a  hello.o a-hello_m2.o
> >> /usr/bin/ranlib /tmp/ccNJ60fa.a

So is there a reason to have the 'scaffold' separate from the object
of hello.mod?
Is there more than a 1:1 relation between a .mod and the 'scaffold'?  Why
are multiple tools involved here - can the m2 frontend not parse imports,
reorder runtime modules and generate the 'scaffold' as GENERIC IL
as part of the translation unit of the .mod file?  Indirection through emitting
C++ source code makes the process a bit awkward IMHO.

Unfortunately I have no m2 installation around to look at how complex
the 'scaffold' is.

> >> # finally collect2 performs the link from the archive and any default
> >>   libraries
> >>
> >> hope this helps
> >
> > Yes, it does.  So historically when there was complex massaging required
> > like this it was offloaded to a "helper driver".  With -flto there's lto-wrapper
> > (but here invoked by the linker), with ada there's gnatmake and others
> > and with certain targets collect2 does extra processing producing global
> > CTORs (or for C++ with -frepo even invoked additional compilations).
>
> Hi Richard,
>
> interesting thank you for the information about different languages (yes
> I recall years ago the lang-specs used to be much more complex).  global
> CTORs would work might be helpful, although I wonder if they are overly
> complex for modula-2?  (As we still need to control order).  I guess
> there would be pros/cons for multi-lingual projects.
>
> I wonder whether it could be resolved in the modula-2 front end by
> placing the scaffold generation inside cc1gm2 (which is generated when a
> program module is seen - and/or perhaps forced by a switch if a user
> really wanted to link an implementation module as the application,
> say by -fm2-scaffold).  So by default the proposal would be that
>
>   $ gm2 -c programmodule.mod
>
> generates programmodule.o (which contains main and a scaffold to
> construct/deconstruct every module as well as the user level code).
> There could be a switch to emit the scaffold in C or C++ should users
> want to interfere.
>
> Overall much of the modula-2 code inside /gm2tools would go into cc1gm2
> and many 100s of C lines of code would disappear from the 'gm2' driver
> and the code base would clean up :-).  In the process it would become
> more like the other GCC language drivers.
>
> Some of the gm2 link options could be passed into cc1gm2 (those forcing
> the order of module initialization and user specified scaffold list
> override).  The make dependencies could also be emitted if required
> as cc1gm2 now has knowledge of all imports.
>
> > I do think that this might all belong into the main driver code but then
> > maybe all the different language compilation models will just make that
> > very hard to maintain.
>
> indeed I can see it could become problematic making the above quite
> attractive, maybe?
>
> > As for modula-2, does
> >
> > $ gm2 -c hello.mod
>
> $ ~/opt/bin/gm2 -c hello.mod
>
> > $ gm2 hello.o
>
> $ ~/opt/bin/gm2 hello.o
> /usr/bin/ld: /lib/x86_64-linux-gnu/crt1.o: in function `_start':
> (.text+0x20): undefined reference to `main'
> collect2: error: ld returned 1 exit status
>
> alas no as there is no scaffold inside hello.o
>
> > "work"?  And what intermediate files are build systems expecting to
> > prevail?  Like for C/C++ code and GNU make there's the preprocessor
> > driven dependence generation, but otherwise a single TU usually
> > produces a single object file.  OTOH for GFortran a single TU might
> > produce multiple .mod files for example.
>
> currently in gm2 there is the single .o file and possibly a .i swig file
> if -fswig is present.  (There is a gm2m tool which is not currently
> deployed - this could be pruned and integrated into cc1gm2 - to generate
> make dependencies).
>
> > Btw, does
> >
> > $ gcc -c hello.mod
>
> yes, well to a degree:
>
>   $ ~/opt/bin/gcc -c hello.mod
>   <built-in>: error: the file containing the definition module ‘SYSTEM’ cannot be found
>
> but if we supply the include path then all is ok (maybe the default path
> should be embedded into cc1gm2).
>
>   $ ~/opt/bin/gcc -c -I/home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim hello.mod
>   $
>
> > "work" (or with -x m2 if the extension isn't auto detected)?
>
> sure yes (all handled via the lang-specs.h)
>
> regards,
> Gaius
  
Gaius Mulley May 25, 2022, 7:50 p.m. UTC | #7
Richard Biener <richard.guenther@gmail.com> writes:

> So is there a reason to have the 'scaffold' separate from the object
> of hello.mod?

Perhaps the major advantage is flexibility?  But no we can by default
produce the scaffold within the object of hello.mod (and give users the
ability to disable scaffold generation should they wish to implement
their own).

> Is there more than a 1:1 relation between a .mod and the 'scaffold'?

yes there is a 1:1 relation between a .mod and the scaffold.  Although
the caveat is that the compiler would need to parse every .def and .mod
imports from the application universe.  Not a major change as gm2 has
the ability to do whole program (application) compiling, so a minor set
of changes to ensure that upon compiling the program module that it also
parses every .def/.mod.

> Why are multiple tools involved here - can the m2 frontend not parse
> imports, reorder runtime modules and generate the 'scaffold' as
> GENERIC IL as part of the translation unit of the .mod file?
> Indirection through emitting C++ source code makes the process a bit
> awkward IMHO.

indeed the m2 front end can parse imports, reorder and generate the
scaffold.

> Unfortunately I have no m2 installation around to look at how complex
> the 'scaffold' is.

the scaffold is really simple for example here it is for hello.mod:

  $ gm2 -c -g -fmakelist hello.mod
  $ cat hello.lst
Storage
SYSTEM
M2RTS
RTExceptions
# libc   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/libc.def FOR 'C'
# SYSTEM   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SYSTEM.mod
# StrIO   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StrIO.mod
# StrLib   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StrLib.mod
# ASCII   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/ASCII.mod
# NumberIO   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/NumberIO.mod
# Indexing   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Indexing.mod
# errno    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/errno.def
# termios    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/termios.def
# FIO    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/FIO.mod
# IO    8 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/IO.mod
# StdIO    7 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StdIO.mod
# Debug    6 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Debug.mod
# SysStorage    5 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SysStorage.mod
# SysExceptions    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SysExceptions.def
# M2EXCEPTION    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/M2EXCEPTION.mod
# Storage    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Storage.mod
# RTExceptions    3 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/RTExceptions.mod
# M2RTS    2 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/M2RTS.mod
# hello    1 hello.mod
#
# Initialization order
#
StrIO
StrLib
ASCII
NumberIO
Indexing
errno
termios
FIO
IO
StdIO
Debug
SysStorage
SysExceptions
M2EXCEPTION
hello

   and now to generate the scaffold for a static application:

   $ ~/opt/bin/gm2 -fmakeinit -c -g hello.mod
   $ cat hello_m2.cpp 
extern "C" void exit(int);

extern "C" void RTExceptions_DefaultErrorCatch(void);
extern "C" void _M2_Storage_init (int argc, char *argv[]);
extern "C" void _M2_Storage_finish (void);
extern "C" void _M2_SYSTEM_init (int argc, char *argv[]);
extern "C" void _M2_SYSTEM_finish (void);
extern "C" void _M2_M2RTS_init (int argc, char *argv[]);
extern "C" void _M2_M2RTS_finish (void);
extern "C" void _M2_RTExceptions_init (int argc, char *argv[]);
extern "C" void _M2_RTExceptions_finish (void);
extern "C" void _M2_StrIO_init (int argc, char *argv[]);
extern "C" void _M2_StrIO_finish (void);
extern "C" void _M2_StrLib_init (int argc, char *argv[]);
extern "C" void _M2_StrLib_finish (void);
extern "C" void _M2_ASCII_init (int argc, char *argv[]);
extern "C" void _M2_ASCII_finish (void);
extern "C" void _M2_NumberIO_init (int argc, char *argv[]);
extern "C" void _M2_NumberIO_finish (void);
extern "C" void _M2_Indexing_init (int argc, char *argv[]);
extern "C" void _M2_Indexing_finish (void);
extern "C" void _M2_errno_init (int argc, char *argv[]);
extern "C" void _M2_errno_finish (void);
extern "C" void _M2_termios_init (int argc, char *argv[]);
extern "C" void _M2_termios_finish (void);
extern "C" void _M2_FIO_init (int argc, char *argv[]);
extern "C" void _M2_FIO_finish (void);
extern "C" void _M2_IO_init (int argc, char *argv[]);
extern "C" void _M2_IO_finish (void);
extern "C" void _M2_StdIO_init (int argc, char *argv[]);
extern "C" void _M2_StdIO_finish (void);
extern "C" void _M2_Debug_init (int argc, char *argv[]);
extern "C" void _M2_Debug_finish (void);
extern "C" void _M2_SysStorage_init (int argc, char *argv[]);
extern "C" void _M2_SysStorage_finish (void);
extern "C" void _M2_SysExceptions_init (int argc, char *argv[]);
extern "C" void _M2_SysExceptions_finish (void);
extern "C" void _M2_M2EXCEPTION_init (int argc, char *argv[]);
extern "C" void _M2_M2EXCEPTION_finish (void);
extern "C" void _M2_hello_init (int argc, char *argv[]);
extern "C" void _M2_hello_finish (void);

extern "C" void M2RTS_ExecuteTerminationProcedures(void);

extern "C" void M2RTS_ExecuteInitialProcedures(void);

static void init (int argc, char *argv[])
{
   try {
       _M2_Storage_init (argc, argv);
       _M2_SYSTEM_init (argc, argv);
       _M2_M2RTS_init (argc, argv);
       _M2_RTExceptions_init (argc, argv);
       _M2_StrIO_init (argc, argv);
       _M2_StrLib_init (argc, argv);
       _M2_ASCII_init (argc, argv);
       _M2_NumberIO_init (argc, argv);
       _M2_Indexing_init (argc, argv);
       _M2_errno_init (argc, argv);
       _M2_termios_init (argc, argv);
       _M2_FIO_init (argc, argv);
       _M2_IO_init (argc, argv);
       _M2_StdIO_init (argc, argv);
       _M2_Debug_init (argc, argv);
       _M2_SysStorage_init (argc, argv);
       _M2_SysExceptions_init (argc, argv);
       _M2_M2EXCEPTION_init (argc, argv);
      M2RTS_ExecuteInitialProcedures ();
       _M2_hello_init (argc, argv);
    }
    catch (...) {
       RTExceptions_DefaultErrorCatch();
    }
}

static void finish (void)
{
   try {
      M2RTS_ExecuteTerminationProcedures ();
      _M2_hello_finish ();
      _M2_M2EXCEPTION_finish ();
      _M2_SysExceptions_finish ();
      _M2_SysStorage_finish ();
      _M2_Debug_finish ();
      _M2_StdIO_finish ();
      _M2_IO_finish ();
      _M2_FIO_finish ();
      _M2_termios_finish ();
      _M2_errno_finish ();
      _M2_Indexing_finish ();
      _M2_NumberIO_finish ();
      _M2_ASCII_finish ();
      _M2_StrLib_finish ();
      _M2_StrIO_finish ();
      _M2_RTExceptions_finish ();
      _M2_M2RTS_finish ();
      _M2_SYSTEM_finish ();
      _M2_Storage_finish ();
      exit (0);
    }
    catch (...) {
       RTExceptions_DefaultErrorCatch();
    }
}

int main (int argc, char *argv[])
{
   init (argc, argv);
   finish ();
   return (0);
}


or similarly for a shared library:

   $ ~/opt/bin/gm2 -fshared -fmakeinit -c -g hello.mod
   $ cat hello_m2.cpp 
extern "C" void exit(int);

extern "C" void RTExceptions_DefaultErrorCatch(void);
extern "C" void _M2_Storage_init (int argc, char *argv[]);
extern "C" void _M2_Storage_finish (void);
extern "C" void _M2_SYSTEM_init (int argc, char *argv[]);
extern "C" void _M2_SYSTEM_finish (void);
extern "C" void _M2_M2RTS_init (int argc, char *argv[]);
extern "C" void _M2_M2RTS_finish (void);
extern "C" void _M2_RTExceptions_init (int argc, char *argv[]);
extern "C" void _M2_RTExceptions_finish (void);
extern "C" void _M2_StrIO_init (int argc, char *argv[]);
extern "C" void _M2_StrIO_finish (void);
extern "C" void _M2_StrLib_init (int argc, char *argv[]);
extern "C" void _M2_StrLib_finish (void);
extern "C" void _M2_ASCII_init (int argc, char *argv[]);
extern "C" void _M2_ASCII_finish (void);
extern "C" void _M2_NumberIO_init (int argc, char *argv[]);
extern "C" void _M2_NumberIO_finish (void);
extern "C" void _M2_Indexing_init (int argc, char *argv[]);
extern "C" void _M2_Indexing_finish (void);
extern "C" void _M2_errno_init (int argc, char *argv[]);
extern "C" void _M2_errno_finish (void);
extern "C" void _M2_termios_init (int argc, char *argv[]);
extern "C" void _M2_termios_finish (void);
extern "C" void _M2_FIO_init (int argc, char *argv[]);
extern "C" void _M2_FIO_finish (void);
extern "C" void _M2_IO_init (int argc, char *argv[]);
extern "C" void _M2_IO_finish (void);
extern "C" void _M2_StdIO_init (int argc, char *argv[]);
extern "C" void _M2_StdIO_finish (void);
extern "C" void _M2_Debug_init (int argc, char *argv[]);
extern "C" void _M2_Debug_finish (void);
extern "C" void _M2_SysStorage_init (int argc, char *argv[]);
extern "C" void _M2_SysStorage_finish (void);
extern "C" void _M2_SysExceptions_init (int argc, char *argv[]);
extern "C" void _M2_SysExceptions_finish (void);
extern "C" void _M2_M2EXCEPTION_init (int argc, char *argv[]);
extern "C" void _M2_M2EXCEPTION_finish (void);
extern "C" void _M2_hello_init (int argc, char *argv[]);
extern "C" void _M2_hello_finish (void);

extern "C" void M2RTS_ExecuteTerminationProcedures(void);

extern "C" void M2RTS_ExecuteInitialProcedures(void);

static void init (int argc, char *argv[])
{
   try {
       _M2_Storage_init (argc, argv);
       _M2_SYSTEM_init (argc, argv);
       _M2_M2RTS_init (argc, argv);
       _M2_RTExceptions_init (argc, argv);
       _M2_StrIO_init (argc, argv);
       _M2_StrLib_init (argc, argv);
       _M2_ASCII_init (argc, argv);
       _M2_NumberIO_init (argc, argv);
       _M2_Indexing_init (argc, argv);
       _M2_errno_init (argc, argv);
       _M2_termios_init (argc, argv);
       _M2_FIO_init (argc, argv);
       _M2_IO_init (argc, argv);
       _M2_StdIO_init (argc, argv);
       _M2_Debug_init (argc, argv);
       _M2_SysStorage_init (argc, argv);
       _M2_SysExceptions_init (argc, argv);
       _M2_M2EXCEPTION_init (argc, argv);
      M2RTS_ExecuteInitialProcedures ();
       _M2_hello_init (argc, argv);
    }
    catch (...) {
       RTExceptions_DefaultErrorCatch();
    }
}

static void finish (void)
{
   try {
      M2RTS_ExecuteTerminationProcedures ();
      _M2_hello_finish ();
      _M2_M2EXCEPTION_finish ();
      _M2_SysExceptions_finish ();
      _M2_SysStorage_finish ();
      _M2_Debug_finish ();
      _M2_StdIO_finish ();
      _M2_IO_finish ();
      _M2_FIO_finish ();
      _M2_termios_finish ();
      _M2_errno_finish ();
      _M2_Indexing_finish ();
      _M2_NumberIO_finish ();
      _M2_ASCII_finish ();
      _M2_StrLib_finish ();
      _M2_StrIO_finish ();
      _M2_RTExceptions_finish ();
      _M2_M2RTS_finish ();
      _M2_SYSTEM_finish ();
      _M2_Storage_finish ();
      exit (0);
    }
    catch (...) {
       RTExceptions_DefaultErrorCatch();
    }
}

int main (int argc, char *argv[])
{
   init (argc, argv);
   finish ();
   return (0);
}

yes indeed all these programs could be placed into the front end,
producing an IR GENERIC scaffold by default

regards,
Gaius
  
Richard Biener May 27, 2022, 7:40 a.m. UTC | #8
On Wed, May 25, 2022 at 9:50 PM Gaius Mulley <gaiusmod2@gmail.com> wrote:
>
> Richard Biener <richard.guenther@gmail.com> writes:
>
> > So is there a reason to have the 'scaffold' separate from the object
> > of hello.mod?
>
> Perhaps the major advantage is flexibility?  But no we can by default
> produce the scaffold within the object of hello.mod (and give users the
> ability to disable scaffold generation should they wish to implement
> their own).
>
> > Is there more than a 1:1 relation between a .mod and the 'scaffold'?
>
> yes there is a 1:1 relation between a .mod and the scaffold.  Although
> the caveat is that the compiler would need to parse every .def and .mod
> imports from the application universe.  Not a major change as gm2 has
> the ability to do whole program (application) compiling, so a minor set
> of changes to ensure that upon compiling the program module that it also
> parses every .def/.mod.
>
> > Why are multiple tools involved here - can the m2 frontend not parse
> > imports, reorder runtime modules and generate the 'scaffold' as
> > GENERIC IL as part of the translation unit of the .mod file?
> > Indirection through emitting C++ source code makes the process a bit
> > awkward IMHO.
>
> indeed the m2 front end can parse imports, reorder and generate the
> scaffold.
>
> > Unfortunately I have no m2 installation around to look at how complex
> > the 'scaffold' is.
>
> the scaffold is really simple for example here it is for hello.mod:
>
>   $ gm2 -c -g -fmakelist hello.mod
>   $ cat hello.lst
> Storage
> SYSTEM
> M2RTS
> RTExceptions
> # libc   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/libc.def FOR 'C'
> # SYSTEM   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SYSTEM.mod
> # StrIO   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StrIO.mod
> # StrLib   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StrLib.mod
> # ASCII   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/ASCII.mod
> # NumberIO   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/NumberIO.mod
> # Indexing   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Indexing.mod
> # errno    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/errno.def
> # termios    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/termios.def
> # FIO    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/FIO.mod
> # IO    8 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/IO.mod
> # StdIO    7 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StdIO.mod
> # Debug    6 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Debug.mod
> # SysStorage    5 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SysStorage.mod
> # SysExceptions    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SysExceptions.def
> # M2EXCEPTION    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/M2EXCEPTION.mod
> # Storage    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Storage.mod
> # RTExceptions    3 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/RTExceptions.mod
> # M2RTS    2 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/M2RTS.mod
> # hello    1 hello.mod
> #
> # Initialization order
> #
> StrIO
> StrLib
> ASCII
> NumberIO
> Indexing
> errno
> termios
> FIO
> IO
> StdIO
> Debug
> SysStorage
> SysExceptions
> M2EXCEPTION
> hello
>
>    and now to generate the scaffold for a static application:
>
>    $ ~/opt/bin/gm2 -fmakeinit -c -g hello.mod
>    $ cat hello_m2.cpp
> extern "C" void exit(int);
>
> extern "C" void RTExceptions_DefaultErrorCatch(void);
> extern "C" void _M2_Storage_init (int argc, char *argv[]);
> extern "C" void _M2_Storage_finish (void);
> extern "C" void _M2_SYSTEM_init (int argc, char *argv[]);
> extern "C" void _M2_SYSTEM_finish (void);
> extern "C" void _M2_M2RTS_init (int argc, char *argv[]);
> extern "C" void _M2_M2RTS_finish (void);
> extern "C" void _M2_RTExceptions_init (int argc, char *argv[]);
> extern "C" void _M2_RTExceptions_finish (void);
> extern "C" void _M2_StrIO_init (int argc, char *argv[]);
> extern "C" void _M2_StrIO_finish (void);
> extern "C" void _M2_StrLib_init (int argc, char *argv[]);
> extern "C" void _M2_StrLib_finish (void);
> extern "C" void _M2_ASCII_init (int argc, char *argv[]);
> extern "C" void _M2_ASCII_finish (void);
> extern "C" void _M2_NumberIO_init (int argc, char *argv[]);
> extern "C" void _M2_NumberIO_finish (void);
> extern "C" void _M2_Indexing_init (int argc, char *argv[]);
> extern "C" void _M2_Indexing_finish (void);
> extern "C" void _M2_errno_init (int argc, char *argv[]);
> extern "C" void _M2_errno_finish (void);
> extern "C" void _M2_termios_init (int argc, char *argv[]);
> extern "C" void _M2_termios_finish (void);
> extern "C" void _M2_FIO_init (int argc, char *argv[]);
> extern "C" void _M2_FIO_finish (void);
> extern "C" void _M2_IO_init (int argc, char *argv[]);
> extern "C" void _M2_IO_finish (void);
> extern "C" void _M2_StdIO_init (int argc, char *argv[]);
> extern "C" void _M2_StdIO_finish (void);
> extern "C" void _M2_Debug_init (int argc, char *argv[]);
> extern "C" void _M2_Debug_finish (void);
> extern "C" void _M2_SysStorage_init (int argc, char *argv[]);
> extern "C" void _M2_SysStorage_finish (void);
> extern "C" void _M2_SysExceptions_init (int argc, char *argv[]);
> extern "C" void _M2_SysExceptions_finish (void);
> extern "C" void _M2_M2EXCEPTION_init (int argc, char *argv[]);
> extern "C" void _M2_M2EXCEPTION_finish (void);
> extern "C" void _M2_hello_init (int argc, char *argv[]);
> extern "C" void _M2_hello_finish (void);
>
> extern "C" void M2RTS_ExecuteTerminationProcedures(void);
>
> extern "C" void M2RTS_ExecuteInitialProcedures(void);
>
> static void init (int argc, char *argv[])
> {
>    try {
>        _M2_Storage_init (argc, argv);
>        _M2_SYSTEM_init (argc, argv);
>        _M2_M2RTS_init (argc, argv);
>        _M2_RTExceptions_init (argc, argv);
>        _M2_StrIO_init (argc, argv);
>        _M2_StrLib_init (argc, argv);
>        _M2_ASCII_init (argc, argv);
>        _M2_NumberIO_init (argc, argv);
>        _M2_Indexing_init (argc, argv);
>        _M2_errno_init (argc, argv);
>        _M2_termios_init (argc, argv);
>        _M2_FIO_init (argc, argv);
>        _M2_IO_init (argc, argv);
>        _M2_StdIO_init (argc, argv);
>        _M2_Debug_init (argc, argv);
>        _M2_SysStorage_init (argc, argv);
>        _M2_SysExceptions_init (argc, argv);
>        _M2_M2EXCEPTION_init (argc, argv);
>       M2RTS_ExecuteInitialProcedures ();
>        _M2_hello_init (argc, argv);
>     }
>     catch (...) {
>        RTExceptions_DefaultErrorCatch();
>     }
> }
>
> static void finish (void)
> {
>    try {
>       M2RTS_ExecuteTerminationProcedures ();
>       _M2_hello_finish ();
>       _M2_M2EXCEPTION_finish ();
>       _M2_SysExceptions_finish ();
>       _M2_SysStorage_finish ();
>       _M2_Debug_finish ();
>       _M2_StdIO_finish ();
>       _M2_IO_finish ();
>       _M2_FIO_finish ();
>       _M2_termios_finish ();
>       _M2_errno_finish ();
>       _M2_Indexing_finish ();
>       _M2_NumberIO_finish ();
>       _M2_ASCII_finish ();
>       _M2_StrLib_finish ();
>       _M2_StrIO_finish ();
>       _M2_RTExceptions_finish ();
>       _M2_M2RTS_finish ();
>       _M2_SYSTEM_finish ();
>       _M2_Storage_finish ();
>       exit (0);
>     }
>     catch (...) {
>        RTExceptions_DefaultErrorCatch();
>     }
> }
>
> int main (int argc, char *argv[])
> {
>    init (argc, argv);
>    finish ();
>    return (0);
> }
>
>
> or similarly for a shared library:
>
>    $ ~/opt/bin/gm2 -fshared -fmakeinit -c -g hello.mod
>    $ cat hello_m2.cpp
> extern "C" void exit(int);
>
> extern "C" void RTExceptions_DefaultErrorCatch(void);
> extern "C" void _M2_Storage_init (int argc, char *argv[]);
> extern "C" void _M2_Storage_finish (void);
> extern "C" void _M2_SYSTEM_init (int argc, char *argv[]);
> extern "C" void _M2_SYSTEM_finish (void);
> extern "C" void _M2_M2RTS_init (int argc, char *argv[]);
> extern "C" void _M2_M2RTS_finish (void);
> extern "C" void _M2_RTExceptions_init (int argc, char *argv[]);
> extern "C" void _M2_RTExceptions_finish (void);
> extern "C" void _M2_StrIO_init (int argc, char *argv[]);
> extern "C" void _M2_StrIO_finish (void);
> extern "C" void _M2_StrLib_init (int argc, char *argv[]);
> extern "C" void _M2_StrLib_finish (void);
> extern "C" void _M2_ASCII_init (int argc, char *argv[]);
> extern "C" void _M2_ASCII_finish (void);
> extern "C" void _M2_NumberIO_init (int argc, char *argv[]);
> extern "C" void _M2_NumberIO_finish (void);
> extern "C" void _M2_Indexing_init (int argc, char *argv[]);
> extern "C" void _M2_Indexing_finish (void);
> extern "C" void _M2_errno_init (int argc, char *argv[]);
> extern "C" void _M2_errno_finish (void);
> extern "C" void _M2_termios_init (int argc, char *argv[]);
> extern "C" void _M2_termios_finish (void);
> extern "C" void _M2_FIO_init (int argc, char *argv[]);
> extern "C" void _M2_FIO_finish (void);
> extern "C" void _M2_IO_init (int argc, char *argv[]);
> extern "C" void _M2_IO_finish (void);
> extern "C" void _M2_StdIO_init (int argc, char *argv[]);
> extern "C" void _M2_StdIO_finish (void);
> extern "C" void _M2_Debug_init (int argc, char *argv[]);
> extern "C" void _M2_Debug_finish (void);
> extern "C" void _M2_SysStorage_init (int argc, char *argv[]);
> extern "C" void _M2_SysStorage_finish (void);
> extern "C" void _M2_SysExceptions_init (int argc, char *argv[]);
> extern "C" void _M2_SysExceptions_finish (void);
> extern "C" void _M2_M2EXCEPTION_init (int argc, char *argv[]);
> extern "C" void _M2_M2EXCEPTION_finish (void);
> extern "C" void _M2_hello_init (int argc, char *argv[]);
> extern "C" void _M2_hello_finish (void);
>
> extern "C" void M2RTS_ExecuteTerminationProcedures(void);
>
> extern "C" void M2RTS_ExecuteInitialProcedures(void);
>
> static void init (int argc, char *argv[])
> {
>    try {
>        _M2_Storage_init (argc, argv);
>        _M2_SYSTEM_init (argc, argv);
>        _M2_M2RTS_init (argc, argv);
>        _M2_RTExceptions_init (argc, argv);
>        _M2_StrIO_init (argc, argv);
>        _M2_StrLib_init (argc, argv);
>        _M2_ASCII_init (argc, argv);
>        _M2_NumberIO_init (argc, argv);
>        _M2_Indexing_init (argc, argv);
>        _M2_errno_init (argc, argv);
>        _M2_termios_init (argc, argv);
>        _M2_FIO_init (argc, argv);
>        _M2_IO_init (argc, argv);
>        _M2_StdIO_init (argc, argv);
>        _M2_Debug_init (argc, argv);
>        _M2_SysStorage_init (argc, argv);
>        _M2_SysExceptions_init (argc, argv);
>        _M2_M2EXCEPTION_init (argc, argv);
>       M2RTS_ExecuteInitialProcedures ();
>        _M2_hello_init (argc, argv);
>     }
>     catch (...) {
>        RTExceptions_DefaultErrorCatch();
>     }
> }
>
> static void finish (void)
> {
>    try {
>       M2RTS_ExecuteTerminationProcedures ();
>       _M2_hello_finish ();
>       _M2_M2EXCEPTION_finish ();
>       _M2_SysExceptions_finish ();
>       _M2_SysStorage_finish ();
>       _M2_Debug_finish ();
>       _M2_StdIO_finish ();
>       _M2_IO_finish ();
>       _M2_FIO_finish ();
>       _M2_termios_finish ();
>       _M2_errno_finish ();
>       _M2_Indexing_finish ();
>       _M2_NumberIO_finish ();
>       _M2_ASCII_finish ();
>       _M2_StrLib_finish ();
>       _M2_StrIO_finish ();
>       _M2_RTExceptions_finish ();
>       _M2_M2RTS_finish ();
>       _M2_SYSTEM_finish ();
>       _M2_Storage_finish ();
>       exit (0);
>     }
>     catch (...) {
>        RTExceptions_DefaultErrorCatch();
>     }
> }
>
> int main (int argc, char *argv[])
> {
>    init (argc, argv);
>    finish ();
>    return (0);
> }

So seeing the above the scaffold is only generated for the main program
translation unit - I suppose an application can consist of more than one
translation unit.  And the main TU compilation (recursively) will import
all other TUs (but they are compiled separately?).  Is there a well-defined
order the module initialization has to happen across a program?

I'm thinking of each m2 TU adding to a global initialization / finalization
vector thus adding

static initvec[] __attribute__((section("m2init"))) = { _M2_..._init,
_M2_..._init, ... };
static finivec[] __attribute__((section("m2fini"))) = {
_M2_..._finish, __M2_..._finish, ...};

and the main program just calling into the m2 runtime with the address
of the sections
which the would apply runtime sorting to weed out duplicates (or have
the individual
_init/_finish protect against multiple invocations).  That's of course
harder if the
initialization/finalization order is well-defined across the import
graph (or tree).

Of course the module objects could also emit meta-data so the runtime can
replicate the import graph.  Not sure if optimizing the compile or the runtime
is more important here.

> yes indeed all these programs could be placed into the front end,
> producing an IR GENERIC scaffold by default

It does look quite managable to create the above indeed.  You might want
to look into the C++ frontend creating global variable
initialization/finalization functions
for a TU like

struct X { X(); ~X(); } x;

Richard.

>
> regards,
> Gaius
  
Gaius Mulley May 28, 2022, 3:34 p.m. UTC | #9
Richard Biener <richard.guenther@gmail.com> writes:

> On Wed, May 25, 2022 at 9:50 PM Gaius Mulley <gaiusmod2@gmail.com> wrote:
>>
>> Richard Biener <richard.guenther@gmail.com> writes:
>>
>> > So is there a reason to have the 'scaffold' separate from the object
>> > of hello.mod?
>>
>> Perhaps the major advantage is flexibility?  But no we can by default
>> produce the scaffold within the object of hello.mod (and give users the
>> ability to disable scaffold generation should they wish to implement
>> their own).
>>
>> > Is there more than a 1:1 relation between a .mod and the 'scaffold'?
>>
>> yes there is a 1:1 relation between a .mod and the scaffold.  Although
>> the caveat is that the compiler would need to parse every .def and .mod
>> imports from the application universe.  Not a major change as gm2 has
>> the ability to do whole program (application) compiling, so a minor set
>> of changes to ensure that upon compiling the program module that it also
>> parses every .def/.mod.
>>
>> > Why are multiple tools involved here - can the m2 frontend not parse
>> > imports, reorder runtime modules and generate the 'scaffold' as
>> > GENERIC IL as part of the translation unit of the .mod file?
>> > Indirection through emitting C++ source code makes the process a bit
>> > awkward IMHO.
>>
>> indeed the m2 front end can parse imports, reorder and generate the
>> scaffold.
>>
>> > Unfortunately I have no m2 installation around to look at how complex
>> > the 'scaffold' is.
>>
>> the scaffold is really simple for example here it is for hello.mod:
>>
>>   $ gm2 -c -g -fmakelist hello.mod
>>   $ cat hello.lst
>> Storage
>> SYSTEM
>> M2RTS
>> RTExceptions
>> # libc   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/libc.def FOR 'C'
>> # SYSTEM   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SYSTEM.mod
>> # StrIO   11 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StrIO.mod
>> # StrLib   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StrLib.mod
>> # ASCII   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/ASCII.mod
>> # NumberIO   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/NumberIO.mod
>> # Indexing   10 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Indexing.mod
>> # errno    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/errno.def
>> # termios    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/termios.def
>> # FIO    9 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/FIO.mod
>> # IO    8 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/IO.mod
>> # StdIO    7 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/StdIO.mod
>> # Debug    6 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Debug.mod
>> # SysStorage    5 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SysStorage.mod
>> # SysExceptions    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/SysExceptions.def
>> # M2EXCEPTION    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/M2EXCEPTION.mod
>> # Storage    4 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/Storage.mod
>> # RTExceptions    3 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/RTExceptions.mod
>> # M2RTS    2 /home/gaius/opt/lib/gcc/x86_64-pc-linux-gnu/13.0.0/m2/m2pim/M2RTS.mod
>> # hello    1 hello.mod
>> #
>> # Initialization order
>> #
>> StrIO
>> StrLib
>> ASCII
>> NumberIO
>> Indexing
>> errno
>> termios
>> FIO
>> IO
>> StdIO
>> Debug
>> SysStorage
>> SysExceptions
>> M2EXCEPTION
>> hello
>>
>>    and now to generate the scaffold for a static application:
>>
>>    $ ~/opt/bin/gm2 -fmakeinit -c -g hello.mod
>>    $ cat hello_m2.cpp
>> extern "C" void exit(int);
>>
>> extern "C" void RTExceptions_DefaultErrorCatch(void);
>> extern "C" void _M2_Storage_init (int argc, char *argv[]);
>> extern "C" void _M2_Storage_finish (void);
>> extern "C" void _M2_SYSTEM_init (int argc, char *argv[]);
>> extern "C" void _M2_SYSTEM_finish (void);
>> extern "C" void _M2_M2RTS_init (int argc, char *argv[]);
>> extern "C" void _M2_M2RTS_finish (void);
>> extern "C" void _M2_RTExceptions_init (int argc, char *argv[]);
>> extern "C" void _M2_RTExceptions_finish (void);
>> extern "C" void _M2_StrIO_init (int argc, char *argv[]);
>> extern "C" void _M2_StrIO_finish (void);
>> extern "C" void _M2_StrLib_init (int argc, char *argv[]);
>> extern "C" void _M2_StrLib_finish (void);
>> extern "C" void _M2_ASCII_init (int argc, char *argv[]);
>> extern "C" void _M2_ASCII_finish (void);
>> extern "C" void _M2_NumberIO_init (int argc, char *argv[]);
>> extern "C" void _M2_NumberIO_finish (void);
>> extern "C" void _M2_Indexing_init (int argc, char *argv[]);
>> extern "C" void _M2_Indexing_finish (void);
>> extern "C" void _M2_errno_init (int argc, char *argv[]);
>> extern "C" void _M2_errno_finish (void);
>> extern "C" void _M2_termios_init (int argc, char *argv[]);
>> extern "C" void _M2_termios_finish (void);
>> extern "C" void _M2_FIO_init (int argc, char *argv[]);
>> extern "C" void _M2_FIO_finish (void);
>> extern "C" void _M2_IO_init (int argc, char *argv[]);
>> extern "C" void _M2_IO_finish (void);
>> extern "C" void _M2_StdIO_init (int argc, char *argv[]);
>> extern "C" void _M2_StdIO_finish (void);
>> extern "C" void _M2_Debug_init (int argc, char *argv[]);
>> extern "C" void _M2_Debug_finish (void);
>> extern "C" void _M2_SysStorage_init (int argc, char *argv[]);
>> extern "C" void _M2_SysStorage_finish (void);
>> extern "C" void _M2_SysExceptions_init (int argc, char *argv[]);
>> extern "C" void _M2_SysExceptions_finish (void);
>> extern "C" void _M2_M2EXCEPTION_init (int argc, char *argv[]);
>> extern "C" void _M2_M2EXCEPTION_finish (void);
>> extern "C" void _M2_hello_init (int argc, char *argv[]);
>> extern "C" void _M2_hello_finish (void);
>>
>> extern "C" void M2RTS_ExecuteTerminationProcedures(void);
>>
>> extern "C" void M2RTS_ExecuteInitialProcedures(void);
>>
>> static void init (int argc, char *argv[])
>> {
>>    try {
>>        _M2_Storage_init (argc, argv);
>>        _M2_SYSTEM_init (argc, argv);
>>        _M2_M2RTS_init (argc, argv);
>>        _M2_RTExceptions_init (argc, argv);
>>        _M2_StrIO_init (argc, argv);
>>        _M2_StrLib_init (argc, argv);
>>        _M2_ASCII_init (argc, argv);
>>        _M2_NumberIO_init (argc, argv);
>>        _M2_Indexing_init (argc, argv);
>>        _M2_errno_init (argc, argv);
>>        _M2_termios_init (argc, argv);
>>        _M2_FIO_init (argc, argv);
>>        _M2_IO_init (argc, argv);
>>        _M2_StdIO_init (argc, argv);
>>        _M2_Debug_init (argc, argv);
>>        _M2_SysStorage_init (argc, argv);
>>        _M2_SysExceptions_init (argc, argv);
>>        _M2_M2EXCEPTION_init (argc, argv);
>>       M2RTS_ExecuteInitialProcedures ();
>>        _M2_hello_init (argc, argv);
>>     }
>>     catch (...) {
>>        RTExceptions_DefaultErrorCatch();
>>     }
>> }
>>
>> static void finish (void)
>> {
>>    try {
>>       M2RTS_ExecuteTerminationProcedures ();
>>       _M2_hello_finish ();
>>       _M2_M2EXCEPTION_finish ();
>>       _M2_SysExceptions_finish ();
>>       _M2_SysStorage_finish ();
>>       _M2_Debug_finish ();
>>       _M2_StdIO_finish ();
>>       _M2_IO_finish ();
>>       _M2_FIO_finish ();
>>       _M2_termios_finish ();
>>       _M2_errno_finish ();
>>       _M2_Indexing_finish ();
>>       _M2_NumberIO_finish ();
>>       _M2_ASCII_finish ();
>>       _M2_StrLib_finish ();
>>       _M2_StrIO_finish ();
>>       _M2_RTExceptions_finish ();
>>       _M2_M2RTS_finish ();
>>       _M2_SYSTEM_finish ();
>>       _M2_Storage_finish ();
>>       exit (0);
>>     }
>>     catch (...) {
>>        RTExceptions_DefaultErrorCatch();
>>     }
>> }
>>
>> int main (int argc, char *argv[])
>> {
>>    init (argc, argv);
>>    finish ();
>>    return (0);
>> }
>>
>>
>> or similarly for a shared library:
>>
>>    $ ~/opt/bin/gm2 -fshared -fmakeinit -c -g hello.mod
>>    $ cat hello_m2.cpp
>> extern "C" void exit(int);
>>
>> extern "C" void RTExceptions_DefaultErrorCatch(void);
>> extern "C" void _M2_Storage_init (int argc, char *argv[]);
>> extern "C" void _M2_Storage_finish (void);
>> extern "C" void _M2_SYSTEM_init (int argc, char *argv[]);
>> extern "C" void _M2_SYSTEM_finish (void);
>> extern "C" void _M2_M2RTS_init (int argc, char *argv[]);
>> extern "C" void _M2_M2RTS_finish (void);
>> extern "C" void _M2_RTExceptions_init (int argc, char *argv[]);
>> extern "C" void _M2_RTExceptions_finish (void);
>> extern "C" void _M2_StrIO_init (int argc, char *argv[]);
>> extern "C" void _M2_StrIO_finish (void);
>> extern "C" void _M2_StrLib_init (int argc, char *argv[]);
>> extern "C" void _M2_StrLib_finish (void);
>> extern "C" void _M2_ASCII_init (int argc, char *argv[]);
>> extern "C" void _M2_ASCII_finish (void);
>> extern "C" void _M2_NumberIO_init (int argc, char *argv[]);
>> extern "C" void _M2_NumberIO_finish (void);
>> extern "C" void _M2_Indexing_init (int argc, char *argv[]);
>> extern "C" void _M2_Indexing_finish (void);
>> extern "C" void _M2_errno_init (int argc, char *argv[]);
>> extern "C" void _M2_errno_finish (void);
>> extern "C" void _M2_termios_init (int argc, char *argv[]);
>> extern "C" void _M2_termios_finish (void);
>> extern "C" void _M2_FIO_init (int argc, char *argv[]);
>> extern "C" void _M2_FIO_finish (void);
>> extern "C" void _M2_IO_init (int argc, char *argv[]);
>> extern "C" void _M2_IO_finish (void);
>> extern "C" void _M2_StdIO_init (int argc, char *argv[]);
>> extern "C" void _M2_StdIO_finish (void);
>> extern "C" void _M2_Debug_init (int argc, char *argv[]);
>> extern "C" void _M2_Debug_finish (void);
>> extern "C" void _M2_SysStorage_init (int argc, char *argv[]);
>> extern "C" void _M2_SysStorage_finish (void);
>> extern "C" void _M2_SysExceptions_init (int argc, char *argv[]);
>> extern "C" void _M2_SysExceptions_finish (void);
>> extern "C" void _M2_M2EXCEPTION_init (int argc, char *argv[]);
>> extern "C" void _M2_M2EXCEPTION_finish (void);
>> extern "C" void _M2_hello_init (int argc, char *argv[]);
>> extern "C" void _M2_hello_finish (void);
>>
>> extern "C" void M2RTS_ExecuteTerminationProcedures(void);
>>
>> extern "C" void M2RTS_ExecuteInitialProcedures(void);
>>
>> static void init (int argc, char *argv[])
>> {
>>    try {
>>        _M2_Storage_init (argc, argv);
>>        _M2_SYSTEM_init (argc, argv);
>>        _M2_M2RTS_init (argc, argv);
>>        _M2_RTExceptions_init (argc, argv);
>>        _M2_StrIO_init (argc, argv);
>>        _M2_StrLib_init (argc, argv);
>>        _M2_ASCII_init (argc, argv);
>>        _M2_NumberIO_init (argc, argv);
>>        _M2_Indexing_init (argc, argv);
>>        _M2_errno_init (argc, argv);
>>        _M2_termios_init (argc, argv);
>>        _M2_FIO_init (argc, argv);
>>        _M2_IO_init (argc, argv);
>>        _M2_StdIO_init (argc, argv);
>>        _M2_Debug_init (argc, argv);
>>        _M2_SysStorage_init (argc, argv);
>>        _M2_SysExceptions_init (argc, argv);
>>        _M2_M2EXCEPTION_init (argc, argv);
>>       M2RTS_ExecuteInitialProcedures ();
>>        _M2_hello_init (argc, argv);
>>     }
>>     catch (...) {
>>        RTExceptions_DefaultErrorCatch();
>>     }
>> }
>>
>> static void finish (void)
>> {
>>    try {
>>       M2RTS_ExecuteTerminationProcedures ();
>>       _M2_hello_finish ();
>>       _M2_M2EXCEPTION_finish ();
>>       _M2_SysExceptions_finish ();
>>       _M2_SysStorage_finish ();
>>       _M2_Debug_finish ();
>>       _M2_StdIO_finish ();
>>       _M2_IO_finish ();
>>       _M2_FIO_finish ();
>>       _M2_termios_finish ();
>>       _M2_errno_finish ();
>>       _M2_Indexing_finish ();
>>       _M2_NumberIO_finish ();
>>       _M2_ASCII_finish ();
>>       _M2_StrLib_finish ();
>>       _M2_StrIO_finish ();
>>       _M2_RTExceptions_finish ();
>>       _M2_M2RTS_finish ();
>>       _M2_SYSTEM_finish ();
>>       _M2_Storage_finish ();
>>       exit (0);
>>     }
>>     catch (...) {
>>        RTExceptions_DefaultErrorCatch();
>>     }
>> }
>>
>> int main (int argc, char *argv[])
>> {
>>    init (argc, argv);
>>    finish ();
>>    return (0);
>> }
>
> So seeing the above the scaffold is only generated for the main program
> translation unit - I suppose an application can consist of more than one
> translation unit.

yes indeed.  There are four module kinds in Modula-2 - the definition
module, implementation module and program module.  There are inner
modules (but for linking purposes we can ignore these).  The definition
module which consists of external prototypes, types, consts, global
variables (but no code) - typically called foo.def.  The implementation
module (foo.mod) must implement everything defined in the corresponding
definition module.  The program module (bar.mod) is the application.

The expected route is for the application module (program module) to be
the module which is linked - but interestingly this does not have to be
enforced and you are allowed to link an implementation module as the
application.

> And the main TU compilation (recursively) will import
> all other TUs (but they are compiled separately?).

yes the *.mod files can be compiled separately.  The *.def modules are
parsed when required aka .h files.

> Is there a well-defined order the module initialization has to happen
> across a program?

yes in ISO m2 it is specified.  The last paragraph is the most crucial.

"The initialization order shall be determined by first processing the
import lists of the program module.  The import list of the program
shall be processed by processing the import lists of each separate
module whose identifier appears in the import lists of the program
module, in order of occurrence in those import lists.

If an import list is an unqualified import, the import list shall be
processed by processing the import lists of the separate module whose
identifier appears in the import list.  If an import list is a simple
import, the import list shall be processed by processing in turn the
import lists of each separate module whose identifier appears in the
import list identifiers.

If the import lists of a separate module have finished being processed,
or have started to be processed, the import lists of that module shall
not be processed again.  Otherwise, the import lists of the definition
module shall be processed, and then the import lists of the
implementation module shall be processed.

The initialization order shall be the order in which the corresponding
separate modules finish the processing of their import lists."

> I'm thinking of each m2 TU adding to a global initialization / finalization
> vector thus adding
>
> static initvec[] __attribute__((section("m2init"))) = { _M2_..._init,
> _M2_..._init, ... };
> static finivec[] __attribute__((section("m2fini"))) = {
> _M2_..._finish, __M2_..._finish, ...};

yes this looks good, very neat.  There already exist a M2RTS pair of
procedures which are created for the init/finish section of the
application which can process these vectors.

> and the main program just calling into the m2 runtime with the address
> of the sections which the would apply runtime sorting to weed out
> duplicates (or have the individual _init/_finish protect against
> multiple invocations).  That's of course harder if the
> initialization/finalization order is well-defined across the import
> graph (or tree).

yes and the compiler can estabish the order using a combination of
topological sort and user defined ordering.

> Of course the module objects could also emit meta-data so the runtime
> can replicate the import graph.  Not sure if optimizing the compile or
> the runtime is more important here.

Yes it would be very easy to add the complete import graph.  I guess it
might be necessary for close source users.  Replicating the import graph
allows for easy runtime satisfying of the ISO initialization sequence.

I think all this is great (when memory is inexpensive).  We also need to
allow users to turn all this off - really trivial by comparison - I'm
remembering the tiny address space targets (separate I/D spaces of 1k
:-).  The IR GENERIC scaffold mentioned in the previous email should
also be useful for tiny memory targets.

>> yes indeed all these programs could be placed into the front end,
>> producing an IR GENERIC scaffold by default
>
> It does look quite managable to create the above indeed.  You might want
> to look into the C++ frontend creating global variable
> initialization/finalization functions
> for a TU like
>
> struct X { X(); ~X(); } x;

yes this looks very useful and clean.  I've taken the liberty of
creating a devel/m2link branch (branched from devel/modula-2) where
development of this new linking mechanism can take place.

I think it might be worth implementing three different mechanisms:

   (i)   generation of source code scaffold.
         gm2 -c -fno-m2link-ir <options to be added here> bar.mod
         generates the scaffold bar_m2.cpp or bar_m2.c and bar.o
         without any extra scaffold code in bar.o.  The user compiles
         and performs the link with gcc/g++/gm2 and a set of
         objects/libraries and the scaffold.

           gcc -c bar_m2.c  or  g++ -c bar_m2.cpp  (if C++ is available
           for the target).
           gm2 bar.o bar_m2.o -lm2min

         Primarily for any legacy code and tiny embedded targets.
         
   (ii)  generation of scaffold as IR in program module.o.
         At least two advantages: easy for the user to debug their code
         and it doesn't require a C++ runtime on the target.

         gm2 -fm2link-ir bar.mod
         
   (iii) the scaffold via struct X { X(); ~X(); } x; pushing function
         addresses, complete import graph replication.  Perhaps allowing
         users to override the order (-fuselist) which is embedded as
         static initvec[] __attribute__((section("m2init"))) = { _M2_..._init,
          _M2_..._init, ... };.  If absent it deduces the sequence from
         the graph.

         gm2 bar.mod

(i) is really a non implementation and (ii) and (iii) are minor variants
of each other.

regards,
Gaius
  

Patch

diff -x '*autom4te*' -rwu gcc/configure.ac gcc-git-devel-modula2/configure.ac
--- gcc/configure.ac	2022-05-17 11:20:57.487964366 +0100
+++ gcc-git-devel-modula2/configure.ac	2022-05-17 14:41:05.480881101 +0100
@@ -140,7 +140,7 @@ 
 # binutils, gas and ld appear in that order because it makes sense to run
 # "make check" in that particular order.
 # If --enable-gold is used, "gold" may replace "ld".
-host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gdbserver gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1 gotools c++tools"
+host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gdbserver gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1 gm2tools gotools c++tools"

 # these libraries are built for the target environment, and are built after
 # the host libraries and the host tools (which may be a cross compiler)
@@ -162,6 +162,7 @@ 
 		target-libffi \
 		target-libobjc \
 		target-libada \
+		target-libgm2 \
 		target-libgo \
 		target-libphobos \
 		target-zlib"
@@ -459,6 +460,14 @@ 
   noconfigdirs="$noconfigdirs gnattools"
 fi

+AC_ARG_ENABLE(libgm2,
+[AS_HELP_STRING([--enable-libgm2], [build libgm2 directory])],
+ENABLE_LIBGM2=$enableval,
+ENABLE_LIBGM2=no)
+if test "${ENABLE_LIBGM2}" != "yes" ; then
+  noconfigdirs="$noconfigdirs gm2tools"
+fi
+
 AC_ARG_ENABLE(libssp,
 [AS_HELP_STRING([--enable-libssp], [build libssp directory])],
 ENABLE_LIBSSP=$enableval,
@@ -3617,6 +3626,7 @@ 
 NCN_STRICT_CHECK_TARGET_TOOLS(GFORTRAN_FOR_TARGET, gfortran)
 NCN_STRICT_CHECK_TARGET_TOOLS(GOC_FOR_TARGET, gccgo)
 NCN_STRICT_CHECK_TARGET_TOOLS(GDC_FOR_TARGET, gdc)
+NCN_STRICT_CHECK_TARGET_TOOLS(GM2_FOR_TARGET, gm2)

 ACX_CHECK_INSTALLED_TARGET_TOOL(AR_FOR_TARGET, ar)
 ACX_CHECK_INSTALLED_TARGET_TOOL(AS_FOR_TARGET, as)
@@ -3655,6 +3665,8 @@ 
 		[gcc/gccgo -B$$r/$(HOST_SUBDIR)/gcc/], go)
 GCC_TARGET_TOOL(gdc, GDC_FOR_TARGET, GDC,
 		[gcc/gdc -B$$r/$(HOST_SUBDIR)/gcc/], d)
+GCC_TARGET_TOOL(gm2, GM2_FOR_TARGET, GM2,
+		[gcc/gm2 -B$$r/$(HOST_SUBDIR)/gcc/], m2)
 GCC_TARGET_TOOL(ld, LD_FOR_TARGET, LD, [ld/ld-new])
 GCC_TARGET_TOOL(lipo, LIPO_FOR_TARGET, LIPO)
 GCC_TARGET_TOOL(nm, NM_FOR_TARGET, NM, [binutils/nm-new])
@@ -3781,6 +3793,9 @@ 
 # Specify what files to not compare during bootstrap.

 compare_exclusions="gcc/cc*-checksum\$(objext) | gcc/ada/*tools/*"
+compare_exclusions="$compare_exclusions | gcc/m2/gm2-compiler-boot/M2Version*"
+compare_exclusions="$compare_exclusions | gcc/m2/gm2-compiler-boot/SYSTEM*"
+compare_exclusions="$compare_exclusions | gcc/m2/gm2version*"
 case "$target" in
   hppa*64*-*-hpux*) ;;
   hppa*-*-hpux*) compare_exclusions="$compare_exclusions | */libgcc/lib2funcs* | gcc/function-tests.o" ;;
diff -x '*autom4te*' -rwu gcc/gcc/c/gccspec.cc gcc-git-devel-modula2/gcc/c/gccspec.cc
--- gcc/gcc/c/gccspec.cc	2022-05-17 11:20:57.919969752 +0100
+++ gcc-git-devel-modula2/gcc/c/gccspec.cc	2022-05-17 14:41:05.552881117 +0100
@@ -105,3 +105,9 @@ 

 /* Number of extra output files that lang_specific_pre_link may generate.  */
 int lang_specific_extra_outfiles = 0;  /* Not used for C.  */
+
+/* lang_register_spec_functions.  Not used for C.  */
+void
+lang_register_spec_functions (void)
+{
+}
diff -x '*autom4te*' -rwu gcc/gcc/c-family/cppspec.cc gcc-git-devel-modula2/gcc/c-family/cppspec.cc
--- gcc/gcc/c-family/cppspec.cc	2022-05-17 11:20:57.911969653 +0100
+++ gcc-git-devel-modula2/gcc/c-family/cppspec.cc	2022-05-17 14:41:05.548881115 +0100
@@ -198,3 +198,9 @@ 

 /* Number of extra output files that lang_specific_pre_link may generate.  */
 int lang_specific_extra_outfiles = 0;  /* Not used for cpp.  */
+
+/* lang_register_spec_functions.  Not used for cpp.  */
+void
+lang_register_spec_functions (void)
+{
+}
diff -x '*autom4te*' -rwu gcc/gcc/cp/g++spec.cc gcc-git-devel-modula2/gcc/cp/g++spec.cc
--- gcc/gcc/cp/g++spec.cc	2022-05-17 11:20:58.163972794 +0100
+++ gcc-git-devel-modula2/gcc/cp/g++spec.cc	2022-05-17 14:41:05.564881118 +0100
@@ -434,3 +434,9 @@ 

 /* Number of extra output files that lang_specific_pre_link may generate.  */
 int lang_specific_extra_outfiles = 0;  /* Not used for C++.  */
+
+/* lang_register_spec_functions.  Not used for C++.  */
+void
+lang_register_spec_functions (void)
+{
+}
diff -x '*autom4te*' -rwu gcc/gcc/d/d-spec.cc gcc-git-devel-modula2/gcc/d/d-spec.cc
--- gcc/gcc/d/d-spec.cc	2022-05-17 11:20:58.183973043 +0100
+++ gcc-git-devel-modula2/gcc/d/d-spec.cc	2022-05-17 14:41:05.580881121 +0100
@@ -525,3 +525,10 @@ 

 int lang_specific_extra_outfiles = 0;  /* Not used for D.  */

+/* lang_register_spec_functions register the D associated spec
+   functions.  Not used for D.  */
+
+void
+lang_register_spec_functions (void)
+{
+}
diff -x '*autom4te*' -rwu gcc/gcc/doc/install.texi gcc-git-devel-modula2/gcc/doc/install.texi
--- gcc/gcc/doc/install.texi	2022-05-17 11:20:58.223973542 +0100
+++ gcc-git-devel-modula2/gcc/doc/install.texi	2022-05-17 14:41:05.600881126 +0100
@@ -1832,18 +1832,19 @@ 
 @smallexample
 grep ^language= */config-lang.in
 @end smallexample
-Currently, you can use any of the following:
-@code{all}, @code{default}, @code{ada}, @code{c}, @code{c++}, @code{d},
-@code{fortran}, @code{go}, @code{jit}, @code{lto}, @code{objc}, @code{obj-c++}.
-Building the Ada compiler has special requirements, see below.
-If you do not pass this flag, or specify the option @code{default}, then the
-default languages available in the @file{gcc} sub-tree will be configured.
-Ada, D, Go, Jit, and Objective-C++ are not default languages.  LTO is not a
-default language, but is built by default because @option{--enable-lto} is
-enabled by default.  The other languages are default languages.  If
-@code{all} is specified, then all available languages are built.  An
-exception is @code{jit} language, which requires
-@option{--enable-host-shared} to be included with @code{all}.
+Currently, you can use any of the following: @code{all},
+@code{default}, @code{ada}, @code{c}, @code{c++}, @code{d},
+@code{fortran}, @code{go}, @code{jit}, @code{lto}, @code{m2},
+@code{objc}, @code{obj-c++}.  Building the Ada compiler has special
+requirements, see below.  If you do not pass this flag, or specify the
+option @code{default}, then the default languages available in the
+@file{gcc} sub-tree will be configured.  Ada, D, Go, Jit,
+Objective-C++ and Modula-2 are not default languages.  LTO is not a
+default language, but is built by default because
+@option{--enable-lto} is enabled by default.  The other languages are
+default languages.  If @code{all} is specified, then all available
+languages are built.  An exception is @code{jit} language, which
+requires @option{--enable-host-shared} to be included with @code{all}.

 @item --enable-stage1-languages=@var{lang1},@var{lang2},@dots{}
 Specify that a particular subset of compilers and their runtime
@@ -1866,6 +1867,10 @@ 
 previous Ada build procedures, when it was required to explicitly
 do a @samp{make -C gcc gnatlib_and_tools}.

+@item --disable-libgm2
+Specify that the run-time libraries and tools used by Modula-2 should not
+be built.  This can be useful for debugging.
+
 @item --disable-libsanitizer
 Specify that the run-time libraries for the various sanitizers should
 not be built.
@@ -3116,10 +3121,10 @@ 
 In order to run sets of tests selectively, there are targets
 @samp{make check-gcc} and language specific @samp{make check-c},
 @samp{make check-c++}, @samp{make check-d} @samp{make check-fortran},
-@samp{make check-ada}, @samp{make check-objc}, @samp{make check-obj-c++},
-@samp{make check-lto}
-in the @file{gcc} subdirectory of the object directory.  You can also
-just run @samp{make check} in a subdirectory of the object directory.
+@samp{make check-ada}, @samp{make check-m2}, @samp{make check-objc},
+@samp{make check-obj-c++}, @samp{make check-lto} in the @file{gcc}
+subdirectory of the object directory.  You can also just run
+@samp{make check} in a subdirectory of the object directory.


 A more selective way to just run all @command{gcc} execute tests in the
diff -x '*autom4te*' -rwu gcc/gcc/doc/sourcebuild.texi gcc-git-devel-modula2/gcc/doc/sourcebuild.texi
--- gcc/gcc/doc/sourcebuild.texi	2022-05-17 11:20:58.231973641 +0100
+++ gcc-git-devel-modula2/gcc/doc/sourcebuild.texi	2022-05-17 14:41:05.604881127 +0100
@@ -52,6 +52,9 @@ 
 language front ends, and testsuites.  @xref{gcc Directory, , The
 @file{gcc} Subdirectory}, for details.

+@item gm2tools
+Support tools for Modula-2.
+
 @item gnattools
 Support tools for GNAT.

@@ -84,6 +87,9 @@ 
 @item libgfortran
 The Fortran runtime library.

+@item libgm2
+The Modula-2 runtime library.
+
 @item libgo
 The Go runtime library.  The bulk of this library is mirrored from the
 @uref{https://github.com/@/golang/go, master Go repository}.
@@ -163,13 +169,12 @@ 
 @item @var{language}
 Subdirectories for various languages.  Directories containing a file
 @file{config-lang.in} are language subdirectories.  The contents of
-the subdirectories @file{c} (for C), @file{cp} (for C++),
-@file{objc} (for Objective-C), @file{objcp} (for Objective-C++),
-and @file{lto} (for LTO) are documented in this
-manual (@pxref{Passes, , Passes and Files of the Compiler});
-those for other languages are not.  @xref{Front End, ,
-Anatomy of a Language Front End}, for details of the files in these
-directories.
+the subdirectories @file{c} (for C), @file{cp} (for C++), @file{m2}
+(for Modula-2), @file{objc} (for Objective-C), @file{objcp} (for
+Objective-C++), and @file{lto} (for LTO) are documented in this manual
+(@pxref{Passes, , Passes and Files of the Compiler}); those for other
+languages are not.  @xref{Front End, , Anatomy of a Language Front
+End}, for details of the files in these directories.

 @item common
 Source files shared between the compiler drivers (such as
diff -x '*autom4te*' -rwu gcc/gcc/fortran/gfortranspec.cc gcc-git-devel-modula2/gcc/fortran/gfortranspec.cc
--- gcc/gcc/fortran/gfortranspec.cc	2022-05-17 11:20:58.263974041 +0100
+++ gcc-git-devel-modula2/gcc/fortran/gfortranspec.cc	2022-05-17 14:41:05.608881127 +0100
@@ -447,4 +447,12 @@ 
 }

 /* Number of extra output files that lang_specific_pre_link may generate.  */
-int lang_specific_extra_outfiles = 0;	/* Not used for F77.  */
+int lang_specific_extra_outfiles = 0;	/* Not used for Fortran.  */
+
+/* lang_register_spec_functions register the Fortran associated spec
+   functions.  */
+
+void
+lang_register_spec_functions (void)
+{
+}
diff -x '*autom4te*' -rwu gcc/gcc/gcc.cc gcc-git-devel-modula2/gcc/gcc.cc
--- gcc/gcc/gcc.cc	2022-05-17 11:20:58.283974290 +0100
+++ gcc-git-devel-modula2/gcc/gcc.cc	2022-05-17 14:41:05.616881129 +0100
@@ -334,6 +334,10 @@ 
 static const char *cross_compile = "0";
 #endif

+/* The lang specs might wish to override the default linker.
+ */
+int allow_linker = 1;
+
 /* Greatest exit code of sub-processes that has been encountered up to
    now.  */
 static int greatest_status = 1;
@@ -1782,6 +1786,10 @@ 
   { 0, 0 }
 };

+/* Front end registered spec functions */
+static struct spec_function *lang_spec_functions = NULL;
+static unsigned int lang_spec_functions_length = 0;
+
 static int processing_spec_function;
 
 /* Add appropriate libgcc specs to OBSTACK, taking into account
@@ -2950,6 +2958,30 @@ 
   env.xput (string);
 }

+/* Get the environment variable through the managed env.  */
+
+static const char *
+xgetenv (const char *key)
+{
+  return env.get (key);
+}
+
+/* Allow front end access to xputenv.  */
+
+void
+fe_putenv (const char *string)
+{
+  xputenv (string);
+}
+
+/* Allow front end access to xgetenv.  */
+
+const char *
+fe_getenv (const char *key)
+{
+  return xgetenv (key);
+}
+
 /* Build a list of search directories from PATHS.
    PREFIX is a string to prepend to the list.
    If CHECK_DIR_P is true we ensure the directory exists.
@@ -3916,6 +3948,15 @@ 
   n_switches++;
 }

+/* Allow front ends to save switches.  */
+
+void
+fe_save_switch (const char *opt, size_t n_args, const char *const *args,
+		bool validated, bool known)
+{
+  save_switch (opt, n_args, args, validated, known);
+}
+
 /* Set the SOURCE_DATE_EPOCH environment variable to the current time if it is
    not set already.  */

@@ -3939,6 +3980,76 @@ 
   setenv ("SOURCE_DATE_EPOCH", source_date_epoch, 0);
 }

+/* Wrapper providing front end access to link options.  */
+
+void
+fe_add_linker_option (const char *option)
+{
+  add_linker_option (option, strlen (option));
+}
+
+/* Handle the -B option by adding the prefix to exec, startfile and
+   include search paths.  */
+
+static void
+handle_opt_b (const char *arg)
+{
+  size_t len = strlen (arg);
+
+  /* Catch the case where the user has forgotten to append a
+     directory separator to the path.  Note, they may be using
+     -B to add an executable name prefix, eg "i386-elf-", in
+     order to distinguish between multiple installations of
+     GCC in the same directory.  Hence we must check to see
+     if appending a directory separator actually makes a
+     valid directory name.  */
+  if (!IS_DIR_SEPARATOR (arg[len - 1])
+      && is_directory (arg, false))
+    {
+      char *tmp = XNEWVEC (char, len + 2);
+      strcpy (tmp, arg);
+      tmp[len] = DIR_SEPARATOR;
+      tmp[++len] = 0;
+      arg = tmp;
+    }
+
+  add_prefix (&exec_prefixes, arg, NULL,
+	      PREFIX_PRIORITY_B_OPT, 0, 0);
+  add_prefix (&startfile_prefixes, arg, NULL,
+	      PREFIX_PRIORITY_B_OPT, 0, 0);
+  add_prefix (&include_prefixes, arg, NULL,
+	      PREFIX_PRIORITY_B_OPT, 0, 0);
+}
+
+/* Wrapper allowing the front end to create a -B option.  */
+
+void
+fe_handle_opt_b (const char *arg)
+{
+  handle_opt_b (arg);
+}
+
+/* Save the infile.  */
+
+void
+fe_add_infile (const char *infile, const char *lang)
+{
+  add_infile (infile, lang);
+}
+
+/* Mark a file as compiled.  */
+
+void
+fe_mark_compiled (const char *name)
+{
+  int max = n_infiles + lang_specific_extra_outfiles;
+  int i;
+
+  for (i = 0; i < max; i++)
+    if (filename_cmp (name, infiles[i].name) == 0)
+      infiles[i].compiled = true;
+}
+
 /* Handle an option DECODED that is unknown to the option-processing
    machinery.  */

@@ -4518,33 +4629,7 @@ 
       break;

     case OPT_B:
-      {
-	size_t len = strlen (arg);
-
-	/* Catch the case where the user has forgotten to append a
-	   directory separator to the path.  Note, they may be using
-	   -B to add an executable name prefix, eg "i386-elf-", in
-	   order to distinguish between multiple installations of
-	   GCC in the same directory.  Hence we must check to see
-	   if appending a directory separator actually makes a
-	   valid directory name.  */
-	if (!IS_DIR_SEPARATOR (arg[len - 1])
-	    && is_directory (arg, false))
-	  {
-	    char *tmp = XNEWVEC (char, len + 2);
-	    strcpy (tmp, arg);
-	    tmp[len] = DIR_SEPARATOR;
-	    tmp[++len] = 0;
-	    arg = tmp;
-	  }
-
-	add_prefix (&exec_prefixes, arg, NULL,
-		    PREFIX_PRIORITY_B_OPT, 0, 0);
-	add_prefix (&startfile_prefixes, arg, NULL,
-		    PREFIX_PRIORITY_B_OPT, 0, 0);
-	add_prefix (&include_prefixes, arg, NULL,
-		    PREFIX_PRIORITY_B_OPT, 0, 0);
-      }
+      handle_opt_b (arg);
       validated = true;
       break;

@@ -4677,6 +4762,69 @@ 
   return ret;
 }

+/* print_option a debugging routine to display option i with a leading desc
+   string.  */
+
+void
+print_option (const char *desc, unsigned int i,
+	      struct cl_decoded_option *in_decoded_options)
+{
+  printf (desc);
+  printf (" [%d]", i);
+  switch (in_decoded_options[i].opt_index)
+    {
+
+    case N_OPTS:
+      break;
+    case OPT_SPECIAL_unknown:
+      printf (" flag <unknown>");
+      break;
+    case OPT_SPECIAL_ignore:
+      printf (" flag <ignore>");
+      break;
+    case OPT_SPECIAL_program_name:
+      printf (" flag <program name>");
+      break;
+    case OPT_SPECIAL_input_file:
+      printf (" flag <input file name>");
+      break;
+    default:
+      printf (" flag [%s]",
+              cl_options[in_decoded_options[i].opt_index].opt_text);
+    }
+
+  if (in_decoded_options[i].arg == NULL)
+    printf (" no arg");
+  else
+    printf (" arg [%s]", in_decoded_options[i].arg);
+  printf (" orig text [%s]",
+          in_decoded_options[i].orig_option_with_args_text);
+  /* On some hosts value is declared as a long long int.  */
+  printf (" value [%ld]", (long int)in_decoded_options[i].value);
+  printf (" error [%d]\n", in_decoded_options[i].errors);
+}
+
+/* print_options display all options with a leading string desc.  */
+
+void
+print_options (const char *desc,
+	       unsigned int in_decoded_options_count,
+	       struct cl_decoded_option *in_decoded_options)
+{
+  for (unsigned int i = 0; i < in_decoded_options_count; i++)
+    print_option (desc, i, in_decoded_options);
+}
+
+/* dbg_options display all options.  */
+
+void
+dbg_options (unsigned int in_decoded_options_count,
+	     struct cl_decoded_option *in_decoded_options)
+{
+  print_options ("dbg_options", in_decoded_options_count,
+		 in_decoded_options);
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */

@@ -6842,6 +6990,35 @@ 
   return 0;
 }

+/* Allow the front end to register a spec function.  */
+
+void fe_add_spec_function (const char *name,
+			   const char *(*func) (int, const char **))
+{
+  const struct spec_function *f = lookup_spec_function (name);
+  struct spec_function *fl;
+  unsigned int i;
+
+  if (f != NULL)
+    fatal_error (input_location, "spec function (%s) already registered", name);
+
+  if (lang_spec_functions == NULL)
+    lang_spec_functions_length = 1;
+
+  lang_spec_functions_length++;
+  fl = (struct spec_function *) xmalloc (sizeof (const struct spec_function)
+					 *lang_spec_functions_length);
+  for (i=0; i<lang_spec_functions_length-2; i++)
+    fl[i] = lang_spec_functions[i];
+  free (lang_spec_functions);
+  lang_spec_functions = fl;
+
+  lang_spec_functions[lang_spec_functions_length-2].name = name;
+  lang_spec_functions[lang_spec_functions_length-2].func = func;
+  lang_spec_functions[lang_spec_functions_length-1].name = NULL;
+  lang_spec_functions[lang_spec_functions_length-1].func = NULL;
+}
+
 /* Look up a spec function.  */

 static const struct spec_function *
@@ -6853,6 +7030,11 @@ 
     if (strcmp (sf->name, name) == 0)
       return sf;

+  if (lang_spec_functions != NULL)
+    for (sf = lang_spec_functions; sf->name != NULL; sf++)
+      if (strcmp (sf->name, name) == 0)
+	return sf;
+
   return NULL;
 }

@@ -8339,6 +8521,8 @@ 
 			   accel_dir_suffix, dir_separator_str, NULL);
   just_machine_suffix = concat (spec_machine, dir_separator_str, NULL);

+  lang_register_spec_functions ();
+
   specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true);
   /* Read the specs file unless it is a default one.  */
   if (specs_file != 0 && strcmp (specs_file, "specs"))
@@ -9070,7 +9254,8 @@ 

   /* Run ld to link all the compiler output files.  */

-  if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2)
+  if (num_linker_inputs > 0 && !seen_error () && print_subprocess_help < 2
+      && allow_linker)
     {
       int tmp = execution_count;

@@ -9139,7 +9324,7 @@ 
   /* If options said don't run linker,
      complain about input files to be given to the linker.  */

-  if (! linker_was_run && !seen_error ())
+  if (! linker_was_run && !seen_error () && allow_linker)
     for (i = 0; (int) i < n_infiles; i++)
       if (explicit_link_files[i]
 	  && !(infiles[i].language && infiles[i].language[0] == '*'))
diff -x '*autom4te*' -rwu gcc/gcc/gcc.h gcc-git-devel-modula2/gcc/gcc.h
--- gcc/gcc/gcc.h	2022-05-17 11:20:58.283974290 +0100
+++ gcc-git-devel-modula2/gcc/gcc.h	2022-05-17 14:41:05.616881129 +0100
@@ -73,9 +73,28 @@ 
 extern int do_spec (const char *);
 extern void record_temp_file (const char *, int, int);
 extern void set_input (const char *);
+extern void fe_save_switch (const char *opt, size_t n_args,
+			 const char *const *args,
+			 bool validated, bool known);
+extern void fe_handle_op_b (const char *arg);
+extern void fe_add_infile (const char *infile, const char *lang);
+extern void fe_add_linker_option (const char *option);
+extern void fe_add_spec_function (const char *name, const char *(*func) (int, const char **));
+extern void fe_putenv (const char *value);
+extern const char *fe_getenv (const char *key);
+extern void print_options (const char *desc,
+			   unsigned int in_decoded_options_count,
+			   struct cl_decoded_option *in_decoded_options);
+extern void print_option (const char *desc, unsigned int i,
+			  struct cl_decoded_option *in_decoded_options);
+extern void dbg_options (unsigned int in_decoded_options_count,
+			 struct cl_decoded_option *in_decoded_options);
+

 /* Spec files linked with gcc.cc must provide definitions for these.  */

+extern void lang_register_spec_functions (void);
+
 /* Called before processing to change/add/remove arguments.  */
 extern void lang_specific_driver (struct cl_decoded_option **,
 				  unsigned int *, int *);
@@ -97,4 +116,8 @@ 
 					      void *user_data),
 				   void *user_data);

+/* Default setting is true, but can be overridden by the language
+   front end to prohibit the linker from being invoked.  */
+extern int allow_linker;
+
 #endif /* ! GCC_GCC_H */
diff -x '*autom4te*' -rwu gcc/gcc/go/gospec.cc gcc-git-devel-modula2/gcc/go/gospec.cc
--- gcc/gcc/go/gospec.cc	2022-05-17 11:20:58.323974789 +0100
+++ gcc-git-devel-modula2/gcc/go/gospec.cc	2022-05-17 14:41:05.616881129 +0100
@@ -464,3 +464,9 @@ 

 /* Number of extra output files that lang_specific_pre_link may generate.  */
 int lang_specific_extra_outfiles = 0;  /* Not used for Go.  */
+
+/* lang_register_spec_functions.  Not used for Go.  */
+void
+lang_register_spec_functions (void)
+{
+}
diff -x '*autom4te*' -rwu gcc/gcc/jit/jit-spec.cc gcc-git-devel-modula2/gcc/jit/jit-spec.cc
--- gcc/gcc/jit/jit-spec.cc	2022-05-17 11:20:58.355975188 +0100
+++ gcc-git-devel-modula2/gcc/jit/jit-spec.cc	2022-05-17 14:41:05.620881130 +0100
@@ -39,3 +39,9 @@ 

 /* Number of extra output files that lang_specific_pre_link may generate.  */
 int lang_specific_extra_outfiles = 0;  /* Not used for jit.  */
+
+/* lang_register_spec_functions.  Not used for jit.  */
+void
+lang_register_spec_functions (void)
+{
+}
diff -x '*autom4te*' -rwu gcc/Makefile.def gcc-git-devel-modula2/Makefile.def
--- gcc/Makefile.def	2022-05-17 11:20:57.467964117 +0100
+++ gcc-git-devel-modula2/Makefile.def	2022-05-17 14:41:05.468881099 +0100
@@ -146,6 +146,7 @@ 
 		extra_configure_flags='--enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@';
 		extra_make_flags='@extra_linker_plugin_flags@'; };
 host_modules= { module= libcc1; extra_configure_flags=--enable-shared; };
+host_modules= { module= gm2tools; };
 host_modules= { module= gotools; };
 host_modules= { module= libctf; bootstrap=true; };

@@ -189,6 +190,7 @@ 
 target_modules = { module= zlib; bootstrap=true; };
 target_modules = { module= rda; };
 target_modules = { module= libada; };
+target_modules = { module= libgm2; lib_path=.libs; };
 target_modules = { module= libgomp; bootstrap= true; lib_path=.libs; };
 target_modules = { module= libitm; lib_path=.libs; };
 target_modules = { module= libatomic; bootstrap=true; lib_path=.libs; };
@@ -311,6 +313,8 @@ 
 flags_to_pass = { flag= GOCFLAGS_FOR_TARGET ; };
 flags_to_pass = { flag= GDC_FOR_TARGET ; };
 flags_to_pass = { flag= GDCFLAGS_FOR_TARGET ; };
+flags_to_pass = { flag= GM2_FOR_TARGET ; };
+flags_to_pass = { flag= GM2FLAGS_FOR_TARGET ; };
 flags_to_pass = { flag= LD_FOR_TARGET ; };
 flags_to_pass = { flag= LIPO_FOR_TARGET ; };
 flags_to_pass = { flag= LDFLAGS_FOR_TARGET ; };
@@ -407,6 +411,8 @@ 
 // we want version.o from gcc, and implicitly depend on libcody
 dependencies = { module=all-c++tools; on=all-gcc; };
 dependencies = { module=all-gotools; on=all-target-libgo; };
+dependencies = { module=all-gm2tools; on=all-target-libgm2; };
+dependencies = { module=all-gm2tools; on=all-target-libstdc++-v3; };

 dependencies = { module=all-utils; on=all-libiberty; };

@@ -623,6 +629,8 @@ 
 dependencies = { module=all-target-libgo; on=all-target-libbacktrace; };
 dependencies = { module=all-target-libgo; on=all-target-libffi; };
 dependencies = { module=all-target-libgo; on=all-target-libatomic; };
+dependencies = { module=configure-target-libgm2; on=all-target-libstdc++-v3; };
+dependencies = { module=all-target-libgm2; on=all-target-libatomic; };
 dependencies = { module=configure-target-libphobos; on=configure-target-libbacktrace; };
 dependencies = { module=configure-target-libphobos; on=configure-target-zlib; };
 dependencies = { module=all-target-libphobos; on=all-target-libbacktrace; };
@@ -681,6 +689,9 @@ 
 languages = { language=go;	gcc-check-target=check-go;
 				lib-check-target=check-target-libgo;
 				lib-check-target=check-gotools; };
+languages = { language=m2;	gcc-check-target=check-m2;
+				lib-check-target=check-target-libgm2;
+				lib-check-target=check-gm2tools; };
 languages = { language=d;	gcc-check-target=check-d;
 				lib-check-target=check-target-libphobos; };
 languages = { language=jit;	gcc-check-target=check-jit; };
diff -x '*autom4te*' -rwu gcc/Makefile.tpl gcc-git-devel-modula2/Makefile.tpl
--- gcc/Makefile.tpl	2022-05-17 11:20:57.475964217 +0100
+++ gcc-git-devel-modula2/Makefile.tpl	2022-05-17 14:41:05.472881100 +0100
@@ -166,6 +166,7 @@ 
 	GOCFLAGS="$(GOCFLAGS_FOR_BUILD)"; export GOCFLAGS; \
 	GDC="$(GDC_FOR_BUILD)"; export GDC; \
 	GDCFLAGS="$(GDCFLAGS_FOR_BUILD)"; export GDCFLAGS; \
+	GM2="$(GM2_FOR_BUILD)"; export GM2; \
 	DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \
 	DSYMUTIL="$(DSYMUTIL_FOR_BUILD)"; export DSYMUTIL; \
 	LD="$(LD_FOR_BUILD)"; export LD; \
@@ -204,6 +205,7 @@ 
 	GFORTRAN="$(GFORTRAN)"; export GFORTRAN; \
 	GOC="$(GOC)"; export GOC; \
 	GDC="$(GDC)"; export GDC; \
+	GM2="$(GM2)"; export GM2; \
 	AR="$(AR)"; export AR; \
 	AS="$(AS)"; export AS; \
 	CC_FOR_BUILD="$(CC_FOR_BUILD)"; export CC_FOR_BUILD; \
@@ -309,6 +311,7 @@ 
 	GFORTRAN="$(GFORTRAN_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GFORTRAN; \
 	GOC="$(GOC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GOC; \
 	GDC="$(GDC_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GDC; \
+	GM2="$(GM2_FOR_TARGET) $(XGCC_FLAGS_FOR_TARGET) $$TFLAGS"; export GM2; \
 	DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \
 	DSYMUTIL="$(DSYMUTIL_FOR_TARGET)"; export DSYMUTIL; \
 	LD="$(COMPILER_LD_FOR_TARGET)"; export LD; \
@@ -379,6 +382,7 @@ 
 GFORTRAN_FOR_BUILD = @GFORTRAN_FOR_BUILD@
 GOC_FOR_BUILD = @GOC_FOR_BUILD@
 GDC_FOR_BUILD = @GDC_FOR_BUILD@
+GM2_FOR_BUILD = @GM2_FOR_BUILD@
 LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
 LD_FOR_BUILD = @LD_FOR_BUILD@
 NM_FOR_BUILD = @NM_FOR_BUILD@
@@ -449,6 +453,7 @@ 
 LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates
 GOCFLAGS = $(CFLAGS)
 GDCFLAGS = $(CFLAGS)
+GM2FLAGS = $(CFLAGS)

 # Pass additional PGO and LTO compiler options to the PGO build.
 BUILD_CFLAGS = $(PGO_BUILD_CFLAGS) $(PGO_BUILD_LTO_CFLAGS)
@@ -584,6 +589,7 @@ 
 GFORTRAN_FOR_TARGET=$(STAGE_CC_WRAPPER) @GFORTRAN_FOR_TARGET@
 GOC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GOC_FOR_TARGET@
 GDC_FOR_TARGET=$(STAGE_CC_WRAPPER) @GDC_FOR_TARGET@
+GM2_FOR_TARGET=$(STAGE_CC_WRAPPER) @GM2_FOR_TARGET@
 DLLTOOL_FOR_TARGET=@DLLTOOL_FOR_TARGET@
 DSYMUTIL_FOR_TARGET=@DSYMUTIL_FOR_TARGET@
 LD_FOR_TARGET=@LD_FOR_TARGET@
@@ -609,6 +615,7 @@ 
 LIBCFLAGS_FOR_TARGET = $(CFLAGS_FOR_TARGET)
 LIBCXXFLAGS_FOR_TARGET = $(CXXFLAGS_FOR_TARGET) -fno-implicit-templates
 LDFLAGS_FOR_TARGET = @LDFLAGS_FOR_TARGET@
+GM2FLAGS_FOR_TARGET = -O2 -g
 GOCFLAGS_FOR_TARGET = -O2 -g
 GDCFLAGS_FOR_TARGET = -O2 -g

@@ -715,6 +722,7 @@ 
 	'GFORTRAN=$(GFORTRAN)' \
 	'GOC=$(GOC)' \
 	'GDC=$(GDC)' \
+	'GM2=$(GM2)' \
 	'LD=$(LD)' \
 	'LIPO=$(LIPO)' \
 	'NM=$(NM)' \
@@ -741,6 +749,7 @@ 
 	CC="$${CC}" CC_FOR_BUILD="$${CC_FOR_BUILD}" \
 	CXX="$${CXX}" CXX_FOR_BUILD="$${CXX_FOR_BUILD}" \
 	GDC="$${GDC}" GDC_FOR_BUILD="$${GDC_FOR_BUILD}" \
+	GM2="$${GM2}" GM2_FOR_BUILD="$${GM2_FOR_BUILD}" \
 	GNATBIND="$${GNATBIND}" \
 	LDFLAGS="$${LDFLAGS}" \
 	HOST_LIBS="$${HOST_LIBS}" \
@@ -776,6 +785,8 @@ 
 	'GOCFLAGS=$$(GOCFLAGS_FOR_TARGET)' \
 	'GDC=$$(GDC_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \
 	'GDCFLAGS=$$(GDCFLAGS_FOR_TARGET)' \
+	'GM2=$$(GM2_FOR_TARGET) $$(XGCC_FLAGS_FOR_TARGET) $$(TFLAGS)' \
+	'GM2FLAGS=$$(GM2FLAGS_FOR_TARGET)' \
 	'LD=$(COMPILER_LD_FOR_TARGET)' \
 	'LDFLAGS=$$(LDFLAGS_FOR_TARGET)' \
 	'LIBCFLAGS=$$(LIBCFLAGS_FOR_TARGET)' \
@@ -802,6 +813,7 @@ 
 # cross-building scheme.
 EXTRA_GCC_FLAGS = \
 	"GCC_FOR_TARGET=$(GCC_FOR_TARGET)" \
+	"GM2_FOR_TARGET=$(GM2_FOR_TARGET)" \
 	"`echo 'STMP_FIXPROTO=$(STMP_FIXPROTO)' | sed -e s'/[^=][^=]*=$$/XFOO=/'`" \
 	"`echo 'LIMITS_H_TEST=$(LIMITS_H_TEST)' | sed -e s'/[^=][^=]*=$$/XFOO=/'`"

@@ -951,7 +963,7 @@ 
 	-rm -f texinfo/doc/Makefile texinfo/po/POTFILES
 	-rmdir texinfo/doc texinfo/info texinfo/intl texinfo/lib 2>/dev/null
 	-rmdir texinfo/makeinfo texinfo/po texinfo/util 2>/dev/null
-	-rmdir c++tools fastjar gcc gnattools gotools 2>/dev/null
+	-rmdir c++tools fastjar gcc gnattools gm2tools gotools 2>/dev/null
 	-rmdir libcc1 libiberty texinfo zlib 2>/dev/null
 	-find . -name config.cache -exec rm -f {} \; \; 2>/dev/null