Skip to content

Commit 7555f35

Browse files
committed
fix: Extend ALTERNATIVE_LOCATIONS for ARM64 Windows
`gix-path` looks for and runs an installed `git` executable, when present, to discover information about how Git is set up. This is used in several functions in `gix_path::env()`, especially on Windows, where if `git` is not found in a `PATH` search, then common installation locations for Git for Windows are checked. These locations on Windows are resolved based on information from the current environment, since different systems have different program files directories. This was implemented in GitoxideLabs#1456 (which built on GitoxideLabs#1419). Although this was sufficient to find the most common Git for Windows installation locations, it did not find ARM64 builds of Git for Windows. Such builds place the non-shim `git.exe` program in `(git root)/clangarm64/bin`, rather than in `(git root)/mingw64/bin` or `(git root)/mingw32/bin`. At the time of GitoxideLabs#1416 and GitoxideLabs#1419, no stable ARM64 builds of Git for Windows were available. Since then, Git for Windows began releasing such builds. This modifies the alternative locations examined if `git.exe` is not found in a `PATH` search on Windows so that, where `(git root)` is in a 64-bit program files directory, we check for a `(git root)/clangarm64/bin` directory, in addition to checking for a `(git root)/mingw64/bin` directory as was already done. (Although 64-bit and 32-bit program files directories are separate, on ARM64 systems the 64-bit program files directory is used for both ARM64 programs that the system can run directly and x86_64 programs that the system must run through emulation.) This checks both `clangarm64` and `mingw64`, where `mingw64` was checked before. It does so in that order, because if both were available, then we are probably on an ARM64 system, and the ARM64 build of Git for Windows should be preferred, both because it will tend to perform better and because the user is likely to expect that to be used (an x86_64 build, especially if present directly alongside an ARM64 build, may be left over from a previous version of Git for Windows that didn't have ARM64 builds and that was only incompletely installed). It does so on all systems where we had chcked `mingw64` before, even on x86_64 systems. This is because, to limit dependencies and code complexity, we have been examining only environment variables to ascertain which program files directories exist and whether they are 64-bit or 32-bit program files directories; and at least for now, this preserves that general approach. But determining whether the system is ARM64 or x86_64 is less straightforward (than program files directory locations) to ascertain from environment variables, if we are to accommodate all reasonable edge cases. This is because, if our parent process (or other ancestor) passes down a sanitized environment, while still attempting to allow the program files directories to be found, then: - That process should make available all of the `ProgramFiles`, `ProgramW6432`, and `ProgramFiles(x86)` variables that exist in its own environment. - Even if not designed with the WoW64 rules in mind, it will likely pass down at least `ProgramFiles`. - In contrast, it may omit the variables `PROCESSOR_ARCHITECTURE` and `PROCESSOR_ARCHITEW6432`, which are not obviously needed for locating programs. - Even if `PROCESSOR_ARCHITE*` variables are preserved, there are common cases where they are not sufficient, such as when we are an x86_64 build, but the system is ARM64 and Git for Windows is ARM64. - Although the `PROCESSOR_IDENTIFIER` variable is more reliable if present (see actions/partner-runner-images#117 for an example of where this is more informative than `PROCESSOR_ARCHITECTURE`), it is more complex to parse, and more importantly it may be omitted even if a parent/ancestor lets `PROCESSOR_ARCHITE*` through.
1 parent 4662233 commit 7555f35

File tree

1 file changed

+17
-13
lines changed

1 file changed

+17
-13
lines changed

gix-path/src/env/git/mod.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,38 +38,42 @@ where
3838
// known. So the situation where a process only passes down `ProgramFiles` sometimes happens.
3939
let varname_current = "ProgramFiles";
4040

41-
// 64-bit relative bin dir. So far, this is always `mingw64`, not `ucrt64`, `clang64`, or `clangarm64`.
42-
let suffix_64 = Path::new(r"Git\mingw64\bin");
41+
// 64-bit relative bin dirs. So far, this is always `mingw64` or `clangarm64`, not `urct64` or
42+
// `clang64`. We check `clangarm64` before `mingw64`, because in the strage case that both are
43+
// available, we don't want to skip over a native ARM64 executable for an emulated x86_64 one.
44+
let suffixes_64 = [r"Git\clangarm64\bin", r"Git\mingw64\bin"].as_slice();
4345

44-
// 32-bit relative bin dir. So far, this is always `mingw32`, not `clang32`.
45-
let suffix_32 = Path::new(r"Git\mingw32\bin");
46+
// 32-bit relative bin dirs. So far, this is only ever `mingw32`, not `clang32`.
47+
let suffixes_32 = [r"Git\mingw32\bin"].as_slice();
4648

4749
// Whichever of the 64-bit or 32-bit relative bin better matches this process's architecture.
4850
// Unlike the system architecture, the process architecture is always known at compile time.
4951
#[cfg(target_pointer_width = "64")]
50-
let suffix_current = suffix_64;
52+
let suffixes_current = suffixes_64;
5153
#[cfg(target_pointer_width = "32")]
52-
let suffix_current = suffix_32;
54+
let suffixes_current = suffixes_32;
5355

5456
let rules = [
55-
(varname_64bit, suffix_64),
56-
(varname_x86, suffix_32),
57-
(varname_current, suffix_current),
57+
(varname_64bit, suffixes_64),
58+
(varname_x86, suffixes_32),
59+
(varname_current, suffixes_current),
5860
];
5961

6062
let mut locations = vec![];
6163

62-
for (name, suffix) in rules {
64+
for (name, suffixes) in rules {
6365
let Some(pf) = var_os_func(name) else { continue };
6466
let pf = Path::new(&pf);
6567
if pf.is_relative() {
6668
// This shouldn't happen, but if it does then don't use the path. This is mainly in
6769
// case we are accidentally invoked with the environment variable set but empty.
6870
continue;
6971
}
70-
let location = pf.join(suffix);
71-
if !locations.contains(&location) {
72-
locations.push(location);
72+
for suffix in suffixes {
73+
let location = pf.join(suffix);
74+
if !locations.contains(&location) {
75+
locations.push(location);
76+
}
7377
}
7478
}
7579

0 commit comments

Comments
 (0)