1use std::borrow::Cow;
2
3use super::{generated, TargetInfo};
4
5impl TargetInfo<'_> {
6 pub(crate) fn llvm_target(
17 &self,
18 rustc_target: &str,
19 version: Option<&str>,
20 ) -> Cow<'static, str> {
21 if rustc_target == "armv7-apple-ios" {
22 return Cow::Borrowed("armv7-apple-ios");
24 } else if self.os == "uefi" {
25 return Cow::Owned(format!("{}-unknown-windows-gnu", self.full_arch));
49 }
50
51 if version.is_none() {
56 if let Ok(index) = generated::LLVM_TARGETS
57 .binary_search_by_key(&rustc_target, |(rustc_target, _)| rustc_target)
58 {
59 let (_, llvm_target) = &generated::LLVM_TARGETS[index];
60 return Cow::Borrowed(llvm_target);
61 }
62 }
63
64 let arch = match self.full_arch {
67 riscv32 if riscv32.starts_with("riscv32") => "riscv32",
68 riscv64 if riscv64.starts_with("riscv64") => "riscv64",
69 "aarch64" if self.vendor == "apple" => "arm64",
70 "armv7" if self.vendor == "sony" => "thumbv7a", arch => arch,
72 };
73 let vendor = match self.vendor {
74 "kmc" | "nintendo" => "unknown",
75 "unknown" if self.os == "android" => "linux",
76 "uwp" => "pc",
77 "espressif" => "",
78 _ if self.arch == "msp430" => "",
79 vendor => vendor,
80 };
81 let os = match self.os {
82 "macos" => "macosx",
83 "visionos" => "xros",
84 "uefi" => "windows",
85 "solid_asp3" | "horizon" | "teeos" | "nuttx" | "espidf" => "none",
86 "nto" => "unknown", "trusty" => "unknown", os => os,
89 };
90 let version = version.unwrap_or("");
91 let env = match self.env {
92 "newlib" | "nto70" | "nto71" | "nto71_iosock" | "p1" | "p2" | "relibc" | "sgx"
93 | "uclibc" => "",
94 env => env,
95 };
96 let abi = match self.abi {
97 "sim" => "simulator",
98 "llvm" | "softfloat" | "uwp" | "vec-extabi" => "",
99 "ilp32" => "_ilp32",
100 "abi64" => "",
101 abi => abi,
102 };
103 Cow::Owned(match (vendor, env, abi) {
104 ("", "", "") => format!("{arch}-{os}{version}"),
105 ("", env, abi) => format!("{arch}-{os}{version}-{env}{abi}"),
106 (vendor, "", "") => format!("{arch}-{vendor}-{os}{version}"),
107 (vendor, env, abi) => format!("{arch}-{vendor}-{os}{version}-{env}{abi}"),
108 })
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use std::process::Command;
115
116 use crate::TargetInfo;
117
118 #[test]
119 fn test_old_ios_target() {
120 assert_eq!(
121 TargetInfo {
122 full_arch: "armv7",
123 arch: "armv7",
124 vendor: "apple",
125 os: "ios",
126 env: "",
127 abi: "",
128 }
129 .llvm_target("armv7-apple-ios", None),
130 "armv7-apple-ios"
131 );
132 }
133
134 #[test]
135 fn basic_llvm_triple_guessing() {
136 assert_eq!(
137 TargetInfo {
138 full_arch: "aarch64",
139 arch: "aarch64",
140 vendor: "unknown",
141 os: "linux",
142 env: "",
143 abi: "",
144 }
145 .llvm_target("invalid", None),
146 "aarch64-unknown-linux"
147 );
148 assert_eq!(
149 TargetInfo {
150 full_arch: "x86_64",
151 arch: "x86_64",
152 vendor: "unknown",
153 os: "linux",
154 env: "gnu",
155 abi: "",
156 }
157 .llvm_target("invalid", None),
158 "x86_64-unknown-linux-gnu"
159 );
160 assert_eq!(
161 TargetInfo {
162 full_arch: "x86_64",
163 arch: "x86_64",
164 vendor: "unknown",
165 os: "linux",
166 env: "gnu",
167 abi: "eabi",
168 }
169 .llvm_target("invalid", None),
170 "x86_64-unknown-linux-gnueabi"
171 );
172 assert_eq!(
173 TargetInfo {
174 full_arch: "x86_64",
175 arch: "x86_64",
176 vendor: "apple",
177 os: "macos",
178 env: "",
179 abi: "",
180 }
181 .llvm_target("invalid", None),
182 "x86_64-apple-macosx"
183 );
184 }
185
186 #[test]
187 fn llvm_version() {
188 assert_eq!(
189 TargetInfo {
190 full_arch: "aarch64",
191 arch: "aarch64",
192 vendor: "apple",
193 os: "ios",
194 env: "",
195 abi: "sim",
196 }
197 .llvm_target("aarch64-apple-ios-sim", Some("14.0")),
198 "arm64-apple-ios14.0-simulator"
199 );
200 assert_eq!(
201 TargetInfo {
202 full_arch: "aarch64",
203 arch: "aarch64",
204 vendor: "apple",
205 os: "visionos",
206 env: "",
207 abi: "",
208 }
209 .llvm_target("aarch64-apple-visionos", Some("2.0")),
210 "arm64-apple-xros2.0"
211 );
212 assert_eq!(
213 TargetInfo {
214 full_arch: "aarch64",
215 arch: "aarch64",
216 vendor: "apple",
217 os: "ios",
218 env: "",
219 abi: "macabi",
220 }
221 .llvm_target("aarch64-apple-ios-macabi", Some("13.1")),
222 "arm64-apple-ios13.1-macabi"
223 );
224 }
225
226 #[test]
227 fn uefi() {
228 assert_eq!(
229 TargetInfo {
230 full_arch: "i686",
231 arch: "x86",
232 vendor: "unknown",
233 os: "uefi",
234 env: "",
235 abi: "",
236 }
237 .llvm_target("i686-unknown-uefi", None),
238 "i686-unknown-windows-gnu"
239 );
240 assert_eq!(
241 TargetInfo {
242 full_arch: "x86_64",
243 arch: "x86_64",
244 vendor: "unknown",
245 os: "uefi",
246 env: "",
247 abi: "",
248 }
249 .llvm_target("x86_64-unknown-uefi", None),
250 "x86_64-unknown-windows-gnu"
251 );
252 assert_eq!(
253 TargetInfo {
254 full_arch: "aarch64",
255 arch: "aarch64",
256 vendor: "unknown",
257 os: "uefi",
258 env: "",
259 abi: "",
260 }
261 .llvm_target("aarch64-unknown-uefi", None),
262 "aarch64-unknown-windows-gnu"
263 );
264 }
265
266 #[test]
267 #[ignore = "not yet done"]
268 fn llvm_for_all_rustc_targets() {
269 let rustc = std::env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string());
270
271 let target_list = Command::new(&rustc)
272 .arg("--print=target-list")
273 .output()
274 .unwrap()
275 .stdout;
276 let target_list = String::from_utf8(target_list).unwrap();
277
278 let mut has_failure = false;
279 for target in target_list.lines() {
280 let spec_json = Command::new(&rustc)
281 .arg("--target")
282 .arg(target)
283 .arg("-Zunstable-options")
284 .arg("--print=target-spec-json")
285 .env("RUSTC_BOOTSTRAP", "1") .output()
287 .unwrap()
288 .stdout;
289 let spec_json = String::from_utf8(spec_json).unwrap();
290
291 let expected = spec_json
293 .split_once("llvm-target\": \"")
294 .unwrap()
295 .1
296 .split_once("\"")
297 .unwrap()
298 .0;
299 let actual = TargetInfo::from_rustc_target(target)
300 .map(|target| target.llvm_target("invalid", None));
301
302 if Some(expected) != actual.as_deref().ok() {
303 eprintln!("failed comparing {target}:");
304 eprintln!(" expected: Ok({expected:?})");
305 eprintln!(" actual: {actual:?}");
306 eprintln!();
307 has_failure = true;
308 }
309 }
310
311 if has_failure {
312 panic!("failed comparing targets");
313 }
314 }
315}