19a8ff24cSMiguel Ojeda // SPDX-License-Identifier: GPL-2.0
29a8ff24cSMiguel Ojeda 
39a8ff24cSMiguel Ojeda //! The custom target specification file generator for `rustc`.
49a8ff24cSMiguel Ojeda //!
59a8ff24cSMiguel Ojeda //! To configure a target from scratch, a JSON-encoded file has to be passed
69a8ff24cSMiguel Ojeda //! to `rustc` (introduced in [RFC 131]). These options and the file itself are
79a8ff24cSMiguel Ojeda //! unstable. Eventually, `rustc` should provide a way to do this in a stable
89a8ff24cSMiguel Ojeda //! manner. For instance, via command-line arguments. Therefore, this file
99a8ff24cSMiguel Ojeda //! should avoid using keys which can be set via `-C` or `-Z` options.
109a8ff24cSMiguel Ojeda //!
119a8ff24cSMiguel Ojeda //! [RFC 131]: https://rust-lang.github.io/rfcs/0131-target-specification.html
129a8ff24cSMiguel Ojeda 
139a8ff24cSMiguel Ojeda use std::{
149a8ff24cSMiguel Ojeda     collections::HashMap,
159a8ff24cSMiguel Ojeda     fmt::{Display, Formatter, Result},
169a8ff24cSMiguel Ojeda     io::BufRead,
179a8ff24cSMiguel Ojeda };
189a8ff24cSMiguel Ojeda 
199a8ff24cSMiguel Ojeda enum Value {
209a8ff24cSMiguel Ojeda     Boolean(bool),
219a8ff24cSMiguel Ojeda     Number(i32),
229a8ff24cSMiguel Ojeda     String(String),
239a8ff24cSMiguel Ojeda     Object(Object),
249a8ff24cSMiguel Ojeda }
259a8ff24cSMiguel Ojeda 
269a8ff24cSMiguel Ojeda type Object = Vec<(String, Value)>;
279a8ff24cSMiguel Ojeda 
289a8ff24cSMiguel Ojeda /// Minimal "almost JSON" generator (e.g. no `null`s, no arrays, no escaping),
299a8ff24cSMiguel Ojeda /// enough for this purpose.
309a8ff24cSMiguel Ojeda impl Display for Value {
fmt(&self, formatter: &mut Formatter<'_>) -> Result319a8ff24cSMiguel Ojeda     fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
329a8ff24cSMiguel Ojeda         match self {
339a8ff24cSMiguel Ojeda             Value::Boolean(boolean) => write!(formatter, "{}", boolean),
349a8ff24cSMiguel Ojeda             Value::Number(number) => write!(formatter, "{}", number),
359a8ff24cSMiguel Ojeda             Value::String(string) => write!(formatter, "\"{}\"", string),
369a8ff24cSMiguel Ojeda             Value::Object(object) => {
379a8ff24cSMiguel Ojeda                 formatter.write_str("{")?;
389a8ff24cSMiguel Ojeda                 if let [ref rest @ .., ref last] = object[..] {
399a8ff24cSMiguel Ojeda                     for (key, value) in rest {
409a8ff24cSMiguel Ojeda                         write!(formatter, "\"{}\": {},", key, value)?;
419a8ff24cSMiguel Ojeda                     }
429a8ff24cSMiguel Ojeda                     write!(formatter, "\"{}\": {}", last.0, last.1)?;
439a8ff24cSMiguel Ojeda                 }
449a8ff24cSMiguel Ojeda                 formatter.write_str("}")
459a8ff24cSMiguel Ojeda             }
469a8ff24cSMiguel Ojeda         }
479a8ff24cSMiguel Ojeda     }
489a8ff24cSMiguel Ojeda }
499a8ff24cSMiguel Ojeda 
509a8ff24cSMiguel Ojeda struct TargetSpec(Object);
519a8ff24cSMiguel Ojeda 
529a8ff24cSMiguel Ojeda impl TargetSpec {
new() -> TargetSpec539a8ff24cSMiguel Ojeda     fn new() -> TargetSpec {
549a8ff24cSMiguel Ojeda         TargetSpec(Vec::new())
559a8ff24cSMiguel Ojeda     }
569a8ff24cSMiguel Ojeda }
579a8ff24cSMiguel Ojeda 
589a8ff24cSMiguel Ojeda trait Push<T> {
push(&mut self, key: &str, value: T)599a8ff24cSMiguel Ojeda     fn push(&mut self, key: &str, value: T);
609a8ff24cSMiguel Ojeda }
619a8ff24cSMiguel Ojeda 
629a8ff24cSMiguel Ojeda impl Push<bool> for TargetSpec {
push(&mut self, key: &str, value: bool)639a8ff24cSMiguel Ojeda     fn push(&mut self, key: &str, value: bool) {
649a8ff24cSMiguel Ojeda         self.0.push((key.to_string(), Value::Boolean(value)));
659a8ff24cSMiguel Ojeda     }
669a8ff24cSMiguel Ojeda }
679a8ff24cSMiguel Ojeda 
689a8ff24cSMiguel Ojeda impl Push<i32> for TargetSpec {
push(&mut self, key: &str, value: i32)699a8ff24cSMiguel Ojeda     fn push(&mut self, key: &str, value: i32) {
709a8ff24cSMiguel Ojeda         self.0.push((key.to_string(), Value::Number(value)));
719a8ff24cSMiguel Ojeda     }
729a8ff24cSMiguel Ojeda }
739a8ff24cSMiguel Ojeda 
749a8ff24cSMiguel Ojeda impl Push<String> for TargetSpec {
push(&mut self, key: &str, value: String)759a8ff24cSMiguel Ojeda     fn push(&mut self, key: &str, value: String) {
769a8ff24cSMiguel Ojeda         self.0.push((key.to_string(), Value::String(value)));
779a8ff24cSMiguel Ojeda     }
789a8ff24cSMiguel Ojeda }
799a8ff24cSMiguel Ojeda 
809a8ff24cSMiguel Ojeda impl Push<&str> for TargetSpec {
push(&mut self, key: &str, value: &str)819a8ff24cSMiguel Ojeda     fn push(&mut self, key: &str, value: &str) {
829a8ff24cSMiguel Ojeda         self.push(key, value.to_string());
839a8ff24cSMiguel Ojeda     }
849a8ff24cSMiguel Ojeda }
859a8ff24cSMiguel Ojeda 
869a8ff24cSMiguel Ojeda impl Push<Object> for TargetSpec {
push(&mut self, key: &str, value: Object)879a8ff24cSMiguel Ojeda     fn push(&mut self, key: &str, value: Object) {
889a8ff24cSMiguel Ojeda         self.0.push((key.to_string(), Value::Object(value)));
899a8ff24cSMiguel Ojeda     }
909a8ff24cSMiguel Ojeda }
919a8ff24cSMiguel Ojeda 
929a8ff24cSMiguel Ojeda impl Display for TargetSpec {
fmt(&self, formatter: &mut Formatter<'_>) -> Result939a8ff24cSMiguel Ojeda     fn fmt(&self, formatter: &mut Formatter<'_>) -> Result {
949a8ff24cSMiguel Ojeda         // We add some newlines for clarity.
959a8ff24cSMiguel Ojeda         formatter.write_str("{\n")?;
969a8ff24cSMiguel Ojeda         if let [ref rest @ .., ref last] = self.0[..] {
979a8ff24cSMiguel Ojeda             for (key, value) in rest {
989a8ff24cSMiguel Ojeda                 write!(formatter, "    \"{}\": {},\n", key, value)?;
999a8ff24cSMiguel Ojeda             }
1009a8ff24cSMiguel Ojeda             write!(formatter, "    \"{}\": {}\n", last.0, last.1)?;
1019a8ff24cSMiguel Ojeda         }
1029a8ff24cSMiguel Ojeda         formatter.write_str("}")
1039a8ff24cSMiguel Ojeda     }
1049a8ff24cSMiguel Ojeda }
1059a8ff24cSMiguel Ojeda 
1069a8ff24cSMiguel Ojeda struct KernelConfig(HashMap<String, String>);
1079a8ff24cSMiguel Ojeda 
1089a8ff24cSMiguel Ojeda impl KernelConfig {
1099a8ff24cSMiguel Ojeda     /// Parses `include/config/auto.conf` from `stdin`.
from_stdin() -> KernelConfig1109a8ff24cSMiguel Ojeda     fn from_stdin() -> KernelConfig {
1119a8ff24cSMiguel Ojeda         let mut result = HashMap::new();
1129a8ff24cSMiguel Ojeda 
1139a8ff24cSMiguel Ojeda         let stdin = std::io::stdin();
1149a8ff24cSMiguel Ojeda         let mut handle = stdin.lock();
1159a8ff24cSMiguel Ojeda         let mut line = String::new();
1169a8ff24cSMiguel Ojeda 
1179a8ff24cSMiguel Ojeda         loop {
1189a8ff24cSMiguel Ojeda             line.clear();
1199a8ff24cSMiguel Ojeda 
1209a8ff24cSMiguel Ojeda             if handle.read_line(&mut line).unwrap() == 0 {
1219a8ff24cSMiguel Ojeda                 break;
1229a8ff24cSMiguel Ojeda             }
1239a8ff24cSMiguel Ojeda 
1249a8ff24cSMiguel Ojeda             if line.starts_with('#') {
1259a8ff24cSMiguel Ojeda                 continue;
1269a8ff24cSMiguel Ojeda             }
1279a8ff24cSMiguel Ojeda 
1289a8ff24cSMiguel Ojeda             let (key, value) = line.split_once('=').expect("Missing `=` in line.");
1299a8ff24cSMiguel Ojeda             result.insert(key.to_string(), value.trim_end_matches('\n').to_string());
1309a8ff24cSMiguel Ojeda         }
1319a8ff24cSMiguel Ojeda 
1329a8ff24cSMiguel Ojeda         KernelConfig(result)
1339a8ff24cSMiguel Ojeda     }
1349a8ff24cSMiguel Ojeda 
1359a8ff24cSMiguel Ojeda     /// Does the option exist in the configuration (any value)?
1369a8ff24cSMiguel Ojeda     ///
1379a8ff24cSMiguel Ojeda     /// The argument must be passed without the `CONFIG_` prefix.
1389a8ff24cSMiguel Ojeda     /// This avoids repetition and it also avoids `fixdep` making us
1399a8ff24cSMiguel Ojeda     /// depend on it.
has(&self, option: &str) -> bool1409a8ff24cSMiguel Ojeda     fn has(&self, option: &str) -> bool {
1419a8ff24cSMiguel Ojeda         let option = "CONFIG_".to_owned() + option;
1429a8ff24cSMiguel Ojeda         self.0.contains_key(&option)
1439a8ff24cSMiguel Ojeda     }
1449a8ff24cSMiguel Ojeda }
1459a8ff24cSMiguel Ojeda 
main()1469a8ff24cSMiguel Ojeda fn main() {
1479a8ff24cSMiguel Ojeda     let cfg = KernelConfig::from_stdin();
1489a8ff24cSMiguel Ojeda     let mut ts = TargetSpec::new();
1499a8ff24cSMiguel Ojeda 
1509a8ff24cSMiguel Ojeda     // `llvm-target`s are taken from `scripts/Makefile.clang`.
151*09498135SMiguel Ojeda     if cfg.has("X86_64") {
152*09498135SMiguel Ojeda         ts.push("arch", "x86_64");
153*09498135SMiguel Ojeda         ts.push(
154*09498135SMiguel Ojeda             "data-layout",
155*09498135SMiguel Ojeda             "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
156*09498135SMiguel Ojeda         );
157*09498135SMiguel Ojeda         let mut features = "-3dnow,-3dnowa,-mmx,+soft-float".to_string();
158*09498135SMiguel Ojeda         if cfg.has("RETPOLINE") {
159*09498135SMiguel Ojeda             features += ",+retpoline-external-thunk";
160*09498135SMiguel Ojeda         }
161*09498135SMiguel Ojeda         ts.push("features", features);
162*09498135SMiguel Ojeda         ts.push("llvm-target", "x86_64-linux-gnu");
163*09498135SMiguel Ojeda         ts.push("target-pointer-width", "64");
1649a8ff24cSMiguel Ojeda     } else {
1659a8ff24cSMiguel Ojeda         panic!("Unsupported architecture");
1669a8ff24cSMiguel Ojeda     }
1679a8ff24cSMiguel Ojeda 
1689a8ff24cSMiguel Ojeda     ts.push("emit-debug-gdb-scripts", false);
1699a8ff24cSMiguel Ojeda     ts.push("frame-pointer", "may-omit");
1709a8ff24cSMiguel Ojeda     ts.push(
1719a8ff24cSMiguel Ojeda         "stack-probes",
1729a8ff24cSMiguel Ojeda         vec![("kind".to_string(), Value::String("none".to_string()))],
1739a8ff24cSMiguel Ojeda     );
1749a8ff24cSMiguel Ojeda 
1759a8ff24cSMiguel Ojeda     // Everything else is LE, whether `CPU_LITTLE_ENDIAN` is declared or not
1769a8ff24cSMiguel Ojeda     // (e.g. x86). It is also `rustc`'s default.
1779a8ff24cSMiguel Ojeda     if cfg.has("CPU_BIG_ENDIAN") {
1789a8ff24cSMiguel Ojeda         ts.push("target-endian", "big");
1799a8ff24cSMiguel Ojeda     }
1809a8ff24cSMiguel Ojeda 
1819a8ff24cSMiguel Ojeda     println!("{}", ts);
1829a8ff24cSMiguel Ojeda }
183