Skip to content

Commit 851e856

Browse files
committed
Append Windows bin directory to PATH
1 parent 21d4b27 commit 851e856

File tree

2 files changed

+97
-5
lines changed

2 files changed

+97
-5
lines changed

src/env_var.rs

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ use crate::process::Process;
77

88
pub const RUST_RECURSION_COUNT_MAX: u32 = 20;
99

10-
pub(crate) fn prepend_path(
10+
pub(crate) fn insert_path(
1111
name: &str,
1212
prepend: Vec<PathBuf>,
13+
append: Option<PathBuf>,
1314
cmd: &mut Command,
1415
process: &Process,
1516
) {
1617
let old_value = process.var_os(name);
17-
let parts = if let Some(ref v) = old_value {
18+
let mut parts = if let Some(ref v) = old_value {
1819
let mut tail = env::split_paths(v).collect::<VecDeque<_>>();
1920
for path in prepend.into_iter().rev() {
2021
if !tail.contains(&path) {
@@ -26,6 +27,12 @@ pub(crate) fn prepend_path(
2627
prepend.into()
2728
};
2829

30+
if let Some(path) = append {
31+
if !parts.contains(&path) {
32+
parts.push_back(path);
33+
}
34+
}
35+
2936
if let Ok(new_value) = env::join_paths(parts) {
3037
cmd.env(name, new_value);
3138
}
@@ -77,7 +84,7 @@ mod tests {
7784
let path_z = PathBuf::from(z);
7885
path_entries.push(path_z);
7986

80-
prepend_path("PATH", path_entries, &mut cmd, &tp.process);
87+
insert_path("PATH", path_entries, None, &mut cmd, &tp.process);
8188
let envs: Vec<_> = cmd.get_envs().collect();
8289

8390
assert_eq!(
@@ -99,4 +106,82 @@ mod tests {
99106
),]
100107
);
101108
}
109+
110+
#[test]
111+
fn append_unique_path() {
112+
let mut vars = HashMap::new();
113+
vars.env(
114+
"PATH",
115+
env::join_paths(["/home/a/.cargo/bin", "/home/b/.cargo/bin"].iter()).unwrap(),
116+
);
117+
let tp = TestProcess::with_vars(vars);
118+
#[cfg(windows)]
119+
let _path_guard = RegistryGuard::new(&USER_PATH).unwrap();
120+
121+
#[track_caller]
122+
fn check(tp: &TestProcess, path_entries: Vec<PathBuf>, append: &str, expected: &[&str]) {
123+
let mut cmd = Command::new("test");
124+
125+
insert_path(
126+
"PATH",
127+
path_entries,
128+
Some(append.into()),
129+
&mut cmd,
130+
&tp.process,
131+
);
132+
let envs: Vec<_> = cmd.get_envs().collect();
133+
134+
assert_eq!(
135+
envs,
136+
&[(
137+
OsStr::new("PATH"),
138+
Some(env::join_paths(expected.iter()).unwrap().as_os_str())
139+
),]
140+
);
141+
}
142+
143+
check(
144+
&tp,
145+
Vec::new(),
146+
"/home/z/.cargo/bin",
147+
&[
148+
"/home/a/.cargo/bin",
149+
"/home/b/.cargo/bin",
150+
"/home/z/.cargo/bin",
151+
],
152+
);
153+
check(
154+
&tp,
155+
Vec::new(),
156+
"/home/a/.cargo/bin",
157+
&["/home/a/.cargo/bin", "/home/b/.cargo/bin"],
158+
);
159+
check(
160+
&tp,
161+
Vec::new(),
162+
"/home/b/.cargo/bin",
163+
&["/home/a/.cargo/bin", "/home/b/.cargo/bin"],
164+
);
165+
check(
166+
&tp,
167+
Vec::from(["/home/c/.cargo/bin".into()]),
168+
"/home/c/.cargo/bin",
169+
&[
170+
"/home/c/.cargo/bin",
171+
"/home/a/.cargo/bin",
172+
"/home/b/.cargo/bin",
173+
],
174+
);
175+
check(
176+
&tp,
177+
Vec::from(["/home/c/.cargo/bin".into()]),
178+
"/home/z/.cargo/bin",
179+
&[
180+
"/home/c/.cargo/bin",
181+
"/home/a/.cargo/bin",
182+
"/home/b/.cargo/bin",
183+
"/home/z/.cargo/bin",
184+
],
185+
);
186+
}
102187
}

src/toolchain.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ impl<'a> Toolchain<'a> {
217217
new_path.push(PathBuf::from("/usr/lib"));
218218
}
219219

220-
env_var::prepend_path(sysenv::LOADER_PATH, new_path, cmd, self.cfg.process);
220+
env_var::insert_path(sysenv::LOADER_PATH, new_path, None, cmd, self.cfg.process);
221221

222222
// Prepend CARGO_HOME/bin to the PATH variable so that we're sure to run
223223
// cargo/rustc via the proxy bins. There is no fallback case for if the
@@ -251,7 +251,14 @@ impl<'a> Toolchain<'a> {
251251
path_entries.push(self.path.join("bin"));
252252
}
253253

254-
env_var::prepend_path("PATH", path_entries, cmd, self.cfg.process);
254+
// On Windows, we append the "bin" directory to PATH.
255+
// Windows loads DLLs from PATH and the "bin" directory contains DLLs
256+
// that proc macros and other tools not in the sysroot use.
257+
// It's appended rather than prepended so that the exe files in "bin"
258+
// do not take precedence over anything else in PATH.
259+
let append = cfg!(target_os = "windows").then_some(self.path.join("bin"));
260+
261+
env_var::insert_path("PATH", path_entries, append, cmd, self.cfg.process);
255262
}
256263

257264
/// Infallible function that describes the version of rustc in an installed distribution

0 commit comments

Comments
 (0)