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

feat: Query rustc for clang target triples instead of hardcoding them #1004

Merged
merged 9 commits into from
Mar 15, 2024
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ jobs:
run: cargo +nightly update -Zminimal-versions
- name: Cache downloaded crates since 1.53 is really slow in fetching
uses: Swatinem/rust-cache@v2
- run: cargo check --lib -p cc
- run: cargo check --lib -p cc --all-features
- run: cargo check --lib -p cc --locked
- run: cargo check --lib -p cc --locked --all-features

clippy:
name: Clippy
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ tempfile = "3"
[workspace]
members = [
"dev-tools/cc-test",
"dev-tools/gen-target-info",
"dev-tools/gen-windows-sys-binding",
]
10 changes: 10 additions & 0 deletions dev-tools/gen-target-info/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "gen-target-info"
version = "0.1.0"
edition = "2018"
publish = false

[dependencies]
serde = { version = "1.0.163", features = ["derive"] }
serde-tuple-vec-map = "1.0.1"
serde_json = "1.0.107"
8 changes: 8 additions & 0 deletions dev-tools/gen-target-info/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod target_specs;
pub use target_specs::*;

mod read;
pub use read::get_target_specs_from_json;

mod write;
pub use write::*;
29 changes: 29 additions & 0 deletions dev-tools/gen-target-info/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use gen_target_info::{get_target_specs_from_json, write_string_mapping_to_file};
use std::{fs::File, io::Write as _};

fn main() {
let target_specs = get_target_specs_from_json();

// Open file to write to
let manifest_dir = env!("CARGO_MANIFEST_DIR");

let path = format!("{manifest_dir}/../../src/target_info.rs");
let mut f = File::create(path).expect("failed to create src/target_info.rs");

NobodyXu marked this conversation as resolved.
Show resolved Hide resolved
// Wrute riscv target mapping
let mut riscv_target_mapping = target_specs
.0
.iter()
.filter_map(|(target, target_spec)| {
let arch = target.split_once('-').unwrap().0;
(arch.contains("riscv") && arch != &target_spec.arch)
.then_some((arch, &*target_spec.arch))
})
.collect::<Vec<_>>();
riscv_target_mapping.sort_unstable_by_key(|(arch, _)| &**arch);
riscv_target_mapping.dedup();
write_string_mapping_to_file(&mut f, "RISCV_ARCH_MAPPING", &riscv_target_mapping);
NobodyXu marked this conversation as resolved.
Show resolved Hide resolved

// Flush the data onto disk
f.flush().unwrap();
}
22 changes: 22 additions & 0 deletions dev-tools/gen-target-info/src/read.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use std::process;

use crate::RustcTargetSpecs;

pub fn get_target_specs_from_json() -> RustcTargetSpecs {
let mut cmd = process::Command::new("rustc");
cmd.args([
"+nightly",
"-Zunstable-options",
"--print",
"all-target-specs-json",
])
.stdout(process::Stdio::piped());

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

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

serde_json::from_slice(&stdout).unwrap()
}
33 changes: 33 additions & 0 deletions dev-tools/gen-target-info/src/target_specs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use serde::Deserialize;

#[derive(Debug, Deserialize)]
#[serde(transparent)]
pub struct PreLinkArgs(
/// First field in the linker name,
/// second field is the args.
#[serde(with = "tuple_vec_map")]
pub Vec<(String, Vec<String>)>,
);

#[derive(Debug, Deserialize)]
#[serde(rename_all(deserialize = "kebab-case"))]
pub struct TargetSpec {
pub arch: String,
pub llvm_target: String,
/// link env to remove, mostly for apple
pub link_env_remove: Option<Vec<String>>,
/// link env to set, mostly for apple, e.g. `ZERO_AR_DATE=1`
pub link_env: Option<Vec<String>>,
pub os: Option<String>,
/// `apple`, `pc`
pub vendor: Option<String>,
pub pre_link_args: Option<PreLinkArgs>,
}

#[derive(Debug, Deserialize)]
#[serde(transparent)]
pub struct RustcTargetSpecs(
/// First field in the tuple is the rustc target
#[serde(with = "tuple_vec_map")]
pub Vec<(String, TargetSpec)>,
);
14 changes: 14 additions & 0 deletions dev-tools/gen-target-info/src/write.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use std::{fmt::Write as _, fs, io::Write as _};

pub fn write_string_mapping_to_file(f: &mut fs::File, variable_name: &str, data: &[(&str, &str)]) {
NobodyXu marked this conversation as resolved.
Show resolved Hide resolved
let mut content = format!("pub const {variable_name}: &[(&str, &str)] = &[\n");

for (f1, f2) in data {
write!(&mut content, r#" ("{f1}", "{f2}"),"#).unwrap();
content.push('\n');
}

content.push_str("];\n");

f.write_all(content.as_bytes()).unwrap();
NobodyXu marked this conversation as resolved.
Show resolved Hide resolved
}
51 changes: 20 additions & 31 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ mod tool;
pub use tool::Tool;
use tool::ToolFamily;

mod target_info;

/// A builder for compilation of a native library.
///
/// A `Build` is the main type of the `cc` crate and is used to control all the
Expand Down Expand Up @@ -312,6 +314,8 @@ enum ErrorKind {
ToolNotFound,
/// One of the function arguments failed validation.
InvalidArgument,
/// Invalid target
InvalidTarget,
#[cfg(feature = "parallel")]
/// jobserver helpthread failure
JobserverHelpThreadError,
Expand Down Expand Up @@ -1900,6 +1904,13 @@ impl Build {
&& !(target.contains("android")
&& android_clang_compiler_uses_target_arg_internally(&cmd.path))
{
let (arch, rest) = target.split_once('-').ok_or_else(|| {
Error::new(
ErrorKind::InvalidTarget,
format!("Invalid target `{}`: no `-` in it", target),
)
})?;

if target.contains("darwin") {
if let Some(arch) =
map_darwin_target_from_rust_to_compiler_architecture(target)
Expand Down Expand Up @@ -1983,39 +1994,17 @@ impl Build {
format!("--target={}-apple-tvos{}", arch, deployment_target).into(),
);
}
} else if target.starts_with("riscv64gc-") {
cmd.args.push(
format!("--target={}", target.replace("riscv64gc", "riscv64")).into(),
);
} else if target.starts_with("riscv64imac-") {
cmd.args.push(
format!("--target={}", target.replace("riscv64imac", "riscv64")).into(),
);
} else if target.starts_with("riscv32gc-") {
} else if let Ok(index) = target_info::RISCV_ARCH_MAPPING
.binary_search_by_key(&arch, |(arch, _)| &arch)
{
cmd.args.push(
format!("--target={}", target.replace("riscv32gc", "riscv32")).into(),
format!(
"--target={}-{}",
target_info::RISCV_ARCH_MAPPING[index].1,
rest
)
.into(),
);
} else if target.starts_with("riscv32i-") {
cmd.args.push(
format!("--target={}", target.replace("riscv32i", "riscv32")).into(),
)
} else if target.starts_with("riscv32im-") {
cmd.args.push(
format!("--target={}", target.replace("riscv32im", "riscv32")).into(),
)
} else if target.starts_with("riscv32imc-") {
cmd.args.push(
format!("--target={}", target.replace("riscv32imc", "riscv32")).into(),
)
} else if target.starts_with("riscv32imac-") {
cmd.args.push(
format!("--target={}", target.replace("riscv32imac", "riscv32")).into(),
)
} else if target.starts_with("riscv32imafc-") {
cmd.args.push(
format!("--target={}", target.replace("riscv32imafc", "riscv32"))
.into(),
)
} else if target.contains("uefi") {
if target.contains("x86_64") {
cmd.args.push("--target=x86_64-unknown-windows-gnu".into());
Expand Down
10 changes: 10 additions & 0 deletions src/target_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pub const RISCV_ARCH_MAPPING: &[(&str, &str)] = &[
("riscv32gc", "riscv32"),
("riscv32i", "riscv32"),
("riscv32im", "riscv32"),
("riscv32imac", "riscv32"),
("riscv32imafc", "riscv32"),
("riscv32imc", "riscv32"),
("riscv64gc", "riscv64"),
("riscv64imac", "riscv64"),
];
NobodyXu marked this conversation as resolved.
Show resolved Hide resolved