Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,8 +1386,17 @@ impl Build {
/// Prefer to use clang-cl over msvc.
///
/// This option defaults to `false`.
///
/// This option is always overridden by the environment variable `CC_PREFER_CLANG_CL_OVER_MSVC`, if set
pub fn prefer_clang_cl_over_msvc(&mut self, prefer_clang_cl_over_msvc: bool) -> &mut Build {
self.prefer_clang_cl_over_msvc = prefer_clang_cl_over_msvc;
match get_prefer_clang_cl_over_msvc_from_env() {
Some(b) => {
self.cargo_output.print_warning(&format_args!("`prefer_clang_cl_over_msvc` is overridden by {:?} to {:?}, the value set by this call is ignored", CC_PREFER_CLANG_CL_OVER_MSVC_ENV_VAR, b));
}
None => {
self.prefer_clang_cl_over_msvc = prefer_clang_cl_over_msvc;
}
}
self
}

Expand Down Expand Up @@ -2869,7 +2878,8 @@ impl Build {
let target = self.get_target()?;
let raw_target = self.get_raw_target()?;

let msvc = if self.prefer_clang_cl_over_msvc {
let prefer_clang_cl_over_msvc_env = get_prefer_clang_cl_over_msvc_from_env();
let msvc = if prefer_clang_cl_over_msvc_env.unwrap_or(self.prefer_clang_cl_over_msvc) {
"clang-cl.exe"
} else {
"cl.exe"
Expand Down Expand Up @@ -4475,6 +4485,19 @@ fn check_exe(mut exe: PathBuf) -> Option<PathBuf> {
check.then_some(exe)
}

const CC_PREFER_CLANG_CL_OVER_MSVC_ENV_VAR: &str = "CC_PREFER_CLANG_CL_OVER_MSVC";
fn get_prefer_clang_cl_over_msvc_from_env() -> Option<bool> {
#[allow(clippy::disallowed_methods)]
Copy link
Copy Markdown
Contributor Author

@ArchangelX360 ArchangelX360 Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understood correclty, getenv or getenv_boolean won't default to the host environment, so it's not applicable to us here as we actually want to have the host environment leak to us if I'm not mistaken.

However, how can I test that? Because tests are run in parallel, so in my current test implementation it just does not work as tests are leaking that env to one another most probably.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See tests/cc_env.rs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks I'll implement it that way for now.

Then we can discuss the following here: would it be an acceptable design for you to always propagate CC_PREFER_CLANG_CL_OVER_MSVC to self.env in the Build::new constructor?

There is two advantages to that:

  • I don't have to use the main function trick in tests and rely on setting self.env
  • I can use self.getenv_boolean in the implementation of Build

CC_FORCE_DISABLE would be under the same regime too, for example.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure I understand the question, but you might wanna wait for #1656 before making too many bold changes to how environment variables work?

match env::var_os(CC_PREFER_CLANG_CL_OVER_MSVC_ENV_VAR) {
None => None,
Some(v) => match v.to_str() {
Some("1") | Some("true") | Some("yes") => Some(true),
Some("0") | Some("false") | Some("no") => Some(false),
_ => None,
},
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
90 changes: 90 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1081,4 +1081,94 @@ mod msvc_clang_cl_tests {
"clang-cl should still be MSVC-like in C++ mode"
);
}

#[test]
fn msvc_prefer_clang_cl_over_msvc_env_tests() {
// these tests are modifying the same environment variable so must be run sequentially to
// avoid flakiness
msvc_prefer_clang_cl_over_msvc_enabled_by_env();
msvc_prefer_clang_cl_over_msvc_disabled_by_env();
msvc_prefer_clang_cl_over_msvc_disabled_by_env_precedence();
msvc_prefer_clang_cl_over_msvc_enabled_by_env_precedence();
}

fn msvc_prefer_clang_cl_over_msvc_enabled_by_env() {
reset_env();
std::env::set_var("CC_PREFER_CLANG_CL_OVER_MSVC", "1");

let test = Test::msvc_autodetect();

let compiler = test
.gcc()
.try_get_compiler()
.expect("Failed to get compiler");

assert!(
compiler.is_like_clang_cl(),
"clang-cl.exe should be identified as clang-cl-like, got {:?}",
compiler
);
assert!(
compiler.is_like_msvc(),
"clang-cl should still be MSVC-like"
);
std::env::remove_var("CC_PREFER_CLANG_CL_OVER_MSVC"); // Clean up after test
}

fn msvc_prefer_clang_cl_over_msvc_disabled_by_env() {
reset_env();
std::env::set_var("CC_PREFER_CLANG_CL_OVER_MSVC", "0");

let test = Test::msvc_autodetect();

let compiler = test
.gcc()
.try_get_compiler()
.expect("Failed to get compiler");

assert!(compiler.is_like_msvc(), "Should still be MSVC-like");
assert!(!compiler.is_like_clang_cl(), "Should not use clang-cl");
std::env::remove_var("CC_PREFER_CLANG_CL_OVER_MSVC"); // Clean up after test
}

fn msvc_prefer_clang_cl_over_msvc_disabled_by_env_precedence() {
reset_env();
std::env::set_var("CC_PREFER_CLANG_CL_OVER_MSVC", "0");

let test = Test::msvc_autodetect();

let compiler = test
.gcc()
.prefer_clang_cl_over_msvc(true)
.try_get_compiler()
.expect("Failed to get compiler");

assert!(compiler.is_like_msvc(), "Should still be MSVC-like");
assert!(!compiler.is_like_clang_cl(), "Should not use clang-cl");
std::env::remove_var("CC_PREFER_CLANG_CL_OVER_MSVC"); // Clean up after test
}

fn msvc_prefer_clang_cl_over_msvc_enabled_by_env_precedence() {
reset_env();
std::env::set_var("CC_PREFER_CLANG_CL_OVER_MSVC", "1");

let test = Test::msvc_autodetect();

let compiler = test
.gcc()
.prefer_clang_cl_over_msvc(false)
.try_get_compiler()
.expect("Failed to get compiler");

assert!(
compiler.is_like_clang_cl(),
"clang-cl.exe should be identified as clang-cl-like, got {:?}",
compiler
);
assert!(
compiler.is_like_msvc(),
"clang-cl should still be MSVC-like"
);
std::env::remove_var("CC_PREFER_CLANG_CL_OVER_MSVC"); // Clean up after test
}
}
Loading