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