Background: commit r17-1532-ga514707ffd7d58 ("find_a_program: Search
with machine prefix in some cases") taught find_a_program to try
MACHINE-NAME ahead of NAME when looking in a directory that is not
already machine-specific, so that a directory holding tools for several
targets can still be disambiguated.

That reached only the exec prefixes -- the compiler's own directories,
-B arguments, and COMPILER_PATH -- because those were the only
directories find_a_program looked in.  PATH was left to execvp, by way
of PEX_SEARCH, and execvp matches NAME alone.

That was basically an oversight on my part.  In Nixpkgs, for example, we
do plenty of PATH-based tool lookup, and indeed PATH is one of the
strongest motivations for machine prefixing, because it is how a single
PATH executable search path can be shared between multiple targets.

The previous commit brought PATH into find_a_program, but did not deal
with MACHINE-NAME in order to be closer to a pure refactor.  This commit
actually implements the feature: PATH entries are never machine-specific,
so MACHINE-NAME is now tried ahead of NAME in each of them, exactly as it
already was in the machine-agnostic exec prefixes.

Note that this is not exactly a new policy: collect2 has long searched
PATH for MACHINE-ld and MACHINE-nm ahead of the bare names.

This also sharpens the -print-prog-name improvement of the previous
commit: the more complex the driver's PATH search, the more a caller
gains from not having to reimplement it.

As a bonus, since the logic for PATH and exec_prefixes directories is
now the same, we can share one callback between the two for_each_*
calls.  There is now a single lambda bound to a name, which is called
by both functions, ensuring the logic for both sorts of directories
will stay in sync.

gcc/ChangeLog:

        * gcc.cc (find_a_program): Try the machine-prefixed name when
        searching PATH.  Name the exec prefix search callback and reuse it
        there.
        * doc/invoke.texi (Developer Options): Document that the
        machine-prefixed name is tried first.

Signed-off-by: John Ericson <[email protected]>
---
 gcc/doc/invoke.texi |  7 +++++--
 gcc/gcc.cc          | 36 ++++++++++++++++--------------------
 2 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 43469bf3d5e..b72fa1d8dec 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -21230,8 +21230,11 @@ relative to some @file{lib} subdirectory.
 @itemx --print-prog-name=@var{program}
 @itemx --print-prog-name @var{program}
 Like @option{-print-file-name}, but searches for a program such as 
@command{cpp}.
-The compiler's own directories are searched first, then @env{PATH}.  If no
-such program is found, @var{program} is printed back unchanged.
+The compiler's own directories are searched first, then @env{PATH}.  In a
+directory that is not already specific to one target, the name prefixed
+with the target machine, such as @command{@var{machine}-ld}, is tried
+before @var{program} itself.  If no such program is found, @var{program}
+is printed back unchanged.
 
 @opindex print-libgcc-file-name
 @item -print-libgcc-file-name
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index c494ddd0665..0b4491e5b89 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -3195,9 +3195,7 @@ find_a_program (const char *name)
   /* Callback appends the file name to the directory path.  If the
      resulting file exists in the right mode, return the full pathname
      to the file.  */
-  char *ret = for_each_path (&exec_prefixes, false,
-                            prefix_len + name_len + suffix_len,
-                            [=](char *path, bool machine_specific) -> char*
+  auto try_dir = [=](char *path, bool machine_specific) -> char*
     {
       size_t path_len = strlen (path);
 
@@ -3235,7 +3233,10 @@ find_a_program (const char *name)
        }
 
       return search(path_len);
-    });
+    };
+
+  char *ret = for_each_path (&exec_prefixes, false,
+                            prefix_len + name_len + suffix_len, try_dir);
 
   if (ret)
     return ret;
@@ -3243,26 +3244,21 @@ find_a_program (const char *name)
   /* Nothing among our own directories, so fall back to PATH.
 
      Searching it here rather than via execvp means we know which file
-     we picked, so -print-prog-name can report it.  */
+     we picked, so -print-prog-name can report it.  It also lets us look
+     for NAME and MACHINE-NAME without revisiting the directory.  */
 
   return for_each_env_path (env.get ("PATH"), [&] (const char *dir) -> char*
     {
-      /* Some systems have a suffix for executable files.  As above, try
-        appending that first.  */
-      if (suffix_len)
-       {
-         char *candidate = concat (dir, name, suffix, NULL);
-         if (access_check (candidate, X_OK) == 0)
-           return candidate;
-         free (candidate);
-       }
+      char *path = XNEWVEC (char, strlen (dir) + prefix_len + name_len
+                           + suffix_len + 1);
+      strcpy (path, dir);
 
-      char *candidate = concat (dir, name, NULL);
-      if (access_check (candidate, X_OK) == 0)
-       return candidate;
-
-      free (candidate);
-      return NULL;
+      char *found = try_dir (path,
+                            /* PATH dirs we consider machine-agnostic.  */
+                            false);
+      if (!found)
+       free (path);
+      return found;
     });
 }
 
-- 
2.54.0

Reply via email to