150783355STrevor Gross use std::process::{Command, Output};
2da089f78STrevor Gross use std::{env, str};
379c80c4eSIsaac Woods
4f8a12ee0SPietro Albini // List of cfgs this build script is allowed to set. The list is needed to support check-cfg, as we
5f8a12ee0SPietro Albini // need to know all the possible cfgs that this script will set. If you need to set another cfg
6f8a12ee0SPietro Albini // make sure to add it to this list as well.
7a598506fSYuri Astrakhan const ALLOWED_CFGS: &[&str] = &[
8e7a9c4a7SKleis Auke Wolthuizen "emscripten_old_stat_abi",
9022a4398SSergio Gasquez "espidf_time32",
10f8a12ee0SPietro Albini "freebsd10",
11f8a12ee0SPietro Albini "freebsd11",
12f8a12ee0SPietro Albini "freebsd12",
13f8a12ee0SPietro Albini "freebsd13",
14f8a12ee0SPietro Albini "freebsd14",
152dc04b82SDavid Carlier "freebsd15",
16aed5b564SOla x Nilsson // Corresponds to `_FILE_OFFSET_BITS=64` in glibc
17aed5b564SOla x Nilsson "gnu_file_offset_bits64",
18*4e7a6411SOla x Nilsson // Corresponds to `_TIME_BITS=64` in glibc
19*4e7a6411SOla x Nilsson "gnu_time_bits64",
205d2b17f3STrevor Gross // FIXME(ctest): this config shouldn't be needed but ctest can't parse `const extern fn`
215d2b17f3STrevor Gross "libc_const_extern_fn",
22f8a12ee0SPietro Albini "libc_deny_warnings",
23f8a12ee0SPietro Albini "libc_thread_local",
24ac6739c5SAlex Crichton "libc_ctest",
2511079fd0SOla x Nilsson // Corresponds to `__USE_TIME_BITS64` in UAPI
2611079fd0SOla x Nilsson "linux_time_bits64",
2728e6ae29STrevor Gross "musl_v1_2_3",
28f8a12ee0SPietro Albini ];
29f8a12ee0SPietro Albini
30e74f7354SPietro Albini // Extra values to allow for check-cfg.
31a598506fSYuri Astrakhan const CHECK_CFG_EXTRA: &[(&str, &[&str])] = &[
329de4a5cfSJan Sommer (
339de4a5cfSJan Sommer "target_os",
34c2e03d56SHuang Qi &[
35bb10d5f7S王宇逸 "switch", "aix", "ohos", "hurd", "rtems", "visionos", "nuttx", "cygwin",
36c2e03d56SHuang Qi ],
379de4a5cfSJan Sommer ),
3808f84149SFlorian Bartels (
3908f84149SFlorian Bartels "target_env",
4008f84149SFlorian Bartels &["illumos", "wasi", "aix", "ohos", "nto71_iosock", "nto80"],
4108f84149SFlorian Bartels ),
423d77fc68SDirreke (
433d77fc68SDirreke "target_arch",
443d77fc68SDirreke &["loongarch64", "mips32r6", "mips64r6", "csky"],
453d77fc68SDirreke ),
46e74f7354SPietro Albini ];
47e74f7354SPietro Albini
main()4879c80c4eSIsaac Woods fn main() {
4945e1681dSYuki Okushi // Avoid unnecessary re-building.
5045e1681dSYuki Okushi println!("cargo:rerun-if-changed=build.rs");
5145e1681dSYuki Okushi
52674cc1f4STrevor Gross let (rustc_minor_ver, _is_nightly) = rustc_minor_nightly();
533fa021d7SJoe Richey let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok();
544f1966f5Sgnzlbg let libc_ci = env::var("LIBC_CI").is_ok();
55aed5b564SOla x Nilsson let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
56aed5b564SOla x Nilsson let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
57aed5b564SOla x Nilsson let target_ptr_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap_or_default();
58aed5b564SOla x Nilsson let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
59a17a91cdSgnzlbg
60874e5277SYuki Okushi // The ABI of libc used by std is backward compatible with FreeBSD 12.
613843c7dbSgnzlbg // The ABI of libc from crates.io is backward compatible with FreeBSD 11.
624f1966f5Sgnzlbg //
634f1966f5Sgnzlbg // On CI, we detect the actual FreeBSD version and match its ABI exactly,
644f1966f5Sgnzlbg // running tests to ensure that the ABI is correct.
65e13cde2dSTrevor Gross println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_FREEBSD_VERSION");
66e13cde2dSTrevor Gross // Allow overriding the default version for testing
67e13cde2dSTrevor Gross let which_freebsd = if let Ok(version) = env::var("RUST_LIBC_UNSTABLE_FREEBSD_VERSION") {
68e13cde2dSTrevor Gross let vers = version.parse().unwrap();
69e13cde2dSTrevor Gross println!("cargo:warning=setting FreeBSD version to {vers}");
70e13cde2dSTrevor Gross vers
71e13cde2dSTrevor Gross } else if libc_ci {
729e43d14eSRalf Jung which_freebsd().unwrap_or(11)
739e43d14eSRalf Jung } else if rustc_dep_of_std {
749e43d14eSRalf Jung 12
759e43d14eSRalf Jung } else {
769e43d14eSRalf Jung 11
779e43d14eSRalf Jung };
78e13cde2dSTrevor Gross
799e43d14eSRalf Jung match which_freebsd {
809e43d14eSRalf Jung x if x < 10 => panic!("FreeBSD older than 10 is not supported"),
819e43d14eSRalf Jung 10 => set_cfg("freebsd10"),
829e43d14eSRalf Jung 11 => set_cfg("freebsd11"),
839e43d14eSRalf Jung 12 => set_cfg("freebsd12"),
849e43d14eSRalf Jung 13 => set_cfg("freebsd13"),
859e43d14eSRalf Jung 14 => set_cfg("freebsd14"),
869e43d14eSRalf Jung _ => set_cfg("freebsd15"),
877437d0a6Sgnzlbg }
887437d0a6Sgnzlbg
8992db93cfSKleis Auke Wolthuizen match emcc_version_code() {
90e7a9c4a7SKleis Auke Wolthuizen Some(v) if (v < 30142) => set_cfg("emscripten_old_stat_abi"),
91e7a9c4a7SKleis Auke Wolthuizen // Non-Emscripten or version >= 3.1.42.
92e7a9c4a7SKleis Auke Wolthuizen _ => (),
9363b0d673SKleis Auke Wolthuizen }
9463b0d673SKleis Auke Wolthuizen
95a485516eSReagan Bohan let musl_v1_2_3 = env::var("RUST_LIBC_UNSTABLE_MUSL_V1_2_3").is_ok();
96a485516eSReagan Bohan println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_MUSL_V1_2_3");
97a485516eSReagan Bohan // loongarch64 and ohos have already updated
98a485516eSReagan Bohan if musl_v1_2_3 || target_os == "loongarch64" || target_env == "ohos" {
99a485516eSReagan Bohan // FIXME(musl): enable time64 api as well
100a485516eSReagan Bohan set_cfg("musl_v1_2_3");
101a485516eSReagan Bohan }
102c5b74654SOla x Nilsson let linux_time_bits64 = env::var("RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64").is_ok();
103c5b74654SOla x Nilsson println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64");
10411079fd0SOla x Nilsson if linux_time_bits64 {
10511079fd0SOla x Nilsson set_cfg("linux_time_bits64");
10611079fd0SOla x Nilsson }
107aed5b564SOla x Nilsson println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS");
108*4e7a6411SOla x Nilsson println!("cargo:rerun-if-env-changed=RUST_LIBC_UNSTABLE_GNU_TIME_BITS");
109aed5b564SOla x Nilsson if target_env == "gnu"
110aed5b564SOla x Nilsson && target_os == "linux"
111aed5b564SOla x Nilsson && target_ptr_width == "32"
112aed5b564SOla x Nilsson && target_arch != "riscv32"
113aed5b564SOla x Nilsson && target_arch != "x86_64"
114aed5b564SOla x Nilsson {
115*4e7a6411SOla x Nilsson match env::var("RUST_LIBC_UNSTABLE_GNU_TIME_BITS") {
116*4e7a6411SOla x Nilsson Ok(val) if val == "64" => {
117aed5b564SOla x Nilsson set_cfg("gnu_file_offset_bits64");
118*4e7a6411SOla x Nilsson set_cfg("linux_time_bits64");
119*4e7a6411SOla x Nilsson set_cfg("gnu_time_bits64");
120aed5b564SOla x Nilsson }
121*4e7a6411SOla x Nilsson Ok(val) if val != "32" => {
122*4e7a6411SOla x Nilsson panic!("RUST_LIBC_UNSTABLE_GNU_TIME_BITS may only be set to '32' or '64'")
123*4e7a6411SOla x Nilsson }
124*4e7a6411SOla x Nilsson _ => {
125*4e7a6411SOla x Nilsson match env::var("RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS") {
126*4e7a6411SOla x Nilsson Ok(val) if val == "64" => {
127*4e7a6411SOla x Nilsson set_cfg("gnu_file_offset_bits64");
128aed5b564SOla x Nilsson }
129aed5b564SOla x Nilsson Ok(val) if val != "32" => {
130aed5b564SOla x Nilsson panic!("RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS may only be set to '32' or '64'")
131aed5b564SOla x Nilsson }
132aed5b564SOla x Nilsson _ => {}
133aed5b564SOla x Nilsson }
134*4e7a6411SOla x Nilsson }
135*4e7a6411SOla x Nilsson }
136*4e7a6411SOla x Nilsson }
1373241ec58Sgnzlbg // On CI: deny all warnings
1383241ec58Sgnzlbg if libc_ci {
13988b7f0d9SPietro Albini set_cfg("libc_deny_warnings");
1403241ec58Sgnzlbg }
1413241ec58Sgnzlbg
1423fa021d7SJoe Richey // #[thread_local] is currently unstable
143df34d17bSJoe Richey if rustc_dep_of_std {
14488b7f0d9SPietro Albini set_cfg("libc_thread_local");
1453fa021d7SJoe Richey }
146b0ba2de7SAaron Hill
1475d2b17f3STrevor Gross // Set unconditionally when ctest is not being invoked.
1485d2b17f3STrevor Gross set_cfg("libc_const_extern_fn");
1495d2b17f3STrevor Gross
150e7dcb974STrevor Gross // Since Rust 1.80, configuration that isn't recognized by default needs to be provided to
151e7dcb974STrevor Gross // avoid warnings.
152e7dcb974STrevor Gross if rustc_minor_ver >= 80 {
153b636da0aSPietro Albini for cfg in ALLOWED_CFGS {
15407bb6bfeSUrgau if rustc_minor_ver >= 75 {
155d716b809SYuri Astrakhan println!("cargo:rustc-check-cfg=cfg({cfg})");
15607bb6bfeSUrgau } else {
157d716b809SYuri Astrakhan println!("cargo:rustc-check-cfg=values({cfg})");
158b636da0aSPietro Albini }
15907bb6bfeSUrgau }
160d63eedc3SPietro Albini for &(name, values) in CHECK_CFG_EXTRA {
161e74f7354SPietro Albini let values = values.join("\",\"");
16207bb6bfeSUrgau if rustc_minor_ver >= 75 {
163d716b809SYuri Astrakhan println!("cargo:rustc-check-cfg=cfg({name},values(\"{values}\"))");
16407bb6bfeSUrgau } else {
165d716b809SYuri Astrakhan println!("cargo:rustc-check-cfg=values({name},\"{values}\")");
166e74f7354SPietro Albini }
167b636da0aSPietro Albini }
168576f7781SYuki Okushi }
16907bb6bfeSUrgau }
17079c80c4eSIsaac Woods
17150783355STrevor Gross /// Run `rustc --version` and capture the output, adjusting arguments as needed if `clippy-driver`
17250783355STrevor Gross /// is used instead.
rustc_version_cmd(is_clippy_driver: bool) -> Output17350783355STrevor Gross fn rustc_version_cmd(is_clippy_driver: bool) -> Output {
17450783355STrevor Gross let rustc = env::var_os("RUSTC").expect("Failed to get rustc version: missing RUSTC env");
17550783355STrevor Gross
176abcb8f87STrevor Gross let mut cmd = match env::var_os("RUSTC_WRAPPER") {
177abcb8f87STrevor Gross Some(ref wrapper) if wrapper.is_empty() => Command::new(rustc),
17850783355STrevor Gross Some(wrapper) => {
17950783355STrevor Gross let mut cmd = Command::new(wrapper);
18050783355STrevor Gross cmd.arg(rustc);
18150783355STrevor Gross if is_clippy_driver {
18250783355STrevor Gross cmd.arg("--rustc");
18350783355STrevor Gross }
18450783355STrevor Gross
18550783355STrevor Gross cmd
18650783355STrevor Gross }
18750783355STrevor Gross None => Command::new(rustc),
18850783355STrevor Gross };
18950783355STrevor Gross
19050783355STrevor Gross cmd.arg("--version");
19150783355STrevor Gross
192bdfe8759STrevor Gross let output = cmd.output().expect("Failed to get rustc version");
19350783355STrevor Gross
194a598506fSYuri Astrakhan assert!(
195a598506fSYuri Astrakhan output.status.success(),
19650783355STrevor Gross "failed to run rustc: {}",
19750783355STrevor Gross String::from_utf8_lossy(output.stderr.as_slice())
19850783355STrevor Gross );
19950783355STrevor Gross
20050783355STrevor Gross output
20150783355STrevor Gross }
20250783355STrevor Gross
20350783355STrevor Gross /// Return the minor version of `rustc`, as well as a bool indicating whether or not the version
20450783355STrevor Gross /// is a nightly.
rustc_minor_nightly() -> (u32, bool)20540c19428Sbjorn3 fn rustc_minor_nightly() -> (u32, bool) {
20679c80c4eSIsaac Woods macro_rules! otry {
20779c80c4eSIsaac Woods ($e:expr) => {
20879c80c4eSIsaac Woods match $e {
20979c80c4eSIsaac Woods Some(e) => e,
21040c19428Sbjorn3 None => panic!("Failed to get rustc version"),
21179c80c4eSIsaac Woods }
21279c80c4eSIsaac Woods };
21379c80c4eSIsaac Woods }
21479c80c4eSIsaac Woods
21550783355STrevor Gross let mut output = rustc_version_cmd(false);
216570d8926SNathaniel
21750783355STrevor Gross if otry!(str::from_utf8(&output.stdout).ok()).starts_with("clippy") {
21850783355STrevor Gross output = rustc_version_cmd(true);
21952808cefSJacob Hoffman-Andrews }
22052808cefSJacob Hoffman-Andrews
22179c80c4eSIsaac Woods let version = otry!(str::from_utf8(&output.stdout).ok());
22250783355STrevor Gross
22379c80c4eSIsaac Woods let mut pieces = version.split('.');
22479c80c4eSIsaac Woods
225a598506fSYuri Astrakhan assert_eq!(
226a598506fSYuri Astrakhan pieces.next(),
227a598506fSYuri Astrakhan Some("rustc 1"),
228a598506fSYuri Astrakhan "Failed to get rustc version"
229a598506fSYuri Astrakhan );
23079c80c4eSIsaac Woods
231476b6759SAaron Hill let minor = pieces.next();
232f10ee11fSAaron Hill
233f10ee11fSAaron Hill // If `rustc` was built from a tarball, its version string
234f10ee11fSAaron Hill // will have neither a git hash nor a commit date
235f10ee11fSAaron Hill // (e.g. "rustc 1.39.0"). Treat this case as non-nightly,
236f10ee11fSAaron Hill // since a nightly build should either come from CI
237f10ee11fSAaron Hill // or a git checkout
238f10ee11fSAaron Hill let nightly_raw = otry!(pieces.next()).split('-').nth(1);
239a598506fSYuri Astrakhan let nightly = nightly_raw.map_or(false, |raw| {
240a598506fSYuri Astrakhan raw.starts_with("dev") || raw.starts_with("nightly")
241a598506fSYuri Astrakhan });
242476b6759SAaron Hill let minor = otry!(otry!(minor).parse().ok());
243476b6759SAaron Hill
24440c19428Sbjorn3 (minor, nightly)
24579c80c4eSIsaac Woods }
2467437d0a6Sgnzlbg
which_freebsd() -> Option<i32>2477437d0a6Sgnzlbg fn which_freebsd() -> Option<i32> {
248b8ac8c8aSEduardo Sánchez Muñoz let output = Command::new("freebsd-version").output().ok()?;
2497437d0a6Sgnzlbg if !output.status.success() {
2507437d0a6Sgnzlbg return None;
2517437d0a6Sgnzlbg }
2527437d0a6Sgnzlbg
253bdfe8759STrevor Gross let stdout = String::from_utf8(output.stdout).ok()?;
2547437d0a6Sgnzlbg
2557437d0a6Sgnzlbg match &stdout {
2563843c7dbSgnzlbg s if s.starts_with("10") => Some(10),
2577437d0a6Sgnzlbg s if s.starts_with("11") => Some(11),
2587437d0a6Sgnzlbg s if s.starts_with("12") => Some(12),
2594a74f1e0SLuca Pizzamiglio s if s.starts_with("13") => Some(13),
26065b16d94SYuki Okushi s if s.starts_with("14") => Some(14),
2612dc04b82SDavid Carlier s if s.starts_with("15") => Some(15),
2627437d0a6Sgnzlbg _ => None,
2637437d0a6Sgnzlbg }
2647437d0a6Sgnzlbg }
26588b7f0d9SPietro Albini
emcc_version_code() -> Option<u64>26692db93cfSKleis Auke Wolthuizen fn emcc_version_code() -> Option<u64> {
2671e47c9cfSGuus Waals let emcc = if cfg!(target_os = "windows") {
2681e47c9cfSGuus Waals "emcc.bat"
2691e47c9cfSGuus Waals } else {
2701e47c9cfSGuus Waals "emcc"
2711e47c9cfSGuus Waals };
2721e47c9cfSGuus Waals
2731e47c9cfSGuus Waals let output = Command::new(emcc).arg("-dumpversion").output().ok()?;
27463b0d673SKleis Auke Wolthuizen if !output.status.success() {
27563b0d673SKleis Auke Wolthuizen return None;
27663b0d673SKleis Auke Wolthuizen }
27763b0d673SKleis Auke Wolthuizen
278bdfe8759STrevor Gross let version = String::from_utf8(output.stdout).ok()?;
279c4245923SKleis Auke Wolthuizen
280c4245923SKleis Auke Wolthuizen // Some Emscripten versions come with `-git` attached, so split the
281c4245923SKleis Auke Wolthuizen // version string also on the `-` char.
282bdfe8759STrevor Gross let mut pieces = version.trim().split(['.', '-']);
28363b0d673SKleis Auke Wolthuizen
28492db93cfSKleis Auke Wolthuizen let major = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
28592db93cfSKleis Auke Wolthuizen let minor = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
28692db93cfSKleis Auke Wolthuizen let patch = pieces.next().and_then(|x| x.parse().ok()).unwrap_or(0);
28763b0d673SKleis Auke Wolthuizen
28892db93cfSKleis Auke Wolthuizen Some(major * 10000 + minor * 100 + patch)
28963b0d673SKleis Auke Wolthuizen }
29063b0d673SKleis Auke Wolthuizen
set_cfg(cfg: &str)29188b7f0d9SPietro Albini fn set_cfg(cfg: &str) {
292a598506fSYuri Astrakhan assert!(
293a598506fSYuri Astrakhan ALLOWED_CFGS.contains(&cfg),
294a598506fSYuri Astrakhan "trying to set cfg {cfg}, but it is not in ALLOWED_CFGS",
295a598506fSYuri Astrakhan );
296d716b809SYuri Astrakhan println!("cargo:rustc-cfg={cfg}");
29788b7f0d9SPietro Albini }
298