[PATCH] Libraries' configure scripts should not read config-ml.in when multilib is disabled

2018-07-30 Thread John Ericson
Currently some multilib variables are initialized, and config.ml.in 
instantiated, whether or not a multilib build is being performed. I ran 
into this because I am building the runtime libraries (libatomic right 
now) separately from GCC. Multilib is disabled, and no multilib 
variables are set, yet the configure script fails after it cannot find 
`${multi_basedir}/config-ml.in`.


I understand this building them separately is not supported, but am 
nevertheless hoping the patch can nevertheless be upstreamed on the 
grounds that this generally cleans up the build system in accordance 
with the principle that "feature foo" variables need not be written and 
should not be read when feature foo is disabled. libgcc's configure 
script, for example, has some similar-looking bespoke m4 script with `. 
${libgcc_topdir}/config-ml.in` instead, side-stepping the issue. Perhaps 
with this fixed, all the libraries could use the same macro. [I suppose 
I'd be willing to investigate that.]


Thanks,

John

[Continuing from https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86746. Did 
not know this sort of thing should exclusively go to this list. My 
apologies.]


From 3e0e7d6e5cfdc46342fcad5fe6b24b4f47af0d87 Mon Sep 17 00:00:00 2001
Message-Id: 
<3e0e7d6e5cfdc46342fcad5fe6b24b4f47af0d87.1532988611.git.John.Ericson@Obsidian.Systems>
From: John Ericson 
Date: Mon, 30 Jul 2018 18:06:02 -0400
Subject: [PATCH] multilib: Don't bother with multilib configuration
To: gcc-patches@gcc.gnu.org

* config/multi.m4: Don't bother with multilib configuration when
it is disabled.
---
 ChangeLog   |  5 +
 config/multi.m4 | 50 +++--
 2 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4bc5123c84e..2445071bea4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2018-07-30  John Ericson  
+
+   * config/multi.m4: Don't bother with multilib configuration when it
+   is disabled.
+
 2018-07-19  DJ Delorie  
 
* MAINTAINERS (m32c, msp43, rl78, libiberty, build): Remove myself
diff --git a/config/multi.m4 b/config/multi.m4
index bba338a8265..f5081155564 100644
--- a/config/multi.m4
+++ b/config/multi.m4
@@ -20,40 +20,45 @@ AC_ARG_ENABLE(multilib,
   no)  multilib=no ;;
   *)   AC_MSG_ERROR([bad value $enableval for multilib option]) ;;
  esac],
- [multilib=yes])
+[multilib=yes])
 
-# We may get other options which we leave undocumented:
-# --with-target-subdir, --with-multisrctop, --with-multisubdir
-# See config-ml.in if you want the gory details.
+if test "x$multilib" = xyes; then
 
-if test "$srcdir" = "."; then
-  if test "$with_target_subdir" != "."; then
-multi_basedir="$srcdir/$with_multisrctop../$2"
+  # We may get other options which we leave undocumented:
+  # --with-target-subdir, --with-multisrctop, --with-multisubdir
+  # See config-ml.in if you want the gory details.
+
+  if test "$srcdir" = "."; then
+if test "$with_target_subdir" != "."; then
+  multi_basedir="$srcdir/$with_multisrctop../$2"
+else
+  multi_basedir="$srcdir/$with_multisrctop$2"
+fi
   else
-multi_basedir="$srcdir/$with_multisrctop$2"
+multi_basedir="$srcdir/$2"
+  fi
+  AC_SUBST(multi_basedir)
+
+  # Even if the default multilib is not a cross compilation,
+  # it may be that some of the other multilibs are.
+  if test $cross_compiling = no && test $multilib = yes \
+ && test "x${with_multisubdir}" != x ; then
+ cross_compiling=maybe
   fi
-else
-  multi_basedir="$srcdir/$2"
-fi
-AC_SUBST(multi_basedir)
 
-# Even if the default multilib is not a cross compilation,
-# it may be that some of the other multilibs are.
-if test $cross_compiling = no && test $multilib = yes \
-   && test "x${with_multisubdir}" != x ; then
-   cross_compiling=maybe
 fi
 
-AC_OUTPUT_COMMANDS([
+AC_CONFIG_COMMANDS([config-ml],
+[if test "x$multilib" = xyes; then
 # Only add multilib support code if we just rebuilt the top-level
 # Makefile.
 case " $CONFIG_FILES " in
  *" ]m4_default([$1],Makefile)[ "*)
ac_file=]m4_default([$1],Makefile)[ . ${multi_basedir}/config-ml.in
;;
-esac],
-  [
-srcdir="$srcdir"
+esac
+fi],
+[srcdir="$srcdir"
 host="$host"
 target="$target"
 with_multisubdir="$with_multisubdir"
@@ -64,4 +69,5 @@ multi_basedir="$multi_basedir"
 CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
 CC="$CC"
 CXX="$CXX"
-GFORTRAN="$GFORTRAN"])])dnl
+GFORTRAN="$GFORTRAN"])
+])dnl
-- 
2.17.1



Re: [PATCH] Libraries' configure scripts should not read config-ml.in when multilib is disabled

2018-07-30 Thread John Ericson

On 07/30/18 19:48, Joseph Myers wrote:

On the contrary, I think an important principle here is that non-multilib
and multilib builds follow the same code paths as far as possible, with
the multilib variables just set to trivial values (modulo osdirname) in
the case of a non-multilib build - a non-multilib build should be building
libraries exactly the same, with the same logic and the same variable
settings, as the default multilib in a multilib build.
I whole-heatedly agree with that principle. [FWIW, I've taken a similar 
approach with keeping the cross and native compilation code paths as 
close as possible. This is why I'm building the libraries separately in 
the first place.]


That said, it is my tentative understanding that the point of having 
config-ml is to cordon-off all the necessarily-multilib-specific logic 
so it doesn't pollute everything else. When that script isn't run, I 
think the Makefiles already contain default "trivial values" for 
capitalized MULTI* variables (which are the only ones actually used by 
the build itself), yielding precisely that deduplication of code paths 
we both want.


John


[PATCH] Factor out `find_a_program` helper around `find_a_file`

2021-08-04 Thread John Ericson
The helper is for `--print-prog-name` and similar things. Since all
executable finding goes through it, we can move the default overrides
into that path too. This also ensures that if some is looking for a
*non*-program that called `as`, `ld`, etc., weird things don't happen.
---
 gcc/gcc.c | 59 ---
 1 file changed, 34 insertions(+), 25 deletions(-)

diff --git a/gcc/gcc.c b/gcc/gcc.c
index 3e98bc7973e..1a74bf92f7a 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -367,6 +367,7 @@ static void putenv_from_prefixes (const struct path_prefix 
*, const char *,
  bool);
 static int access_check (const char *, int);
 static char *find_a_file (const struct path_prefix *, const char *, int, bool);
+static char *find_a_program (const char *);
 static void add_prefix (struct path_prefix *, const char *, const char *,
int, int, int);
 static void add_sysrooted_prefix (struct path_prefix *, const char *,
@@ -3052,22 +3053,7 @@ find_a_file (const struct path_prefix *pprefix, const 
char *name, int mode,
 {
   struct file_at_path_info info;
 
-#ifdef DEFAULT_ASSEMBLER
-  if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
-return xstrdup (DEFAULT_ASSEMBLER);
-#endif
-
-#ifdef DEFAULT_LINKER
-  if (! strcmp (name, "ld") && access (DEFAULT_LINKER, mode) == 0)
-return xstrdup (DEFAULT_LINKER);
-#endif
-
-#ifdef DEFAULT_DSYMUTIL
-  if (! strcmp (name, "dsymutil") && access (DEFAULT_DSYMUTIL, mode) == 0)
-return xstrdup (DEFAULT_DSYMUTIL);
-#endif
-
-  /* Determine the filename to execute (special case for absolute paths).  */
+  /* Find the filename in question (special case for absolute paths).  */
 
   if (IS_ABSOLUTE_PATH (name))
 {
@@ -3088,6 +3074,32 @@ find_a_file (const struct path_prefix *pprefix, const 
char *name, int mode,
file_at_path, &info);
 }
 
+/* Specialization of find_a_file for programs that also takes into account
+   configure-specified default programs. */
+
+static char*
+find_a_program (const char *name)
+{
+  /* Do not search if default matches query. */
+
+#ifdef DEFAULT_ASSEMBLER
+  if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
+return xstrdup (DEFAULT_ASSEMBLER);
+#endif
+
+#ifdef DEFAULT_LINKER
+  if (! strcmp (name, "ld") && access (DEFAULT_LINKER, mode) == 0)
+return xstrdup (DEFAULT_LINKER);
+#endif
+
+#ifdef DEFAULT_DSYMUTIL
+  if (! strcmp (name, "dsymutil") && access (DEFAULT_DSYMUTIL, mode) == 0)
+return xstrdup (DEFAULT_DSYMUTIL);
+#endif
+
+  return find_a_file (&exec_prefixes, name, X_OK, false);
+}
+
 /* Ranking of prefixes in the sort list. -B prefixes are put before
all others.  */
 
@@ -3243,8 +3255,7 @@ execute (void)
 
   if (wrapper_string)
 {
-  string = find_a_file (&exec_prefixes,
-   argbuf[0], X_OK, false);
+  string = find_a_program (argbuf[0]);
   if (string)
argbuf[0] = string;
   insert_wrapper (wrapper_string);
@@ -3269,7 +3280,7 @@ execute (void)
 
   if (!wrapper_string)
 {
-  string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false);
+  string = find_a_program(commands[0].prog);
   if (string)
commands[0].argv[0] = string;
 }
@@ -3284,8 +3295,7 @@ execute (void)
commands[n_commands].prog = argbuf[i + 1];
commands[n_commands].argv
  = &(argbuf.address ())[i + 1];
-   string = find_a_file (&exec_prefixes, commands[n_commands].prog,
- X_OK, false);
+   string = find_a_program(commands[n_commands].prog);
if (string)
  commands[n_commands].argv[0] = string;
n_commands++;
@@ -8556,8 +8566,7 @@ driver::maybe_putenv_COLLECT_LTO_WRAPPER () const
   if (have_c)
 lto_wrapper_file = NULL;
   else
-lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper",
-   X_OK, false);
+lto_wrapper_file = find_a_program ("lto-wrapper");
   if (lto_wrapper_file)
 {
   lto_wrapper_file = convert_white_space (lto_wrapper_file);
@@ -8671,7 +8680,7 @@ driver::maybe_print_and_exit () const
 #endif
  print_prog_name = concat (print_prog_name, use_ld, NULL);
}
-  char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK, 0);
+  char *newname = find_a_program (print_prog_name);
   printf ("%s\n", (newname ? newname : print_prog_name));
   return (0);
 }
@@ -9070,7 +9079,7 @@ driver::maybe_run_linker (const char *argv0) const
  /* We'll use ld if we can't find collect2.  */
  if (! strcmp (linker_name_spec, "collect2"))
{
- char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false);
+ char *s = find_a_program ("collect2");
  if (s == NULL)
set_static_spec_shared (&linker_name_spec, "ld");
}
-- 
2.31.1



Re: Optional machine prefix for programs in for -B dirs

2021-08-17 Thread John Ericson
OK I have polished off my code in light of previous discussion and will
submit it in follow-up emails.

As mentioned before, this patch series is on top of the
non-behavior-changing cleanup I previously submitted in
https://gcc.gnu.org/pipermail/gcc-patches/2021-August/576725.html

The first patch implements my original approach of always searching for
`$machine-prog`. The next two patches refine that approach by only
searching for `$machine-prog` in directories that are not already
machine-disambiguated, as discussed. I wanted to include this fuller
history to allow both approaches to be compared, but if desired I am
happy to submit a v2 patch set with a more condensed history for
whichever option is chosen.

Thanks,

John



[PATCH 3/3] find_a_program: Only search for prefixed paths in undisambiguated dirs

2021-08-17 Thread John Ericson
This means, we might search for:

- path/$machine/$version/prog
- path/$machine/prog
- path/$machine-prog

But not

- path/$machine/$version/$machine-prog

because disambiguating $machine twice is unnecessary.

This does mean we less liberal in what we accept than LLVM, but that's
OK. The down side of always Postel's law is everyone converges on
accepting all sorts of garbage, which makes debugging end-to-end hard
when mistakes are not caught early.
---
 gcc/gcc.c | 25 -
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/gcc/gcc.c b/gcc/gcc.c
index f32c7a8de46..7b6b89ac6e9 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -3080,15 +3080,9 @@ program_at_path (char *path, bool machine_specific, void 
*data)
   struct file_at_path_info *info = (struct file_at_path_info *) data;
   size_t path_len = strlen (path);
 
-  for (auto prefix : { just_machine_prefix, "" })
+  auto search = [=](size_t len) -> void *
 {
-  auto len = path_len;
-
-  auto prefix_len = strlen(prefix);
-  memcpy (path + len, prefix, prefix_len);
-  len += prefix_len;
-
-  memcpy (path + len, info->name, info->name_len);
+  memcpy (path + len, info->name, info->name_len + 1);
   len += info->name_len;
 
   /* Some systems have a suffix for executable files.
@@ -3103,9 +3097,22 @@ program_at_path (char *path, bool machine_specific, void 
*data)
   path[len] = '\0';
   if (access_check (path, info->mode) == 0)
return path;
+
+  return NULL;
+};
+
+  /* Additionally search for $target-prog in machine-agnostic dirs, as an
+ additional way to disambiguate targets. Do not do this in machine-specific
+ dirs because so further disambiguation is needed. */
+  if (!machine_specific)
+{
+  auto prefix_len = strlen(just_machine_prefix);
+  memcpy (path + path_len, just_machine_prefix, prefix_len);
+  auto res = search(path_len + prefix_len);
+  if (res) return res;
 }
 
-  return NULL;
+  return search(path_len);
 }
 
 /* Specialization of find_a_file for programs that also takes into account
-- 
2.31.1



[PATCH 1/3] find_a_program: First search with machine prefix

2021-08-17 Thread John Ericson
This matches the behavior of Clang, and makes it easier to work with
cross compilers without heeding to hard-code paths at build time.
---
 gcc/gcc.c | 78 ---
 1 file changed, 68 insertions(+), 10 deletions(-)

diff --git a/gcc/gcc.c b/gcc/gcc.c
index 1a74bf92f7a..710cbfe9a66 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1582,6 +1582,11 @@ static const char *machine_suffix = 0;
 
 static const char *just_machine_suffix = 0;
 
+/* Prefix to attach to *basename* of commands being searched.
+   This is just `MACHINE-'.  */
+
+static const char *just_machine_prefix = 0;
+
 /* Adjusted value of GCC_EXEC_PREFIX envvar.  */
 
 static const char *gcc_exec_prefix;
@@ -3026,15 +3031,6 @@ file_at_path (char *path, void *data)
   memcpy (path + len, info->name, info->name_len);
   len += info->name_len;
 
-  /* Some systems have a suffix for executable files.
- So try appending that first.  */
-  if (info->suffix_len)
-{
-  memcpy (path + len, info->suffix, info->suffix_len + 1);
-  if (access_check (path, info->mode) == 0)
-   return path;
-}
-
   path[len] = '\0';
   if (access_check (path, info->mode) == 0)
 return path;
@@ -3074,12 +3070,52 @@ find_a_file (const struct path_prefix *pprefix, const 
char *name, int mode,
file_at_path, &info);
 }
 
+/* Callback for find_a_program.  Appends the file name to the directory
+   path. Like file_at_path but tries machine prefix and exe suffix too. */
+
+static void *
+program_at_path (char *path, void *data)
+{
+  /* try first with machine-prefixed name */
+  struct file_at_path_info *info = (struct file_at_path_info *) data;
+  size_t path_len = strlen (path);
+
+  for (auto prefix : { just_machine_prefix, "" })
+{
+  auto len = path_len;
+
+  auto prefix_len = strlen(prefix);
+  memcpy (path + len, prefix, prefix_len);
+  len += prefix_len;
+
+  memcpy (path + len, info->name, info->name_len);
+  len += info->name_len;
+
+  /* Some systems have a suffix for executable files.
+So try appending that first.  */
+  if (info->suffix_len)
+   {
+ memcpy (path + len, info->suffix, info->suffix_len + 1);
+ if (access_check (path, info->mode) == 0)
+   return path;
+   }
+
+  path[len] = '\0';
+  if (access_check (path, info->mode) == 0)
+   return path;
+}
+
+  return NULL;
+}
+
 /* Specialization of find_a_file for programs that also takes into account
configure-specified default programs. */
 
 static char*
 find_a_program (const char *name)
 {
+  const int mode = X_OK;
+
   /* Do not search if default matches query. */
 
 #ifdef DEFAULT_ASSEMBLER
@@ -3097,7 +3133,28 @@ find_a_program (const char *name)
 return xstrdup (DEFAULT_DSYMUTIL);
 #endif
 
-  return find_a_file (&exec_prefixes, name, X_OK, false);
+  /* Find the filename in question (special case for absolute paths).  */
+
+  if (IS_ABSOLUTE_PATH (name))
+{
+  if (access (name, mode) == 0)
+   return xstrdup (name);
+
+  return NULL;
+}
+
+  struct file_at_path_info info;
+
+  info.name = name;
+  info.suffix = HOST_EXECUTABLE_SUFFIX;
+  info.name_len = strlen (info.name);
+  info.suffix_len = strlen (info.suffix);
+  info.mode = mode;
+
+  return (char*) for_each_path (
+&exec_prefixes, false,
+info.name_len + info.suffix_len + strlen(just_machine_prefix),
+program_at_path, &info);
 }
 
 /* Ranking of prefixes in the sort list. -B prefixes are put before
@@ -8328,6 +8385,7 @@ driver::set_up_specs () const
   machine_suffix = concat (spec_host_machine, dir_separator_str, spec_version,
   accel_dir_suffix, dir_separator_str, NULL);
   just_machine_suffix = concat (spec_machine, dir_separator_str, NULL);
+  just_machine_prefix = concat (spec_machine, "-", NULL);
 
   specs_file = find_a_file (&startfile_prefixes, "specs", R_OK, true);
   /* Read the specs file unless it is a default one.  */
-- 
2.31.1



[PATCH 2/3] driver: for_each_pass: Pass to callback whether dir is machine-disambiguated

2021-08-17 Thread John Ericson
We will use this in the subsequent diff to control what basenames we
search for. In machine-specific subdirectories, we should just look for
the original basename, but in machine-agnostic subdirectories, we might
additionally look for prefixed disambiguated names, as an alternate
method of keeping targets apart.
---
 gcc/gcc.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/gcc/gcc.c b/gcc/gcc.c
index 710cbfe9a66..f32c7a8de46 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -2766,7 +2766,7 @@ static void *
 for_each_path (const struct path_prefix *paths,
   bool do_multi,
   size_t extra_space,
-  void *(*callback) (char *, void *),
+  void *(*callback) (char *, bool, void *),
   void *callback_info)
 {
   struct prefix_list *pl;
@@ -2827,7 +2827,7 @@ for_each_path (const struct path_prefix *paths,
  if (!skip_multi_dir)
{
  memcpy (path + len, multi_suffix, suffix_len + 1);
- ret = callback (path, callback_info);
+ ret = callback (path, true, callback_info);
  if (ret)
break;
}
@@ -2838,7 +2838,7 @@ for_each_path (const struct path_prefix *paths,
  && pl->require_machine_suffix == 2)
{
  memcpy (path + len, just_multi_suffix, just_suffix_len + 1);
- ret = callback (path, callback_info);
+ ret = callback (path, true, callback_info);
  if (ret)
break;
}
@@ -2848,7 +2848,7 @@ for_each_path (const struct path_prefix *paths,
  && !pl->require_machine_suffix && multiarch_dir)
{
  memcpy (path + len, multiarch_suffix, multiarch_len + 1);
- ret = callback (path, callback_info);
+ ret = callback (path, true, callback_info);
  if (ret)
break;
}
@@ -2876,7 +2876,7 @@ for_each_path (const struct path_prefix *paths,
  else
path[len] = '\0';
 
- ret = callback (path, callback_info);
+ ret = callback (path, false, callback_info);
  if (ret)
break;
}
@@ -2931,7 +2931,7 @@ struct add_to_obstack_info {
 };
 
 static void *
-add_to_obstack (char *path, void *data)
+add_to_obstack (char *path, bool, void *data)
 {
   struct add_to_obstack_info *info = (struct add_to_obstack_info *) data;
 
@@ -3023,7 +3023,7 @@ struct file_at_path_info {
 };
 
 static void *
-file_at_path (char *path, void *data)
+file_at_path (char *path, bool, void *data)
 {
   struct file_at_path_info *info = (struct file_at_path_info *) data;
   size_t len = strlen (path);
@@ -3074,7 +3074,7 @@ find_a_file (const struct path_prefix *pprefix, const 
char *name, int mode,
path. Like file_at_path but tries machine prefix and exe suffix too. */
 
 static void *
-program_at_path (char *path, void *data)
+program_at_path (char *path, bool machine_specific, void *data)
 {
   /* try first with machine-prefixed name */
   struct file_at_path_info *info = (struct file_at_path_info *) data;
@@ -5945,7 +5945,7 @@ struct spec_path_info {
 };
 
 static void *
-spec_path (char *path, void *data)
+spec_path (char *path, bool, void *data)
 {
   struct spec_path_info *info = (struct spec_path_info *) data;
   size_t len = 0;
-- 
2.31.1



[PATCH v2] Allow explicitly specifying the thread model for runtime libs

2021-08-21 Thread John Ericson
Previously, they always scraped the thread mode from `$CC -v', now, that
is the default but one may pass `--with-threads=MODEL` to be explicit
instead.

One use-case is bootstraping with a shorter critical path. The
traditionally route was to build an entire "static stage" GCC, build
libc, and then build GCC again supporting dynamic linking,
multithreading, etc. But this is wasteful in that GCC itself is built
twice.

With this change, rather than having to mess with spec files we can just
configure the runtime libraries the way we want directly. In turn, that
opens to just building libgcc twice rather than all of GCC.

Frankly, specs were always a rather indirect approach to coordinate this
during GCC's bootstrap, since GCC itself really doesn't care what the
threading model is, just that the runtime libraries agree among
themselves. Relying on a hard-coded spec for this also keeps us one step
further from the long-term goal of multi-target GCC, for what it's
worth.

For the record, "single stage" builds of GCC have some precedent in
downstream packaging, for example with [1]. That one, as far as I can
tell, builds libgcc once, but with the headers of the libc
implementation provided and then cyclic linking down later. They are
both fine approaches, but I don't think one should have to be forced
into cyclic dependencies if they don't want to. That opens the door to
non-terminating programs due to, e.g., atomics used in a threads
implementation being lowered to threads absent hardware support.

Finally, I understand that such custom bootstrapping is not officially
supported. I don't mean to imply it should be --- a lot more cleanup
work to the build system would be necessary before supporting it
wouldn't be a huge additional maintainer burden --- I just hope to add a
reasonable knob for those comfortable with doing unsupported things
already.

[1]: https://github.com/richfelker/musl-cross-make
---
 config/gthr.m4  | 32 
 libatomic/configure.ac  |  4 +---
 libgcc/configure.ac |  4 +---
 libphobos/m4/druntime/os.m4 |  2 +-
 libstdc++-v3/acinclude.m4   |  8 +++-
 5 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/config/gthr.m4 b/config/gthr.m4
index 4b937306ad0..754e622f159 100644
--- a/config/gthr.m4
+++ b/config/gthr.m4
@@ -5,6 +5,35 @@ dnl Public License, this file may be distributed as part of a 
program
 dnl that contains a configuration script generated by Autoconf, under
 dnl the same distribution terms as the rest of that program.
 
+dnl Define thread model
+
+dnl usage: GCC_AC_THREAD_MODEL
+AC_DEFUN([GCC_AC_THREAD_MODEL],
+[
+# With threads
+# Pass with no value to take from compiler's metadata
+# Pass with a value to specify a thread package
+# 'single' means single threaded -- without threads.
+AC_ARG_WITH(threads,
+[AS_HELP_STRING([[--with-threads=MODEL]],
+   [specify thread model for this GCC
+runtime library])],,
+[with_threads=''])
+
+if test x"$with_threads" = x'yes'; then
+AC_MSG_ERROR([Cannot pass bare --with-threads, must pass explicit 
--with-threads=MODEL])
+elif test x"$with_threads" = x'no'; then
+target_thread_file=single
+elif test x"$with_threads" = x''; then
+AC_MSG_CHECKING([for thread model used by GCC])
+target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
+AC_MSG_RESULT([$target_thread_file])
+else
+target_thread_file=$with_threads
+fi
+])
+
+
 dnl Define header location by thread model
 
 dnl usage: GCC_AC_THREAD_HEADER([thread_model])
@@ -22,6 +51,9 @@ case $1 in
 tpf)   thread_header=config/s390/gthr-tpf.h ;;
 vxworks)   thread_header=config/gthr-vxworks.h ;;
 win32) thread_header=config/i386/gthr-win32.h ;;
+*)
+AC_MSG_ERROR([No known header for threading model '$1'.])
+;;
 esac
 AC_SUBST(thread_header)
 ])
diff --git a/libatomic/configure.ac b/libatomic/configure.ac
index 2a371870c2f..42d2016b7a2 100644
--- a/libatomic/configure.ac
+++ b/libatomic/configure.ac
@@ -161,9 +161,7 @@ libtool_VERSION=3:0:2
 AC_SUBST(libtool_VERSION)
 
 # Check for used threading-model
-AC_MSG_CHECKING([for thread model used by GCC])
-target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
-AC_MSG_RESULT([$target_thread_file])
+GCC_AC_THREAD_MODEL
 
 case "$target" in
  *aarch64*)
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 13a80b2551b..1209a0986e0 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -298,9 +298,7 @@ AC_SUBST([use_tm_clone_registry])
 
 AC_LIB_PROG_LD_GNU
 
-AC_MSG_CHECKING([for thread model used by GCC])
-target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
-AC_MSG_RESULT([$target_thread_file]) 
+GCC_AC_THREAD_MODEL
 
 # Check for assembler CFI support.
 AC_CACHE_CHECK([whether assembler supports CFI directives], [libgcc_cv_cfi],
diff --git a/libphobos/m4/druntime/os.m4 b/libphobos/m4/druntime/os.m4
index 351558dbcda..2b44fbca8fc 100644
--- a/libphobos/m4/

[PATCH] Allow explicitly specifying the thread model for runtime libs

2021-08-18 Thread John Ericson via Gcc-patches
From: John Ericson 

Previously, they always scraped the thread mode from `$CC -v', now, that
is the default but one may pass `--with-threads=MODEL` to be explicit
instead.

One use-case is bootstraping with a shorter critical path. The
traditionally route was to build an entire "static stage" GCC, build
libc, and then build GCC again supporting dynamic linking,
multithreading, etc. But this is wasteful in that GCC itself is built
twice.

With this change, rather than having to mess with spec files we can just
configure the runtime libraries the way we want directly. In turn, that
opens to just building libgcc twice rather than all of GCC.

Frankly, specs were always a rather indirect approach to coordinate this
during GCC's bootstrap, since GCC itself really doesn't care what the
threading model is, just that the runtime libraries agree among
themselves. Relying on a hard-coded spec for this also keeps us one step
further from the long-term goal of multi-target GCC, for what it's
worth.

For the record, "single stage" builds of GCC have some precedent in
downstream packaging, for example with [1]. That one, as far as I can
tell, builds libgcc once, but with the headers of the libc
implementation provided and then cyclic linking down later. They are
both fine approaches, but I don't think one should have to be forced
into cyclic dependencies if they don't want to. That opens the door to
non-terminating programs due to, e.g., atomics used in a threads
implementation being lowered to threads absent hardware support.

Finally, I understand that such custom bootstrapping is not officially
supported. I don't mean to imply it should be --- a lot more cleanup
work to the build system would be necessary before supporting it
wouldn't be a huge additional maintainer burden --- I just hope to add a
reasonable knob for those comfortable with doing unsupported things
already.

[1]: https://github.com/richfelker/musl-cross-make
---
 config/gthr.m4  | 32 
 libatomic/configure.ac  |  4 +---
 libgcc/configure.ac |  4 +---
 libphobos/m4/druntime/os.m4 |  2 +-
 libstdc++-v3/acinclude.m4   |  8 +++-
 5 files changed, 38 insertions(+), 12 deletions(-)

diff --git a/config/gthr.m4 b/config/gthr.m4
index 4b937306ad0..c585b618e40 100644
--- a/config/gthr.m4
+++ b/config/gthr.m4
@@ -5,6 +5,35 @@ dnl Public License, this file may be distributed as part of a 
program
 dnl that contains a configuration script generated by Autoconf, under
 dnl the same distribution terms as the rest of that program.
 
+dnl Define thread model
+
+dnl usage: GCC_AC_THREAD_MODEL
+AC_DEFUN([GCC_AC_THREAD_MODEL],
+[
+# With threads
+# Pass with no value to take from compiler's metadata
+# Pass with a value to specify a thread package
+# 'single' means single threaded -- without threads.
+AC_ARG_WITH(threads,
+[AS_HELP_STRING([[--with-threads=MODEL]],
+   [specify thread model for this GCC
+runtime library])],,
+[with_threads=''])
+
+if test x"$with_threads" = x'yes'; then
+AC_MSG_ERROR([Cannot pass bare --with-threads, must pass explicit 
--with-threads=MODEL])
+elif test x"$with_threads" = x'no'; then
+target_thread_file=single
+elif test x"$with_threads" = ''; then
+AC_MSG_CHECKING([for thread model used by GCC])
+target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
+AC_MSG_RESULT([$target_thread_file])
+else
+target_thread_file=$with_threads
+fi
+])
+
+
 dnl Define header location by thread model
 
 dnl usage: GCC_AC_THREAD_HEADER([thread_model])
@@ -22,6 +51,9 @@ case $1 in
 tpf)   thread_header=config/s390/gthr-tpf.h ;;
 vxworks)   thread_header=config/gthr-vxworks.h ;;
 win32) thread_header=config/i386/gthr-win32.h ;;
+*)
+AC_MSG_ERROR([No known header for threading model '$1'.])
+;;
 esac
 AC_SUBST(thread_header)
 ])
diff --git a/libatomic/configure.ac b/libatomic/configure.ac
index 2a371870c2f..42d2016b7a2 100644
--- a/libatomic/configure.ac
+++ b/libatomic/configure.ac
@@ -161,9 +161,7 @@ libtool_VERSION=3:0:2
 AC_SUBST(libtool_VERSION)
 
 # Check for used threading-model
-AC_MSG_CHECKING([for thread model used by GCC])
-target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
-AC_MSG_RESULT([$target_thread_file])
+GCC_AC_THREAD_MODEL
 
 case "$target" in
  *aarch64*)
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 13a80b2551b..1209a0986e0 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -298,9 +298,7 @@ AC_SUBST([use_tm_clone_registry])
 
 AC_LIB_PROG_LD_GNU
 
-AC_MSG_CHECKING([for thread model used by GCC])
-target_thread_file=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
-AC_MSG_RESULT([$target_thread_file]) 
+GCC_AC_THREAD_MODEL