From: John Ericson <g...@johnericson.me>

Prefatory note:

I've since learned that this quite similar to
https://inbox.sourceware.org/gcc-patches/20240522095404.1825269-1-...@gcc.gnu.org/,
postdating my original patch series, but predating this version. See
that thread for additional motivation. That patch updated a few specific
callsite for various programs; I instead opted to enhance find_a_program
(which I myself originally factored out of find_a_file in
5fee8a0a9223d030c66d53c104fb0a431369248f for this purpose) to catch all
such cases programmatically.

Behavior Change:

Today, GCC will search for:

1. path/$machine/$version/prog
2. path/$machine/prog
3. path/prog

This means, we might search for:

1. path/$machine/$version/prog
2. path/$machine/prog
3. path/$machine-prog # new
4. path/prog

But it will not search for:

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

I want this change because when cross compiling, users expect prefixed
tools, like

 - $AS = $machine-as
 - $LD = $machine-ld

etc. and it would be less confusing if GCC would find those same tools
in a similar way. GCC instead looking for its own (less widely used than
prefixing) nested-directory way of disambiguating, and then falling back
looking for *unprefixed* tools (which typically are for the wrong
platform in cross cases) is quite confusing. In my distro, Nixpkgs, and
elsewhere, I've seen people draw the wrong conclusions because of this,
which is that one must use absolute paths hard-coded at build time in
order to get the right behavior, and dodge the incorrect unprefixed
tools.

For what its worth, Clang/LLVM also look for prefixed tools in this
manner, so this isn't the first time it would be done. The difference is
that they will look for prefixed tools in *all* cases --- i.e. also
within the machine-specific locations as I outlined above (as things
this patch does *not* do). I think that was done for mere coding
convenience, and there is no actual motivation "doubly disambiguating"
tools with machine directories and machine prefixes. So in the interest
of sticking strictly to the motivation / being conservative in how much
new behavior is implemented, I did not implement that part.

gcc/ChangeLog:

        * gcc.cc (program_at_path): Implement the new behavior described
        above.
        (find_a_program): Slightly adjust caller to make room for
        suffix.
        (driver::set_up_specs): Initilize variable. It would be nice to
        have less spooky-action-at-a-distince using C++ features, but I
        just matched how the corresponding suffix variable worked for
        now for uniformity.

Signed-off-by: John Ericson <g...@johnericson.me>
---
 gcc/gcc.cc | 52 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 15 deletions(-)

diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index c60d4870902..bff0379e9fa 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -1600,6 +1600,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;
@@ -3084,29 +3089,45 @@ find_a_file (const struct path_prefix *pprefix, const 
char *name,
    path. Like file_at_path but tries machine prefix and exe suffix too. */
 
 static void *
-program_at_path (char *path, bool, 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;
-  size_t len = strlen (path);
+  size_t path_len = strlen (path);
 
-  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)
+  auto search = [=](size_t len) -> void *
     {
-      memcpy (path + len, info->suffix, info->suffix_len + 1);
+      memcpy (path + len, info->name, info->name_len + 1);
+      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, X_OK) == 0)
+           return path;
+       }
+
+      path[len] = '\0';
       if (access_check (path, X_OK) == 0)
        return path;
-    }
 
-  path[len] = '\0';
-  if (access_check (path, X_OK) == 0)
-    return path;
+      return NULL;
+    };
 
-  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 search(path_len);
 }
 
 /* Specialization of find_a_file for programs that also takes into account
@@ -3151,7 +3172,7 @@ find_a_program (const char *name)
 
   return (char*) for_each_path (
     &exec_prefixes, false,
-    info.name_len + info.suffix_len,
+    info.name_len + info.suffix_len + strlen(just_machine_prefix),
     program_at_path, &info);
 }
 
@@ -8531,6 +8552,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", true);
   /* Read the specs file unless it is a default one.  */
-- 
2.49.0

Reply via email to