generate_rust_target.rs 5.2 KB

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