From 31b7b545bd4cfd53619dea2d9278f7e0720cf31b Mon Sep 17 00:00:00 2001 From: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:18:59 +1000 Subject: [PATCH 01/12] CI: Cap release at once per week (#1291) Signed-off-by: Jiahao XU --- .github/workflows/publish.yml | 8 +++++--- .github/workflows/release-pr.yml | 31 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/release-pr.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cc5bc4ffb..32f4aa9a0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,4 +1,4 @@ -name: Release-plz +name: Publish release permissions: pull-requests: write @@ -10,8 +10,8 @@ on: - main jobs: - release-plz: - name: Release-plz + release-plz-release: + name: Release-plz release runs-on: ubuntu-latest steps: - name: Checkout repository @@ -22,6 +22,8 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Run release-plz uses: MarcoIeni/release-plz-action@v0.5 + with: + command: release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml new file mode 100644 index 000000000..eb8bbceb1 --- /dev/null +++ b/.github/workflows/release-pr.yml @@ -0,0 +1,31 @@ +name: Create release PR + +permissions: + pull-requests: write + contents: write + +on: + schedule: + - cron: "0 3 * * 5" + +jobs: + release-plz-pr: + name: Release-plz PR + runs-on: ubuntu-latest + concurrency: + group: release-plz-${{ github.ref }} + cancel-in-progress: false + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + - name: Run release-plz + uses: MarcoIeni/release-plz-action@v0.5 + with: + command: release-pr + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} From 7ff29cd924d1c4b13fb62dc1ecf5e62d1e232c44 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 18:10:38 +1000 Subject: [PATCH 02/12] Regenerate target info (#1293) --- src/target/generated.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/generated.rs b/src/target/generated.rs index 0c9b0ae1a..1f7fd8fcb 100644 --- a/src/target/generated.rs +++ b/src/target/generated.rs @@ -707,7 +707,7 @@ pub(crate) const LIST: &[(&str, TargetInfo<'static>)] = &[ arch: "arm", vendor: "unknown", os: "freebsd", - env: "gnu", + env: "", abi: "eabihf", unversioned_llvm_target: "armv6-unknown-freebsd-gnueabihf", }, @@ -791,7 +791,7 @@ pub(crate) const LIST: &[(&str, TargetInfo<'static>)] = &[ arch: "arm", vendor: "unknown", os: "freebsd", - env: "gnu", + env: "", abi: "eabihf", unversioned_llvm_target: "armv7-unknown-freebsd-gnueabihf", }, From 29d6ca194cca33f96071355764da436e21c34d12 Mon Sep 17 00:00:00 2001 From: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Date: Fri, 15 Nov 2024 18:58:47 +1000 Subject: [PATCH 03/12] Allow disabling cc's ability to compile via env var CC_FORCE_DISABLE (#1292) --- src/lib.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index a0aaa30d4..fb78b7624 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,6 +89,13 @@ //! For example, with `CFLAGS='a "b c"'`, the compiler will be invoked with 2 arguments - //! `a` and `b c` - rather than 3: `a`, `"b` and `c"`. //! * `CXX...` - see [C++ Support](#c-support). +//! * `CC_FORCE_DISABLE` - If set, `cc` will never run any [`Command`]s, and methods that +//! would return an [`Error`]. This is intended for use by third-party build systems +//! which want to be absolutely sure that they are in control of building all +//! dependencies. Note that operations that return [`Tool`]s such as +//! [`Build::get_compiler`] may produce less accurate results as in some cases `cc` runs +//! commands in order to locate compilers. Additionally, this does nothing to prevent +//! users from running [`Tool::to_command`] and executing the [`Command`] themselves.//! //! //! Furthermore, projects using this crate may specify custom environment variables //! to be inspected, for example via the `Build::try_flags_from_environment` @@ -226,7 +233,10 @@ use std::path::{Component, Path, PathBuf}; #[cfg(feature = "parallel")] use std::process::Child; use std::process::Command; -use std::sync::{Arc, RwLock}; +use std::sync::{ + atomic::{AtomicU8, Ordering::Relaxed}, + Arc, RwLock, +}; use shlex::Shlex; @@ -340,6 +350,8 @@ enum ErrorKind { #[cfg(feature = "parallel")] /// jobserver helpthread failure JobserverHelpThreadError, + /// `cc` has been disabled by an environment variable. + Disabled, } /// Represents an internal error that occurred, with an explanation. @@ -1542,6 +1554,8 @@ impl Build { use parallel::async_executor::{block_on, YieldOnce}; + check_disabled()?; + if objs.len() <= 1 { for obj in objs { let (mut cmd, name) = self.create_compile_object_cmd(obj)?; @@ -1688,6 +1702,8 @@ impl Build { #[cfg(not(feature = "parallel"))] fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { + check_disabled()?; + for obj in objs { let (mut cmd, name) = self.create_compile_object_cmd(obj)?; run(&mut cmd, &name, &self.cargo_output)?; @@ -4023,6 +4039,51 @@ impl AsmFileExt { } } +/// Returns true if `cc` has been disabled by `CC_FORCE_DISABLE`. +fn is_disabled() -> bool { + static CACHE: AtomicU8 = AtomicU8::new(0); + + let val = CACHE.load(Relaxed); + // We manually cache the environment var, since we need it in some places + // where we don't have access to a `Build` instance. + #[allow(clippy::disallowed_methods)] + fn compute_is_disabled() -> bool { + match std::env::var_os("CC_FORCE_DISABLE") { + // Not set? Not disabled. + None => false, + // Respect `CC_FORCE_DISABLE=0` and some simple synonyms. + Some(v) if &*v != "0" && &*v != "false" && &*v != "no" => false, + // Otherwise, we're disabled. This intentionally includes `CC_FORCE_DISABLE=""` + Some(_) => true, + } + } + match val { + 2 => true, + 1 => false, + 0 => { + let truth = compute_is_disabled(); + let encoded_truth = if truth { 2u8 } else { 1 }; + // Might race against another thread, but we'd both be setting the + // same value so it should be fine. + CACHE.store(encoded_truth, Relaxed); + truth + } + _ => unreachable!(), + } +} + +/// Automates the `if is_disabled() { return error }` check and ensures +/// we produce a consistent error message for it. +fn check_disabled() -> Result<(), Error> { + if is_disabled() { + return Err(Error::new( + ErrorKind::Disabled, + "the `cc` crate's functionality has been disabled by the `CC_FORCE_DISABLE` environment variable." + )); + } + Ok(()) +} + #[cfg(test)] mod tests { use super::*; From a8f061147f3c25bc2b01bef798df029a619889c0 Mon Sep 17 00:00:00 2001 From: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:15:15 +1000 Subject: [PATCH 04/12] Fix two files with different extensions having the same object name (#1295) --- src/command_helpers.rs | 3 +++ tests/test.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/command_helpers.rs b/src/command_helpers.rs index adedab294..62e366299 100644 --- a/src/command_helpers.rs +++ b/src/command_helpers.rs @@ -327,6 +327,9 @@ pub(crate) fn objects_from_files(files: &[Arc], dst: &Path) -> Result Date: Fri, 22 Nov 2024 09:50:51 +0100 Subject: [PATCH 05/12] Fix: Fetch target info from Cargo even if `Build::target` is manually set (#1299) --- src/lib.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fb78b7624..c3b10c2a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1088,10 +1088,16 @@ impl Build { self } - /// Configures the target this configuration will be compiling for. + /// Configures the `rustc` target this configuration will be compiling + /// for. /// - /// This option is automatically scraped from the `TARGET` environment - /// variable by build scripts, so it's not required to call this function. + /// This will fail if using a target not in a pre-compiled list taken from + /// `rustc +nightly --print target-list`. The list will be updated + /// periodically. + /// + /// You should avoid setting this in build scripts, target information + /// will instead be retrieved from the environment variables `TARGET` and + /// `CARGO_CFG_TARGET_*` that Cargo sets. /// /// # Example /// @@ -3411,8 +3417,11 @@ impl Build { fn get_target(&self) -> Result, Error> { match &self.target { - Some(t) => t.parse(), - None => self + Some(t) if Some(&**t) != self.getenv_unwrap_str("TARGET").ok().as_deref() => t.parse(), + // Fetch target information from environment if not set, or if the + // target was the same as the TARGET environment variable, in + // case the user did `build.target(&env::var("TARGET").unwrap())`. + _ => self .build_cache .target_info_parser .parse_from_cargo_environment_variables(), From 5e3c2579bcefa9f438cfb7d045055557bd31d3a5 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 22 Nov 2024 09:54:27 +0100 Subject: [PATCH 06/12] Fix compilation of C++ code for armv7-unknown-linux-gnueabihf (#1298) --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index c3b10c2a7..187eb705e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2193,6 +2193,7 @@ impl Build { if target.abi == "eabihf" { // lowest common denominator FPU cmd.args.push("-mfpu=vfpv3-d16".into()); + cmd.args.push("-mfloat-abi=hard".into()); } } From 11f0f2e3ff1e1ec7cd90df01ef95be86bb7b19d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 20:04:12 +1100 Subject: [PATCH 07/12] Regenerate target info (#1301) Co-authored-by: github-actions --- src/target/generated.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/generated.rs b/src/target/generated.rs index 1f7fd8fcb..bf157979e 100644 --- a/src/target/generated.rs +++ b/src/target/generated.rs @@ -3241,7 +3241,7 @@ pub(crate) const LIST: &[(&str, TargetInfo<'static>)] = &[ os: "windows", env: "msvc", abi: "", - unversioned_llvm_target: "x86_64-win7-windows-msvc", + unversioned_llvm_target: "x86_64-pc-windows-msvc", }, ), ( From 1eefa743c28ba31feb38aaceb1c24714a3f31155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sat, 23 Nov 2024 02:28:09 +0100 Subject: [PATCH 08/12] CI: Avoid running scheduled jobs on forks (#1302) --- .github/workflows/publish.yml | 1 + .github/workflows/regenerate-target-info.yml | 1 + .github/workflows/regenerate-windows-sys.yml | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 32f4aa9a0..d67f86304 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,6 +11,7 @@ on: jobs: release-plz-release: + if: github.repository_owner == 'rust-lang' name: Release-plz release runs-on: ubuntu-latest steps: diff --git a/.github/workflows/regenerate-target-info.yml b/.github/workflows/regenerate-target-info.yml index d3b5afa7f..32fd5bc78 100644 --- a/.github/workflows/regenerate-target-info.yml +++ b/.github/workflows/regenerate-target-info.yml @@ -7,6 +7,7 @@ on: jobs: regenerate: + if: github.repository_owner == 'rust-lang' name: Regenerate target info & Open Pull Request if necessary runs-on: ubuntu-latest steps: diff --git a/.github/workflows/regenerate-windows-sys.yml b/.github/workflows/regenerate-windows-sys.yml index 8fabbe30b..f5d518e5b 100644 --- a/.github/workflows/regenerate-windows-sys.yml +++ b/.github/workflows/regenerate-windows-sys.yml @@ -7,6 +7,7 @@ on: jobs: regenerate: + if: github.repository_owner == 'rust-lang' name: Regenerate windows sys bindings & Open Pull Request if necessary runs-on: ubuntu-latest steps: @@ -20,7 +21,7 @@ jobs: - name: Create lockfile run: cargo update - + - uses: Swatinem/rust-cache@v2 with: cache-all-crates: 'true' From f770d563321c2a74bc8f0b34436242e0c111cd01 Mon Sep 17 00:00:00 2001 From: Jiahao XU <30436523+NobodyXu@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:58:19 +1000 Subject: [PATCH 09/12] Fix msvc stdout not shown on error (#1303) * Fix msvc stdout not shown on error Fixed #1260 * Fix clippy lint * Call disable_localization unconditionally * Call disable_localization in try_get_compiler` * Set localization env based on msvc * Fix setting env * Fix fmt * Fix confusing wording in comment --- src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 187eb705e..da1b91be0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1950,6 +1950,19 @@ impl Build { cmd.push_cc_arg(warnings_to_errors_flag); } + // Copied from + // + // Disables non-English messages from localized linkers. + // Such messages may cause issues with text encoding on Windows + // and prevent inspection of msvc output in case of errors, which we occasionally do. + // This should be acceptable because other messages from rustc are in English anyway, + // and may also be desirable to improve searchability of the compiler diagnostics. + if matches!(cmd.family, ToolFamily::Msvc { clang_cl: false }) { + cmd.env.push(("VSLANG".into(), "1033".into())); + } else { + cmd.env.push(("LC_ALL".into(), "C".into())); + } + Ok(cmd) } From 4f312e3f3b2b4623e84518582a3ff17bbae70906 Mon Sep 17 00:00:00 2001 From: Frank Laub Date: Wed, 27 Nov 2024 01:04:15 -0800 Subject: [PATCH 10/12] Add support for using sccache wrapper with cuda/nvcc (#1304) --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index da1b91be0..7f21b05bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2813,6 +2813,9 @@ impl Build { .args .push(format!("-ccbin={}", tool.path.display()).into()); } + if let Some(cc_wrapper) = self.rustc_wrapper_fallback() { + nvcc_tool.cc_wrapper_path = Some(Path::new(&cc_wrapper).to_owned()); + } nvcc_tool.family = tool.family; nvcc_tool } else { From afb6d601713bd163434608c8cfa9608ddd46c851 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Wed, 27 Nov 2024 23:25:47 +0000 Subject: [PATCH 11/12] build: Inherit flags from rustc (#1279) --- src/flags.rs | 482 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 44 ++++- tests/rustflags.rs | 29 +++ 3 files changed, 552 insertions(+), 3 deletions(-) create mode 100644 src/flags.rs create mode 100644 tests/rustflags.rs diff --git a/src/flags.rs b/src/flags.rs new file mode 100644 index 000000000..a94743fcc --- /dev/null +++ b/src/flags.rs @@ -0,0 +1,482 @@ +use crate::target::TargetInfo; +use crate::{Build, Error, ErrorKind, ToolFamily}; +use std::borrow::Cow; +use std::ffi::OsString; +use std::path::Path; + +#[derive(Debug, PartialEq, Default)] +pub(crate) struct RustcCodegenFlags { + branch_protection: Option, + code_model: Option, + no_vectorize_loops: bool, + no_vectorize_slp: bool, + profile_generate: Option, + profile_use: Option, + control_flow_guard: Option, + lto: Option, + relocation_model: Option, + embed_bitcode: Option, + force_frame_pointers: Option, + link_dead_code: Option, + no_redzone: Option, + soft_float: Option, +} + +impl RustcCodegenFlags { + // Parse flags obtained from CARGO_ENCODED_RUSTFLAGS + pub(crate) fn parse(rustflags_env: &str) -> Result { + fn is_flag_prefix(flag: &str) -> bool { + [ + "-Z", + "-C", + "--codegen", + "-L", + "-l", + "-o", + "-W", + "--warn", + "-A", + "--allow", + "-D", + "--deny", + "-F", + "--forbid", + ] + .contains(&flag) + } + + fn handle_flag_prefix<'a>(prev: &'a str, curr: &'a str) -> Cow<'a, str> { + match prev { + "--codegen" | "-C" => Cow::from(format!("-C{}", curr)), + // Handle flags passed like --codegen=code-model=small + _ if curr.starts_with("--codegen=") => Cow::from(format!("-C{}", &curr[10..])), + "-Z" => Cow::from(format!("-Z{}", curr)), + "-L" | "-l" | "-o" => Cow::from(format!("{}{}", prev, curr)), + // Handle lint flags + "-W" | "--warn" => Cow::from(format!("-W{}", curr)), + "-A" | "--allow" => Cow::from(format!("-A{}", curr)), + "-D" | "--deny" => Cow::from(format!("-D{}", curr)), + "-F" | "--forbid" => Cow::from(format!("-F{}", curr)), + _ => Cow::from(curr), + } + } + + let mut codegen_flags = Self::default(); + + let mut prev_prefix = None; + for curr in rustflags_env.split("\u{1f}") { + let prev = prev_prefix.take().unwrap_or(""); + if prev.is_empty() && is_flag_prefix(curr) { + prev_prefix = Some(curr); + continue; + } + + let rustc_flag = handle_flag_prefix(prev, curr); + codegen_flags.set_rustc_flag(&rustc_flag)?; + } + + Ok(codegen_flags) + } + + fn set_rustc_flag(&mut self, flag: &str) -> Result<(), Error> { + // Convert a textual representation of a bool-like rustc flag argument into an actual bool + fn arg_to_bool(arg: impl AsRef) -> Option { + match arg.as_ref() { + "y" | "yes" | "on" | "true" => Some(true), + "n" | "no" | "off" | "false" => Some(false), + _ => None, + } + } + + let (flag, value) = if let Some((flag, value)) = flag.split_once('=') { + (flag, Some(value.to_owned())) + } else { + (flag, None) + }; + + fn flag_ok_or(flag: Option, msg: &'static str) -> Result { + flag.ok_or(Error::new(ErrorKind::InvalidFlag, msg)) + } + + match flag { + // https://doc.rust-lang.org/rustc/codegen-options/index.html#code-model + "-Ccode-model" => { + self.code_model = Some(flag_ok_or(value, "-Ccode-model must have a value")?); + } + // https://doc.rust-lang.org/rustc/codegen-options/index.html#no-vectorize-loops + "-Cno-vectorize-loops" => self.no_vectorize_loops = true, + // https://doc.rust-lang.org/rustc/codegen-options/index.html#no-vectorize-slp + "-Cno-vectorize-slp" => self.no_vectorize_slp = true, + // https://doc.rust-lang.org/rustc/codegen-options/index.html#profile-generate + "-Cprofile-generate" => { + self.profile_generate = + Some(flag_ok_or(value, "-Cprofile-generate must have a value")?); + } + // https://doc.rust-lang.org/rustc/codegen-options/index.html#profile-use + "-Cprofile-use" => { + self.profile_use = Some(flag_ok_or(value, "-Cprofile-use must have a value")?); + } + // https://doc.rust-lang.org/rustc/codegen-options/index.html#control-flow-guard + "-Ccontrol-flow-guard" => self.control_flow_guard = value.or(Some("true".into())), + // https://doc.rust-lang.org/rustc/codegen-options/index.html#lto + "-Clto" => self.lto = value.or(Some("true".into())), + // https://doc.rust-lang.org/rustc/codegen-options/index.html#relocation-model + "-Crelocation-model" => { + self.relocation_model = + Some(flag_ok_or(value, "-Crelocation-model must have a value")?); + } + // https://doc.rust-lang.org/rustc/codegen-options/index.html#embed-bitcode + "-Cembed-bitcode" => self.embed_bitcode = value.map_or(Some(true), arg_to_bool), + // https://doc.rust-lang.org/rustc/codegen-options/index.html#force-frame-pointers + "-Cforce-frame-pointers" => { + self.force_frame_pointers = value.map_or(Some(true), arg_to_bool) + } + // https://doc.rust-lang.org/rustc/codegen-options/index.html#link-dead-code + "-Clink-dead-code" => self.link_dead_code = value.map_or(Some(true), arg_to_bool), + // https://doc.rust-lang.org/rustc/codegen-options/index.html#no-redzone + "-Cno-redzone" => self.no_redzone = value.map_or(Some(true), arg_to_bool), + // https://doc.rust-lang.org/rustc/codegen-options/index.html#soft-float + // Note: This flag is now deprecated in rustc. + "-Csoft-float" => self.soft_float = value.map_or(Some(true), arg_to_bool), + // https://doc.rust-lang.org/beta/unstable-book/compiler-flags/branch-protection.html + // FIXME: Drop the -Z variant and update the doc link once the option is stabilised + "-Zbranch-protection" | "-Cbranch-protection" => { + self.branch_protection = + Some(flag_ok_or(value, "-Zbranch-protection must have a value")?); + } + _ => {} + } + Ok(()) + } + + // Rust and clang/cc don't agree on what equivalent flags should look like. + pub(crate) fn cc_flags( + &self, + build: &Build, + path: &Path, + family: ToolFamily, + target: &TargetInfo, + flags: &mut Vec, + ) { + // Push `flag` to `flags` if it is supported by the currently used CC + let mut push_if_supported = |flag: OsString| { + if build + .is_flag_supported_inner(&flag, path, target) + .unwrap_or(false) + { + flags.push(flag); + } else { + build.cargo_output.print_warning(&format!( + "Inherited flag {:?} is not supported by the currently used CC", + flag + )); + } + }; + + match family { + ToolFamily::Clang { .. } | ToolFamily::Gnu => { + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mbranch-protection + if let Some(value) = &self.branch_protection { + push_if_supported( + format!("-mbranch-protection={}", value.replace(",", "+")).into(), + ); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mcmodel + if let Some(value) = &self.code_model { + push_if_supported(format!("-mcmodel={value}").into()); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fno-vectorize + if self.no_vectorize_loops { + push_if_supported("-fno-vectorize".into()); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fno-slp-vectorize + if self.no_vectorize_slp { + push_if_supported("-fno-slp-vectorize".into()); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fprofile-generate + if let Some(value) = &self.profile_generate { + push_if_supported(format!("-fprofile-generate={value}").into()); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fprofile-use + if let Some(value) = &self.profile_use { + push_if_supported(format!("-fprofile-use={value}").into()); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mguard + if let Some(value) = &self.control_flow_guard { + let cc_val = match value.as_str() { + "y" | "yes" | "on" | "true" | "checks" => Some("cf"), + "nochecks" => Some("cf-nochecks"), + "n" | "no" | "off" | "false" => Some("none"), + _ => None, + }; + if let Some(cc_val) = cc_val { + push_if_supported(format!("-mguard={cc_val}").into()); + } + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-flto + if let Some(value) = &self.lto { + let cc_val = match value.as_str() { + "y" | "yes" | "on" | "true" | "fat" => Some("full"), + "thin" => Some("thin"), + _ => None, + }; + if let Some(cc_val) = cc_val { + push_if_supported(format!("-flto={cc_val}").into()); + } + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fPIC + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fPIE + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mdynamic-no-pic + if let Some(value) = &self.relocation_model { + let cc_flag = match value.as_str() { + "pic" => Some("-fPIC"), + "pie" => Some("-fPIE"), + "dynamic-no-pic" => Some("-mdynamic-no-pic"), + _ => None, + }; + if let Some(cc_flag) = cc_flag { + push_if_supported(cc_flag.into()); + } + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fembed-bitcode + if let Some(value) = &self.embed_bitcode { + let cc_val = if *value { "all" } else { "off" }; + push_if_supported(format!("-fembed-bitcode={cc_val}").into()); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fno-omit-frame-pointer + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fomit-frame-pointer + if let Some(value) = &self.force_frame_pointers { + let cc_flag = if *value { + "-fno-omit-frame-pointer" + } else { + "-fomit-frame-pointer" + }; + push_if_supported(cc_flag.into()); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-dead_strip + if let Some(value) = &self.link_dead_code { + if !value { + push_if_supported("-dead_strip".into()); + } + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mno-red-zone + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mred-zone + if let Some(value) = &self.no_redzone { + let cc_flag = if *value { + "-mno-red-zone" + } else { + "-mred-zone" + }; + push_if_supported(cc_flag.into()); + } + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-msoft-float + // https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mno-soft-float + if let Some(value) = &self.soft_float { + let cc_flag = if *value { + "-msoft-float" + } else { + "-mno-soft-float" + }; + push_if_supported(cc_flag.into()); + } + } + ToolFamily::Msvc { .. } => { + // https://learn.microsoft.com/en-us/cpp/build/reference/guard-enable-control-flow-guard + if let Some(value) = &self.control_flow_guard { + let cc_val = match value.as_str() { + "y" | "yes" | "on" | "true" | "checks" => Some("cf"), + "n" | "no" | "off" | "false" => Some("cf-"), + _ => None, + }; + if let Some(cc_val) = cc_val { + push_if_supported(format!("/guard:{cc_val}").into()); + } + } + // https://learn.microsoft.com/en-us/cpp/build/reference/oy-frame-pointer-omission + if let Some(value) = &self.force_frame_pointers { + let cc_flag = if *value { "/Oy-" } else { "/Oy" }; + push_if_supported(cc_flag.into()); + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[track_caller] + fn check(env: &str, expected: &RustcCodegenFlags) { + let actual = RustcCodegenFlags::parse(env).unwrap(); + assert_eq!(actual, *expected); + } + + #[test] + fn codegen_type() { + let expected = RustcCodegenFlags { + code_model: Some("tiny".into()), + ..RustcCodegenFlags::default() + }; + check("-Ccode-model=tiny", &expected); + check("-C\u{1f}code-model=tiny", &expected); + check("--codegen\u{1f}code-model=tiny", &expected); + check("--codegen=code-model=tiny", &expected); + } + + #[test] + fn precedence() { + check( + "-ccode-model=tiny\u{1f}-Ccode-model=small", + &RustcCodegenFlags { + code_model: Some("small".into()), + ..RustcCodegenFlags::default() + }, + ); + } + + #[test] + fn two_valid_prefixes() { + let expected = RustcCodegenFlags::default(); + check("-L\u{1f}-Clto", &expected); + } + + #[test] + fn three_valid_prefixes() { + let expected = RustcCodegenFlags { + lto: Some("true".into()), + ..RustcCodegenFlags::default() + }; + check("-L\u{1f}-L\u{1f}-Clto", &expected); + } + + #[test] + fn all_rustc_flags() { + // Throw all possible flags at the parser to catch false positives + let flags = [ + // Set all the flags we recognise first + "-Ccode-model=tiny", + "-Ccontrol-flow-guard=yes", + "-Cembed-bitcode=no", + "-Cforce-frame-pointers=yes", + "-Clto=false", + "-Clink-dead-code=yes", + "-Cno-redzone=yes", + "-Cno-vectorize-loops", + "-Cno-vectorize-slp", + "-Cprofile-generate=fooprofile", + "-Cprofile-use=fooprofile", + "-Crelocation-model=pic", + "-Csoft-float=yes", + "-Zbranch-protection=bti,pac-ret,leaf", + // Set flags we don't recognise but rustc supports next + // rustc flags + "--cfg", + "a", + "--check-cfg 'cfg(verbose)", + "-L", + "/usr/lib/foo", + "-l", + "static:+whole-archive=mylib", + "--crate-type=dylib", + "--crate-name=foo", + "--edition=2021", + "--emit=asm", + "--print=crate-name", + "-g", + "-O", + "-o", + "foooutput", + "--out-dir", + "foooutdir", + "--target", + "aarch64-unknown-linux-gnu", + "-W", + "missing-docs", + "-D", + "unused-variables", + "--force-warn", + "dead-code", + "-A", + "unused", + "-F", + "unused", + "--cap-lints", + "warn", + "--version", + "--verbose", + "-v", + "--extern", + "foocrate", + "--sysroot", + "fooroot", + "--error-format", + "human", + "--color", + "auto", + "--diagnostic-width", + "80", + "--remap-path-prefix", + "foo=bar", + "--json=artifact", + // Codegen flags + "-Car", + "-Ccodegen-units=1", + "-Ccollapse-macro-debuginfo=yes", + "-Cdebug-assertions=yes", + "-Cdebuginfo=1", + "-Cdefault-linker-libraries=yes", + "-Cdlltool=foo", + "-Cextra-filename=foo", + "-Cforce-unwind-tables=yes", + "-Cincremental=foodir", + "-Cinline-threshold=6", + "-Cinstrument-coverage", + "-Clink-arg=-foo", + "-Clink-args=-foo", + "-Clink-self-contained=yes", + "-Clinker=lld", + "-Clinker-flavor=ld.lld", + "-Clinker-plugin-lto=yes", + "-Cllvm-args=foo", + "-Cmetadata=foo", + "-Cno-prepopulate-passes", + "-Cno-stack-check", + "-Copt-level=3", + "-Coverflow-checks=yes", + "-Cpanic=abort", + "-Cpasses=foopass", + "-Cprefer-dynamic=yes", + "-Crelro-level=partial", + "-Cremark=all", + "-Crpath=yes", + "-Csave-temps=yes", + "-Csplit-debuginfo=packed", + "-Cstrip=symbols", + "-Csymbol-mangling-version=v0", + "-Ctarget-cpu=native", + "-Ctarget-feature=+sve", + // Unstable options + "-Ztune-cpu=machine", + ]; + check( + &flags.join("\u{1f}"), + &RustcCodegenFlags { + code_model: Some("tiny".into()), + control_flow_guard: Some("yes".into()), + embed_bitcode: Some(false), + force_frame_pointers: Some(true), + link_dead_code: Some(true), + lto: Some("false".into()), + no_redzone: Some(true), + no_vectorize_loops: true, + no_vectorize_slp: true, + profile_generate: Some("fooprofile".into()), + profile_use: Some("fooprofile".into()), + relocation_model: Some("pic".into()), + soft_float: Some(true), + branch_protection: Some("bti,pac-ret,leaf".into()), + }, + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 7f21b05bc..2d0daa6de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -261,6 +261,9 @@ mod tempfile; mod utilities; use utilities::*; +mod flags; +use flags::*; + #[derive(Debug, Eq, PartialEq, Hash)] struct CompilerFlag { compiler: Box, @@ -328,6 +331,7 @@ pub struct Build { emit_rerun_if_env_changed: bool, shell_escaped_flags: Option, build_cache: Arc, + inherit_rustflags: bool, } /// Represents the types of errors that may occur while using cc-rs. @@ -343,10 +347,12 @@ enum ErrorKind { ToolNotFound, /// One of the function arguments failed validation. InvalidArgument, - /// No known macro is defined for the compiler when discovering tool family + /// No known macro is defined for the compiler when discovering tool family. ToolFamilyMacroNotFound, - /// Invalid target + /// Invalid target. InvalidTarget, + /// Invalid rustc flag. + InvalidFlag, #[cfg(feature = "parallel")] /// jobserver helpthread failure JobserverHelpThreadError, @@ -449,6 +455,7 @@ impl Build { emit_rerun_if_env_changed: true, shell_escaped_flags: None, build_cache: Arc::default(), + inherit_rustflags: true, } } @@ -563,7 +570,6 @@ impl Build { /// .flag("unwanted_flag") /// .remove_flag("unwanted_flag"); /// ``` - pub fn remove_flag(&mut self, flag: &str) -> &mut Build { self.flags.retain(|other_flag| &**other_flag != flag); self @@ -677,6 +683,7 @@ impl Build { .debug(false) .cpp(self.cpp) .cuda(self.cuda) + .inherit_rustflags(false) .emit_rerun_if_env_changed(self.emit_rerun_if_env_changed); if let Some(target) = &self.target { cfg.target(target); @@ -1333,6 +1340,15 @@ impl Build { self } + /// Configure whether cc should automatically inherit compatible flags passed to rustc + /// from `CARGO_ENCODED_RUSTFLAGS`. + /// + /// This option defaults to `true`. + pub fn inherit_rustflags(&mut self, inherit_rustflags: bool) -> &mut Build { + self.inherit_rustflags = inherit_rustflags; + self + } + #[doc(hidden)] pub fn __set_env(&mut self, a: A, b: B) -> &mut Build where @@ -1928,6 +1944,11 @@ impl Build { cmd.args.push((**flag).into()); } + // Add cc flags inherited from matching rustc flags + if self.inherit_rustflags { + self.add_inherited_rustflags(&mut cmd, &target)?; + } + for flag in self.flags_supported.iter() { if self .is_flag_supported_inner(flag, &cmd.path, &target) @@ -2378,6 +2399,23 @@ impl Build { Ok(()) } + fn add_inherited_rustflags(&self, cmd: &mut Tool, target: &TargetInfo) -> Result<(), Error> { + let env_os = match self.getenv("CARGO_ENCODED_RUSTFLAGS") { + Some(env) => env, + // No encoded RUSTFLAGS -> nothing to do + None => return Ok(()), + }; + + let Tool { + family, path, args, .. + } = cmd; + + let env = env_os.to_string_lossy(); + let codegen_flags = RustcCodegenFlags::parse(&env)?; + codegen_flags.cc_flags(self, path, *family, target, args); + Ok(()) + } + fn has_flags(&self) -> bool { let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" }; let flags_env_var_value = self.getenv_with_target_prefixes(flags_env_var_name); diff --git a/tests/rustflags.rs b/tests/rustflags.rs new file mode 100644 index 000000000..c9c6fc140 --- /dev/null +++ b/tests/rustflags.rs @@ -0,0 +1,29 @@ +use crate::support::Test; +mod support; + +/// This test is in its own module because it modifies the environment and would affect other tests +/// when run in parallel with them. +#[test] +#[cfg(not(windows))] +fn inherits_rustflags() { + // Sanity check - no flags + std::env::set_var("CARGO_ENCODED_RUSTFLAGS", ""); + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + test.cmd(0) + .must_not_have("-fno-omit-frame-pointer") + .must_not_have("-mcmodel=small") + .must_not_have("-msoft-float"); + + // Correctly inherits flags from rustc + std::env::set_var( + "CARGO_ENCODED_RUSTFLAGS", + "-Cforce-frame-pointers=true\u{1f}-Ccode-model=small\u{1f}-Csoft-float", + ); + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + test.cmd(0) + .must_have("-fno-omit-frame-pointer") + .must_have("-mcmodel=small") + .must_have("-msoft-float"); +} From 5daf14e96f28bfa634c135c87a953afdbefeb63e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 19:12:12 +1100 Subject: [PATCH 12/12] chore: release v1.2.2 (#1306) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CHANGELOG.md | 14 ++++++++++++++ Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 953bbda18..06a8156e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.2.2](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.1...cc-v1.2.2) - 2024-11-29 + +### Other + +- Inherit flags from rustc ([#1279](https://github.com/rust-lang/cc-rs/pull/1279)) +- Add support for using sccache wrapper with cuda/nvcc ([#1304](https://github.com/rust-lang/cc-rs/pull/1304)) +- Fix msvc stdout not shown on error ([#1303](https://github.com/rust-lang/cc-rs/pull/1303)) +- Regenerate target info ([#1301](https://github.com/rust-lang/cc-rs/pull/1301)) +- Fix compilation of C++ code for armv7-unknown-linux-gnueabihf ([#1298](https://github.com/rust-lang/cc-rs/pull/1298)) +- Fetch target info from Cargo even if `Build::target` is manually set ([#1299](https://github.com/rust-lang/cc-rs/pull/1299)) +- Fix two files with different extensions having the same object name ([#1295](https://github.com/rust-lang/cc-rs/pull/1295)) +- Allow disabling cc's ability to compile via env var CC_FORCE_DISABLE ([#1292](https://github.com/rust-lang/cc-rs/pull/1292)) +- Regenerate target info ([#1293](https://github.com/rust-lang/cc-rs/pull/1293)) + ## [1.2.1](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.0...cc-v1.2.1) - 2024-11-14 ### Other diff --git a/Cargo.toml b/Cargo.toml index b9f09a0a0..8dded2d50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cc" -version = "1.2.1" +version = "1.2.2" authors = ["Alex Crichton "] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/cc-rs"