1use std::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum Os {
12 Linux,
13 Macos,
14 Windows,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Arch {
19 X64,
20 Arm64,
21 X86,
22 Arm,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum Libc {
28 Glibc,
29 Musl,
30 None,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub struct Platform {
35 pub os: Os,
36 pub arch: Arch,
37 pub libc: Libc,
38}
39
40impl Os {
41 pub fn current() -> Os {
42 #[cfg(target_os = "linux")]
43 {
44 Os::Linux
45 }
46 #[cfg(target_os = "macos")]
47 {
48 Os::Macos
49 }
50 #[cfg(target_os = "windows")]
51 {
52 Os::Windows
53 }
54 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
55 {
56 compile_error!("unsupported target_os")
57 }
58 }
59
60 pub fn exe_suffix(self) -> &'static str {
62 match self {
63 Os::Windows => ".exe",
64 _ => "",
65 }
66 }
67
68 pub fn node_token(self) -> &'static str {
70 match self {
71 Os::Linux => "linux",
72 Os::Macos => "darwin",
73 Os::Windows => "win",
74 }
75 }
76
77 pub fn go_token(self) -> &'static str {
79 match self {
80 Os::Linux => "linux",
81 Os::Macos => "darwin",
82 Os::Windows => "windows",
83 }
84 }
85}
86
87impl Arch {
88 pub fn current() -> Arch {
89 #[cfg(target_arch = "x86_64")]
90 {
91 Arch::X64
92 }
93 #[cfg(target_arch = "aarch64")]
94 {
95 Arch::Arm64
96 }
97 #[cfg(target_arch = "x86")]
98 {
99 Arch::X86
100 }
101 #[cfg(target_arch = "arm")]
102 {
103 Arch::Arm
104 }
105 #[cfg(not(any(
106 target_arch = "x86_64",
107 target_arch = "aarch64",
108 target_arch = "x86",
109 target_arch = "arm"
110 )))]
111 {
112 compile_error!("unsupported target_arch")
113 }
114 }
115
116 pub fn node_token(self) -> &'static str {
118 match self {
119 Arch::X64 => "x64",
120 Arch::Arm64 => "arm64",
121 Arch::X86 => "x86",
122 Arch::Arm => "armv7l",
123 }
124 }
125
126 pub fn parse_node(value: &str) -> Option<Arch> {
127 match value.trim().to_ascii_lowercase().as_str() {
128 "x64" | "amd64" | "x86_64" => Some(Arch::X64),
129 "arm64" | "aarch64" => Some(Arch::Arm64),
130 "x86" | "ia32" | "i386" | "i686" => Some(Arch::X86),
131 "arm" | "armv7" | "armv7l" => Some(Arch::Arm),
132 _ => None,
133 }
134 }
135
136 pub fn go_token(self) -> &'static str {
138 match self {
139 Arch::X64 => "amd64",
140 Arch::Arm64 => "arm64",
141 Arch::X86 => "386",
142 Arch::Arm => "armv6l",
143 }
144 }
145
146 pub fn llvm_token(self) -> &'static str {
148 match self {
149 Arch::X64 => "x86_64",
150 Arch::Arm64 => "aarch64",
151 Arch::X86 => "i686",
152 Arch::Arm => "armv7",
153 }
154 }
155}
156
157impl Libc {
158 pub fn current() -> Libc {
163 #[cfg(target_os = "linux")]
164 {
165 if cfg!(target_env = "musl") {
166 return Libc::Musl;
167 }
168 if std::path::Path::new("/lib/ld-musl-x86_64.so.1").exists()
170 || std::path::Path::new("/lib/ld-musl-aarch64.so.1").exists()
171 {
172 return Libc::Musl;
173 }
174 Libc::Glibc
175 }
176 #[cfg(not(target_os = "linux"))]
177 {
178 Libc::None
179 }
180 }
181}
182
183impl Platform {
184 pub fn current() -> Platform {
185 Platform {
186 os: Os::current(),
187 arch: Arch::current(),
188 libc: Libc::current(),
189 }
190 }
191
192 pub fn llvm_triple(&self) -> String {
196 let cpu = self.arch.llvm_token();
197 match self.os {
198 Os::Linux => {
199 let libc = match self.libc {
200 Libc::Musl => "musl",
201 _ => "gnu",
202 };
203 format!("{cpu}-unknown-linux-{libc}")
204 }
205 Os::Macos => format!("{cpu}-apple-darwin"),
206 Os::Windows => format!("{cpu}-pc-windows-msvc"),
207 }
208 }
209}
210
211impl fmt::Display for Platform {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 let os = match self.os {
214 Os::Linux => "linux",
215 Os::Macos => "macos",
216 Os::Windows => "windows",
217 };
218 let arch = match self.arch {
219 Arch::X64 => "x64",
220 Arch::Arm64 => "arm64",
221 Arch::X86 => "x86",
222 Arch::Arm => "arm",
223 };
224 write!(f, "{os}-{arch}")?;
225 if matches!(self.libc, Libc::Musl) {
226 write!(f, "-musl")?;
227 }
228 Ok(())
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 #[test]
237 fn llvm_triple_shape() {
238 let p = Platform {
239 os: Os::Linux,
240 arch: Arch::X64,
241 libc: Libc::Glibc,
242 };
243 assert_eq!(p.llvm_triple(), "x86_64-unknown-linux-gnu");
244
245 let p = Platform {
246 os: Os::Macos,
247 arch: Arch::Arm64,
248 libc: Libc::None,
249 };
250 assert_eq!(p.llvm_triple(), "aarch64-apple-darwin");
251
252 let p = Platform {
253 os: Os::Windows,
254 arch: Arch::X64,
255 libc: Libc::None,
256 };
257 assert_eq!(p.llvm_triple(), "x86_64-pc-windows-msvc");
258 }
259
260 #[test]
261 fn tokens() {
262 assert_eq!(Os::Windows.exe_suffix(), ".exe");
263 assert_eq!(Os::Linux.exe_suffix(), "");
264 assert_eq!(Arch::X64.go_token(), "amd64");
265 assert_eq!(Arch::X64.node_token(), "x64");
266 }
267}