Skip to content

Commit 5c1d5fc

Browse files
committed
Auto merge of #31064 - retep998:msvc-host-dlls, r=alexcrichton
Fixes #31063 r? @alexcrichton
2 parents 18b851b + a65f5ac commit 5c1d5fc

File tree

2 files changed

+106
-83
lines changed

2 files changed

+106
-83
lines changed

Diff for: src/librustc_trans/back/link.rs

+3
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,9 @@ fn command_path(sess: &Session) -> OsString {
396396
if let Some(path) = env::var_os("PATH") {
397397
new_path.extend(env::split_paths(&path));
398398
}
399+
if sess.target.target.options.is_like_msvc {
400+
new_path.extend(msvc::host_dll_path());
401+
}
399402
env::join_paths(new_path).unwrap()
400403
}
401404

Diff for: src/librustc_trans/back/msvc/mod.rs

+103-83
Original file line numberDiff line numberDiff line change
@@ -31,98 +31,106 @@
3131
//! paths/files is based on Microsoft's logic in their vcvars bat files, but
3232
//! comments can also be found below leading through the various code paths.
3333
34-
use std::process::Command;
35-
use session::Session;
36-
3734
#[cfg(windows)]
3835
mod registry;
3936

4037
#[cfg(windows)]
41-
pub fn link_exe_cmd(sess: &Session) -> Command {
38+
mod platform {
4239
use std::env;
4340
use std::ffi::OsString;
4441
use std::fs;
4542
use std::path::{Path, PathBuf};
46-
use self::registry::{LOCAL_MACHINE};
47-
48-
let arch = &sess.target.target.arch;
49-
let (binsub, libsub, vclibsub) =
50-
match (bin_subdir(arch), lib_subdir(arch), vc_lib_subdir(arch)) {
51-
(Some(x), Some(y), Some(z)) => (x, y, z),
52-
_ => return Command::new("link.exe"),
53-
};
43+
use std::process::Command;
44+
use session::Session;
45+
use super::registry::{LOCAL_MACHINE};
5446

55-
// First we need to figure out whether the environment is already correctly
56-
// configured by vcvars. We do this by looking at the environment variable
57-
// `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
58-
// otherwise. If it is defined, then we derive the path to `link.exe` from
59-
// that and trust that everything else is configured correctly.
60-
//
61-
// If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where it
62-
// claimed it should be), then we resort to finding everything ourselves.
63-
// First we find where the latest version of MSVC is installed and what
64-
// version it is. Then based on the version we find the appropriate SDKs.
65-
//
66-
// For MSVC 14 (VS 2015) we look for the Win10 SDK and failing that we look
67-
// for the Win8.1 SDK. We also look for the Universal CRT.
68-
//
69-
// For MSVC 12 (VS 2013) we look for the Win8.1 SDK.
70-
//
71-
// For MSVC 11 (VS 2012) we look for the Win8 SDK.
72-
//
73-
// For all other versions the user has to execute the appropriate vcvars bat
74-
// file themselves to configure the environment.
75-
//
76-
// If despite our best efforts we are still unable to find MSVC then we just
77-
// blindly call `link.exe` and hope for the best.
78-
return env::var_os("VCINSTALLDIR").and_then(|dir| {
79-
debug!("Environment already configured by user. Assuming it works.");
80-
let mut p = PathBuf::from(dir);
81-
p.push("bin");
82-
p.push(binsub);
83-
p.push("link.exe");
84-
if !p.is_file() { return None }
85-
Some(Command::new(p))
86-
}).or_else(|| {
87-
get_vc_dir().and_then(|(ver, vcdir)| {
88-
debug!("Found VC installation directory {:?}", vcdir);
89-
let mut linker = vcdir.clone();
90-
linker.push("bin");
91-
linker.push(binsub);
92-
linker.push("link.exe");
93-
if !linker.is_file() { return None }
94-
let mut cmd = Command::new(linker);
95-
add_lib(&mut cmd, &vcdir.join("lib").join(vclibsub));
96-
if ver == "14.0" {
97-
if let Some(dir) = get_ucrt_dir() {
98-
debug!("Found Universal CRT {:?}", dir);
99-
add_lib(&mut cmd, &dir.join("ucrt").join(libsub));
100-
}
101-
if let Some(dir) = get_sdk10_dir() {
102-
debug!("Found Win10 SDK {:?}", dir);
103-
add_lib(&mut cmd, &dir.join("um").join(libsub));
104-
} else if let Some(dir) = get_sdk81_dir() {
105-
debug!("Found Win8.1 SDK {:?}", dir);
106-
add_lib(&mut cmd, &dir.join("um").join(libsub));
107-
}
108-
} else if ver == "12.0" {
109-
if let Some(dir) = get_sdk81_dir() {
110-
debug!("Found Win8.1 SDK {:?}", dir);
111-
add_lib(&mut cmd, &dir.join("um").join(libsub));
112-
}
113-
} else { // ver == "11.0"
114-
if let Some(dir) = get_sdk8_dir() {
115-
debug!("Found Win8 SDK {:?}", dir);
116-
add_lib(&mut cmd, &dir.join("um").join(libsub));
117-
}
118-
}
119-
Some(cmd)
47+
// Cross toolchains depend on dlls from the host toolchain
48+
// We can't just add it to the Command's PATH in `link_exe_cmd` because it
49+
// is later overridden so we publicly expose it here instead
50+
pub fn host_dll_path() -> Option<PathBuf> {
51+
get_vc_dir().and_then(|(_, vcdir)| {
52+
host_dll_subdir().map(|sub| {
53+
vcdir.join("bin").join(sub)
54+
})
12055
})
121-
}).unwrap_or_else(|| {
122-
debug!("Failed to locate linker.");
123-
Command::new("link.exe")
124-
});
56+
}
57+
58+
pub fn link_exe_cmd(sess: &Session) -> Command {
59+
let arch = &sess.target.target.arch;
60+
let (binsub, libsub, vclibsub) =
61+
match (bin_subdir(arch), lib_subdir(arch), vc_lib_subdir(arch)) {
62+
(Some(x), Some(y), Some(z)) => (x, y, z),
63+
_ => return Command::new("link.exe"),
64+
};
12565

66+
// First we need to figure out whether the environment is already correctly
67+
// configured by vcvars. We do this by looking at the environment variable
68+
// `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
69+
// otherwise. If it is defined, then we derive the path to `link.exe` from
70+
// that and trust that everything else is configured correctly.
71+
//
72+
// If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where it
73+
// claimed it should be), then we resort to finding everything ourselves.
74+
// First we find where the latest version of MSVC is installed and what
75+
// version it is. Then based on the version we find the appropriate SDKs.
76+
//
77+
// For MSVC 14 (VS 2015) we look for the Win10 SDK and failing that we look
78+
// for the Win8.1 SDK. We also look for the Universal CRT.
79+
//
80+
// For MSVC 12 (VS 2013) we look for the Win8.1 SDK.
81+
//
82+
// For MSVC 11 (VS 2012) we look for the Win8 SDK.
83+
//
84+
// For all other versions the user has to execute the appropriate vcvars bat
85+
// file themselves to configure the environment.
86+
//
87+
// If despite our best efforts we are still unable to find MSVC then we just
88+
// blindly call `link.exe` and hope for the best.
89+
return env::var_os("VCINSTALLDIR").and_then(|dir| {
90+
debug!("Environment already configured by user. Assuming it works.");
91+
let mut p = PathBuf::from(dir);
92+
p.push("bin");
93+
p.push(binsub);
94+
p.push("link.exe");
95+
if !p.is_file() { return None }
96+
Some(Command::new(p))
97+
}).or_else(|| {
98+
get_vc_dir().and_then(|(ver, vcdir)| {
99+
debug!("Found VC installation directory {:?}", vcdir);
100+
let linker = vcdir.clone().join("bin").join(binsub).join("link.exe");
101+
if !linker.is_file() { return None }
102+
let mut cmd = Command::new(linker);
103+
add_lib(&mut cmd, &vcdir.join("lib").join(vclibsub));
104+
if ver == "14.0" {
105+
if let Some(dir) = get_ucrt_dir() {
106+
debug!("Found Universal CRT {:?}", dir);
107+
add_lib(&mut cmd, &dir.join("ucrt").join(libsub));
108+
}
109+
if let Some(dir) = get_sdk10_dir() {
110+
debug!("Found Win10 SDK {:?}", dir);
111+
add_lib(&mut cmd, &dir.join("um").join(libsub));
112+
} else if let Some(dir) = get_sdk81_dir() {
113+
debug!("Found Win8.1 SDK {:?}", dir);
114+
add_lib(&mut cmd, &dir.join("um").join(libsub));
115+
}
116+
} else if ver == "12.0" {
117+
if let Some(dir) = get_sdk81_dir() {
118+
debug!("Found Win8.1 SDK {:?}", dir);
119+
add_lib(&mut cmd, &dir.join("um").join(libsub));
120+
}
121+
} else { // ver == "11.0"
122+
if let Some(dir) = get_sdk8_dir() {
123+
debug!("Found Win8 SDK {:?}", dir);
124+
add_lib(&mut cmd, &dir.join("um").join(libsub));
125+
}
126+
}
127+
Some(cmd)
128+
})
129+
}).unwrap_or_else(|| {
130+
debug!("Failed to locate linker.");
131+
Command::new("link.exe")
132+
});
133+
}
126134
// A convenience function to make the above code simpler
127135
fn add_lib(cmd: &mut Command, lib: &Path) {
128136
let mut arg: OsString = "/LIBPATH:".into();
@@ -257,11 +265,23 @@ pub fn link_exe_cmd(sess: &Session) -> Command {
257265
_ => None,
258266
}
259267
}
268+
fn host_dll_subdir() -> Option<&'static str> {
269+
if cfg!(target_arch = "x86_64") { Some("amd64") }
270+
else if cfg!(target_arch = "x86") { Some("") }
271+
else { None }
272+
}
260273
}
261274

262275
// If we're not on Windows, then there's no registry to search through and MSVC
263276
// wouldn't be able to run, so we just call `link.exe` and hope for the best.
264277
#[cfg(not(windows))]
265-
pub fn link_exe_cmd(_sess: &Session) -> Command {
266-
Command::new("link.exe")
278+
mod platform {
279+
use std::path::PathBuf;
280+
use std::process::Command;
281+
use session::Session;
282+
pub fn link_exe_cmd(_sess: &Session) -> Command {
283+
Command::new("link.exe")
284+
}
285+
pub fn host_dll_path() -> Option<PathBuf> { None }
267286
}
287+
pub use self::platform::*;

0 commit comments

Comments
 (0)