diff mbox series

Modula-2 into the GCC tree on master

Message ID 878s8rf3uu.fsf@gmail.com
State New
Headers show
Series Modula-2 into the GCC tree on master | expand

Commit Message

Gaius Mulley Jan. 18, 2021, 1:09 a.m. UTC
Hello,

here is a patch which merges the gm2 front end into the GCC tree.  The
patches have been boostrapped under x86_64 GNU/Linux Debian Stretch
built using make -j 24 and also under x86_64 GNU/Linux Debian Buster
using make -j 4.

Tested on Debian Stretch x86_64
===============================

built GCC bootstrap 3 times:

1.  built vanilla GCC (enabling bootstrap) enabling front ends:
    brig,c,c++,go,d,fortran and ran the regression tests.

2.  the patches below were applied and associated tarball untarred.
    The same front ends brig,c,c++,go,d,fortran (again building from
    bootstrap) were enabled (no m2) and ran the regression tests.
    There were no changes to the regression test results between 1 and
    2.

3.  Then it was rebuilt (from bootstrap) enabling the front ends
    brig,c,c++,go,d,fortran,m2 and ran the
    regression tests and again no extra failures were seen.

[should I also be testing ada?]

Built on Debian Buster x86_64
=============================

Built a patched tree enabling bootstrap make -j 4 for front ends c,c++,m2
all compiled and bootstrapped.

How to merge
============

1.  apply patches below to the master GCC tree.

2.  cd gcc-git-top
    wget http://floppsie.comp.glam.ac.uk/download/c/gm2-front-end-20210116-tar.gz
    tar zxf gm2-front-end-20210116-tar.gz
    rm gm2-front-end-20210116-tar.gz
    # new directories libgm2 and gcc/m2 are created and populated

3.  cd gcc-git-top
    autogen Makefile.def
    autoconf
    cd libgm2
    /bin/sh ./autogen.sh

when built this implements iso, pim2, pim3 and pim4 editions of Modula-2
with access to GCC features (gcc/m2/gm2.texi).

hope this is useful - enjoy,

regards,
Gaius



2021-01-18  Gaius Mulley   <gaiusmod2@gmail.com>

* configure.ac (GM2_FOR_TARGET): Added.
Request build driver program gm2.
(libgm2) option added.
(compare_exclusions) includes SYSTEM and M2Version.
* Makefile.def (GM2_FOR_TARGET): Added.
(GM2FLAGS_FOR_TARGET): Added.  Assign GM2,
GM2_FOR_BUILD, GM2_FOR_TARGET and GM2FLAGS.
Pass variables to make.  Add new language Modula-2
(m2).  (target_modules) includes libgm2.  (flags_to_pass)
includes GM2_FOR_TARGET and GM2FLAGS_FOR_TARGET.
* Makefile.tpl (GM2FLAGS): Added.  (GM2) Added.
(GM2_FOR_BUILD) Added.

gcc/

* gcc/brig/brigspec.c (lang_register_spec_functions): Added.
* gcc/c-family/cppspec.c (lang_register_spec_functions): Added.
* gcc/c/gccspec.c (lang_register_spec_functions): Added.
* gcc/cp/g++spec.c (lang_register_spec_functions): Added.
* gcc/d/d-spec.cc (lang_register_spec_functions): Added.
* gcc/fortran/gfortranspec.c(lang_register_spec_functions): Added.
* gcc/gcc.c (allow_linker): Global variable to disable
linker by the front end.  (xputenv) available externally.
(xgetenv) New function.  (save_switch) available externally.
(fe_add_linker_option) New function.  (handle_OPT_B) New function.
(fe_add_infile) New function.  (fe_mark_compiled) New function.
(driver_handle_option) call handle_OPT_B.  (print_option) New
function.  (print_options) New function.  (dbg_options) New function.
(fe_add_spec_function) New function.  (lookup_spec_function)
checks front end registered functions.
(driver::set_up_specs):  call lang_register_spec_functions.
(maybe_run_linker): Check allow_linker before running the linker.
* gcc/gcc.h (fe_save_switch): Prototype.
(handle_OPT_B) Prototype.  (fe_add_infile) Prototype.
(fe_add_linker_option) Prototype.  (fe_add_spec_function) Prototype.
(xputenv) Prototype.  (xgetenv) Prototype.  (print_options) Prototype.
(print_option) Prototype.  (dbg_options) Prototype.
(lang_register_spec_functions) Prototype.
(allow_linker): Extern.
* gcc/go/gospec.c (lang_register_spec_functions): Added.

Patches
=======

Comments

Richard Biener Jan. 18, 2021, 10:19 a.m. UTC | #1
On Mon, Jan 18, 2021 at 2:09 AM Gaius Mulley via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
>
> Hello,
>
> here is a patch which merges the gm2 front end into the GCC tree.  The
> patches have been boostrapped under x86_64 GNU/Linux Debian Stretch
> built using make -j 24 and also under x86_64 GNU/Linux Debian Buster
> using make -j 4.
>
> Tested on Debian Stretch x86_64
> ===============================
>
> built GCC bootstrap 3 times:
>
> 1.  built vanilla GCC (enabling bootstrap) enabling front ends:
>     brig,c,c++,go,d,fortran and ran the regression tests.
>
> 2.  the patches below were applied and associated tarball untarred.
>     The same front ends brig,c,c++,go,d,fortran (again building from
>     bootstrap) were enabled (no m2) and ran the regression tests.
>     There were no changes to the regression test results between 1 and
>     2.
>
> 3.  Then it was rebuilt (from bootstrap) enabling the front ends
>     brig,c,c++,go,d,fortran,m2 and ran the
>     regression tests and again no extra failures were seen.
>
> [should I also be testing ada?]
>
> Built on Debian Buster x86_64
> =============================
>
> Built a patched tree enabling bootstrap make -j 4 for front ends c,c++,m2
> all compiled and bootstrapped.
>
> How to merge
> ============
>
> 1.  apply patches below to the master GCC tree.
>
> 2.  cd gcc-git-top
>     wget http://floppsie.comp.glam.ac.uk/download/c/gm2-front-end-20210116-tar.gz
>     tar zxf gm2-front-end-20210116-tar.gz
>     rm gm2-front-end-20210116-tar.gz
>     # new directories libgm2 and gcc/m2 are created and populated
>
> 3.  cd gcc-git-top
>     autogen Makefile.def
>     autoconf
>     cd libgm2
>     /bin/sh ./autogen.sh
>
> when built this implements iso, pim2, pim3 and pim4 editions of Modula-2
> with access to GCC features (gcc/m2/gm2.texi).
>
> hope this is useful - enjoy,

It looks like libgm2 is built independently on whether m2 is enabled or not?
I'd like to see a while-listing of supported targets like done for example
for libgomp via configure.tgt or for libgo (see toplevel configure).

The driver changes have been posted and reviewed previously but I
didn't see any real OK there but motivational questions - they never
were posted together with the m2 driver portion (I guess that would
be gcc/m2/gm2spec.c in the tarball).

I've not seen reviews or postings (besides as tarball) of the frontend
or the library (but I don't remember seeing extensive reviews of
other languages frontends or runtime portions at the point of their
inclusion - still the glueing to the middle-end should get the chance
to be reviewed).

I've tried to find my way through gcc/m2 but am quite lost in the
number of subdirectories.  I do see in gm2-lang.c and elsewhere
inclusion of system headers outside of system.h which is going
to be a portability problem.  From the parse_file langhook we
eventually dispatch to init_PerCompilationInit which looks
like a Modula-2 scaffolding file?  Is the compiler written in Modula-2?
It's not clear what parts make up the interface to the GCC middle-end.

I'm missing a patch for gcc/doc/install.texi which should list
requirements plus a patch to sourcebuild.texi listing the new
toplevel dirs (at least).

We don't usally ship "examples" in the GCC source tree,
there's a gm2-tools directory which name suggests those are
host tools which should usually reside in the toplevel.

There's copies of gpl and gpl-3.0.texi files in m2/ but I think
all .texi stuff (even language specific) should be in gcc/doc/
and not the lang specific subdirectory.

I've just tried following the merge instructions and a build
on SUSE Leap 15.2 produces a toplevel m2/ and stage{1,2,3,4}
directories (empty?!) which hints at some bootstrapping magic taking place?
In the end the build fails like the following in stage2

bash: ..//home/rguenther/src/trunk/gcc/m2/tools-src/makeversion: No
such file or directory
make[3]: *** [/home/rguenther/src/trunk/gcc/m2/Make-lang.in:111:
gm2version-check] Error 127
make[3]: *** Waiting for unfinished jobs....
/bin/sh: ..//home/rguenther/src/trunk/gcc/m2/configure: No such file
or directory
make[3]: *** [/home/rguenther/src/trunk/gcc/m2/Make-lang.in:1159:
m2/gm2config.h] Error 127

(sorry, parallel make), re-doing serial make ontop of the above yields

bash: ..//home/rguenther/src/trunk/gcc/m2/tools-src/makeversion: No
such file or directory
make[3]: *** [/home/rguenther/src/trunk/gcc/m2/Make-lang.in:111:
gm2version-check] Error 127

looks like

gm2version-check:
        cd m2 ; bash ../$(srcdir)/m2/tools-src/makeversion -p ../$(srcdir)
        $(STAMP) gm2version-check

is bogus (in particular using $(srcdir) as part of a relative path?)

I've just done ./configure --enable-languages=m2; make -j24

I would suggest to not rush this in now during stage4
but instead take the opportunity of this "quiet" phase
to prepare an integration branch with all the issues above
sorted out which we can merge at the beginning of stage1
for GCC 12 (or later during stage4 if everyone is happy
and/or backport for GCC 11.2 when it landed in trunk).

Thanks,
Richard.

> regards,
> Gaius
>
>
>
> 2021-01-18  Gaius Mulley   <gaiusmod2@gmail.com>
>
> * configure.ac (GM2_FOR_TARGET): Added.
> Request build driver program gm2.
> (libgm2) option added.
> (compare_exclusions) includes SYSTEM and M2Version.
> * Makefile.def (GM2_FOR_TARGET): Added.
> (GM2FLAGS_FOR_TARGET): Added.  Assign GM2,
> GM2_FOR_BUILD, GM2_FOR_TARGET and GM2FLAGS.
> Pass variables to make.  Add new language Modula-2
> (m2).  (target_modules) includes libgm2.  (flags_to_pass)
> includes GM2_FOR_TARGET and GM2FLAGS_FOR_TARGET.
> * Makefile.tpl (GM2FLAGS): Added.  (GM2) Added.
> (GM2_FOR_BUILD) Added.
>
> gcc/
>
> * gcc/brig/brigspec.c (lang_register_spec_functions): Added.
> * gcc/c-family/cppspec.c (lang_register_spec_functions): Added.
> * gcc/c/gccspec.c (lang_register_spec_functions): Added.
> * gcc/cp/g++spec.c (lang_register_spec_functions): Added.
> * gcc/d/d-spec.cc (lang_register_spec_functions): Added.
> * gcc/fortran/gfortranspec.c(lang_register_spec_functions): Added.
> * gcc/gcc.c (allow_linker): Global variable to disable
> linker by the front end.  (xputenv) available externally.
> (xgetenv) New function.  (save_switch) available externally.
> (fe_add_linker_option) New function.  (handle_OPT_B) New function.
> (fe_add_infile) New function.  (fe_mark_compiled) New function.
> (driver_handle_option) call handle_OPT_B.  (print_option) New
> function.  (print_options) New function.  (dbg_options) New function.
> (fe_add_spec_function) New function.  (lookup_spec_function)
> checks front end registered functions.
> (driver::set_up_specs):  call lang_register_spec_functions.
> (maybe_run_linker): Check allow_linker before running the linker.
> * gcc/gcc.h (fe_save_switch): Prototype.
> (handle_OPT_B) Prototype.  (fe_add_infile) Prototype.
> (fe_add_linker_option) Prototype.  (fe_add_spec_function) Prototype.
> (xputenv) Prototype.  (xgetenv) Prototype.  (print_options) Prototype.
> (print_option) Prototype.  (dbg_options) Prototype.
> (lang_register_spec_functions) Prototype.
> (allow_linker): Extern.
> * gcc/go/gospec.c (lang_register_spec_functions): Added.
>
> Patches
> =======
>
> diff --git a/Makefile.def b/Makefile.def
> index 3e38f61193f..ef428b98f40 100644
> --- a/Makefile.def
> +++ b/Makefile.def
> @@ -180,6 +180,7 @@ target_modules = { module= libffi; no_install=true; };
>  target_modules = { module= zlib; };
>  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; lib_path=.libs; };
> @@ -298,6 +299,8 @@ flags_to_pass = { flag= GOC_FOR_TARGET ; };
>  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 ; };
> @@ -652,6 +655,7 @@ languages = { language=obj-c++;     gcc-check-target=check-obj-c++; };
>  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; };
>  languages = { language=brig;   gcc-check-target=check-brig;
>                                 lib-check-target=check-target-libhsail-rt; };
>  languages = { language=d;      gcc-check-target=check-d;
> diff --git a/Makefile.tpl b/Makefile.tpl
> index 3b88f351d5b..fb1c3cfc47a 100644
> --- a/Makefile.tpl
> +++ b/Makefile.tpl
> @@ -161,6 +161,7 @@ BUILD_EXPORTS = \
>         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; \
>         LD="$(LD_FOR_BUILD)"; export LD; \
>         LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \
> @@ -198,6 +199,7 @@ HOST_EXPORTS = \
>         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; \
> @@ -296,6 +298,7 @@ BASE_TARGET_EXPORTS = \
>         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; \
>         LD="$(COMPILER_LD_FOR_TARGET)"; export LD; \
>         LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \
> @@ -362,6 +365,7 @@ DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@
>  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@
> @@ -431,6 +435,7 @@ CXXFLAGS = @CXXFLAGS@
>  LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates
>  GOCFLAGS = $(CFLAGS)
>  GDCFLAGS = $(CFLAGS)
> +GM2FLAGS = $(CFLAGS)
>
>  CREATE_GCOV = create_gcov
>
> @@ -518,6 +523,7 @@ RAW_CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @RAW_CXX_FOR_TARGET@
>  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@
>  LD_FOR_TARGET=@LD_FOR_TARGET@
>
> @@ -647,6 +653,7 @@ EXTRA_HOST_FLAGS = \
>         'GFORTRAN=$(GFORTRAN)' \
>         'GOC=$(GOC)' \
>         'GDC=$(GDC)' \
> +       'GM2=$(GM2)' \
>         'LD=$(LD)' \
>         'LIPO=$(LIPO)' \
>         'NM=$(NM)' \
> @@ -673,6 +680,7 @@ POSTSTAGE1_FLAGS_TO_PASS = \
>         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}" \
> @@ -707,6 +715,8 @@ EXTRA_TARGET_FLAGS = \
>         '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)' \
> @@ -733,6 +743,7 @@ TARGET_FLAGS_TO_PASS = $(BASE_FLAGS_TO_PASS) $(EXTRA_TARGET_FLAGS)
>  # 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=/'`"
>
> diff --git a/configure.ac b/configure.ac
> index 088e735c5db..917d5255997 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -163,6 +163,7 @@ target_libraries="target-libgcc \
>                 target-libffi \
>                 target-libobjc \
>                 target-libada \
> +               target-libgm2 \
>                 target-libgo \
>                 target-libphobos \
>                 target-zlib"
> @@ -452,6 +453,12 @@ if test "${ENABLE_LIBADA}" != "yes" ; then
>    noconfigdirs="$noconfigdirs gnattools"
>  fi
>
> +AC_ARG_ENABLE(libgm2,
> +[AS_HELP_STRING([--enable-libgm2], [build libgm2 directory])],
> +ENABLE_LIBGM2=$enableval,
> +ENABLE_LIBGM2=yes)
> +
> +
>  AC_ARG_ENABLE(libssp,
>  [AS_HELP_STRING([--enable-libssp], [build libssp directory])],
>  ENABLE_LIBSSP=$enableval,
> @@ -3504,6 +3511,7 @@ NCN_STRICT_CHECK_TARGET_TOOLS(GCC_FOR_TARGET, gcc, ${CC_FOR_TARGET})
>  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)
> @@ -3540,6 +3548,8 @@ GCC_TARGET_TOOL(gccgo, GOC_FOR_TARGET, GOC,
>                 [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])
> @@ -3666,6 +3676,8 @@ AC_SUBST(stage2_werror_flag)
>  # Specify what files to not compare during bootstrap.
>
>  compare_exclusions="gcc/cc*-checksum\$(objext) | gcc/ada/*tools/*"
> +compare_exclusions="$compare_exclusions | *m2/*/M2Version*\$(objext)"
> +compare_exclusions="$compare_exclusions | *m2/*/SYSTEM*\$(objext)"
>  case "$target" in
>    hppa*64*-*-hpux*) ;;
>    hppa*-*-hpux*) compare_exclusions="$compare_exclusions | */libgcc/lib2funcs* | gcc/function-tests.o" ;;
> diff --git a/gcc/brig/brigspec.c b/gcc/brig/brigspec.c
> index cbbc8ea076d..e10a1fb3023 100644
> --- a/gcc/brig/brigspec.c
> +++ b/gcc/brig/brigspec.c
> @@ -134,3 +134,11 @@ int lang_specific_pre_link (void) /* Not used for Brig.  */ { return 0; }
>  /* Number of extra output files that lang_specific_pre_link may generate.  */
>
>  int lang_specific_extra_outfiles = 0; /* Not used for Brig.  */
> +
> +/* lang_register_spec_functions register the Brig associated spec
> +   functions.  Not used for Brig.  */
> +
> +void
> +lang_register_spec_functions (void)
> +{
> +}
> diff --git a/gcc/c-family/cppspec.c b/gcc/c-family/cppspec.c
> index 65902b9f0d5..7a1f8d10a21 100644
> --- a/gcc/c-family/cppspec.c
> +++ b/gcc/c-family/cppspec.c
> @@ -198,3 +198,9 @@ int lang_specific_pre_link (void)
>
>  /* 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 --git a/gcc/c/gccspec.c b/gcc/c/gccspec.c
> index db353a35585..67af876eb99 100644
> --- a/gcc/c/gccspec.c
> +++ b/gcc/c/gccspec.c
> @@ -105,3 +105,9 @@ lang_specific_pre_link (void)
>
>  /* 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 --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c
> index 3c9bd1490b4..88a302c2157 100644
> --- a/gcc/cp/g++spec.c
> +++ b/gcc/cp/g++spec.c
> @@ -434,3 +434,9 @@ int lang_specific_pre_link (void)  /* Not used for C++.  */
>
>  /* 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 --git a/gcc/d/d-spec.cc b/gcc/d/d-spec.cc
> index 16ff1539e9f..e2fb787f5e1 100644
> --- a/gcc/d/d-spec.cc
> +++ b/gcc/d/d-spec.cc
> @@ -490,3 +490,10 @@ lang_specific_pre_link (void)
>
>  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 --git a/gcc/fortran/gfortranspec.c b/gcc/fortran/gfortranspec.c
> index 97db139deea..4c6045b9f06 100644
> --- a/gcc/fortran/gfortranspec.c
> +++ b/gcc/fortran/gfortranspec.c
> @@ -447,4 +447,12 @@ lang_specific_pre_link (void)
>  }
>
>  /* 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 --git a/gcc/gcc.c b/gcc/gcc.c
> index 7dccfadfef2..27ef1f1bf07 100644
> --- a/gcc/gcc.c
> +++ b/gcc/gcc.c
> @@ -328,6 +328,10 @@ static const char *cross_compile = "1";
>  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;
> @@ -356,7 +360,6 @@ static void set_spec (const char *, const char *, bool);
>  static struct compiler *lookup_compiler (const char *, size_t, const char *);
>  static char *build_search_list (const struct path_prefix *, const char *,
>                                 bool, bool);
> -static void xputenv (const char *);
>  static void putenv_from_prefixes (const struct path_prefix *, const char *,
>                                   bool);
>  static int access_check (const char *, int);
> @@ -1775,6 +1779,10 @@ static const struct spec_function static_spec_functions[] =
>    { 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
> @@ -2937,12 +2945,20 @@ add_to_obstack (char *path, void *data)
>
>  /* Add or change the value of an environment variable, outputting the
>     change to standard error if in verbose mode.  */
> -static void
> +void
>  xputenv (const char *string)
>  {
>    env.xput (string);
>  }
>
> +/* Get the environment variable through the managed env.  */
> +
> +const char *
> +xgetenv (const char *key)
> +{
> +  return env.get (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.
> @@ -3871,7 +3887,7 @@ alloc_switch (void)
>  /* Save an option OPT with N_ARGS arguments in array ARGS, marking it
>     as validated if VALIDATED and KNOWN if it is an internal switch.  */
>
> -static void
> +void
>  save_switch (const char *opt, size_t n_args, const char *const *args,
>              bool validated, bool known)
>  {
> @@ -3916,6 +3932,66 @@ set_source_date_epoch_envvar ()
>    setenv ("SOURCE_DATE_EPOCH", source_date_epoch, 0);
>  }
>
> +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.  */
> +
> +void
> +handle_OPT_B (const char *arg)
> +{
> +  size_t len = strlen (arg);
> +
> +  /* Catch the case where the user has forgotten to append a
> +     directory separator to the path.  Note, they may be using
> +     -B to add an executable name prefix, eg "i386-elf-", in
> +     order to distinguish between multiple installations of
> +     GCC in the same directory.  Hence we must check to see
> +     if appending a directory separator actually makes a
> +     valid directory name.  */
> +  if (!IS_DIR_SEPARATOR (arg[len - 1])
> +      && is_directory (arg, false))
> +    {
> +      char *tmp = XNEWVEC (char, len + 2);
> +      strcpy (tmp, arg);
> +      tmp[len] = DIR_SEPARATOR;
> +      tmp[++len] = 0;
> +      arg = tmp;
> +    }
> +
> +  add_prefix (&exec_prefixes, arg, NULL,
> +             PREFIX_PRIORITY_B_OPT, 0, 0);
> +  add_prefix (&startfile_prefixes, arg, NULL,
> +             PREFIX_PRIORITY_B_OPT, 0, 0);
> +  add_prefix (&include_prefixes, arg, NULL,
> +             PREFIX_PRIORITY_B_OPT, 0, 0);
> +}
> +
> +/* Save the infile.  */
> +
> +void
> +fe_add_infile (const char *infile, const char *lang)
> +{
> +  add_infile (infile, lang);
> +}
> +
> +/* 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.  */
>
> @@ -4417,33 +4493,7 @@ driver_handle_option (struct gcc_options *opts,
>        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;
>
> @@ -4566,6 +4616,68 @@ single_input_file_index ()
>    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);
> +  printf (" value [%ld]", 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'.  */
>
> @@ -6752,6 +6864,33 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
>    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 *
> @@ -6763,6 +6902,11 @@ lookup_spec_function (const char *name)
>      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;
>  }
>
> @@ -8249,6 +8393,8 @@ driver::set_up_specs () const
>                            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"))
> @@ -8979,7 +9125,8 @@ driver::maybe_run_linker (const char *argv0) const
>
>    /* 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;
>
> @@ -9048,7 +9195,7 @@ driver::maybe_run_linker (const char *argv0) const
>    /* 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 --git a/gcc/gcc.h b/gcc/gcc.h
> index 244edbc26c6..217352fef73 100644
> --- a/gcc/gcc.h
> +++ b/gcc/gcc.h
> @@ -73,9 +73,28 @@ struct spec_function
>  extern int do_spec (const char *);
>  extern void record_temp_file (const char *, int, int);
>  extern void set_input (const char *);
> +extern void save_switch (const char *opt, size_t n_args,
> +                        const char *const *args,
> +                        bool validated, bool known);
> +extern void handle_OPT_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 xputenv (const char *value);
> +extern const char *xgetenv (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.c 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 @@ driver_get_configure_time_options (void (*cb)(const char *option,
>                                               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 --git a/gcc/go/gospec.c b/gcc/go/gospec.c
> index aaf64e73949..3a4f50e2fc9 100644
> --- a/gcc/go/gospec.c
> +++ b/gcc/go/gospec.c
> @@ -440,3 +440,9 @@ int lang_specific_pre_link (void)  /* Not used for Go.  */
>
>  /* 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)
> +{
> +}
Matthias Klose Jan. 18, 2021, 12:26 p.m. UTC | #2
On 1/18/21 2:09 AM, Gaius Mulley via Gcc-patches wrote:
> gcc/
> 
> * gcc/brig/brigspec.c (lang_register_spec_functions): Added.
> * gcc/c-family/cppspec.c (lang_register_spec_functions): Added.
> * gcc/c/gccspec.c (lang_register_spec_functions): Added.
> * gcc/cp/g++spec.c (lang_register_spec_functions): Added.
> * gcc/d/d-spec.cc (lang_register_spec_functions): Added.
> * gcc/fortran/gfortranspec.c(lang_register_spec_functions): Added.
> * gcc/gcc.c (allow_linker): Global variable to disable
> linker by the front end.  (xputenv) available externally.
> (xgetenv) New function.  (save_switch) available externally.
> (fe_add_linker_option) New function.  (handle_OPT_B) New function.
> (fe_add_infile) New function.  (fe_mark_compiled) New function.
> (driver_handle_option) call handle_OPT_B.  (print_option) New
> function.  (print_options) New function.  (dbg_options) New function.
> (fe_add_spec_function) New function.  (lookup_spec_function)
> checks front end registered functions.
> (driver::set_up_specs):  call lang_register_spec_functions.
> (maybe_run_linker): Check allow_linker before running the linker.
> * gcc/gcc.h (fe_save_switch): Prototype.
> (handle_OPT_B) Prototype.  (fe_add_infile) Prototype.
> (fe_add_linker_option) Prototype.  (fe_add_spec_function) Prototype.
> (xputenv) Prototype.  (xgetenv) Prototype.  (print_options) Prototype.
> (print_option) Prototype.  (dbg_options) Prototype.
> (lang_register_spec_functions) Prototype.
> (allow_linker): Extern.
> * gcc/go/gospec.c (lang_register_spec_functions): Added.

this is mising the definition of lang_register_spec_functions for the jit build.

2020-03-23  Matthias Klose  <doko@ubuntu.com>

        * jit-spec.c (lang_register_spec_functions): New, not used for jit.


--- a/gcc/jit/jit-spec.c
+++ b/gcc/jit/jit-spec.c
@@ -39,3 +39,9 @@ lang_specific_pre_link (void)

 /* 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)
+{
+}
Gaius Mulley Jan. 18, 2021, 1:55 p.m. UTC | #3
Richard Biener <richard.guenther@gmail.com> writes:

Hello Richard,

many thanks for taking the time to review the patches and tarball.

> It looks like libgm2 is built independently on whether m2 is enabled or not?
> I'd like to see a while-listing of supported targets like done for example
> for libgomp via configure.tgt or for libgo (see toplevel configure).

ok thanks for the pointers - will do.

> The driver changes have been posted and reviewed previously but I
> didn't see any real OK there but motivational questions - they never
> were posted together with the m2 driver portion (I guess that would
> be gcc/m2/gm2spec.c in the tarball).

yes true.

> I've not seen reviews or postings (besides as tarball) of the frontend
> or the library (but I don't remember seeing extensive reviews of
> other languages frontends or runtime portions at the point of their
> inclusion - still the glueing to the middle-end should get the chance
> to be reviewed).

the glue code for gm2 is in the directory gcc/m2/gm2-gcc which is
implemented in C and associated matching C header and M2 definition
modules.

> I've tried to find my way through gcc/m2 but am quite lost in the
> number of subdirectories.  I do see in gm2-lang.c and elsewhere
> inclusion of system headers outside of system.h which is going
> to be a portability problem.

ah thanks for spotting this - will fix.

> From the parse_file langhook we eventually dispatch to
> init_PerCompilationInit which looks like a Modula-2 scaffolding file?
> Is the compiler written in Modula-2?

yes mainly written in Modula-2, the sources are in gcc/m2/gm2-compiler,
core libraries are in gcc/m2/gm2-libs.  These are converted into C++
files during the build using the translator in gcc/m2/mc (gcc/m2/mc-boot
C++ version).  (For developers the Modula-2 compiler sources can be
built using stage1 gm2 later on).  All libraries are eventually compiled
by gm2 for target of course.

> It's not clear what parts make up the interface to the GCC middle-end.

the interface to the GCC middle-end is in gcc/m2/gm2-gcc which are
called by the front end sources in gcc/m2/gm2-compiler.  For example the
main declarations are performed by gcc/m2/gm2-compiler/M2GCCDeclare.mod
and the code trees are produced by gcc/m2/gm2-compiler/M2GenGCC.mod.

> I'm missing a patch for gcc/doc/install.texi which should list
> requirements plus a patch to sourcebuild.texi listing the new
> toplevel dirs (at least).

ah thank you yes I missed this.

> We don't usally ship "examples" in the GCC source tree,
> there's a gm2-tools directory which name suggests those are
> host tools which should usually reside in the toplevel.

ok sure, maybe best to move the examples into the regression test suite
and move the minimal number of gm2-tools required into the toplevel.

> There's copies of gpl and gpl-3.0.texi files in m2/ but I think
> all .texi stuff (even language specific) should be in gcc/doc/
> and not the lang specific subdirectory.

yes indeed sounds good and clean.

> I've just tried following the merge instructions and a build
> on SUSE Leap 15.2 produces a toplevel m2/ and stage{1,2,3,4}
> directories (empty?!) which hints at some bootstrapping magic taking place?
> In the end the build fails like the following in stage2
>
> bash: ..//home/rguenther/src/trunk/gcc/m2/tools-src/makeversion: No
> such file or directory
> make[3]: *** [/home/rguenther/src/trunk/gcc/m2/Make-lang.in:111:
> gm2version-check] Error 127
> make[3]: *** Waiting for unfinished jobs....
> /bin/sh: ..//home/rguenther/src/trunk/gcc/m2/configure: No such file
> or directory
> make[3]: *** [/home/rguenther/src/trunk/gcc/m2/Make-lang.in:1159:
> m2/gm2config.h] Error 127
>
> (sorry, parallel make), re-doing serial make ontop of the above yields
>
> bash: ..//home/rguenther/src/trunk/gcc/m2/tools-src/makeversion: No
> such file or directory
> make[3]: *** [/home/rguenther/src/trunk/gcc/m2/Make-lang.in:111:
> gm2version-check] Error 127
>
> looks like
>
> gm2version-check:
>         cd m2 ; bash ../$(srcdir)/m2/tools-src/makeversion -p ../$(srcdir)
>         $(STAMP) gm2version-check
>
> is bogus (in particular using $(srcdir) as part of a relative path?)

ah very sorry - yes - I'll fix this.

> I've just done ./configure --enable-languages=m2; make -j24
>
> I would suggest to not rush this in now during stage4
> but instead take the opportunity of this "quiet" phase
> to prepare an integration branch with all the issues above
> sorted out which we can merge at the beginning of stage1
> for GCC 12 (or later during stage4 if everyone is happy
> and/or backport for GCC 11.2 when it landed in trunk).

ok sure - this sounds a good plan

regards,
Gaius
Gaius Mulley Jan. 18, 2021, 7:16 p.m. UTC | #4
Matthias Klose <doko@ubuntu.com> writes:

> this is mising the definition of lang_register_spec_functions for the jit build.
>
> 2020-03-23  Matthias Klose  <doko@ubuntu.com>
>
>         * jit-spec.c (lang_register_spec_functions): New, not used for jit.
>
>
> --- a/gcc/jit/jit-spec.c
> +++ b/gcc/jit/jit-spec.c
> @@ -39,3 +39,9 @@ lang_specific_pre_link (void)
>
>  /* 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)
> +{
> +}

Hello Matthias,

thanks for spotting this - yes - quite correct,
Matthias Klose May 27, 2021, 12:02 p.m. UTC | #5
On 1/18/21 2:55 PM, Gaius Mulley via Gcc-patches wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> I've just done ./configure --enable-languages=m2; make -j24
>>
>> I would suggest to not rush this in now during stage4
>> but instead take the opportunity of this "quiet" phase
>> to prepare an integration branch with all the issues above
>> sorted out which we can merge at the beginning of stage1
>> for GCC 12 (or later during stage4 if everyone is happy
>> and/or backport for GCC 11.2 when it landed in trunk).
> 
> ok sure - this sounds a good plan

Gaius, now with the 1.1 relase out of the door, please could you clarify about
your plans getting this into trunk, and do you plan to get this into 11.2 as well?

Thanks, Matthias
Gaius Mulley May 27, 2021, 2 p.m. UTC | #6
Matthias Klose <doko@ubuntu.com> writes:

> On 1/18/21 2:55 PM, Gaius Mulley via Gcc-patches wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> I've just done ./configure --enable-languages=m2; make -j24
>>>
>>> I would suggest to not rush this in now during stage4
>>> but instead take the opportunity of this "quiet" phase
>>> to prepare an integration branch with all the issues above
>>> sorted out which we can merge at the beginning of stage1
>>> for GCC 12 (or later during stage4 if everyone is happy
>>> and/or backport for GCC 11.2 when it landed in trunk).
>>
>> ok sure - this sounds a good plan
>
> Gaius, now with the 1.1 relase out of the door, please could you clarify about
> your plans getting this into trunk, and do you plan to get this into 11.2 as well?
>
> Thanks, Matthias

Hi Matthias,

sure yes - I plan on getting it into trunk and then backporting it to
11.2.  If anyone with copyright assignment wants to expedite this - feel
free to forge ahead (and post patches).  I'm working though Richard's
review:

 https://gcc.gnu.org/pipermail/gcc-patches/2021-January/563747.html

and should be able to post the latest patch set in say 2 weeks
time (for trunk) - would that time frame work?


regards,
Gaius
Gaius Mulley June 10, 2021, 3 p.m. UTC | #7
Matthias Klose <doko@ubuntu.com> writes:

> On 1/18/21 2:55 PM, Gaius Mulley via Gcc-patches wrote:
>> Richard Biener <richard.guenther@gmail.com> writes:
>>> I've just done ./configure --enable-languages=m2; make -j24
>>>
>>> I would suggest to not rush this in now during stage4
>>> but instead take the opportunity of this "quiet" phase
>>> to prepare an integration branch with all the issues above
>>> sorted out which we can merge at the beginning of stage1
>>> for GCC 12 (or later during stage4 if everyone is happy
>>> and/or backport for GCC 11.2 when it landed in trunk).
>>
>> ok sure - this sounds a good plan
>
> Gaius, now with the 1.1 relase out of the door, please could you clarify about
> your plans getting this into trunk, and do you plan to get this into 11.2 as well?
>
> Thanks, Matthias

Hello Matthias and Richard,

just a small update to say that I think all the code changes are done -
I've a tiny amount of documentation texinfo file moving / reorganising
then testing and then the patches will be posted.


regards,
Gaius
diff mbox series

Patch

diff --git a/Makefile.def b/Makefile.def
index 3e38f61193f..ef428b98f40 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -180,6 +180,7 @@  target_modules = { module= libffi; no_install=true; };
 target_modules = { module= zlib; };
 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; lib_path=.libs; };
@@ -298,6 +299,8 @@  flags_to_pass = { flag= GOC_FOR_TARGET ; };
 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 ; };
@@ -652,6 +655,7 @@  languages = { language=obj-c++;	gcc-check-target=check-obj-c++; };
 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; };
 languages = { language=brig;	gcc-check-target=check-brig;
 				lib-check-target=check-target-libhsail-rt; };
 languages = { language=d;	gcc-check-target=check-d;
diff --git a/Makefile.tpl b/Makefile.tpl
index 3b88f351d5b..fb1c3cfc47a 100644
--- a/Makefile.tpl
+++ b/Makefile.tpl
@@ -161,6 +161,7 @@  BUILD_EXPORTS = \
 	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; \
 	LD="$(LD_FOR_BUILD)"; export LD; \
 	LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \
@@ -198,6 +199,7 @@  HOST_EXPORTS = \
 	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; \
@@ -296,6 +298,7 @@  BASE_TARGET_EXPORTS = \
 	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; \
 	LD="$(COMPILER_LD_FOR_TARGET)"; export LD; \
 	LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \
@@ -362,6 +365,7 @@  DLLTOOL_FOR_BUILD = @DLLTOOL_FOR_BUILD@
 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@
@@ -431,6 +435,7 @@  CXXFLAGS = @CXXFLAGS@
 LIBCXXFLAGS = $(CXXFLAGS) -fno-implicit-templates
 GOCFLAGS = $(CFLAGS)
 GDCFLAGS = $(CFLAGS)
+GM2FLAGS = $(CFLAGS)

 CREATE_GCOV = create_gcov

@@ -518,6 +523,7 @@  RAW_CXX_FOR_TARGET=$(STAGE_CC_WRAPPER) @RAW_CXX_FOR_TARGET@
 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@
 LD_FOR_TARGET=@LD_FOR_TARGET@

@@ -647,6 +653,7 @@  EXTRA_HOST_FLAGS = \
 	'GFORTRAN=$(GFORTRAN)' \
 	'GOC=$(GOC)' \
 	'GDC=$(GDC)' \
+	'GM2=$(GM2)' \
 	'LD=$(LD)' \
 	'LIPO=$(LIPO)' \
 	'NM=$(NM)' \
@@ -673,6 +680,7 @@  POSTSTAGE1_FLAGS_TO_PASS = \
 	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}" \
@@ -707,6 +715,8 @@  EXTRA_TARGET_FLAGS = \
 	'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)' \
@@ -733,6 +743,7 @@  TARGET_FLAGS_TO_PASS = $(BASE_FLAGS_TO_PASS) $(EXTRA_TARGET_FLAGS)
 # 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=/'`"

diff --git a/configure.ac b/configure.ac
index 088e735c5db..917d5255997 100644
--- a/configure.ac
+++ b/configure.ac
@@ -163,6 +163,7 @@  target_libraries="target-libgcc \
 		target-libffi \
 		target-libobjc \
 		target-libada \
+		target-libgm2 \
 		target-libgo \
 		target-libphobos \
 		target-zlib"
@@ -452,6 +453,12 @@  if test "${ENABLE_LIBADA}" != "yes" ; then
   noconfigdirs="$noconfigdirs gnattools"
 fi

+AC_ARG_ENABLE(libgm2,
+[AS_HELP_STRING([--enable-libgm2], [build libgm2 directory])],
+ENABLE_LIBGM2=$enableval,
+ENABLE_LIBGM2=yes)
+
+
 AC_ARG_ENABLE(libssp,
 [AS_HELP_STRING([--enable-libssp], [build libssp directory])],
 ENABLE_LIBSSP=$enableval,
@@ -3504,6 +3511,7 @@  NCN_STRICT_CHECK_TARGET_TOOLS(GCC_FOR_TARGET, gcc, ${CC_FOR_TARGET})
 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)
@@ -3540,6 +3548,8 @@  GCC_TARGET_TOOL(gccgo, GOC_FOR_TARGET, GOC,
 		[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])
@@ -3666,6 +3676,8 @@  AC_SUBST(stage2_werror_flag)
 # Specify what files to not compare during bootstrap.

 compare_exclusions="gcc/cc*-checksum\$(objext) | gcc/ada/*tools/*"
+compare_exclusions="$compare_exclusions | *m2/*/M2Version*\$(objext)"
+compare_exclusions="$compare_exclusions | *m2/*/SYSTEM*\$(objext)"
 case "$target" in
   hppa*64*-*-hpux*) ;;
   hppa*-*-hpux*) compare_exclusions="$compare_exclusions | */libgcc/lib2funcs* | gcc/function-tests.o" ;;
diff --git a/gcc/brig/brigspec.c b/gcc/brig/brigspec.c
index cbbc8ea076d..e10a1fb3023 100644
--- a/gcc/brig/brigspec.c
+++ b/gcc/brig/brigspec.c
@@ -134,3 +134,11 @@  int lang_specific_pre_link (void) /* Not used for Brig.  */ { return 0; }
 /* Number of extra output files that lang_specific_pre_link may generate.  */

 int lang_specific_extra_outfiles = 0; /* Not used for Brig.  */
+
+/* lang_register_spec_functions register the Brig associated spec
+   functions.  Not used for Brig.  */
+
+void
+lang_register_spec_functions (void)
+{
+}
diff --git a/gcc/c-family/cppspec.c b/gcc/c-family/cppspec.c
index 65902b9f0d5..7a1f8d10a21 100644
--- a/gcc/c-family/cppspec.c
+++ b/gcc/c-family/cppspec.c
@@ -198,3 +198,9 @@  int lang_specific_pre_link (void)

 /* 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 --git a/gcc/c/gccspec.c b/gcc/c/gccspec.c
index db353a35585..67af876eb99 100644
--- a/gcc/c/gccspec.c
+++ b/gcc/c/gccspec.c
@@ -105,3 +105,9 @@  lang_specific_pre_link (void)

 /* 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 --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c
index 3c9bd1490b4..88a302c2157 100644
--- a/gcc/cp/g++spec.c
+++ b/gcc/cp/g++spec.c
@@ -434,3 +434,9 @@  int lang_specific_pre_link (void)  /* Not used for C++.  */

 /* 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 --git a/gcc/d/d-spec.cc b/gcc/d/d-spec.cc
index 16ff1539e9f..e2fb787f5e1 100644
--- a/gcc/d/d-spec.cc
+++ b/gcc/d/d-spec.cc
@@ -490,3 +490,10 @@  lang_specific_pre_link (void)

 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 --git a/gcc/fortran/gfortranspec.c b/gcc/fortran/gfortranspec.c
index 97db139deea..4c6045b9f06 100644
--- a/gcc/fortran/gfortranspec.c
+++ b/gcc/fortran/gfortranspec.c
@@ -447,4 +447,12 @@  lang_specific_pre_link (void)
 }

 /* 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 --git a/gcc/gcc.c b/gcc/gcc.c
index 7dccfadfef2..27ef1f1bf07 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -328,6 +328,10 @@  static const char *cross_compile = "1";
 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;
@@ -356,7 +360,6 @@  static void set_spec (const char *, const char *, bool);
 static struct compiler *lookup_compiler (const char *, size_t, const char *);
 static char *build_search_list (const struct path_prefix *, const char *,
 				bool, bool);
-static void xputenv (const char *);
 static void putenv_from_prefixes (const struct path_prefix *, const char *,
 				  bool);
 static int access_check (const char *, int);
@@ -1775,6 +1779,10 @@  static const struct spec_function static_spec_functions[] =
   { 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
@@ -2937,12 +2945,20 @@  add_to_obstack (char *path, void *data)

 /* Add or change the value of an environment variable, outputting the
    change to standard error if in verbose mode.  */
-static void
+void
 xputenv (const char *string)
 {
   env.xput (string);
 }

+/* Get the environment variable through the managed env.  */
+
+const char *
+xgetenv (const char *key)
+{
+  return env.get (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.
@@ -3871,7 +3887,7 @@  alloc_switch (void)
 /* Save an option OPT with N_ARGS arguments in array ARGS, marking it
    as validated if VALIDATED and KNOWN if it is an internal switch.  */

-static void
+void
 save_switch (const char *opt, size_t n_args, const char *const *args,
 	     bool validated, bool known)
 {
@@ -3916,6 +3932,66 @@  set_source_date_epoch_envvar ()
   setenv ("SOURCE_DATE_EPOCH", source_date_epoch, 0);
 }

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

@@ -4417,33 +4493,7 @@  driver_handle_option (struct gcc_options *opts,
       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;

@@ -4566,6 +4616,68 @@  single_input_file_index ()
   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);
+  printf (" value [%ld]", 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'.  */

@@ -6752,6 +6864,33 @@  do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
   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 *
@@ -6763,6 +6902,11 @@  lookup_spec_function (const char *name)
     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;
 }

@@ -8249,6 +8393,8 @@  driver::set_up_specs () const
 			   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"))
@@ -8979,7 +9125,8 @@  driver::maybe_run_linker (const char *argv0) const

   /* 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;

@@ -9048,7 +9195,7 @@  driver::maybe_run_linker (const char *argv0) const
   /* 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 --git a/gcc/gcc.h b/gcc/gcc.h
index 244edbc26c6..217352fef73 100644
--- a/gcc/gcc.h
+++ b/gcc/gcc.h
@@ -73,9 +73,28 @@  struct spec_function
 extern int do_spec (const char *);
 extern void record_temp_file (const char *, int, int);
 extern void set_input (const char *);
+extern void save_switch (const char *opt, size_t n_args,
+			 const char *const *args,
+			 bool validated, bool known);
+extern void handle_OPT_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 xputenv (const char *value);
+extern const char *xgetenv (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.c 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 @@  driver_get_configure_time_options (void (*cb)(const char *option,
 					      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 --git a/gcc/go/gospec.c b/gcc/go/gospec.c
index aaf64e73949..3a4f50e2fc9 100644
--- a/gcc/go/gospec.c
+++ b/gcc/go/gospec.c
@@ -440,3 +440,9 @@  int lang_specific_pre_link (void)  /* Not used for Go.  */

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