[PATCH 3/3] driver: Search PATH with the machine prefix too

John Ericson <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.