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