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