Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fall back to rustc's default value for crt-static #1266

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
10 changes: 10 additions & 0 deletions dev-tools/gen-target-info/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fn generate_target_mapping(f: &mut File, target_specs: &RustcTargetSpecs) -> std
let os = spec.os.as_deref().unwrap_or("none");
let env = spec.env.as_deref().unwrap_or("");
let abi = spec.abi.as_deref().unwrap_or("");
let features = spec.cfgs.target_features.join(",");

let unversioned_llvm_target = if spec.llvm_target.contains("apple") {
// Remove deployment target information from LLVM target triples (we
Expand Down Expand Up @@ -84,6 +85,15 @@ fn generate_target_mapping(f: &mut File, target_specs: &RustcTargetSpecs) -> std
f,
" unversioned_llvm_target: {unversioned_llvm_target:?},"
)?;
// NOTE: Features are generated from nightly versions, which will
// result in unstable values being output here as well. That is
// probably desirable since:
// 1. They're only used when `cc` is used outside a build script, and
// then we can't do feature detection, so we have to pick either
// the stable or the nightly representation.
// 2. The nightly representation is much more feature-ful, and `cc`'s
// conversion is going to be best-effort anyhow.
writeln!(f, " features: {features:?},")?;
writeln!(f, " }},")?;
writeln!(f, " ),")?;
}
Expand Down
38 changes: 34 additions & 4 deletions dev-tools/gen-target-info/src/read.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
use std::process;
use std::{io::BufRead, process};

use crate::{RustcTargetSpecs, TargetSpec};
use crate::{Cfgs, RustcTargetSpecs, TargetSpec};

fn get_cfgs(version: &str, target: &str) -> Cfgs {
let mut cmd = process::Command::new("rustc");
cmd.args([
version,
"-Zunstable-options",
"--print",
"cfg",
"--target",
target,
]);
cmd.env("RUSTC_BOOTSTRAP", "1");
cmd.stdout(process::Stdio::piped());
cmd.stderr(process::Stdio::inherit());

let process::Output { status, stdout, .. } = cmd.output().unwrap();

if !status.success() {
panic!("{:?} failed with non-zero exit status: {}", cmd, status)
}

let cfgs: Vec<String> = stdout.lines().map(|line| line.unwrap()).collect();
Cfgs::parse(&cfgs)
}

pub fn get_targets_msrv() -> Vec<u8> {
let mut cmd = process::Command::new("rustc");
Expand Down Expand Up @@ -37,7 +61,9 @@ pub fn get_target_spec_from_msrv(target: &str) -> TargetSpec {
panic!("{:?} failed with non-zero exit status: {}", cmd, status)
}

serde_json::from_slice(&stdout).unwrap()
let mut spec: TargetSpec = serde_json::from_slice(&stdout).unwrap();
spec.cfgs = get_cfgs("+1.63", target);
spec
}

pub fn get_target_specs_from_json() -> RustcTargetSpecs {
Expand All @@ -57,5 +83,9 @@ pub fn get_target_specs_from_json() -> RustcTargetSpecs {
panic!("{:?} failed with non-zero exit status: {}", cmd, status)
}

serde_json::from_slice(&stdout).unwrap()
let mut specs: RustcTargetSpecs = serde_json::from_slice(&stdout).unwrap();
for (target, spec) in &mut specs.0 {
spec.cfgs = get_cfgs("+nightly", target);
}
specs
}
48 changes: 48 additions & 0 deletions dev-tools/gen-target-info/src/target_specs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ pub struct TargetSpec {
pub vendor: Option<String>,
pub env: Option<String>,
pub abi: Option<String>,
pub target_pointer_width: String,
pub pre_link_args: Option<PreLinkArgs>,
#[serde(skip)]
pub cfgs: Cfgs,
}

#[derive(Debug, Deserialize)]
Expand All @@ -32,3 +35,48 @@ pub struct RustcTargetSpecs(
/// First field in the tuple is the rustc target
pub BTreeMap<String, TargetSpec>,
);

/// Potentially useful values from:
/// <https://doc.rust-lang.org/reference/conditional-compilation.html>
/// That are not directly / easily exposed in `TargetSpec`.
#[derive(Debug, Default)]
pub struct Cfgs {
pub target_features: Vec<String>,
pub target_families: Vec<String>,
pub target_endian: String,
pub target_atomics: Vec<String>,
pub target_thread_local: bool,
}

impl Cfgs {
pub fn parse(cfgs: &[String]) -> Self {
let mut target_features = vec![];
let mut target_families = vec![];
let mut target_endian = None;
let mut target_atomics = vec![];
let mut target_thread_local = false;
for cfg in cfgs {
let (name, value) = cfg
.split_once('=')
.map(|(n, v)| (n.trim(), Some(v.trim().trim_matches('"'))))
.unwrap_or((cfg.trim(), None));

match (name, value) {
("target_feature", Some(value)) => target_features.push(value.to_string()),
("target_family", Some(value)) => target_families.push(value.to_string()),
("target_endian", Some(value)) => target_endian = Some(value.to_string()),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit:

Shall we have a check for duplicate value, just in case rustc gives us some invalid output?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea

("target_has_atomic", Some(value)) => target_atomics.push(value.to_string()),
("target_thread_local", None) => target_thread_local = true,
_ => {} // Ignore the rest
}
}

Self {
target_features,
target_families,
target_endian: target_endian.expect("must have target_endian cfg"),
target_atomics,
target_thread_local,
}
}
}
31 changes: 13 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,10 @@ impl Build {
/// When enabled on systems that support dynamic linking, this prevents
/// linking with the shared libraries.
///
/// If not specified, this falls back to:
/// - `-Ctarget-features=+crt-static` when compiling in a build script.
/// - A target-specific default.
///
/// # Example
///
/// ```no_run
Expand Down Expand Up @@ -1301,6 +1305,9 @@ impl Build {
/// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools.
///
/// This option defaults to `false`, and affect only msvc targets.
///
/// If not specified, this falls back to `-Ctarget-features=+crt-static`
/// when compiling in a build script.
pub fn static_crt(&mut self, static_crt: bool) -> &mut Build {
self.static_crt = Some(static_crt);
self
Expand Down Expand Up @@ -1944,18 +1951,10 @@ impl Build {
ToolFamily::Msvc { .. } => {
cmd.push_cc_arg("-nologo".into());

let crt_flag = match self.static_crt {
Some(true) => "-MT",
Some(false) => "-MD",
None => {
let features = self.getenv("CARGO_CFG_TARGET_FEATURE");
let features = features.as_deref().unwrap_or_default();
if features.to_string_lossy().contains("crt-static") {
"-MT"
} else {
"-MD"
}
}
let crt_flag = if self.static_crt.unwrap_or_else(|| target.crt_static()) {
"-MT"
} else {
"-MD"
};
cmd.push_cc_arg(crt_flag.into());

Expand Down Expand Up @@ -2142,12 +2141,8 @@ impl Build {
cmd.args.push("-finput-charset=utf-8".into());
}

if self.static_flag.is_none() {
let features = self.getenv("CARGO_CFG_TARGET_FEATURE");
let features = features.as_deref().unwrap_or_default();
if features.to_string_lossy().contains("crt-static") {
cmd.args.push("-static".into());
}
if self.static_flag.is_none() && target.crt_static() {
cmd.args.push("-static".into());
}

// armv7 targets get to use armv7 instructions
Expand Down
17 changes: 17 additions & 0 deletions src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ pub(crate) struct TargetInfo<'a> {
///
/// This is the same as the value of `cfg!(target_abi)`.
pub abi: &'a str,
/// The set of target features, separated by commas.
/// See <https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute>
///
/// This is the same as the value of `CARGO_CFG_TARGET_FEATURE`, and
/// can be overwritten by the user with `-Ctarget-feature=...`.
///
/// This means it also includes the special feature `crt-static`.
/// NOTE: The default value is not available to build scripts, see:
/// <https://github.com/rust-lang/cargo/issues/14778>
features: &'a str,
/// The unversioned LLVM/Clang target triple.
unversioned_llvm_target: &'a str,
}
Expand All @@ -66,6 +76,13 @@ impl FromStr for TargetInfo<'_> {
}
}

impl TargetInfo<'_> {
/// See <https://doc.rust-lang.org/reference/linkage.html#static-and-dynamic-c-runtimes>
pub(crate) fn crt_static(&self) -> bool {
self.features.contains("crt-static")
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down
Loading