1 use std::env;
2 use std::ffi::OsString;
3 use std::process::Command;
4
main()5 fn main() {
6 // We check rustc version to enable features beyond MSRV, such as:
7 // - 1.59 => neon_intrinsics
8 let rustc = env::var_os("RUSTC").unwrap_or(OsString::from("rustc"));
9 let output = Command::new(rustc)
10 .arg("--version")
11 .output()
12 .expect("failed to check 'rustc --version'")
13 .stdout;
14
15 let raw_version = String::from_utf8(output)
16 .expect("rustc version output should be utf-8");
17
18 let version = match Version::parse(&raw_version) {
19 Ok(version) => version,
20 Err(err) => {
21 println!("cargo:warning=failed to parse `rustc --version`: {}", err);
22 return;
23 }
24 };
25
26 enable_new_features(version);
27 }
28
enable_new_features(version: Version)29 fn enable_new_features(version: Version) {
30 enable_simd(version);
31 }
32
enable_simd(version: Version)33 fn enable_simd(version: Version) {
34 if env::var_os("CARGO_FEATURE_STD").is_none() {
35 println!("cargo:warning=building for no_std disables httparse SIMD");
36 return;
37 }
38 if env::var_os("CARGO_CFG_MIRI").is_some() {
39 println!("cargo:warning=building for Miri disables httparse SIMD");
40 return;
41 }
42
43 let env_disable = "CARGO_CFG_HTTPARSE_DISABLE_SIMD";
44 if var_is(env_disable, "1") {
45 println!("cargo:warning=detected {} environment variable, disabling SIMD", env_disable);
46 return;
47 }
48
49 // 1.59.0 is the first version to support neon_intrinsics
50 if version >= Version(1, 59, 0) {
51 println!("cargo:rustc-cfg=httparse_simd_neon_intrinsics");
52 }
53
54 println!("cargo:rustc-cfg=httparse_simd");
55
56 // cfg(target_feature) isn't stable yet, but CARGO_CFG_TARGET_FEATURE has
57 // a list... We aren't doing anything unsafe, since the is_x86_feature_detected
58 // macro still checks in the actual lib, BUT!
59 //
60 // By peeking at the list here, we can change up slightly how we do feature
61 // detection in the lib. If our features aren't in the feature list, we
62 // stick with a cached runtime detection strategy.
63 //
64 // But if the features *are* in the list, we benefit from removing our cache,
65 // since the compiler will eliminate several branches with its internal
66 // cfg(target_feature) usage.
67
68
69 let env_runtime_only = "CARGO_CFG_HTTPARSE_DISABLE_SIMD_COMPILETIME";
70 if var_is(env_runtime_only, "1") {
71 println!("cargo:warning=detected {} environment variable, using runtime SIMD detection only", env_runtime_only);
72 return;
73 }
74 let feature_list = match env::var_os("CARGO_CFG_TARGET_FEATURE") {
75 Some(var) => match var.into_string() {
76 Ok(s) => s,
77 Err(_) => {
78 println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not valid utf-8");
79 return;
80 },
81 },
82 None => {
83 println!("cargo:warning=CARGO_CFG_TARGET_FEATURE was not set");
84 return
85 },
86 };
87
88 let features = feature_list.split(',').map(|s| s.trim());
89 if features.clone().any(|f| f == "sse4.2") {
90 println!("cargo:rustc-cfg=httparse_simd_target_feature_sse42");
91 }
92 if features.clone().any(|f| f == "avx2") {
93 println!("cargo:rustc-cfg=httparse_simd_target_feature_avx2");
94 }
95 }
96
97 #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
98 struct Version (u32, u32, u32);
99
100 impl Version {
parse(s: &str) -> Result<Version, String>101 fn parse(s: &str) -> Result<Version, String> {
102 if !s.starts_with("rustc ") {
103 return Err(format!("unrecognized version string: {}", s));
104 }
105 let s = s.trim_start_matches("rustc ");
106
107 let mut iter = s
108 .split('.')
109 .take(3)
110 .map(|s| match s.find(|c: char| !c.is_ascii_digit()) {
111 Some(end) => &s[..end],
112 None => s,
113 })
114 .map(|s| s.parse::<u32>().map_err(|e| e.to_string()));
115
116 if iter.clone().count() != 3 {
117 return Err(format!("not enough version parts: {:?}", s));
118 }
119
120 let major = iter.next().unwrap()?;
121 let minor = iter.next().unwrap()?;
122 let patch = iter.next().unwrap()?;
123
124 Ok(Version(major, minor, patch))
125 }
126 }
127
var_is(key: &str, val: &str) -> bool128 fn var_is(key: &str, val: &str) -> bool {
129 match env::var(key) {
130 Ok(v) => v == val,
131 Err(_) => false,
132 }
133 }
134