Skip to content

Commit 29d6ca1

Browse files
authored
Allow disabling cc's ability to compile via env var CC_FORCE_DISABLE (#1292)
1 parent 7ff29cd commit 29d6ca1

File tree

1 file changed

+62
-1
lines changed

1 file changed

+62
-1
lines changed

src/lib.rs

+62-1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@
8989
//! For example, with `CFLAGS='a "b c"'`, the compiler will be invoked with 2 arguments -
9090
//! `a` and `b c` - rather than 3: `a`, `"b` and `c"`.
9191
//! * `CXX...` - see [C++ Support](#c-support).
92+
//! * `CC_FORCE_DISABLE` - If set, `cc` will never run any [`Command`]s, and methods that
93+
//! would return an [`Error`]. This is intended for use by third-party build systems
94+
//! which want to be absolutely sure that they are in control of building all
95+
//! dependencies. Note that operations that return [`Tool`]s such as
96+
//! [`Build::get_compiler`] may produce less accurate results as in some cases `cc` runs
97+
//! commands in order to locate compilers. Additionally, this does nothing to prevent
98+
//! users from running [`Tool::to_command`] and executing the [`Command`] themselves.//!
9299
//!
93100
//! Furthermore, projects using this crate may specify custom environment variables
94101
//! to be inspected, for example via the `Build::try_flags_from_environment`
@@ -226,7 +233,10 @@ use std::path::{Component, Path, PathBuf};
226233
#[cfg(feature = "parallel")]
227234
use std::process::Child;
228235
use std::process::Command;
229-
use std::sync::{Arc, RwLock};
236+
use std::sync::{
237+
atomic::{AtomicU8, Ordering::Relaxed},
238+
Arc, RwLock,
239+
};
230240

231241
use shlex::Shlex;
232242

@@ -340,6 +350,8 @@ enum ErrorKind {
340350
#[cfg(feature = "parallel")]
341351
/// jobserver helpthread failure
342352
JobserverHelpThreadError,
353+
/// `cc` has been disabled by an environment variable.
354+
Disabled,
343355
}
344356

345357
/// Represents an internal error that occurred, with an explanation.
@@ -1542,6 +1554,8 @@ impl Build {
15421554

15431555
use parallel::async_executor::{block_on, YieldOnce};
15441556

1557+
check_disabled()?;
1558+
15451559
if objs.len() <= 1 {
15461560
for obj in objs {
15471561
let (mut cmd, name) = self.create_compile_object_cmd(obj)?;
@@ -1688,6 +1702,8 @@ impl Build {
16881702

16891703
#[cfg(not(feature = "parallel"))]
16901704
fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> {
1705+
check_disabled()?;
1706+
16911707
for obj in objs {
16921708
let (mut cmd, name) = self.create_compile_object_cmd(obj)?;
16931709
run(&mut cmd, &name, &self.cargo_output)?;
@@ -4023,6 +4039,51 @@ impl AsmFileExt {
40234039
}
40244040
}
40254041

4042+
/// Returns true if `cc` has been disabled by `CC_FORCE_DISABLE`.
4043+
fn is_disabled() -> bool {
4044+
static CACHE: AtomicU8 = AtomicU8::new(0);
4045+
4046+
let val = CACHE.load(Relaxed);
4047+
// We manually cache the environment var, since we need it in some places
4048+
// where we don't have access to a `Build` instance.
4049+
#[allow(clippy::disallowed_methods)]
4050+
fn compute_is_disabled() -> bool {
4051+
match std::env::var_os("CC_FORCE_DISABLE") {
4052+
// Not set? Not disabled.
4053+
None => false,
4054+
// Respect `CC_FORCE_DISABLE=0` and some simple synonyms.
4055+
Some(v) if &*v != "0" && &*v != "false" && &*v != "no" => false,
4056+
// Otherwise, we're disabled. This intentionally includes `CC_FORCE_DISABLE=""`
4057+
Some(_) => true,
4058+
}
4059+
}
4060+
match val {
4061+
2 => true,
4062+
1 => false,
4063+
0 => {
4064+
let truth = compute_is_disabled();
4065+
let encoded_truth = if truth { 2u8 } else { 1 };
4066+
// Might race against another thread, but we'd both be setting the
4067+
// same value so it should be fine.
4068+
CACHE.store(encoded_truth, Relaxed);
4069+
truth
4070+
}
4071+
_ => unreachable!(),
4072+
}
4073+
}
4074+
4075+
/// Automates the `if is_disabled() { return error }` check and ensures
4076+
/// we produce a consistent error message for it.
4077+
fn check_disabled() -> Result<(), Error> {
4078+
if is_disabled() {
4079+
return Err(Error::new(
4080+
ErrorKind::Disabled,
4081+
"the `cc` crate's functionality has been disabled by the `CC_FORCE_DISABLE` environment variable."
4082+
));
4083+
}
4084+
Ok(())
4085+
}
4086+
40264087
#[cfg(test)]
40274088
mod tests {
40284089
use super::*;

0 commit comments

Comments
 (0)