1 use std::env; 2 use std::process::Command; 3 use std::str; 4 5 fn main() { 6 let (rustc_minor_ver, is_nightly) = 7 rustc_minor_nightly().expect("Failed to get rustc version"); 8 let rustc_dep_of_std = env::var("CARGO_FEATURE_RUSTC_DEP_OF_STD").is_ok(); 9 let align_cargo_feature = env::var("CARGO_FEATURE_ALIGN").is_ok(); 10 let const_extern_fn_cargo_feature = 11 env::var("CARGO_FEATURE_CONST_EXTERN_FN").is_ok(); 12 let libc_ci = env::var("LIBC_CI").is_ok(); 13 14 if env::var("CARGO_FEATURE_USE_STD").is_ok() { 15 println!( 16 "cargo:warning=\"libc's use_std cargo feature is deprecated since libc 0.2.55; \ 17 please consider using the `std` cargo feature instead\"" 18 ); 19 } 20 21 // The ABI of libc used by libstd is backward compatible with FreeBSD 10. 22 // The ABI of libc from crates.io is backward compatible with FreeBSD 11. 23 // 24 // On CI, we detect the actual FreeBSD version and match its ABI exactly, 25 // running tests to ensure that the ABI is correct. 26 match which_freebsd() { 27 Some(10) if libc_ci || rustc_dep_of_std => { 28 println!("cargo:rustc-cfg=freebsd10") 29 } 30 Some(11) if libc_ci => println!("cargo:rustc-cfg=freebsd11"), 31 Some(12) if libc_ci => println!("cargo:rustc-cfg=freebsd12"), 32 Some(13) if libc_ci => println!("cargo:rustc-cfg=freebsd13"), 33 Some(_) | None => println!("cargo:rustc-cfg=freebsd11"), 34 } 35 36 // On CI: deny all warnings 37 if libc_ci { 38 println!("cargo:rustc-cfg=libc_deny_warnings"); 39 } 40 41 // Rust >= 1.15 supports private module use: 42 if rustc_minor_ver >= 15 || rustc_dep_of_std { 43 println!("cargo:rustc-cfg=libc_priv_mod_use"); 44 } 45 46 // Rust >= 1.19 supports unions: 47 if rustc_minor_ver >= 19 || rustc_dep_of_std { 48 println!("cargo:rustc-cfg=libc_union"); 49 } 50 51 // Rust >= 1.24 supports const mem::size_of: 52 if rustc_minor_ver >= 24 || rustc_dep_of_std { 53 println!("cargo:rustc-cfg=libc_const_size_of"); 54 } 55 56 // Rust >= 1.25 supports repr(align): 57 if rustc_minor_ver >= 25 || rustc_dep_of_std || align_cargo_feature { 58 println!("cargo:rustc-cfg=libc_align"); 59 } 60 61 // Rust >= 1.30 supports `core::ffi::c_void`, so libc can just re-export it. 62 // Otherwise, it defines an incompatible type to retaining 63 // backwards-compatibility. 64 if rustc_minor_ver >= 30 || rustc_dep_of_std { 65 println!("cargo:rustc-cfg=libc_core_cvoid"); 66 } 67 68 // Rust >= 1.33 supports repr(packed(N)) and cfg(target_vendor). 69 if rustc_minor_ver >= 33 || rustc_dep_of_std { 70 println!("cargo:rustc-cfg=libc_packedN"); 71 println!("cargo:rustc-cfg=libc_cfg_target_vendor"); 72 } 73 74 // #[thread_local] is currently unstable 75 if rustc_dep_of_std { 76 println!("cargo:rustc-cfg=libc_thread_local"); 77 } 78 79 if const_extern_fn_cargo_feature { 80 if !is_nightly || rustc_minor_ver < 40 { 81 panic!("const-extern-fn requires a nightly compiler >= 1.40") 82 } 83 println!("cargo:rustc-cfg=libc_const_extern_fn"); 84 } 85 } 86 87 fn rustc_minor_nightly() -> Option<(u32, bool)> { 88 macro_rules! otry { 89 ($e:expr) => { 90 match $e { 91 Some(e) => e, 92 None => return None, 93 } 94 }; 95 } 96 97 let rustc = otry!(env::var_os("RUSTC")); 98 let output = otry!(Command::new(rustc).arg("--version").output().ok()); 99 let version = otry!(str::from_utf8(&output.stdout).ok()); 100 let mut pieces = version.split('.'); 101 102 if pieces.next() != Some("rustc 1") { 103 return None; 104 } 105 106 let minor = pieces.next(); 107 108 // If `rustc` was built from a tarball, its version string 109 // will have neither a git hash nor a commit date 110 // (e.g. "rustc 1.39.0"). Treat this case as non-nightly, 111 // since a nightly build should either come from CI 112 // or a git checkout 113 let nightly_raw = otry!(pieces.next()).split('-').nth(1); 114 let nightly = nightly_raw 115 .map(|raw| raw.starts_with("dev") || raw.starts_with("nightly")) 116 .unwrap_or(false); 117 let minor = otry!(otry!(minor).parse().ok()); 118 119 Some((minor, nightly)) 120 } 121 122 fn which_freebsd() -> Option<i32> { 123 let output = std::process::Command::new("freebsd-version").output().ok(); 124 if output.is_none() { 125 return None; 126 } 127 let output = output.unwrap(); 128 if !output.status.success() { 129 return None; 130 } 131 132 let stdout = String::from_utf8(output.stdout).ok(); 133 if stdout.is_none() { 134 return None; 135 } 136 let stdout = stdout.unwrap(); 137 138 match &stdout { 139 s if s.starts_with("10") => Some(10), 140 s if s.starts_with("11") => Some(11), 141 s if s.starts_with("12") => Some(12), 142 s if s.starts_with("13") => Some(13), 143 _ => None, 144 } 145 } 146