Commit | Line | Data |
---|---|---|
9a8ff24c MO |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | //! The custom target specification file generator for `rustc`. | |
4 | //! | |
5 | //! To configure a target from scratch, a JSON-encoded file has to be passed | |
6 | //! to `rustc` (introduced in [RFC 131]). These options and the file itself are | |
7 | //! unstable. Eventually, `rustc` should provide a way to do this in a stable | |
8 | //! manner. For instance, via command-line arguments. Therefore, this file | |
9 | //! should avoid using keys which can be set via `-C` or `-Z` options. | |
10 | //! | |
11 | //! [RFC 131]: https://rust-lang.github.io/rfcs/0131-target-specification.html | |
12 | ||
13 | use std::{ | |
14 | collections::HashMap, | |
15 | fmt::{Display, Formatter, Result}, | |
16 | io::BufRead, | |
17 | }; | |
18 | ||
19 | enum Value { | |
20 | Boolean(bool), | |
21 | Number(i32), | |
22 | String(String), | |
23 | Object(Object), | |
24 | } | |
25 | ||
26 | type Object = Vec<(String, Value)>; | |
27 | ||
28 | /// Minimal "almost JSON" generator (e.g. no `null`s, no arrays, no escaping), | |
29 | /// enough for this purpose. | |
30 | impl Display for Value { | |
31 | fn fmt(&self, formatter: &mut Formatter<'_>) -> Result { | |
32 | match self { | |
33 | Value::Boolean(boolean) => write!(formatter, "{}", boolean), | |
34 | Value::Number(number) => write!(formatter, "{}", number), | |
35 | Value::String(string) => write!(formatter, "\"{}\"", string), | |
36 | Value::Object(object) => { | |
37 | formatter.write_str("{")?; | |
38 | if let [ref rest @ .., ref last] = object[..] { | |
39 | for (key, value) in rest { | |
40 | write!(formatter, "\"{}\": {},", key, value)?; | |
41 | } | |
42 | write!(formatter, "\"{}\": {}", last.0, last.1)?; | |
43 | } | |
44 | formatter.write_str("}") | |
45 | } | |
46 | } | |
47 | } | |
48 | } | |
49 | ||
50 | struct TargetSpec(Object); | |
51 | ||
52 | impl TargetSpec { | |
53 | fn new() -> TargetSpec { | |
54 | TargetSpec(Vec::new()) | |
55 | } | |
56 | } | |
57 | ||
58 | trait Push<T> { | |
59 | fn push(&mut self, key: &str, value: T); | |
60 | } | |
61 | ||
62 | impl Push<bool> for TargetSpec { | |
63 | fn push(&mut self, key: &str, value: bool) { | |
64 | self.0.push((key.to_string(), Value::Boolean(value))); | |
65 | } | |
66 | } | |
67 | ||
68 | impl Push<i32> for TargetSpec { | |
69 | fn push(&mut self, key: &str, value: i32) { | |
70 | self.0.push((key.to_string(), Value::Number(value))); | |
71 | } | |
72 | } | |
73 | ||
74 | impl Push<String> for TargetSpec { | |
75 | fn push(&mut self, key: &str, value: String) { | |
76 | self.0.push((key.to_string(), Value::String(value))); | |
77 | } | |
78 | } | |
79 | ||
80 | impl Push<&str> for TargetSpec { | |
81 | fn push(&mut self, key: &str, value: &str) { | |
82 | self.push(key, value.to_string()); | |
83 | } | |
84 | } | |
85 | ||
86 | impl Push<Object> for TargetSpec { | |
87 | fn push(&mut self, key: &str, value: Object) { | |
88 | self.0.push((key.to_string(), Value::Object(value))); | |
89 | } | |
90 | } | |
91 | ||
92 | impl Display for TargetSpec { | |
93 | fn fmt(&self, formatter: &mut Formatter<'_>) -> Result { | |
94 | // We add some newlines for clarity. | |
95 | formatter.write_str("{\n")?; | |
96 | if let [ref rest @ .., ref last] = self.0[..] { | |
97 | for (key, value) in rest { | |
98 | write!(formatter, " \"{}\": {},\n", key, value)?; | |
99 | } | |
100 | write!(formatter, " \"{}\": {}\n", last.0, last.1)?; | |
101 | } | |
102 | formatter.write_str("}") | |
103 | } | |
104 | } | |
105 | ||
106 | struct KernelConfig(HashMap<String, String>); | |
107 | ||
108 | impl KernelConfig { | |
109 | /// Parses `include/config/auto.conf` from `stdin`. | |
110 | fn from_stdin() -> KernelConfig { | |
111 | let mut result = HashMap::new(); | |
112 | ||
113 | let stdin = std::io::stdin(); | |
114 | let mut handle = stdin.lock(); | |
115 | let mut line = String::new(); | |
116 | ||
117 | loop { | |
118 | line.clear(); | |
119 | ||
120 | if handle.read_line(&mut line).unwrap() == 0 { | |
121 | break; | |
122 | } | |
123 | ||
124 | if line.starts_with('#') { | |
125 | continue; | |
126 | } | |
127 | ||
128 | let (key, value) = line.split_once('=').expect("Missing `=` in line."); | |
129 | result.insert(key.to_string(), value.trim_end_matches('\n').to_string()); | |
130 | } | |
131 | ||
132 | KernelConfig(result) | |
133 | } | |
134 | ||
135 | /// Does the option exist in the configuration (any value)? | |
136 | /// | |
137 | /// The argument must be passed without the `CONFIG_` prefix. | |
138 | /// This avoids repetition and it also avoids `fixdep` making us | |
139 | /// depend on it. | |
140 | fn has(&self, option: &str) -> bool { | |
141 | let option = "CONFIG_".to_owned() + option; | |
142 | self.0.contains_key(&option) | |
143 | } | |
144 | } | |
145 | ||
146 | fn main() { | |
147 | let cfg = KernelConfig::from_stdin(); | |
148 | let mut ts = TargetSpec::new(); | |
149 | ||
150 | // `llvm-target`s are taken from `scripts/Makefile.clang`. | |
09498135 MO |
151 | if cfg.has("X86_64") { |
152 | ts.push("arch", "x86_64"); | |
153 | ts.push( | |
154 | "data-layout", | |
155 | "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", | |
156 | ); | |
157 | let mut features = "-3dnow,-3dnowa,-mmx,+soft-float".to_string(); | |
158 | if cfg.has("RETPOLINE") { | |
159 | features += ",+retpoline-external-thunk"; | |
160 | } | |
161 | ts.push("features", features); | |
162 | ts.push("llvm-target", "x86_64-linux-gnu"); | |
163 | ts.push("target-pointer-width", "64"); | |
9a8ff24c MO |
164 | } else { |
165 | panic!("Unsupported architecture"); | |
166 | } | |
167 | ||
168 | ts.push("emit-debug-gdb-scripts", false); | |
169 | ts.push("frame-pointer", "may-omit"); | |
170 | ts.push( | |
171 | "stack-probes", | |
172 | vec![("kind".to_string(), Value::String("none".to_string()))], | |
173 | ); | |
174 | ||
175 | // Everything else is LE, whether `CPU_LITTLE_ENDIAN` is declared or not | |
176 | // (e.g. x86). It is also `rustc`'s default. | |
177 | if cfg.has("CPU_BIG_ENDIAN") { | |
178 | ts.push("target-endian", "big"); | |
179 | } | |
180 | ||
181 | println!("{}", ts); | |
182 | } |