|
89 | 89 | //! For example, with `CFLAGS='a "b c"'`, the compiler will be invoked with 2 arguments -
|
90 | 90 | //! `a` and `b c` - rather than 3: `a`, `"b` and `c"`.
|
91 | 91 | //! * `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.//! |
92 | 99 | //!
|
93 | 100 | //! Furthermore, projects using this crate may specify custom environment variables
|
94 | 101 | //! to be inspected, for example via the `Build::try_flags_from_environment`
|
@@ -226,7 +233,10 @@ use std::path::{Component, Path, PathBuf};
|
226 | 233 | #[cfg(feature = "parallel")]
|
227 | 234 | use std::process::Child;
|
228 | 235 | use std::process::Command;
|
229 |
| -use std::sync::{Arc, RwLock}; |
| 236 | +use std::sync::{ |
| 237 | + atomic::{AtomicU8, Ordering::Relaxed}, |
| 238 | + Arc, RwLock, |
| 239 | +}; |
230 | 240 |
|
231 | 241 | use shlex::Shlex;
|
232 | 242 |
|
@@ -340,6 +350,8 @@ enum ErrorKind {
|
340 | 350 | #[cfg(feature = "parallel")]
|
341 | 351 | /// jobserver helpthread failure
|
342 | 352 | JobserverHelpThreadError,
|
| 353 | + /// `cc` has been disabled by an environment variable. |
| 354 | + Disabled, |
343 | 355 | }
|
344 | 356 |
|
345 | 357 | /// Represents an internal error that occurred, with an explanation.
|
@@ -1542,6 +1554,8 @@ impl Build {
|
1542 | 1554 |
|
1543 | 1555 | use parallel::async_executor::{block_on, YieldOnce};
|
1544 | 1556 |
|
| 1557 | + check_disabled()?; |
| 1558 | + |
1545 | 1559 | if objs.len() <= 1 {
|
1546 | 1560 | for obj in objs {
|
1547 | 1561 | let (mut cmd, name) = self.create_compile_object_cmd(obj)?;
|
@@ -1688,6 +1702,8 @@ impl Build {
|
1688 | 1702 |
|
1689 | 1703 | #[cfg(not(feature = "parallel"))]
|
1690 | 1704 | fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> {
|
| 1705 | + check_disabled()?; |
| 1706 | + |
1691 | 1707 | for obj in objs {
|
1692 | 1708 | let (mut cmd, name) = self.create_compile_object_cmd(obj)?;
|
1693 | 1709 | run(&mut cmd, &name, &self.cargo_output)?;
|
@@ -4023,6 +4039,51 @@ impl AsmFileExt {
|
4023 | 4039 | }
|
4024 | 4040 | }
|
4025 | 4041 |
|
| 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 | + |
4026 | 4087 | #[cfg(test)]
|
4027 | 4088 | mod tests {
|
4028 | 4089 | use super::*;
|
|
0 commit comments