Skip to content

Commit 0250abd

Browse files
committed
MSVC: Add support for linking against the "spectre-mitigated" CRT
Issue Details: Since VS 2017, MSVC has shipped a set of "spectre-mitigated" CRT static libs: https://devblogs.microsoft.com/cppblog/spectre-mitigations-in-msvc/ Typically these are used by opening a VS Command Prompt in "spectre mode" (https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#vcvarsall-syntax) which then sets the `LIB` environment variable to point to the directory with the spectre-mitigated libs. However, since `cc` builds its own `LIB` environment variable, it uses the non-spectre-mitigated libs even when invoked from a VS Command Prompt in "spectre mode". This causes issues when trying to build a spectre-mitigated binary using Rust, as `rustc` uses `cc` for linking. Fix Details: When `cc` detects that the `VSCMD_ARG_VCVARS_SPECTRE` environment variable is set to `spectre` (either by being run from a VS Command Prompt in "spectre mode", or users may explicitly set this themselves), it will use the spectre-mitigated lib directory when building its `LIB` environment variable.
1 parent f2e1b1c commit 0250abd

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

cc-test/build.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ fn main() {
5757
cc::Build::new().file("src/windows.c").compile("windows");
5858
}
5959

60-
// Test that the `windows_registry` module will set PATH by looking for
61-
// nmake which runs vanilla cl, and then also test it after we remove all
62-
// the relevant env vars from our own process.
6360
if target.contains("msvc") {
61+
// Test that the `windows_registry` module will set PATH by looking for
62+
// nmake which runs vanilla cl, and then also test it after we remove all
63+
// the relevant env vars from our own process.
6464
let out = out.join("tmp");
6565
fs::create_dir(&out).unwrap();
6666
println!("nmake 1");
@@ -91,6 +91,26 @@ fn main() {
9191
assert!(status.success());
9292
println!("cargo:rustc-link-lib=msvc");
9393
println!("cargo:rustc-link-search={}", out.display());
94+
95+
// Test that the `windows_registry` module detects if we're in a "spectre
96+
// mode" VS environment.
97+
fn has_spectre(target: &str) -> bool {
98+
cc::windows_registry::find_tool(target, "cl.exe").unwrap().env().iter().any(|(k, v)| {
99+
(k == "LIB") && v.to_str().unwrap().contains(r"\lib\spectre\")
100+
})
101+
}
102+
103+
std::env::set_var("VSCMD_ARG_VCVARS_SPECTRE", "spectre");
104+
assert!(
105+
has_spectre(&target),
106+
"LIB should use spectre-mitigated libs when VSCMD_ARG_VCVARS_SPECTRE is set"
107+
);
108+
109+
std::env::remove_var("VSCMD_ARG_VCVARS_SPECTRE");
110+
assert!(
111+
!has_spectre(&target),
112+
"LIB should not use spectre-mitigated libs when VSCMD_ARG_VCVARS_SPECTRE is not set"
113+
);
94114
}
95115

96116
// This tests whether we can build a library but not link it to the main

src/windows_registry.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,11 +488,24 @@ mod impl_ {
488488
.join("bin")
489489
.join(&format!("Host{}", host))
490490
.join(&host.to_lowercase());
491-
let lib_path = path.join("lib").join(&target);
491+
let lib_path = path
492+
.join(if use_spectre_mitigated_libs() {
493+
r"lib\spectre"
494+
} else {
495+
"lib"
496+
})
497+
.join(&target);
492498
let include_path = path.join("include");
493499
Some((bin_path, host_dylib_path, lib_path, include_path))
494500
}
495501

502+
fn use_spectre_mitigated_libs() -> bool {
503+
match env::var("VSCMD_ARG_VCVARS_SPECTRE") {
504+
Ok(s) => s == "spectre",
505+
_ => false,
506+
}
507+
}
508+
496509
fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> {
497510
let atl_path = path.join("atlmfc");
498511
let sub = lib_subdir(target)?;

0 commit comments

Comments
 (0)