Skip to content

Commit abf67d7

Browse files
authored
feat: Query rustc for clang target triples instead of hardcoding them (#1004)
* Add new workspace crate `gen-target-info` For generating `src/target_info.rs`, and use it to simplify riscv target arch mapping logic in `Build::add_default_flags` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Fix msrv CI: Pass `--locked` to `cargo` to use constructed lockfile Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Fix msrv: Use edition 2018 in workspace gen-target-info Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Fix `gen-target-info`: Generate formatted rust code Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Fix `gen-target-info` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Format `Cargo.toml` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Rename `write_string_mapping_to_file` to `write_target_tuple_mapping` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Refactor: Extract new fn `generate_riscv_arch_mapping` Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> * Add doc for the `target_info.rs` to warn against manually editing the file Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com> --------- Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
1 parent df62625 commit abf67d7

File tree

10 files changed

+163
-33
lines changed

10 files changed

+163
-33
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ jobs:
170170
run: cargo +nightly update -Zminimal-versions
171171
- name: Cache downloaded crates since 1.53 is really slow in fetching
172172
uses: Swatinem/rust-cache@v2
173-
- run: cargo check --lib -p cc
174-
- run: cargo check --lib -p cc --all-features
173+
- run: cargo check --lib -p cc --locked
174+
- run: cargo check --lib -p cc --locked --all-features
175175

176176
clippy:
177177
name: Clippy

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ tempfile = "3"
3636
[workspace]
3737
members = [
3838
"dev-tools/cc-test",
39+
"dev-tools/gen-target-info",
3940
"dev-tools/gen-windows-sys-binding",
4041
]

dev-tools/gen-target-info/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "gen-target-info"
3+
version = "0.1.0"
4+
edition = "2018"
5+
publish = false
6+
7+
[dependencies]
8+
serde = { version = "1.0.163", features = ["derive"] }
9+
serde-tuple-vec-map = "1.0.1"
10+
serde_json = "1.0.107"

dev-tools/gen-target-info/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
mod target_specs;
2+
pub use target_specs::*;
3+
4+
mod read;
5+
pub use read::get_target_specs_from_json;
6+
7+
mod write;
8+
pub use write::*;

dev-tools/gen-target-info/src/main.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use gen_target_info::{get_target_specs_from_json, write_target_tuple_mapping, RustcTargetSpecs};
2+
use std::{fs::File, io::Write as _};
3+
4+
const PRELUDE: &str = r#"//! This file is generated code. Please edit the generator
5+
//! in dev-tools/gen-target-info if you need to make changes.
6+
7+
"#;
8+
9+
fn generate_riscv_arch_mapping(f: &mut File, target_specs: &RustcTargetSpecs) {
10+
let mut riscv_target_mapping = target_specs
11+
.0
12+
.iter()
13+
.filter_map(|(target, target_spec)| {
14+
let arch = target.split_once('-').unwrap().0;
15+
(arch.contains("riscv") && arch != &target_spec.arch)
16+
.then_some((arch, &*target_spec.arch))
17+
})
18+
.collect::<Vec<_>>();
19+
riscv_target_mapping.sort_unstable_by_key(|(arch, _)| &**arch);
20+
riscv_target_mapping.dedup();
21+
write_target_tuple_mapping(f, "RISCV_ARCH_MAPPING", &riscv_target_mapping);
22+
}
23+
24+
fn main() {
25+
let target_specs = get_target_specs_from_json();
26+
27+
// Open file to write to
28+
let manifest_dir = env!("CARGO_MANIFEST_DIR");
29+
30+
let path = format!("{manifest_dir}/../../src/target_info.rs");
31+
let mut f = File::create(path).expect("failed to create src/target_info.rs");
32+
33+
f.write_all(PRELUDE.as_bytes()).unwrap();
34+
35+
// Start generating
36+
generate_riscv_arch_mapping(&mut f, &target_specs);
37+
38+
// Flush the data onto disk
39+
f.flush().unwrap();
40+
}

dev-tools/gen-target-info/src/read.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use std::process;
2+
3+
use crate::RustcTargetSpecs;
4+
5+
pub fn get_target_specs_from_json() -> RustcTargetSpecs {
6+
let mut cmd = process::Command::new("rustc");
7+
cmd.args([
8+
"+nightly",
9+
"-Zunstable-options",
10+
"--print",
11+
"all-target-specs-json",
12+
])
13+
.stdout(process::Stdio::piped());
14+
15+
let process::Output { status, stdout, .. } = cmd.output().unwrap();
16+
17+
if !status.success() {
18+
panic!("{:?} failed with non-zero exit status: {}", cmd, status)
19+
}
20+
21+
serde_json::from_slice(&stdout).unwrap()
22+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use serde::Deserialize;
2+
3+
#[derive(Debug, Deserialize)]
4+
#[serde(transparent)]
5+
pub struct PreLinkArgs(
6+
/// First field in the linker name,
7+
/// second field is the args.
8+
#[serde(with = "tuple_vec_map")]
9+
pub Vec<(String, Vec<String>)>,
10+
);
11+
12+
#[derive(Debug, Deserialize)]
13+
#[serde(rename_all(deserialize = "kebab-case"))]
14+
pub struct TargetSpec {
15+
pub arch: String,
16+
pub llvm_target: String,
17+
/// link env to remove, mostly for apple
18+
pub link_env_remove: Option<Vec<String>>,
19+
/// link env to set, mostly for apple, e.g. `ZERO_AR_DATE=1`
20+
pub link_env: Option<Vec<String>>,
21+
pub os: Option<String>,
22+
/// `apple`, `pc`
23+
pub vendor: Option<String>,
24+
pub pre_link_args: Option<PreLinkArgs>,
25+
}
26+
27+
#[derive(Debug, Deserialize)]
28+
#[serde(transparent)]
29+
pub struct RustcTargetSpecs(
30+
/// First field in the tuple is the rustc target
31+
#[serde(with = "tuple_vec_map")]
32+
pub Vec<(String, TargetSpec)>,
33+
);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use std::{fmt::Write as _, fs, io::Write as _};
2+
3+
pub fn write_target_tuple_mapping(f: &mut fs::File, variable_name: &str, data: &[(&str, &str)]) {
4+
let mut content = format!("pub const {variable_name}: &[(&str, &str)] = &[\n");
5+
6+
for (f1, f2) in data {
7+
write!(&mut content, r#" ("{f1}", "{f2}"),"#).unwrap();
8+
content.push('\n');
9+
}
10+
11+
content.push_str("];\n");
12+
13+
f.write_all(content.as_bytes()).unwrap();
14+
}

src/lib.rs

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ mod tool;
247247
pub use tool::Tool;
248248
use tool::ToolFamily;
249249

250+
mod target_info;
251+
250252
/// A builder for compilation of a native library.
251253
///
252254
/// A `Build` is the main type of the `cc` crate and is used to control all the
@@ -312,6 +314,8 @@ enum ErrorKind {
312314
ToolNotFound,
313315
/// One of the function arguments failed validation.
314316
InvalidArgument,
317+
/// Invalid target
318+
InvalidTarget,
315319
#[cfg(feature = "parallel")]
316320
/// jobserver helpthread failure
317321
JobserverHelpThreadError,
@@ -1900,6 +1904,13 @@ impl Build {
19001904
&& !(target.contains("android")
19011905
&& android_clang_compiler_uses_target_arg_internally(&cmd.path))
19021906
{
1907+
let (arch, rest) = target.split_once('-').ok_or_else(|| {
1908+
Error::new(
1909+
ErrorKind::InvalidTarget,
1910+
format!("Invalid target `{}`: no `-` in it", target),
1911+
)
1912+
})?;
1913+
19031914
if target.contains("darwin") {
19041915
if let Some(arch) =
19051916
map_darwin_target_from_rust_to_compiler_architecture(target)
@@ -1983,39 +1994,17 @@ impl Build {
19831994
format!("--target={}-apple-tvos{}", arch, deployment_target).into(),
19841995
);
19851996
}
1986-
} else if target.starts_with("riscv64gc-") {
1987-
cmd.args.push(
1988-
format!("--target={}", target.replace("riscv64gc", "riscv64")).into(),
1989-
);
1990-
} else if target.starts_with("riscv64imac-") {
1991-
cmd.args.push(
1992-
format!("--target={}", target.replace("riscv64imac", "riscv64")).into(),
1993-
);
1994-
} else if target.starts_with("riscv32gc-") {
1997+
} else if let Ok(index) = target_info::RISCV_ARCH_MAPPING
1998+
.binary_search_by_key(&arch, |(arch, _)| &arch)
1999+
{
19952000
cmd.args.push(
1996-
format!("--target={}", target.replace("riscv32gc", "riscv32")).into(),
2001+
format!(
2002+
"--target={}-{}",
2003+
target_info::RISCV_ARCH_MAPPING[index].1,
2004+
rest
2005+
)
2006+
.into(),
19972007
);
1998-
} else if target.starts_with("riscv32i-") {
1999-
cmd.args.push(
2000-
format!("--target={}", target.replace("riscv32i", "riscv32")).into(),
2001-
)
2002-
} else if target.starts_with("riscv32im-") {
2003-
cmd.args.push(
2004-
format!("--target={}", target.replace("riscv32im", "riscv32")).into(),
2005-
)
2006-
} else if target.starts_with("riscv32imc-") {
2007-
cmd.args.push(
2008-
format!("--target={}", target.replace("riscv32imc", "riscv32")).into(),
2009-
)
2010-
} else if target.starts_with("riscv32imac-") {
2011-
cmd.args.push(
2012-
format!("--target={}", target.replace("riscv32imac", "riscv32")).into(),
2013-
)
2014-
} else if target.starts_with("riscv32imafc-") {
2015-
cmd.args.push(
2016-
format!("--target={}", target.replace("riscv32imafc", "riscv32"))
2017-
.into(),
2018-
)
20192008
} else if target.contains("uefi") {
20202009
if target.contains("x86_64") {
20212010
cmd.args.push("--target=x86_64-unknown-windows-gnu".into());

src/target_info.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//! This file is generated code. Please edit the generator
2+
//! in dev-tools/gen-target-info if you need to make changes.
3+
4+
pub const RISCV_ARCH_MAPPING: &[(&str, &str)] = &[
5+
("riscv32gc", "riscv32"),
6+
("riscv32i", "riscv32"),
7+
("riscv32im", "riscv32"),
8+
("riscv32imac", "riscv32"),
9+
("riscv32imafc", "riscv32"),
10+
("riscv32imc", "riscv32"),
11+
("riscv64gc", "riscv64"),
12+
("riscv64imac", "riscv64"),
13+
];

0 commit comments

Comments
 (0)