1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 //! The custom target specification file gener 3 //! The custom target specification file generator for `rustc`. 4 //! 4 //! 5 //! To configure a target from scratch, a JSON 5 //! To configure a target from scratch, a JSON-encoded file has to be passed 6 //! to `rustc` (introduced in [RFC 131]). Thes 6 //! to `rustc` (introduced in [RFC 131]). These options and the file itself are 7 //! unstable. Eventually, `rustc` should provi 7 //! unstable. Eventually, `rustc` should provide a way to do this in a stable 8 //! manner. For instance, via command-line arg 8 //! manner. For instance, via command-line arguments. Therefore, this file 9 //! should avoid using keys which can be set v 9 //! should avoid using keys which can be set via `-C` or `-Z` options. 10 //! 10 //! 11 //! [RFC 131]: https://rust-lang.github.io/rfc 11 //! [RFC 131]: https://rust-lang.github.io/rfcs/0131-target-specification.html 12 12 13 use std::{ 13 use std::{ 14 collections::HashMap, 14 collections::HashMap, 15 fmt::{Display, Formatter, Result}, 15 fmt::{Display, Formatter, Result}, 16 io::BufRead, 16 io::BufRead, 17 }; 17 }; 18 18 19 enum Value { 19 enum Value { 20 Boolean(bool), 20 Boolean(bool), 21 Number(i32), 21 Number(i32), 22 String(String), 22 String(String), 23 Array(Vec<Value>), << 24 Object(Object), 23 Object(Object), 25 } 24 } 26 25 27 type Object = Vec<(String, Value)>; 26 type Object = Vec<(String, Value)>; 28 27 29 fn comma_sep<T>( !! 28 /// Minimal "almost JSON" generator (e.g. no `null`s, no arrays, no escaping), 30 seq: &[T], << 31 formatter: &mut Formatter<'_>, << 32 f: impl Fn(&mut Formatter<'_>, &T) -> Resu << 33 ) -> Result { << 34 if let [ref rest @ .., ref last] = seq[..] << 35 for v in rest { << 36 f(formatter, v)?; << 37 formatter.write_str(",")?; << 38 } << 39 f(formatter, last)?; << 40 } << 41 Ok(()) << 42 } << 43 << 44 /// Minimal "almost JSON" generator (e.g. no ` << 45 /// enough for this purpose. 29 /// enough for this purpose. 46 impl Display for Value { 30 impl Display for Value { 47 fn fmt(&self, formatter: &mut Formatter<'_ 31 fn fmt(&self, formatter: &mut Formatter<'_>) -> Result { 48 match self { 32 match self { 49 Value::Boolean(boolean) => write!( 33 Value::Boolean(boolean) => write!(formatter, "{}", boolean), 50 Value::Number(number) => write!(fo 34 Value::Number(number) => write!(formatter, "{}", number), 51 Value::String(string) => write!(fo 35 Value::String(string) => write!(formatter, "\"{}\"", string), 52 Value::Array(values) => { << 53 formatter.write_str("[")?; << 54 comma_sep(&values[..], formatt << 55 formatter.write_str("]") << 56 } << 57 Value::Object(object) => { 36 Value::Object(object) => { 58 formatter.write_str("{")?; 37 formatter.write_str("{")?; 59 comma_sep(&object[..], formatt !! 38 if let [ref rest @ .., ref last] = object[..] { 60 write!(formatter, "\"{}\": !! 39 for (key, value) in rest { 61 })?; !! 40 write!(formatter, "\"{}\": {},", key, value)?; >> 41 } >> 42 write!(formatter, "\"{}\": {}", last.0, last.1)?; >> 43 } 62 formatter.write_str("}") 44 formatter.write_str("}") 63 } 45 } 64 } 46 } 65 } 47 } 66 } 48 } 67 49 68 impl From<bool> for Value { !! 50 struct TargetSpec(Object); 69 fn from(value: bool) -> Self { << 70 Self::Boolean(value) << 71 } << 72 } << 73 51 74 impl From<i32> for Value { !! 52 impl TargetSpec { 75 fn from(value: i32) -> Self { !! 53 fn new() -> TargetSpec { 76 Self::Number(value) !! 54 TargetSpec(Vec::new()) 77 } 55 } 78 } 56 } 79 57 80 impl From<String> for Value { !! 58 trait Push<T> { 81 fn from(value: String) -> Self { !! 59 fn push(&mut self, key: &str, value: T); 82 Self::String(value) << 83 } << 84 } 60 } 85 61 86 impl From<&str> for Value { !! 62 impl Push<bool> for TargetSpec { 87 fn from(value: &str) -> Self { !! 63 fn push(&mut self, key: &str, value: bool) { 88 Self::String(value.to_string()) !! 64 self.0.push((key.to_string(), Value::Boolean(value))); 89 } 65 } 90 } 66 } 91 67 92 impl From<Object> for Value { !! 68 impl Push<i32> for TargetSpec { 93 fn from(object: Object) -> Self { !! 69 fn push(&mut self, key: &str, value: i32) { 94 Self::Object(object) !! 70 self.0.push((key.to_string(), Value::Number(value))); 95 } 71 } 96 } 72 } 97 73 98 impl<T: Into<Value>, const N: usize> From<[T; !! 74 impl Push<String> for TargetSpec { 99 fn from(i: [T; N]) -> Self { !! 75 fn push(&mut self, key: &str, value: String) { 100 Self::Array(i.into_iter().map(|v| v.in !! 76 self.0.push((key.to_string(), Value::String(value))); 101 } 77 } 102 } 78 } 103 79 104 struct TargetSpec(Object); !! 80 impl Push<&str> for TargetSpec { 105 !! 81 fn push(&mut self, key: &str, value: &str) { 106 impl TargetSpec { !! 82 self.push(key, value.to_string()); 107 fn new() -> TargetSpec { << 108 TargetSpec(Vec::new()) << 109 } 83 } >> 84 } 110 85 111 fn push(&mut self, key: &str, value: impl !! 86 impl Push<Object> for TargetSpec { 112 self.0.push((key.to_string(), value.in !! 87 fn push(&mut self, key: &str, value: Object) { >> 88 self.0.push((key.to_string(), Value::Object(value))); 113 } 89 } 114 } 90 } 115 91 116 impl Display for TargetSpec { 92 impl Display for TargetSpec { 117 fn fmt(&self, formatter: &mut Formatter<'_ 93 fn fmt(&self, formatter: &mut Formatter<'_>) -> Result { 118 // We add some newlines for clarity. 94 // We add some newlines for clarity. 119 formatter.write_str("{\n")?; 95 formatter.write_str("{\n")?; 120 if let [ref rest @ .., ref last] = sel 96 if let [ref rest @ .., ref last] = self.0[..] { 121 for (key, value) in rest { 97 for (key, value) in rest { 122 write!(formatter, " \"{}\": 98 write!(formatter, " \"{}\": {},\n", key, value)?; 123 } 99 } 124 write!(formatter, " \"{}\": {}\ 100 write!(formatter, " \"{}\": {}\n", last.0, last.1)?; 125 } 101 } 126 formatter.write_str("}") 102 formatter.write_str("}") 127 } 103 } 128 } 104 } 129 105 130 struct KernelConfig(HashMap<String, String>); 106 struct KernelConfig(HashMap<String, String>); 131 107 132 impl KernelConfig { 108 impl KernelConfig { 133 /// Parses `include/config/auto.conf` from 109 /// Parses `include/config/auto.conf` from `stdin`. 134 fn from_stdin() -> KernelConfig { 110 fn from_stdin() -> KernelConfig { 135 let mut result = HashMap::new(); 111 let mut result = HashMap::new(); 136 112 137 let stdin = std::io::stdin(); 113 let stdin = std::io::stdin(); 138 let mut handle = stdin.lock(); 114 let mut handle = stdin.lock(); 139 let mut line = String::new(); 115 let mut line = String::new(); 140 116 141 loop { 117 loop { 142 line.clear(); 118 line.clear(); 143 119 144 if handle.read_line(&mut line).unw 120 if handle.read_line(&mut line).unwrap() == 0 { 145 break; 121 break; 146 } 122 } 147 123 148 if line.starts_with('#') { 124 if line.starts_with('#') { 149 continue; 125 continue; 150 } 126 } 151 127 152 let (key, value) = line.split_once 128 let (key, value) = line.split_once('=').expect("Missing `=` in line."); 153 result.insert(key.to_string(), val 129 result.insert(key.to_string(), value.trim_end_matches('\n').to_string()); 154 } 130 } 155 131 156 KernelConfig(result) 132 KernelConfig(result) 157 } 133 } 158 134 159 /// Does the option exist in the configura 135 /// Does the option exist in the configuration (any value)? 160 /// 136 /// 161 /// The argument must be passed without th 137 /// The argument must be passed without the `CONFIG_` prefix. 162 /// This avoids repetition and it also avo 138 /// This avoids repetition and it also avoids `fixdep` making us 163 /// depend on it. 139 /// depend on it. 164 fn has(&self, option: &str) -> bool { 140 fn has(&self, option: &str) -> bool { 165 let option = "CONFIG_".to_owned() + op 141 let option = "CONFIG_".to_owned() + option; 166 self.0.contains_key(&option) 142 self.0.contains_key(&option) 167 } 143 } 168 } 144 } 169 145 170 fn main() { 146 fn main() { 171 let cfg = KernelConfig::from_stdin(); 147 let cfg = KernelConfig::from_stdin(); 172 let mut ts = TargetSpec::new(); 148 let mut ts = TargetSpec::new(); 173 149 174 // `llvm-target`s are taken from `scripts/ 150 // `llvm-target`s are taken from `scripts/Makefile.clang`. 175 if cfg.has("ARM64") { !! 151 if cfg.has("X86_64") { 176 panic!("arm64 uses the builtin rustc a << 177 } else if cfg.has("RISCV") { << 178 if cfg.has("64BIT") { << 179 panic!("64-bit RISC-V uses the bui << 180 } else { << 181 panic!("32-bit RISC-V is an unsupp << 182 } << 183 } else if cfg.has("X86_64") { << 184 ts.push("arch", "x86_64"); 152 ts.push("arch", "x86_64"); 185 ts.push( 153 ts.push( 186 "data-layout", 154 "data-layout", 187 "e-m:e-p270:32:32-p271:32:32-p272: !! 155 "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", 188 ); 156 ); 189 let mut features = "-mmx,+soft-float". !! 157 let mut features = "-3dnow,-3dnowa,-mmx,+soft-float".to_string(); 190 if cfg.has("MITIGATION_RETPOLINE") { !! 158 if cfg.has("RETPOLINE") { 191 // The kernel uses `-mretpoline-ex << 192 // target feature of the same name << 193 // `clang/lib/Driver/ToolChains/Ar << 194 // `-Ctarget-feature` when `rustc` << 195 // flag); see https://github.com/r << 196 features += ",+retpoline-external- 159 features += ",+retpoline-external-thunk"; 197 features += ",+retpoline-indirect- << 198 features += ",+retpoline-indirect- << 199 } << 200 if cfg.has("MITIGATION_SLS") { << 201 // The kernel uses `-mharden-sls=a << 202 // `clang/lib/Driver/ToolChains/Ar << 203 // `-Ctarget-feature` when `rustc` << 204 // flag); see https://github.com/r << 205 features += ",+harden-sls-ijmp"; << 206 features += ",+harden-sls-ret"; << 207 } 160 } 208 ts.push("features", features); 161 ts.push("features", features); 209 ts.push("llvm-target", "x86_64-linux-g 162 ts.push("llvm-target", "x86_64-linux-gnu"); 210 ts.push("supported-sanitizers", ["kcfi << 211 ts.push("target-pointer-width", "64"); 163 ts.push("target-pointer-width", "64"); 212 } else if cfg.has("X86_32") { << 213 // This only works on UML, as i386 oth << 214 if !cfg.has("UML") { << 215 panic!("32-bit x86 only works unde << 216 } << 217 ts.push("arch", "x86"); << 218 ts.push( << 219 "data-layout", << 220 "e-m:e-p:32:32-p270:32:32-p271:32: << 221 ); << 222 let mut features = "-mmx,+soft-float". << 223 if cfg.has("MITIGATION_RETPOLINE") { << 224 features += ",+retpoline-external- << 225 } << 226 ts.push("features", features); << 227 ts.push("llvm-target", "i386-unknown-l << 228 ts.push("target-pointer-width", "32"); << 229 } else if cfg.has("LOONGARCH") { 164 } else if cfg.has("LOONGARCH") { 230 panic!("loongarch uses the builtin rus !! 165 ts.push("arch", "loongarch64"); >> 166 ts.push("data-layout", "e-m:e-p:64:64-i64:64-i128:128-n64-S128"); >> 167 ts.push("features", "-f,-d"); >> 168 ts.push("llvm-target", "loongarch64-linux-gnusf"); >> 169 ts.push("llvm-abiname", "lp64s"); >> 170 ts.push("target-pointer-width", "64"); 231 } else { 171 } else { 232 panic!("Unsupported architecture"); 172 panic!("Unsupported architecture"); 233 } 173 } 234 174 235 ts.push("emit-debug-gdb-scripts", false); 175 ts.push("emit-debug-gdb-scripts", false); 236 ts.push("frame-pointer", "may-omit"); 176 ts.push("frame-pointer", "may-omit"); 237 ts.push( 177 ts.push( 238 "stack-probes", 178 "stack-probes", 239 vec![("kind".to_string(), Value::Strin 179 vec![("kind".to_string(), Value::String("none".to_string()))], 240 ); 180 ); 241 181 242 // Everything else is LE, whether `CPU_LIT 182 // Everything else is LE, whether `CPU_LITTLE_ENDIAN` is declared or not 243 // (e.g. x86). It is also `rustc`'s defaul 183 // (e.g. x86). It is also `rustc`'s default. 244 if cfg.has("CPU_BIG_ENDIAN") { 184 if cfg.has("CPU_BIG_ENDIAN") { 245 ts.push("target-endian", "big"); 185 ts.push("target-endian", "big"); 246 } 186 } 247 187 248 println!("{}", ts); 188 println!("{}", ts); 249 } 189 }
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.